Русский

Учебник по MQL4  Создание обычной программы  Структура обычной программы


Структура обычной программы


Основной отличительной особенностью обычной программы является её структура, позволяющая легко применять те или иные пользовательские функции. Обычно для удобства пользовательские функции оформляются в виде включаемых файлов (.mqh), которые хранятся в каталоге Каталог_терминала\experts\include.

Как правило, обычная программа содержит все три специальные функции, которые вызывают для исполнения необходимые пользовательские функции. Пользовательские функции, в свою очередь, могут вызывать для исполнения другие пользовательские функции, при этом каждая из них имеет своё функционально ограниченное назначение.

В составе эксперта могут применяться пользовательские функции с самыми разнообразными свойствами. Одни функции, например, предназначены для отслеживания событий и удобного вывода информации, другие - для формирования торговых приказов, третьи - для различных вычислений, например, определения торговых критериев, вычисления стоимости ордеров и т.д. Решение о том, какие функции использовать в программе, зависит от назначения эксперта и от того, какой сервис программа должна предоставлять пользователю. На рис. 155 приведена структурная схема обычного торгующего эксперта, построенного на небольшом наборе пользовательских функций.



Рис. 155. Структурная схема обычной программы (эксперт).


Стрелками на структурной схеме показаны связи между различными функциями. Например, функция учёта ордеров вызывается в эксперте из специальной функции init(), специальной функции start(), а также может быть вызвана из любого другого места программы. В правой части схемы показаны стрелки связей, символизирующие возможность вызова одной пользовательской функции из другой. Например, функция определения торговых критериев не вызывается ни из одной специальной функции, но может быть вызвана для исполнения торговой функцией. Информационная функция вызывается из специальной функции deinit(), а также при необходимости вызывается другими функциями, например, функцией обработки ошибок, торговыми функциями, функцией слежения за событиями. Включаемый файл объявления переменных не вызывается ни из одной функции, потому что имеющийся в нём код не является описанием функции, которая может быть вызвана и исполнена. Этот файл содержит строки объявления глобальных переменных, поэтому просто является составной частью эксперта. Для того чтобы понять, каким образом различные части эксперта взаимодействуют между собой, рассмотрим порядок создания и использования включаемых файлов.

Использование включаемых файлов


Если прикладная программа содержит множество программных строк, то её отладка бывает затруднительной - программисту приходится многократно прокручивать текст программы, чтобы внести изменения в код в том или ином месте. В подобных случаях для удобства программа может быть разделена на несколько фрагментов, каждый из которых оформляется в виде отдельного включаемого файла. Включаемые файлы могут содержать любой фрагмент кода, который предполагается использовать в программе. Обычно каждая используемая в программе функция оформляется в виде включаемого файла. Если несколько функций логически связаны между собой, то содержанием одного включаемого файла может быть описание нескольких пользовательских функций.

В разделе Информация о счёте рассматривался пример защитного кода, предотвращающего несанкционированное использование коммерческих программ. В эксперте check.mq4 соответствующая часть программного кода представлена в виде пользовательской функции Check(), описание которой содержится непосредственно в исходном тексте эксперта. В эксперте usualexpert.mq4 (см. рис. 91.3) также используется эта функция, но в этом случае функция оформлена в виде включаемого файла Check.mqh.

Пользовательская функция Check()

bool Check()

Функция возвращает TRUE, если соблюдены условия использования прикладной программы, возвращает FALSE, если условия не соблюдены.

Условия использования программы считаются выполненными, если:

  • программа используется на демо-счёте;
  • счёт открыт в компании SuperBank;
  • при работе на реальном счёте пользователь установил правильное значение внешней переменной Parol.

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

