Русский

Учебник по MQL4  Программа на MQL4  Примеры реализации

Примеры реализации


В предыдущем параграфе рассматривался пример исполнения специальных функций в простом эксперте simple.mq4. Для того, чтобы закрепить материал, необходимо рассмотреть ещё несколько модификаций этой программы.

Пример правильной структуры программы

Как правило, описания функций в программе указываются в той последовательности, в которой они вызываются для исполнения клиентским терминалом, а именно, сначала приводится описание специальной функции init(), затем специальной функции start(), и последним указывается описание специальной функции deinit(). Однако специальные функции вызываются для исполнения клиентским терминалом в соответствии с их собственными свойствами, поэтому не имеет значения, в каком месте программы указано описание той или иной функции. Давайте переставим местами специальные функции и посмотрим, что из этого получится (эксперт possible.mq4).

//--------------------------------------------------------------------
// possible.mq4
// Предназначен для использования в качестве примера в учебнике MQL4.
//--------------------------------------------------------------------
int Count=0; // Глобальная перемен.
//--------------------------------------------------------------------
int start() // Спец. ф-ия start()
{
double Price = Bid; // Локальная перемен.
Count++;
Alert("Новый тик ",Count," Цена = ",Price);// Сообщение
return; // Выход из start()
}
//--------------------------------------------------------------------
int init() // Спец. ф-ия init()
{
Alert ("Сработала ф-ия init() при запуске"); // Сообщение
return; // Выход из init()
}
//--------------------------------------------------------------------
int deinit() // Спец. ф-ия deinit()
{
Alert ("Сработала ф-ия deinit() при выгрузке");// Сообщение
return; // Выход из deinit()
}
//--------------------------------------------------------------------

Запустив этот эксперт на выполнение, легко убедиться, что порядок исполнения специальных функций в программе не зависит от порядка следования в программе описаний специальных функций. Вы можете самостоятельно по своему выбору поменять местами специальные функции в исходном коде и убедиться, что для любого варианта результат будет таким же, как и в случае исполнения эксперта simple.mq4.

Пример неправильной структуры программы

Совсем иные события произойдут, если в программе изменить положение головной части. В данном примере специальная функция start() указана раньше (выше по тексту), чем головная часть программы (эксперт incorrect.mq4):

//--------------------------------------------------------------------
// incorrect.mq4
// Предназначен для использования в качестве примера в учебнике MQL4.
//--------------------------------------------------------------------
int start() // Спец. ф-ия start()
{
double Price = Bid; // Локальная перемен.
Count++;
Alert ("Новый тик ",Count," Цена = ",Price);// Сообщение
return; // Выход из start()
}
//--------------------------------------------------------------------
int Count=0; // Глобальная перемен.
//--------------------------------------------------------------------
int init() // Спец. ф-ия init()
{
Alert ("Сработала ф-ия init() при запуске"); // Сообщение
return; // Выход из init()
}
//--------------------------------------------------------------------
int deinit() // Спец. ф-ия deinit()
{
Alert ("Сработала ф-ия deinit() при выгрузке");// Сообщение
return; // Выход из deinit()
}
//--------------------------------------------------------------------

При попытке компиляции этого эксперта редактор MetaEditor выдаст сообщение об ошибке:


Рис. 36. Сообщение об ошибках при компиляции программы incorrect.mq4.

В данном случае строка

int Count=0;                                    // Глобальная перемен.

написана за пределами всех функций, но находится не в первых строках программы, а где-то в середине.

Определяющим моментом в структуре этой программы является то, что объявление глобальной переменной Count происходит после объявления функции (в данном случае - специальной функции start()). На данном этапе изложения мы не можем обсуждать подробности применения глобальных переменных; виды переменных и правила их использования приведены в разделе Переменные. Здесь достаточно сказать, что любая глобальная переменная должна быть объявлена раньше (выше по тексту программы), чем первое обращение к этой переменной (в данном случае из функции start()). В рассматриваемой программе это правило нарушено, поэтому компилятор сообщил об ошибке.

Пример применения пользовательской функции

Теперь посмотрим, как программа проявляется в отношении пользовательских функций. Для этого несколько модернизируем код, представленный в примере простого эксперта simple.mq4, и подробно его разберём. Программа, содержащая пользовательскую функцию, будет выглядеть так (эксперт userfunction.mq4):

//--------------------------------------------------------------------
// userfunction.mq4
// Предназначен для использования в качестве примера в учебнике MQL4.
//--------------------------------------------------------------------
int Count=0; // Глобальная перемен.
//--------------------------------------------------------------------
int init() // Спец. ф-ия init()
{
Alert ("Сработала ф-ия init() при запуске"); // Сообщение
return; // Выход из init()
}
//--------------------------------------------------------------------
int start() // Спец. ф-ия start()
{
double Price = Bid; // Локальная перемен.
My_Function(); // Вызов польз. ф-ии
Alert("Новый тик ",Count," Цена = ",Price);// Сообщение
return; // Выход из start()
}
//--------------------------------------------------------------------
int deinit() // Спец. ф-ия deinit()
{
Alert ("Сработала ф-ия deinit() при выгрузке");// Сообщение
return; // Выход из deinit()
}
//--------------------------------------------------------------------
int My_Function() // Описание польз.ф-ии
{
Count++; // Счётчик обращений
}
//--------------------------------------------------------------------

