Программирование советников по индикаторам | Путешествуем по всему миру!

Avito Путешествия

Программирование советников по индикаторам

Программирование советников, для проверки своей стратегии по каким либо индикаторам – достаточно простое дело. Шаблон для написания советника по индикатору позволяет программировать советники по любым индикаторам!
Рекомендую ознакомится с нашим новым советником: Exp – The xCustomEA Универсальный написать советник по индикатору на пользовательских индикаторах. Советник по индикатору!
И особых познаний в области программирования не нужны.
Я расскажу Вам, как сделать советника за 5 минут на основе каких либо индикаторов.
Данный шаблон подходит только для стратегий , которые явно показывают работу индикатора.
Для заказа более сложных систем – обращайтесь к программистам(Программист MQL, Программист форекс, Советники на заказ).
Такой вид программирования будет платный, но он даст Вам надежность, что Ваша система будет работать именно так, как Вы этого хотите.
Код полностью открытый и комментированный, поэтому Вам не составит особого труда разобраться в его содержимом.
Эта статья предназначена для начинающих, для тех, кто хочет научиться написанию простых советников на новом языке MQL5. Сначала мы определимся с тем, что требуется от нашего советника, а затем приступим к написанию того, каким образом он будет это делать.

1. Торговая стратегия

Что будет делать наш советник:
  • Он будет следить за некоторыми индикаторами и при определенном условии (или условиях) помещать торговый запрос (на продажу или покупку) в зависимости от условий.
Это называется торговой стратегией. Перед тем, как писать советник, сначала нужно разработать стратегию, которую вы хотите автоматизировать в советнике. Давайте конкретизируем нашу стратегию, которую будем применять в советнике.
  1. Мы будем использовать индикатор Moving Average (скользящие средние) с периодом 8 (вы можете выбрать любой период, но в данной стратегии мы будем использовать период 8).
  2. Мы хотим, чтобы наш советник покупал, если 8-периодная скользящая средняя (далее для удобства будем называть ее MA-8) возрастает и текущая цена закрытия находится выше ее; советник должен продавать, когда MA-8 падает и цена закрытия находится ниже MA-8.
  3. Также мы собираемся использовать другой индикатор, называемый Average Directional Movement (ADX) с периодом 8 для определения факта наличия тренда на рынке. Это нужно для того, чтобы входить в рынок, когда он находится в состоянии тренда. Для того, чтобы это реализовать, мы будем помещать торговый запрос (на покупку или продажу) при наступлении условий, указанных выше, а также при значениях ADX, больших 22. Если ADX>22, но уменьшается или ADX<22, мы не будем помещать торговые запросы даже при наступлении условий, изложенных в пункте 2.
  4. Мы хотим защитить себя установкой ордеров Stop Loss в 30 пунктов, Take Proft установим на уровне 100 пунктов.
  5. Также мы хотим, чтобы советник проверял возможности для продажи/покупки только при формировании нового бара, при этом советник должен помещать ордер на покупку только в случае сигнала на покупку и отсутствия открытых длинных позиций. Аналогично в случае продажи – условия на продажу и отсутствие открытых коротких позиций.
Стратегия разработана, теперь время начать писать код.

2. Пишем советник