//--------------------------------------------------------------------
// Check.mqh
// Предназначен для использования в качестве примера в учебнике MQL4.
//--------------------------------------------------------------- 1 --
// Функция проверки легальности использования программы
// Входные параметры:
// - глобальная переменная Parol
// - локальная константа "SuperBank"
// Возвращаемые значения:
// true - если условия использования соблюдены
// false - если условия использования нарушены
//--------------------------------------------------------------- 2 --
extern int Parol=12345; // Пароль для работы на реальном счёте
//--------------------------------------------------------------- 3 --
bool Check() // Пользовательская функция
{
if (IsDemo()==true) // Если это демо-счёт, то..
return(true); // .. других ограничений нет
if (AccountCompany()=="SuperBank") // Для корпоративных клиентов..
return(true); // ..пароль не нужен
int Key=AccountNumber()*2+1000001; // Вычисляем ключ
if (Parol==Key) // Если пароль верный, то..
return(true); // ..разрешаем работу на реале
Inform(14); // Сообщение о несанкц. работе
return(false); // Выход из пользов. функции
}
//--------------------------------------------------------------- 4 --

Легко заметить, что название включаемого файла совпадает с названием содержащейся в нём функции. Правилами языка MQL4 такое требование не предусмотрено. В общем случае название включаемого файла не обязательно должно совпадать с названием функции, которая в нём содержится. Тем более это понятно, если учесть, что один файл может нести описание нескольких функций или какого-либо фрагмента программы, вообще не являющегося функцией. Однако практика присваивать включаемому файлу имя, совпадающее с именем описанной в нём функции, оправданна. При этом значительно облегчается труд программиста: он легко может понять, какие функции имеются в каталоге Каталог_терминала\experts\include, ориентируясь по именам файлов. Для того чтобы фрагмент программы, содержащийся в файле, включить в программу, используется директива #include.

Директива #include


#include <Имя файла>
#include "Имя файла"

Директива #include может быть указана в любом месте программы, но обычно все включения размешаются в начале файла исходного текста. Препроцессор заменяет строку #include <имя_файла> (или строку #include "имя_файла") содержимым файла с указанным именем.

Угловые скобки обозначают, что файл будет взят из стандартного каталога Каталог_терминала\experts\include (текущий каталог не просматривается). Если имя файла заключено в кавычки, то поиск производится в текущем каталоге, а именно в том, в котором содержится основной файл исходного текста (стандартный каталог не просматривается).

Ниже представлен обычный эксперт usualexpert.mq4. Все включаемые файлы размещены в головной части программы.

//--------------------------------------------------------------------
// usualexpert.mq4
// Предназначен для использования в качестве примера в учебнике MQL4.
//--------------------------------------------------------------- 1 --
#property copyright "Copyright © Book, 2007"
#property link "http://AutoGraf.dp.ua"
//--------------------------------------------------------------- 2 --
#include <stdlib.mqh>
#include <stderror.mqh>
#include <WinUser32.mqh>
//--------------------------------------------------------------- 3 --
#include <Variables.mqh> // Описание переменных
#include <Check.mqh> // Проверка легальности использов. программ
#include <Terminal.mqh> // Учёт ордеров
#include <Events.mqh> // Функция слежения за событиями, обновлен.
#include <Inform.mqh> // Информационная функция
#include <Trade.mqh> // Торговая функция
#include <Open_Ord.mqh> // Открытие одного ордера заданного типа
#include <Close_All.mqh> // Закрытие всех ордеров заданного типа
#include <Tral_Stop.mqh> // Модификация StopLoss всех ордеров типа
#include <Lot.mqh> // Вычисление количества лотов
#include <Criterion.mqh> // Торговые критерии
#include <Errors.mqh> // Функция обработки ошибок.
//--------------------------------------------------------------- 4 --
int init() // Спец. функция init
{
Level_old=MarketInfo(Symbol(),MODE_STOPLEVEL );//Миним. дистаниция
Terminal(); // Функция учёта ордеров
return; // Выход из init()
}
//--------------------------------------------------------------- 5 --
int start() // Спец. функция start
{
if(Check()==false) // Если условия использования..
return; // ..не выполняются, то выход
PlaySound("tick.wav"); // На каждом тике
Terminal(); // Функция учёта ордеров
Events(); // Информация о событиях
Trade(Criterion()); // Торговая функция
Inform(0); // Для перекрашивания объектов
return; // Выход из start()
}
//--------------------------------------------------------------- 6 --
int deinit() // Спец. функция deinit()
{
Inform(-1); // Для удаления объектов
return; // Выход из deinit()
}
//--------------------------------------------------------------- 7 --

