
Пример создания эксперта
Принципы построения пользовательских программ на языке MQL4 рассматриваются на примере создания простейшей экспертной системы на основе стандартного индикатора MACD. В данной экспертной системе также рассмотрены примеры реализации таких функций как выставление уровней тейкпрофита с поддержкой трейлинг-стопа и большинство предохраняющих условий для безопасной работы. В предлагаемом примере торговля идет с открытием и контролем одной позиции.
Принципы торговли:
вход в Long (BUY) – индикатор MACD ниже нуля, идет снизу вверх, а его сверху вниз пересекает сигнальная линия.
вход в Short (SELL) – индикатор MACD выше нуля, идет cверху вниз, а его снизу вверх пересекает сигнальная линия.
выход из Long – по тейкпрофиту, по трейлинг-стопу или при пересечении MACD со своей сигнальной линией (MACD выше нуля, идет cверху вниз, а его снизу вверх пересекает сигнальная линия).
выход из Short – по тейкпрофиту, по трейлинг-стопу или при пересечении MACD со своей сигнальной линией (MACD ниже нуля, идет снизу вверх, а его сверху вниз пересекает сигнальная линия).
Важное замечание: Для исключения из анализа незначительных(мелкие 'бугорки' на графике) изменений индикатора MACD введем дополнительный контроль за размером рисуемых 'бугров' в виде следующего условия – величина индикатора должна составлять не менее 5 единиц минимальной цены (5*Point, что для USD/CHF равно 0.0005, для USD/JPY = 0.05).