2.1 Мастер MQL5 Начнем с запуска редактора MetaQuotes Language Editor 5. Затем нажимаем Ctrl-N или на кнопку “Создать” в панели инструментов. Рисунок 1. Создание нового документа MQL5 Рисунок 1. Создание нового документа MQL5 В окне Мастера MQL5 выбираем “Советник” и нажимаем “Далее”, как показано на рис. 2: Рисунок 2. Выбор типа создаваемой программы Рисунок 2. Выбор типа создаваемой программы В следующем окне в поле “Имя” напишите имя, которое вы хотите дать вашему советнику, я написал “My_First_EA“. Вы можете указать свое имя в поле “Автор” и адрес в виде ссылки на ваш сайт или e-mail (если есть). Рисунок 3. Общие свойства советника Рисунок 3. Общие параметры советника Поскольку мы хотим иметь возможность менять некоторые параметры нашего советника, для того, чтобы найти лучшие, мы добавим их при помощи кнопки “Добавить”. Рисунок 4. Входные параметры советника Рисунок 4. Входные параметры советника В нашем советнике нам нужно иметь возможность изменять Stop Loss, Take Profit, ADX Period and Moving Average Period, так что укажем их здесь. Дважды кликнем мышкой по колонке “Имя” в параметрах и напишем наименование параметра, аналогично в колонках “Тип” и “Начальное значение” укажем тип данных параметра и начальные значения. После этого, результат будет примерно следующий: Рисунок 5. Типы данных входных параметров советника Рисунок 5. Типы данных входных параметров советника Как видно, мы выбрали тип integer (int) для всех параметров. Рассмотрим подробнее типы данных.
  • char: Целый тип char занимает в памяти 1 байт (8 бит) и позволяет выразить в двоичной системе счисления 2^8 значений=256. Тип char может содержать как положительные, так и отрицательные значения. Диапазон изменения значений составляет от -128 до 127.
  • uchar: Целый тип uchar также занимает в памяти 1 байт, как и тип char, но в отличие от него, uchar предназначен только для положительных значений. Минимальное значение равно нулю, максимальное значение равно 255. Первая буква u в названии типа uchar является сокращением слова unsigned (беззнаковый).
  • short: Целый тип short имеет размер 2 байта(16 бит) и, соответственно, позволяет выразить множество значений равное 2 в степени 16:  2^16=65 536. Так как тип short является знаковым и содержит как положительные, так и отрицательные значения, то диапазон значений находится между -32 768 и 32 767.
  • ushort: Беззнаковым типом short является тип ushort, который также имеет размер 2 байта. Минимальное значение равно 0, максимальное значение 65 535.
  • int: Целый тип int имеет размер 4 байта (32 бита). Минимальное значение -2 147 483 648, максимальное значение 2 147 483 647.
  • uint: Беззнаковый целый тип uint занимает в памяти 4 байта и позволяет выражать целочисленные значения от 0 до 4 294 967 295.
  • long: Целый тип long имеет размер 8 байт (64 бита). Минимальное значение -9 223 372 036 854 775 808, максимальное значение 9 223 372 036 854 775 807.
  • ulong: Целый тип ulong также занимает 8 байт и позволяет хранить значения от 0 до 18 446 744 073 709 551 615.
Как видно из описания различных типов данных, беззнаковые целые (uint) не предназначены для хранения отрицательных значений, любые попытки установить отрицательные значения могут привести к непредсказуемым результатам. Например, если вы хотите хранить отрицательные значения, нельзя для них использовать переменные типа uchar, uint, ushort, ulong. Вернемся к нашему советнику. Для значений, меньших 127 или 255, для экономии памяти можно использовать значения типа char or uchar, соответственно, однако для удобства мы зададим их значения как тип int. После того, как закончено определение необходимых входных параметров индикатора, нажмем на кнопку “Finish” и MetaQuotes Editor5 создаст шаблон кода, представленный ниже: Для лучшего понимания, рассмотрим отдельно различные секции кода. В верхней части кода (заголовок) определяются свойства советника. Как видно, это значения, которые были установлены в Мастере MQL5 на рис. 3. В этой части кода также можно задать дополнительные параметры, например description (текст с кратким описанием советника), определить константы, включить дополнительные файлы или импортируемые функции. Для выражений, начинающихся с символа “#”, не нужно ставить точку с запятой в конце строки, это директивы препроцессора. Другой пример:
  • #define Директива #define используется для определения констант. Записывается в виде:
  • #define identifier token_string Это означает, что компилятор заменит в коде переменные identifier численным значением, равным token_string.
