Программирование советников по индикаторам
Программирование советников, для проверки своей стратегии по каким либо индикаторам – достаточно простое дело. Шаблон для написания советника по индикатору позволяет программировать советники по любым индикаторам!
Рекомендую ознакомится с нашим новым советником: Exp – The xCustomEA Универсальный написать советник по индикатору на пользовательских индикаторах. Советник по индикатору!
И особых познаний в области программирования не нужны.
Я расскажу Вам, как сделать советника за 5 минут на основе каких либо индикаторов.
Данный шаблон подходит только для стратегий , которые явно показывают работу индикатора.
Для заказа более сложных систем – обращайтесь к программистам(Программист MQL, Программист форекс, Советники на заказ).
Такой вид программирования будет платный, но он даст Вам надежность, что Ваша система будет работать именно так, как Вы этого хотите.
Код полностью открытый и комментированный, поэтому Вам не составит особого труда разобраться в его содержимом.
Эта статья предназначена для начинающих, для тех, кто хочет научиться написанию простых советников на новом языке MQL5. Сначала мы определимся с тем, что требуется от нашего советника, а затем приступим к написанию того, каким образом он будет это делать.
1. Торговая стратегия
Что будет делать наш советник:- Он будет следить за некоторыми индикаторами и при определенном условии (или условиях) помещать торговый запрос (на продажу или покупку) в зависимости от условий.
- Мы будем использовать индикатор Moving Average (скользящие средние) с периодом 8 (вы можете выбрать любой период, но в данной стратегии мы будем использовать период 8).
- Мы хотим, чтобы наш советник покупал, если 8-периодная скользящая средняя (далее для удобства будем называть ее MA-8) возрастает и текущая цена закрытия находится выше ее; советник должен продавать, когда MA-8 падает и цена закрытия находится ниже MA-8.
- Также мы собираемся использовать другой индикатор, называемый Average Directional Movement (ADX) с периодом 8 для определения факта наличия тренда на рынке. Это нужно для того, чтобы входить в рынок, когда он находится в состоянии тренда. Для того, чтобы это реализовать, мы будем помещать торговый запрос (на покупку или продажу) при наступлении условий, указанных выше, а также при значениях ADX, больших 22. Если ADX>22, но уменьшается или ADX<22, мы не будем помещать торговые запросы даже при наступлении условий, изложенных в пункте 2.
- Мы хотим защитить себя установкой ордеров Stop Loss в 30 пунктов, Take Proft установим на уровне 100 пунктов.
- Также мы хотим, чтобы советник проверял возможности для продажи/покупки только при формировании нового бара, при этом советник должен помещать ордер на покупку только в случае сигнала на покупку и отсутствия открытых длинных позиций. Аналогично в случае продажи – условия на продажу и отсутствие открытых коротких позиций.
2. Пишем советник
2.1 Мастер MQL5 Начнем с запуска редактора MetaQuotes Language Editor 5. Затем нажимаем Ctrl-N или на кнопку “Создать” в панели инструментов. Рисунок 1. Создание нового документа MQL5 В окне Мастера MQL5 выбираем “Советник” и нажимаем “Далее”, как показано на рис. 2: Рисунок 2. Выбор типа создаваемой программы В следующем окне в поле “Имя” напишите имя, которое вы хотите дать вашему советнику, я написал “My_First_EA“. Вы можете указать свое имя в поле “Автор” и адрес в виде ссылки на ваш сайт или e-mail (если есть). Рисунок 3. Общие параметры советника Поскольку мы хотим иметь возможность менять некоторые параметры нашего советника, для того, чтобы найти лучшие, мы добавим их при помощи кнопки “Добавить”. Рисунок 4. Входные параметры советника В нашем советнике нам нужно иметь возможность изменять Stop Loss, Take Profit, ADX Period and Moving Average Period, так что укажем их здесь. Дважды кликнем мышкой по колонке “Имя” в параметрах и напишем наименование параметра, аналогично в колонках “Тип” и “Начальное значение” укажем тип данных параметра и начальные значения. После этого, результат будет примерно следующий: Рисунок 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.
- #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. Торговля советником разрешена
Теперь, когда мы рассмотрели разделы кода нашего советника, начнем добавления кода в шаблон.
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. Входные параметры советника
Вернемся к нашему коду.
Мы решили добавить дополнительные параметры в наш советник. Параметр 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 – Символьное имя инструмента, на данных которого будет вычисляться индикатор (можно использовать _symbol, symbol() или NULL для текущего символа).
- period – Значение периода может быть одним из значений перечисления ENUM_TIMEFRAMES, (можно использовать _period, period() или 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);
}