1-й этап – создание описания эксперта
![]() |
В окне "Navigator" устанавливаем курсор мыши на разделе "Expert Advisors", нажимаем на правую кнопку мыши и в появившемся меню выбираем команду "Create". Мастер первоначальных настроек эксперта предложит ввести некоторые данные: "Name" – название программы, "Author" – автор программы, "Link" – ссылка на веб-сайт. |
2-й этап – создание первичной структуры программы
Код тестового эксперта будет занимать всего несколько страниц, но и такой объем зачастую бывает труден для восприятия. Особенно, если мы с вами не профессиональные программисты... Так ведь? Иначе этого описания не пришлось бы писать :)
Для ознакомления со структурой стандартного эксперта взглянем на предлагаемое описание:
Инициализация переменных
Первичные проверки данных
проверка графика, количество баров на графике
проверка значений внешних переменных Lots, S/L, T/P, T/S
Установка внутренних переменных для быстрого доступа к данным
Проверка торгового терминала – пустой ли? Eсли да, то:
проверки: если ли деньги на счету и тд...
можно встать в длинную позицию(BUY)?
открыть длинную позицию и выйти
можно встать в короткую позицию(SELL)?
открыть короткую позицию и выйти
Контроль открытых ранее позиций в цикле
если это длинная позиция
нужно ли закрыть?
нужно ли передвинуть трейлинг-стоп?
если это короткая позиция
нужно ли закрыть?
нужно ли передвинуть трейлинг-стоп?
Инициализация переменных
Все переменные, которые будут использоваться в программе-эксперте, должны быть предварительно описаны в соответствии с синтаксисом языка MetaQuotes Language 4. Поэтому в начале программы вставляем блок инициализации переменныхextern double TakeProfit = 50; extern double Lots = 0.1; extern double TrailingStop = 30; extern double MACDOpenLevel=3; extern double MACDCloseLevel=2; extern double MATrendPeriod=26;
В MetaQuotes Language 4 введено такое понятие, как дополнительные пользовательские переменные, которые могут быть установлены извне, без вмешательства в исходный текст программы-эксперта. Это придает дополнительную гибкость. Переменная MATrendPeriod как раз и является такой пользовательской переменной. В начале программы вставляем описание этой переменной.
extern double MATrendPeriod=26;
Первичные проверки данных
Этот кусок кода обычно кочует из одного эксперта в другой с мелкими изменениями – практически стандартный блок проверок:// первичные проверки данных // важно удостовериться что эксперт работает на нормальном графике и // пользователь правильно выставил внешние переменные (Lots, StopLoss, // TakeProfit, TrailingStop) // в нашем случае проверяем только TakeProfit if(Bars<100) { Print("bars less than 100"); return(0); } if(TakeProfit<10) { Print("TakeProfit less than 10"); return(0); // проверяем TakeProfit }
Установка внутренних переменных для быстрого доступа к данным
В коде программы приходится достаточно часто обращаться к значениям индикаторов или оперировать вычисляемыми значениями.int start() { double MacdCurrent, MacdPrevious, SignalCurrent; double SignalPrevious, MaCurrent, MaPrevious; int cnt, ticket, total;
Для облегчения кодирования и ускорения доступа применяется предварительное помещение данных во внутренние переменные.
MacdCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,0); MacdPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,1); SignalCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,0); SignalPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,1); MaCurrent=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,0); MaPrevious=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,1);
Теперь вместо громадной записи iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,0) в тексте программы можно использовать MacdCurrent.
Проверка торгового терминала – пустой ли? Если да, то:
В нашем эксперте мы используем только позиции, открытые по маркету и не трогаем отложенные ордеры. Но для безопасности лучше внесем проверку торгового терминала на наличие выставленных ордеров:// теперь надо определиться - в каком состоянии торговый терминал? // проверим, есть ли ранее открытые позиции или ордеры? total=OrdersTotal(); if(total<1) {
проверки: доступны ли деньги на счете и тд...
Перед анализом рыночной ситуации желательно проверить состояние своего счета – есть ли свободные деньги для открытия позиции?// нет ни одного открытого ордера // на всякий случай проверим, если у нас свободные деньги на счету? // значение 1000 взято для примера, обычно можно открыть 1 лот if(AccountFreeMargin()<(1000*Lots)) { Print("We have no money. Free Margin = ", AccountFreeMargin()); return(0); }
проверка возможности встать в длинную позицию (BUY)
Условие входа в длинную позицию: MACD ниже нуля, идет снизу вверх, а его сверху вниз пересекает сигнальная линия. Как это записывается на MQL4 (обратите внимание что работа идет с сохраненными ранее в переменных значениями индикаторов):// проверяем на возможность встать в длинную позицию (BUY) if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SingnalPrevious && MathAbs(MacdCurrent)>(MACDOpenLevel*Point) && MaCurrent>MaPrevious) { ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0, Ask+TakeProfit*Point,"macd sample", 16384,0,Green); if(ticket>0) { if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) Print("BUY order opened : ",OrderOpenPrice()); } else Print("Error opening BUY order : ",GetLastError()); return(0); }
Выше говорилось о дополнительном контроле за размером рисуемых 'бугров'. Переменная MACDOpenLevel является 'пользовательской' переменной, которую можно менять, не трогая текста программы, для гибкости контроля. В начале программы вставляем описание этой переменной (заодно и описание переменной, используемой ниже).
проверка возможности встать в короткую позицию (SELL)
Условие входа в короткую позицию: MACD выше нуля, идет сверху вниз, а его снизу вверх пересекает сигнальная линия. Как это записывается:// проверяем на возможность встать в короткую позицию (SELL) if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious && MacdCurrent>(MACDOpenLevel*Point) && MaCurrent<MaPrevious) { ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,0, Bid-TakeProfit*Point,"macd sample", 16384,0,Red); if(ticket>0) { if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) Print("SELL order opened : ",OrderOpenPrice()); } else Print("Error opening SELL order : ",GetLastError()); return(0); }
// здесь мы завершили проверку на возможность открытия новых позиций. // новые позиции открыты не были и просто выходим return(0); }
Контроль открытых ранее позиций в цикле
// переходим к важной части эксперта - контролю открытых позиций // 'важно правильно войти в рынок, но выйти - еще важнее...' for(cnt=0;cnt<total;cnt++) { OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES); if(OrderType()<=OP_SELL && // это открытая позиция? OP_BUY или OP_SELL OrderSymbol()==Symbol()) // инструмент совпадает? {
"Cnt" – это переменная цикла, которая должна быть описана в начале программы следующим образом :
int cnt = 0;
Eсли это длинная позиция
if(OrderType()==OP_BUY) // открыта длинная позиция {
нужно ли закрыть?
Условие выхода из длиной позиции: при пересечении MACD со своей сигнальной линией, когда MACD выше нуля, идет вверху вниз, а его снизу вверх пересекает сигнальная линия.// проверим, может уже пора закрываться? if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious && MacdCurrent>(MACDCloseLevel*Point)) { OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet); // закрываем позицию return(0); // выходим }
нужно ли передвинуть трейлинг-стоп?
Трейлинг-стоп выставляем только тогда, когда у позиции уже есть прибыль, превышающая величину трейлинг-стопа в пунктах и если новый уровень стопа лучше предыдущего.// проверим - может можно/нужно уже трейлинг стоп ставить? if(TrailingStop>0) { if(Bid-OrderOpenPrice()>Point*TrailingStop) { if(OrderStopLoss() { OrderModify(OrderTicket(),OrderOpenPrice(), Bid-Point*TrailingStop,OrderTakeProfit(),0,Green); return(0); } } }
Закрываем операторную скобку
}
Eсли это короткая позиция
else // иначе это короткая позиция {
нужно ли закрыть?
Условие выхода из короткой позиции: при пересечении MACD со своей сигнальной линией, когда MACD ниже нуля, идет снизу вверх, а его сверху вниз пересекает сигнальная линия.// проверим, может уже пора закрываться? if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious && MathAbs(MacdCurrent)>(MACDCloseLevel*Point)) { OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet); // закрываем позицию return(0); // выходим }
нужно ли передвинуть трейлинг-стоп?
Трейлинг-стоп выставляем только тогда, когда у позиции уже есть прибыль, превышающая величину трейлинг-стопа в пунктах и если новый уровень стопа лучше предыдущего.// проверим - может можно/нужно уже трейлинг стоп ставить? if(TrailingStop>0) { if((OrderOpenPrice()-Ask)>(Point*TrailingStop)) { if((OrderStopLoss()>(Ask+Point*TrailingStop)) || (OrderStopLoss()==0)) { OrderModify(OrderTicket(),OrderOpenPrice(), Ask+Point*TrailingStop,OrderTakeProfit(),0,Red); return(0); } } }
Закрываем все оставшиеся открытые операторные скобки
} } } return(0); }
Получилось достаточно просто, всего 4 основных блока.
Теперь попробуем по шагам сформировать куски кода под каждый раздел структурной схемы:
Вот так, шаг за шагом и написан эксперт...
3-й этап – сборка результирующего кода программы
Откроем настройки эксперта (кнопка F7 или строка меню "Properties..."). Перед нами появится окно, в котором необходимо выставить внешние настройки параметров работы:

