Структура обычной программы
Основной отличительной особенностью обычной программы является её структура, позволяющая
легко применять те или иные пользовательские функции. Обычно для удобства пользовательские
функции оформляются в виде включаемых файлов (.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():
extern int Parol=12345;
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);
}
Легко заметить, что название включаемого файла совпадает с названием содержащейся
в нём функции. Правилами языка MQL4 такое требование не предусмотрено. В общем
случае название включаемого файла не обязательно должно совпадать с названием функции,
которая в нём содержится. Тем более это понятно, если учесть, что один файл может
нести описание нескольких функций или какого-либо фрагмента программы, вообще не
являющегося функцией. Однако практика присваивать включаемому файлу имя, совпадающее
с именем описанной в нём функции, оправданна. При этом значительно облегчается труд
программиста: он легко может понять, какие функции имеются в каталоге Каталог_терминала\experts\include, ориентируясь по именам файлов. Для того чтобы фрагмент программы, содержащийся
в файле, включить в программу, используется директива #include.
Директива #include
#include <Имя файла>
#include "Имя файла" |
Директива #include может быть указана в любом месте программы, но обычно все включения
размешаются в начале файла исходного текста. Препроцессор заменяет строку #include
<имя_файла> (или строку #include "имя_файла") содержимым файла
с указанным именем.
Угловые скобки обозначают, что файл будет взят из стандартного каталога Каталог_терминала\experts\include (текущий каталог не просматривается). Если имя файла заключено в кавычки, то поиск
производится в текущем каталоге, а именно в том, в котором содержится основной
файл исходного текста (стандартный каталог не просматривается).
Ниже представлен обычный эксперт usualexpert.mq4.
Все включаемые файлы размещены в головной части программы.
#property copyright "Copyright © Book, 2007"
#property link "http://AutoGraf.dp.ua"
#include <stdlib.mqh>
#include <stderror.mqh>
#include <WinUser32.mqh>
#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>
#include <Lot.mqh>
#include <Criterion.mqh>
#include <Errors.mqh>
int init()
{
Level_old=MarketInfo(Symbol(),MODE_STOPLEVEL );
Terminal();
return;
}
int start()
{
if(Check()==false)
return;
PlaySound("tick.wav");
Terminal();
Events();
Trade(Criterion());
Inform(0);
return;
}
int deinit()
{
Inform(-1);
return;
}
В блоке 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>
и содержит описание глобальных переменных, которые используются различными пользовательскими
функциями.
extern double Lots = 0.0;
extern int Percent = 0;
extern int StopLoss =100;
extern int TakeProfit =40;
extern int TralingStop=100;
int
Level_new,
Level_old,
Mas_Tip[6];
double
Lots_New,
Mas_Ord_New[31][9],
Mas_Ord_Old[31][9];
В соответствии с правилами MQL4 объявление любой, в том числе и глобальной, переменной
должно осуществляться до первого обращения к этой переменной. По этой причине файл
Variables.mqh включён в программу раньше (выше по тексту), чем файлы функций, использующих
значения указанных в этом файле переменных. По этой же причине в этот файл вынесены
все глобальные переменные.
В некоторых (редких) случаях имеется техническая возможность объявить глобальную
переменную во включаемом файле, описывающем функцию, в которой впервые в программе
используется значение этой переменной. В таких случаях необходимо следить за порядком
включения файлов. Т.е. требуется, чтобы программная строка с директивой #include,
включающей файл (с объявлением глобальной переменной) в программу, находилась
выше по тексту, чем строки, включающие другие файлы, где используется значение этой
глобальной переменной.
В других случаях нет даже указанной технической возможности. Например, если имеется
два включаемых файла, каждый из которых использует две глобальные переменные, одна
из которых объявлена в одном файле, а другая в другом, то при компиляции такой
программы будет получена ошибка, т.к. независимо от порядка включения файлов одна
из переменных используется раньше, чем она объявлена в программе. Поэтому, обычная
практика объявления глобальных переменных в обычной программе предполагает объявление
всех без исключения глобальных переменных в одном файле, который включается в программу
раньше других файлов, содержащих описание пользовательских функций.
В блоке 1-2 включаемого файла Variables.mqh указаны внешние переменные, значения
которых определяют количество лотов для новых ордеров, процент свободных средств,
выделенный для новых ордеров, заявленные цены для стоп-приказов открываемых рыночных
ордеров, а также дистанцию TralingStop для модификации StopLoss ордера. В блоках
2-4 указаны другие глобальные переменные, смысл которых будет понятен при рассмотрении
соответствующих пользовательских функций. В следующих разделах главы представлены включаемые файлы,
каждый из которых содержит описание одноимённой пользовательской функции.