В блоке 2-3 с помощью директивы #include в программу включены стандартные файлы stdlib.mqh, stderror.mqh и WinUser32.mqh. Использование этих файлов в программе бывает необходимо не всегда. Например, файл stderror.mqh содержит определение стандартных констант, используемых при обработке ошибок. Если в программе не предусмотрен анализ ошибок (указанные константы не используются), то включать этот фал в исходный текст нет необходимости. Вместе с тем, в обычной программе, как правило, требуется использование указанных файлов.

В блоке 3-4 в программу включены несколько файлов, содержащих описание пользовательских функций. В том числе, с помощью директивы #include, в строке:

#include <Check.mqh>       // Проверка легальности использов. программ

в исходный текст программы включается пользовательская функция Check(). Программист видит исходный текст эксперта (в данном случае - usualexpert.mq4) таким, каким он представлен выше. Однако при компиляции исходный текст программы преобразуется, а именно: вместо каждой строки, содержащей директиву #include, в программу вставляется текст, содержащийся в файле с указанным именем. Таким образом, исполняемый файл .ex4 создаётся на основе полного кода эксперта, в котором вместо каждой строки #include<Имя файла> (или #include "Имя файла") содержится соответствующий фрагмент кода.

Примером включаемого файла, в котором содержится некоторый фрагмент программы, не являющийся описанием функции, может служить файл Variables.mqh. Этот файл включается в текст программы в строке:

#include <Variables.mqh>   // Описание переменных

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

//--------------------------------------------------------------------
// Variables.mqh
// Предназначен для использования в качестве примера в учебнике MQL4.
//--------------------------------------------------------------- 1 --
// Описание глобальных переменных
extern double Lots = 0.0;// Количество лотов
extern int Percent = 0; // Процент выделенных средств
extern int StopLoss =100; // StopLoss для новых ордеров (пунктов)
extern int TakeProfit =40; // TakeProfit для новых ордеров (пунктов)
extern int TralingStop=100; // TralingStop для рыночных ордеров (пунк)
//--------------------------------------------------------------- 2 --
int
Level_new, // Новое значение минимальной дистанции
Level_old, // Предыдущее значение минимальной дистанции
Mas_Tip[6]; // Массив типов ордеров
// [] тип орд: 0=B,1=S,2=BL,3=SL,4=BS,5=SS
//--------------------------------------------------------------- 3 --
double
Lots_New, // Количество лотов для новых ордеров
Mas_Ord_New[31][9], // Массив ордеров текущий ..
Mas_Ord_Old[31][9]; // .. и старый
// 1й индекс = порядковый номер ордера
// [][0] не определяется
// [][1] курс откр. ордера (абс.знач.курса)
// [][2] StopLoss ордера (абс.знач.курса)
// [][3] TakeProfit ордера (абс.знач.курса)
// [][4] номер ордера
// [][5] колич. лотов орд. (абс.знач.курса)
// [][6] тип орд. 0=B,1=S,2=BL,3=SL,4=BS,5=SS
// [][7] магическое число ордера
// [][8] 0/1 факт наличия комментария
//--------------------------------------------------------------- 4 --

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

В некоторых (редких) случаях имеется техническая возможность объявить глобальную переменную во включаемом файле, описывающем функцию, в которой впервые в программе используется значение этой переменной. В таких случаях необходимо следить за порядком включения файлов. Т.е. требуется, чтобы программная строка с директивой #include, включающей файл (с объявлением глобальной переменной) в программу, находилась выше по тексту, чем строки, включающие другие файлы, где используется значение этой глобальной переменной.

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

В блоке 1-2 включаемого файла Variables.mqh указаны внешние переменные, значения которых определяют количество лотов для новых ордеров, процент свободных средств, выделенный для новых ордеров, заявленные цены для стоп-приказов открываемых рыночных ордеров, а также дистанцию TralingStop для модификации StopLoss ордера. В блоках 2-4 указаны другие глобальные переменные, смысл которых будет понятен при рассмотрении соответствующих пользовательских функций. В следующих разделах главы представлены включаемые файлы, каждый из которых содержит описание одноимённой пользовательской функции.