Соберем весь код из предыдущего раздела воедино...
//+------------------------------------------------------------------+ //| MACD Sample.mq4 | //| Copyright © 2005, MetaQuotes Software Corp. | //| https://www.metaquotes.net/ | //+------------------------------------------------------------------+ extern double TakeProfit = 50; extern double Lots = 0.1; extern double TrailingStop = 30; extern double MACDOpenLevel=3; extern double MACDCloseLevel=2; extern double MATrendPeriod=26; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int start() { double MacdCurrent, MacdPrevious, SignalCurrent; double SignalPrevious, MaCurrent, MaPrevious; int cnt=0, ticket, total; // первичные проверки данных // важно удостовериться что эксперт работает на нормальном графике и // пользователь правильно выставил внешние переменные (Lots, StopLoss, // TakeProfit, TrailingStop) // в нашем случае проверяем только TakeProfit if(Bars<100) { Print("bars less than 100"); return(0); } if(TakeProfit<10) { Print("TakeProfit less than 10"); return(0); // проверяем TakeProfit } // ради упрощения и ускорения кода, сохраним необходимые // данные индикаторов во временных переменных MacdCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,0); MacdPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,1); SignalCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,0); SignalPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,1); MaCurrent=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,0); MaPrevious=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,1); total=OrdersTotal(); if(total<1) { // нет ни одного открытого ордера if(AccountFreeMargin()<(1000*Lots)) { Print("We have no money. Free Margin = ", AccountFreeMargin()); return(0); } // проверяем на возможность встать в длинную позицию (BUY) if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious && MathAbs(MacdCurrent)>(MACDOpenLevel*Point) && MaCurrent>MaPrevious) { ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0,Ask+TakeProfit*Point, "macd sample",16384,0,Green); if(ticket>0) { if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) Print("BUY order opened : ",OrderOpenPrice()); } else Print("Error opening BUY order : ",GetLastError()); return(0); } // проверяем на возможность встать в короткую позицию (SELL) if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious && MacdCurrent>(MACDOpenLevel*Point) && MaCurrent<MaPrevious) { ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,0,Bid-TakeProfit*Point, "macd sample",16384,0,Red); if(ticket>0) { if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) Print("SELL order opened : ",OrderOpenPrice()); } else Print("Error opening SELL order : ",GetLastError()); return(0); } return(0); } // переходим к важной части эксперта - контролю открытых позиций // 'важно правильно войти в рынок, но выйти - еще важнее...' for(cnt=0;cnt<total;cnt++) { OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES); if(OrderType()<=OP_SELL && // это открытая позиция? OP_BUY или OP_SELL OrderSymbol()==Symbol()) // инструмент совпадает? { if(OrderType()==OP_BUY) // открыта длинная позиция { // проверим, может уже пора закрываться? if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious && MacdCurrent>(MACDCloseLevel*Point)) { OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet); // закрываем позицию return(0); // выходим } // проверим - может можно/нужно уже трейлинг стоп ставить? if(TrailingStop>0) { if(Bid-OrderOpenPrice()>Point*TrailingStop) { if(OrderStopLoss()<Bid-Point*TrailingStop) { OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*TrailingStop, OrderTakeProfit(),0,Green); return(0); } } } } else // иначе это короткая позиция { // проверим, может уже пора закрываться? if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious && MathAbs(MacdCurrent)>(MACDCloseLevel*Point)) { OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet); // закрываем позицию return(0); // выходим } // проверим - может можно/нужно уже трейлинг стоп ставить? if(TrailingStop>0) { if((OrderOpenPrice()-Ask)>(Point*TrailingStop)) { if((OrderStopLoss()>(Ask+Point*TrailingStop)) || (OrderStopLoss()==0)) { OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*TrailingStop, OrderTakeProfit(),0,Red); return(0); } } } } } } return(0); } // конец.
Для финальной настройки эксперта необходимо лишь указать значения внешних
переменных "Lots = 1", "Stop Loss (S/L) = 0" (не используется), "Take Profit (T/P) = 120" (для часовок
подходит), "Trailing Stop (T/S) = 30". Конечно же, значения вы можете поставить свои.
Нажмите на кнопку "Compile" и, если не
обнаружатся ошибки (кстати, в редактор MetaEditor можно скопировать текст из вышеприведенной распечатки программы),
нажмите на кнопку "Save", чтобы эксперт сохранился.





- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
в общем сначала я пытался печатать по инструкции, потом редактировал как описано в примере. в итоге у меня 60 ошибок и 2 варнинга.
Почитайте статью Типичные ошибки в программах на MQL4 и методы их устранения, думаю, она поможет.
А как сделать так что бы через эксперт добавить функцию (применить к другому индикатору)???
Доброго времени суток!
А может ли кто ответить, насколько этот эксперт соответствует реальной торговле на 2018 год на MQ4?
Сам MQ4 обновился, да и брокеры с тех пор могут взаимодействовать с терминалом несколько иначе.
Ведь с 2005 года с момента написания статьи много воды утекло.
Почитайте статью Типичные ошибки в программах на MQL4 и методы их устранения, думаю, она поможет.