Например:
#define ABC               100 #define COMPANY_NAME      “MetaQuotes Software Corp.”
В данном случае COMPANY_NAME будет означать строку “MetaQuotes Software Corp.”, вместо ABC будет подразумеваться число, равное 100. Более подробнее о директивах препроцессора можно прочитать в руководстве по MQL5. Идем далее. Вторая часть заголовка в нашем коде – это секция входных параметров. Здесь мы задаем входные параметры, которые будут использоваться в советнике как переменные, они могут быть использованы во всех функциях нашего советника. Переменные, определенные на этом уровне, называются глобальными переменными, поскольку они доступны из любой функции советника. Входные параметры могут быть изменены только вне кода советника при запуске. Также мы можем определить другие переменные, которые будем использовать в нашем советнике, они не будут доступны для модификации извне. Далее идет функция инициализации советника. Это функция вызывается первой после запуска советника или смены графика и вызывается только один раз. Этот раздел – лучшее место для проведения проверок, чтобы убедиться в правильности работы нашего советника. Например, можно проверить, достаточно ли баров на графике для работы нашего советника и т.п. Также это лучшее место для получения хэндлов технических индикаторов, которые будут использоваться (в нашем случае это индикаторы ADX и Moving Average). Функция OnDeinit вызывается при удалении советника с графика. В нашем советнике, в данной функции мы будем освобождать хэндлы индикаторов, созданных в разделе инициализации. Данная функция производит обработку события NewTick, которое генерируется при приходе новой котировки для символа. Большая часть кода, отвечающего за реализацию нашей торговой стратегии будет содержаться в данной функции. Отметим, что советник не сможет производить торговые операции, если в авто-трейдинг не разрешен в клиентском терминале: Рисунок 6. Авто-торговля включена Рисунок 6. Торговля советником разрешена Теперь, когда мы рассмотрели разделы кода нашего советника, начнем добавления кода в шаблон. 2.2. Раздел входных параметров
//--- входные параметры
input int      StopLoss=30;      // Stop Loss
input int      TakeProfit=100;   // Take Profit
input int      ADX_Period=8;     // Период ADX
input int      MA_Period=8;      // Период Moving Average
input int      EA_Magic=12345;   // Magic Number советника
input double   Adx_Min=22.0;     // Минимальное значение ADX
input double   Lot=0.1;          // Количество лотов для торговли
//--- глобальные переменные
int adxHandle; // хэндл индикатора ADX
int maHandle;  // хэндл индикатора Moving Average
double plsDI[],minDI[],adxVal[]; // динамические массивы для хранения численных значений +DI, -DI и ADX для каждого бара
double maVal[]; // динамический массив для хранения значений индикатора Moving Average для каждого бара
double p_close; // переменная для хранения значения close бара
int STP, TKP; // будут использованы для значений Stop Loss и Take Profit
Как видно, мы добавили новые параметры. Перед тем, как обсудить их предназначение, посмотрим на код. При помощи двойного слэша “//” в код можно помещать комментарии. При помощи комментариев мы можем описывать предназначение наших переменных или производимые нами действия. Комментарии позволяют улучшить понимание кода. Существуют два основных способа написания комментариев:
// глобальные переменные …
Это однострочный комментарий.
/* Это многострочный комментарий */
Это многострочный комментарий. Многострочные комментарии начинаются с пары символов “/*” и заканчиваются “*/”. При компиляции кода комментарии игнорируются компилятором. Использование однострочных комментариев для входных параметров позволяет описать предназначение входных параметров. В этом случае вместо наименования параметров будут показаны комментарии, как показано ниже: Рисунок 7. Входные параметры советника Рисунок 7. Входные параметры советника Вернемся к нашему коду. Мы решили добавить дополнительные параметры в наш советник. Параметр EA_Magic (Magic Number)  будет использован для всех ордеров нашего советника. Минимальное значение ADX задано как переменная типа double. Значения типа double используются для констант, которые, наряду с целой частью, также могут содержать и дробную часть. Например:
double mysum = 123.5678; double b7 = 0.09876;
Количество лотов для торговли (Lot) представляет собой объем финансового инструмента, который мы хотим торговать. Далее мы также объявили дополнительные переменные, которые будут использованы следующим образом: переменная adxHandle будет использоваться для хранения хэндла индикатора ADX, переменная maHandle для хэндла индикатора Moving Average. Динамические массивы plsDI[], minDI[], adxVal[] are будут использованы для хранения значений +DI, -DI и самого значения ADX для каждого бара графика. Численные значения индикатора Moving Average для каждого бара графика будут храниться в динамическом массиве maVal[]. Кстати, что представляют собой динамические массивы? Динамический массив – это массив, объявленный без указания размера. Другими словами, в квадратных скобках при его описании нет конкретного числа, указывающего его размер. С другой стороны, для статических массивов их размер определяется при объявлении. Пример:
double allbars[20]; // этот массив содержит 20 элементов – от 0 до 19
Переменная p_close будет использоваться для хранения численного значения цены Close  для бара, который мы собираемся отслеживать в процессе проверки торговых сигналов на покупку и продажу. Переменные STP и TKP нужны для установки значений Stop Loss и Take Profit ордеров нашего советника. 2.3. Секция инициализации советника
int OnInit()
  {
//--- Получить хэндл индикатора ADX
   adxHandle=iADX(NULL,0,ADX_Period);
//--- Получить хэндл индикатора Moving Average
   maHandle=iMA(_Symbol,_Period,MA_Period,0,MODE_EMA,PRICE_CLOSE);
//--- Нужно проверить, не были ли возвращены значения Invalid Handle
   if(adxHandle<0 || maHandle<0)
     {
      Alert("Ошибка при создании индикаторов - номер ошибки: ",GetLastError(),"!!");
     }
Далее мы получаем хэндлы индикаторов, используя соответствующие функции индикаторов. Хэндл индикатора ADX получаем при помощи функции iADX. В качестве аргументов ей передается символ графика symbol (NULL  также означает символ текущего графика), период/таймфрейм (0 означает таймфрейм текущего графика), период индикатора ADX,  который будет использоваться для вычисления индикатора (ADX_Period мы определили в разделе входных параметров индикатора):
int  iADX(
   string          symbol,       // имя символа
   ENUM_TIMEFRAMES  period,       // период
   int            adx_period     // период усреднения индикатора ADX
   );
Хэндл индикатора Moving Average получаем при помощи функции iMA. Аргументы этой функции следующие:
  • symbol – Символьное имя инструмента, на данных которого будет вычисляться индикатор (можно использовать _symbolsymbol() или NULL для текущего символа).
  • period – Значение периода может быть одним из значений перечисления ENUM_TIMEFRAMES, (можно использовать  _periodperiod() или 0 для таймфрейма текущего графика).
  • ma_period – Период усреднения для вычисления скользящего среднего (который мы определили ранее в разделе входных параметров индикатора).
  • ma_shift – Сдвиг индикатора относительно ценового графика (мы используем 0).
  • ma_method – Метод усреднения. Может быть любым из значений MODE_SMA, MODE_EMA, MODE_SMMA или MODE_LWMA.
  • applied_price – Используемая цена. Может быть любой из ценовых констант ENUM_APPLIED_PRICE или хендлом другого индикатора.
int  iMA(
   string              symbol,        // имя символа
   ENUM_TIMEFRAMES      period,        // период
   int                 ma_period,    // период усреднения
   int                 ma_shift,     // смещение индикатора по горизонтали
   ENUM_MA_METHOD       ma_method,    // тип сглаживания
   ENUM_APPLIED_PRICE   applied_price  // тип цены или handle
   );
Для получения более подробной информации, посмотрите справку по этим индикатным функциям в документации по MQL5. Это даст лучшее понимание того, как использовать этот индикатор. Мы проверяем результат выполнения функций на наличие ошибок, в случае неудачи можем получить ошибку INVALID_HANDLE. В этом случае выводим сообщение об ошибке и ее код, используя функцию   GetlastError и завершаем работу советника. Мы решили хранить значения Stop Loss и Take Profit в определенных ранее переменных STP и TKP. Почему мы это сделали? Это сделано потому, что значения входных параметров не могут быть модифицированы, они только для чтения. Мы должны быть уверены в том, что наш советник будет корректно работать со всеми брокерами. Для определения точности цены котировок по текущему символу графика можно воспользоваться Предопределенной переменной _Digits или функцией Digits(). Для 3-х и 5-ти значных котировок мы умножаем значения Stop Loss и Take Profit на 10. 2.4. Раздел деинициализации советника Поскольку эта функция вызывается при прекращении работы советника или удалении советника с графика, здесь мы освобождаем хэндлы индикаторов, созданные в процессе инициализации. Мы создали два индикатора, ADX и Moving Average. Для их удаления мы используем функцию IndicatorRelease(). Эта функция имеет лишь один параметр (хэндл индикатора).
bool  IndicatorRelease( int       indicator_handle,     // хэндл индикатора );
Функция удаляет хэндл индикатора и освобождает расчетную часть индикатора, если ею больше никто не пользуется. 2.5 Раздел OnTick советника Первое, что мы здесь делаем – проверяем достаточно ли баров на текущем графике. Количество баров на любом графике можно узнать при помощи функции Bars. У нее есть два входных параметра, первый – symbol, (символ текущего графика можно получить используя предопределенную переменную _Symbol или функцию Symbol()) и period  или timeframe  текущего графика (для текущего графика  – предопределенная переменная _Period или функция Period()). При количестве баров на графике менее 60, наш советник не будет работать и выйдет из функции OnTick. Функция Alert показывает сообщение в отдельном окне. Эта функция выводит значения аргументов/параметров, разделенных запятыми. В нашем случае выводится только одно значение в виде строки и завершается работа функции OnTick.
Остановимся на главном:
Настройки
extern string Indicators_=” Настройки индикатора”;
/* Здесь прописываем настройки Вашего индикатора\индикаторов */
/* Стандартные переменные для шаблона НЕ ИЗМЕНЯТЬ!!! */
extern string In_=” Настройки входа”;
extern bool ReverseSignal=false; // true – Переворачивать сигнал стратегии.
extern string trade_=”Настройки торговли”;
extern bool StopOrderUSE=false;           // Использовать Отложенные ордера
extern int StopOrderDeltaifUSE=0;         // Дистанция для отложенных ордеров
extern int Magic=777;                     // Магический номер
extern int StopLoss=0;                    // Стоплосс, 0 – не используется
extern int TakeProfit=0;                  // Тейкпрофит , 0 – не используется
extern int Slippage=0;                    // Проскальзывание
extern bool MarketWatch=false;            // Режим торговли по MarketWatch true  = сначала выставляются позиции/ордера без стопов, потом происходит модификация – для некоторых брокеров
extern bool ClosePosifChange=true;        // Закрывать позиции при обратном сигнале
extern bool ONlyOnePosbySignal=true;      // Играть только или бай и / или селл 1 позицией
extern string autolot_=”Настройки автолота”;
extern double Lots=0.1;                   // Фиксирвоанный лот
extern bool DynamicLot=false;             // Динамический лот
extern double LotBalancePcnt=20;          // % от депозита
extern double MaxLot = 5;                 // Максимальный лот при расчете
extern double Martin=1; // Если 1 то не используется, Коэффициент мартина на следующую сделку после убытончой
extern string timetrade_=”Настройки времени торговли”;
extern int OpenHour=0;                    // Час открытия торгов
extern int OpenMinute=0;                  // Минута открытия торгов
extern int CloseHour=23;                  // Час закрытия торгов
extern int CloseMinute=59;                // Минута закрытия торгов
extern string Trailing_=”Настройки трейлингстопа”;
extern bool TrailingStopUSE=false;        // Использовать трейлингстоп
extern bool IfProfTrail=false;            // Использовать только дял профитных позиций – режим безубытка
extern int TrailingStop=0;                // Дистанция трейлинга = 0 – минимально допустимый
extern int TrailingStep=1;                // Шаг дистанции
extern string Trailing_SAR=”Настройки трейлингстопа SAR”;
extern bool TrailingStopSAR=false;        // Использовать трейлингстоп
extern double step   =0.02;//-   Приращение уровня стопа, обычно 0.02.
extern double maximum=0.2;//   –   Максимальный уровень стопа, обычно 0.2.
extern string CloseProfitLoss=” Настройки закрытия по общему профиту”;
extern string  сlose=”= 1 – Доллар, 2 -Пункты ,3 -%Эквити ,4 -%Баланс”;
extern int     TypeofClose=1; // Тип закрытия по прибыли
extern bool CloseProfit=false;// Закрывать если +
extern double prifitessss=10; // Количество юнитов(в зависимости от выбора TypeofClose) для закрытия профита
extern bool CloseLoss=false;// закрывать если –
extern double lossss=-10;// Количество юнитов(в зависимости от выбора TypeofClose) для закрытия убытка
extern bool OFFAllEaAfterClosePROF=false;// Выключать все советники и скрипты после закрытия прибыли.
extern bool OFFAllEaAfterCloseLOSS=false;// Выключать все советники и скрипты после закрытия убытка.
extern string BU_=”Настройки безубытка”;
extern bool MovingInWLUSE=false;   // Перенос позиции в безубыток
extern int LevelWLoss=0; // Переносим стоплосс в +LevelWLoss пунктов
extern int LevelProfit=0;// Когда сделка вышла в плюс LevelProfit пунктов
Как видите в настройках существует блок, в который нужно перенести все внешние параметры индикатора. 
Далее, для запуска Вашей стратегии, необходимо прописать сигналы от Вашего индикатора в блок:
 /* Блок управления сигналом от Вашего индикатора
Создаем переменные для сигналов индикатора
*/
int IndicatorSignal()
{
int Sig=0;
double ExampleMA=iMA(Symbol(),0,20,0,MODE_SMA,PRICE_CLOSE,1); // Пример Вызова МА
double ExampleADX=iADX(Symbol(),0,34,PRICE_CLOSE,MODE_MAIN,1);// Пример Вызова АДХ
double ExampleCustom=iCustom(Symbol(),0,”Moving Averages”,20,0,MODE_SMA,1); // Пример вызова пользовательского индикатора
//Указываем Сигналы:
if( ExampleMA<Bid)Sig=1; // Если МА ниже цены БИД – открываемся в бай
if( ExampleMA>Bid)Sig=2; // Если МА выше цены БИД – открываемся в селл
// 1 – бай 2 – селл
return(Sig);
}