Пример создания эксперта

Автор: lexy Среда, Сентябрь 10th, 2014 Нет комментариев

Рубрика: Разное

Принципы построения пользовательских программ на языке 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-й этап – создание первичной структуры программы

Код тестового эксперта будет занимать всего несколько страниц, но и такой объем зачастую бывает труден для восприятия. Особенно, если мы с вами не профессиональные программисты… Так ведь? Иначе этого описания не пришлось бы писать :)

Для ознакомления со структурой стандартного эксперта взглянем на предлагаемое описание:

  1. Инициализация переменных
  2. Первичные проверки данных
    • проверка графика, количество баров на графике
    • проверка значений внешних переменных Lots, S/L, T/P, T/S
  3. Установка внутренних переменных для быстрого доступа к данным
  4. Проверка торгового терминала – пустой ли? Eсли да, то:
    • проверки: если ли деньги на счету и тд…
    • можно встать в длинную позицию(BUY)?
      • открыть длинную позицию и выйти
    • можно встать в короткую позицию(SELL)?
      • открыть короткую позицию и выйти

выход из эксперта…

    • Контроль открытых ранее позиций в цикле
      • если это длинная позиция
        • нужно ли закрыть?
        • нужно ли передвинуть трейлинг-стоп?
      • если это короткая позиция
        • нужно ли закрыть?
        • нужно ли передвинуть трейлинг-стоп?

Получилось достаточно просто, всего 4 основных блока.

Теперь попробуем по шагам сформировать куски кода под каждый раздел структурной схемы:

 

    1. Инициализация переменных
      Все переменные, которые будут использоваться в программе-эксперте, должны быть предварительно описаны в соответствии с синтаксисом языка 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;
    2. Первичные проверки данных
      Этот кусок кода обычно кочует из одного эксперта в другой с мелкими изменениями – практически стандартный блок проверок:

      // первичные проверки данных
      // важно удостовериться что эксперт работает на нормальном графике и
      // пользователь правильно выставил внешние переменные (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
           }
    3. Установка внутренних переменных для быстрого доступа к данным
      В коде программы приходится достаточно часто обращаться к значениям индикаторов или оперировать вычисляемыми значениями.

      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.

    4. Проверка торгового терминала – пустой ли? Если да, то:
      В нашем эксперте мы используем только позиции, открытые по маркету и не трогаем отложенные ордеры. Но для безопасности лучше внесем проверку торгового терминала на наличие выставленных ордеров: 

      // теперь надо определиться - в каком состоянии торговый терминал?
      // проверим, есть ли ранее открытые позиции или ордеры?
         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);
           }
    5. Контроль открытых ранее позиций в цикле
         // переходим к важной части эксперта - контролю открытых позиций
         // 'важно правильно войти в рынок, но выйти - еще важнее...'
         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);
          }

Вот так, шаг за шагом и написан эксперт…

3-й этап – сборка результирующего кода программы

Откроем настройки эксперта (кнопка F7 или строка меню «Properties…»). Перед нами появится окно, в котором необходимо выставить внешние настройки параметров работы:

 

Соберем весь код из предыдущего раздела воедино…

//+——————————————————————+ //| MACD Sample.mq4 | //| Copyright © 2005, MetaQuotes Software Corp. | //| http://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», чтобы эксперт сохранился.

 

Источник: mql4.com

Оставить комментарий

Чтобы оставлять комментарии Вы должны быть авторизованы.

Похожие посты