Прежде всего, посмотрим, какие внесены изменения и какая часть кода осталась нетронутой.

Остались без изменений:

1. Головная часть осталась без изменений.

// userfunction.mq4
// Предназначен для использования в качестве примера в учебнике MQL4.
//--------------------------------------------------------------------
int Count=0; // Глобальная перемен.

2. Специальная функция init() осталась без изменений.

int init()                                      // Спец. ф-ия init()
{
Alert ("Сработала ф-ия init() при запуске"); // Сообщение
return; // Выход из init()
}

3. Специальная функция deinit() осталась без изменений.

int deinit()                                    // Спец. ф-ия deinit()
{
Alert("Сработала ф-ия deinit() при выгрузке");// Сообщение
return; // Выход из deinit()
}

Изменения:

1. Добавилась пользовательская функция My_Function().

int My_Function()                               // Описание польз.ф-ии
{
Count++; // Счётчик обращений
}

2. Претерпел изменение код специальной функции start(): в нём появилось обращение к пользовательской функции, а также отсутствует строка вычисления переменной Count.

int start()                                     // Спец. ф-ия start()
{
double Price = Bid; // Локальная перемен.
My_Function(); // Вызов польз. ф-ии
Alert("Новый тик ",Count," Цена = ",Price);// Сообщение
return; // Выход из start()
}

В разделе Выполнение программы рассматривался порядок исполнения специальных функций init() и deinit(). В данном примере исполнение этих функций будет происходить так же, поэтому здесь нет необходимости останавливаться на их работе. Рассмотрим исполнение специальной функции start() и пользовательской функции My_Function(). Описание пользовательской функции расположено за пределами всех специальных функций, как и должно быть. Вызов пользовательской функции указан в коде специальной функции start(), что тоже верно.

После того, как исполнится специальная функция init(), программа будет исполняться так:

31. Специальная функция start() находится в ожидании запуска клиентским терминалом. С приходом нового тика терминал запустит функцию start() на исполнение, в результате чего произойдут следующие события:

32 (1). В строке

      double Price = Bid;                        // Локальная перемен.

производятся те же действия:

32.1(1). Инициализация локальной переменной Price (см. Виды переменных). Значение этой локальной переменной будет доступно из любого места специальной функции start().

32.2(1). Выполнение оператора присваивания. Переменной Price будет присвоено последнее известное значение текущей цены Bid (например, на первом тике цена финансового инструмента окажется равной 1.2744).

33(1). Следующей записью в коде является обращение к пользовательской функции My_Function():

   My_Function();                                // Вызов польз. ф-ии

Эта строка будет исполнена в рамках продолжающейся работы специальной функции start(). Результатом выполнения этой части кода (обращение к пользовательской функции) будет передача управления в тело (описание) пользовательской функции с последующим возвратом управления в место вызова.

34(1). В описании пользовательской функции имеется всего один оператор:

   Count++;

При первом вызове пользовательской функции значение переменной Count равно нулю. В результате выполнения оператора Count++ значение переменной Count будет увеличено на единицу. Исполнив этот оператор (единственный и последний) пользовательская функция заканчивает свою работу и передаёт управление в то место, откуда она была вызвана.

Необходимо подчеркнуть, что пользовательские функции могут быть вызваны для работы только из специальных функций ( или из других пользовательских, которые в конечном счёте всё равно вызваны из специальных). Поэтому справедливым является утверждение, что в любой текущий момент работает одна из специальных функций (или специальная функция start() может находиться в состоянии ожидания нового тика - запуска её на исполнение клиентским терминалом), а пользовательские функции исполняются лишь в рамках исполнения специальных функций.

В данном случае управление возвращается в (исполняющуюся) специальную функцию start(), а именно в строку, следующую за оператором вызова функции:

35(1). В этой строке содержится вызов функции Alert():

   Alert ("Новый тик ",Count,"   Цена = ",Price);// Сообщение

Функция Alert() выведет в окно сообщения все константы и переменные, перечисленные в круглых скобках:

Новый тик 1 Цена = 1.2744

36(1). Оператор

   return;                                       // Выход из start()

заканчивает работу специальной функции start().

37. Управление передаётся клиентскому терминалу на ожидание нового тика.

При следующих исполнениях специальной функции start() переменные получат новые значения и снова будут выведены в окно сообщения функции Alert(), т.е. программа снова выполнится по пп 32 - 36. В том числе, при каждом исполнении функции start() (на каждом тике) будет срабатывать обращение к пользовательской функции My_Function(), и эта функция будет выполняться. Исполнение специальной функции start() будет продолжаться до тех пор, пока пользователь не примет решение о прекращении работы программы. В этом случае отработает специальная функция deinit() и программа прекратит свою работу.

Запущенная на исполнение программа userfunction.ех4 отобразит на экране окно, в котором будут выводиться сообщения функции Alert(). Обратите внимание, результат работы программы будет таким же, как и результат работы простого эксперта simple.mq4. Легко увидеть, что структура программы userfunction.mq4 составлена в соответствии с обычным порядком расположения функциональных блоков. Если же этот порядок изменить на другой допустимый порядок, то результат работы программы не изменится.