Универсальный шаблон экспертов

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

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

Многие трейдеры сталкивалось с проблемой написания своих экспертов. С чего начать? Как задать в коде советника тейк-профит, стоп-лосс или трейлинг-стоп? Как проверить стратегию на работоспособность? В данной статье рассматриваются основные функции для создания экспертов. Возможно для кого-нибудь код трейлинг-стопа окажется полезным.

Переменные в советнике

Какие же переменные нам нужны в каждом советнике? Как сделать так, чтобы тестировать его только по одному из его условий входа? Как сделать так, чтобы в тестере перебирались и параметры, заданные переменными логического типа (bool)? Во-первых, я задам общий код советника, который работает на всех видах валют; советую для скорости подстроить под Ваш тип валюты. Во-вторых, 0-выключено, 1-включено (мы же хотим все параметры перебирать в оптимизаторе? В готовом коде советую сменить этот параметр, если он редко оптимизируется). В-третьих, переменные уровней (стопов) мы задаем целыми числами, а в коде, где надо, превращаем в дробные. Мы же на разных валютах торгуем, а это универсальный шаблон! В-четвертых, если параметры стопов равны нулю, то данный вид стопа не работает.

Задание переменных

Теперь начнем задавать переменные. Вначале зададим те, которые подвержены оптимизации — внешние переменные.

extern double MaxLot;
extern double TakeProfit;
extern double TrailingStop;
extern double StopLoss;
extern double MinProfit;
extern double ProfitPoints;
extern int    Slippage=0;
extern int Condition1=1;
extern double LotSpliter=1.0;
extern int CloseByOtherSideCondition;

Переменная MaxLot задает максимальный лот, когда мы хотим ограничить максимально используемый лот (лот также ограничен сервером, но об этом мы поговорим далее).
TakeProfit, StopLoss и TrailingStop работают в нашем коде, когда они больше нуля.
MinProfit и ProfitPoints работают, когда ProfitPoints больше нуля по принципу: цена дошла до ProfitPoints и развернулась до MinProfit.
ConditionX включает условия входа.
LotSpliter — делитель лотов, использует только часть лотов из возможных, например, 0.1 включает лоты которые в 10 раз меньше, чем можно сделать ставку на весь депозит.
CloseByOtherSideCondition закрывает ордер при возникновении условий в обратном направлении.
Зададим внутренние переменные, которые будут рассмотрены по ходу описания эксперта.

double Lot;
double PP=0;
double slu,sld,a,b;
double tp,sl;

Код инициализации

Теперь рассмотрим то, что можно рассчитать только при запуске советника, и использовать дальше в коде.

int init()
  {
   tp=TakeProfit;
   sl=StopLoss;
   return(0);
  }

Мы берем значения этих переменных на случай смены стоп-уровней. Также можно сразу расчитать лот, если мы будет торговать все время одинаковой размерностью, а избыток выводить (далее в статье рассмотрен расчет лота). Можно, например, также создать выводимый комментарий с описанием эксперта или авторским правом. Делается это так:

Comment("cloud trade \n v2.0.11");

«\n» — означает переход на следующую строку отображения.

 

Код каркаса

Теперь мы рассмотрим код, когда нет ни единого ордера:

   if(OrdersTotal()==0)
   {
      preinit();
      if(U()==1)
      {
         OrderBuy();
         return(0);
      }
      if(U()==2)
      {
         OrderSell();
         return(0);
      }
      return(0);
   }

Часть из этих функций мы рассмотрим позже, а пока принцип: проводим инициализацию параметров, проверяем, нет ли условий на вход, входим по условию.

Теперь рассмотрим код, когда уже есть один ордер:

 

      if(OrderType()==OP_BUY)
        {
         if((slu)>PP)
           {
            PP=slu;
           }
         if(((slu)>0.001) && (OrderStopLoss()<(b-TrailingStop))
          && (OrderOpenPrice()<(b-TrailingStop))
           && (OrderProfit()>MathAbs(OrderSwap())))
           {
            if(TrailingStop!=0)
              {
               OrderModify(OrderTicket(), 0, b-TrailingStop, 0, 0, 0);
              }
           }
        }
      if(OrderType()==OP_SELL)
        {
         if((sld)>PP)
           {
            PP=sld;
           }
         if(((sld)>0.001) && (OrderStopLoss()>(a+TrailingStop))
          && (OrderOpenPrice()>(a+TrailingStop)))
           {
            if(TrailingStop!=0)
              {
               OrderModify(OrderTicket(), 0, a+TrailingStop, 0, 0, 0);
              }
           }
        }
      if(ProfitPoints!=0)
        {
         if(OrderType()==OP_BUY && PP>=ProfitPoints && (slu)<=MinProfit)
           {
            CloseOnlyOrder(OrderTicket());
            return(0);
           }
         if(OrderType()==OP_SELL && PP>=ProfitPoints && (sld)<=MinProfit)
           {
            CloseOnlyOrder(OrderTicket());
            return(0);
           }
        }
      if(CloseByOtherSideCondition==1)
        {
         if(OrderType()==OP_BUY && U()==2)
           {
            CloseOnlyOrder(OrderTicket());
            return(0);
           }
         if(OrderType()==OP_SELL && U()==1)
           {
            CloseOnlyOrder(OrderTicket());
            return(0);
           }
        }

Вначале мы выбираем единственный ордер для дальнейших операций над ним (позже мы разберем этот код в отдельном разделе статьи). Теперь мы обозначим цены переменными, чтобы не изменять ордер, например, по трелинг-стопу в ненужном направлении, по невыгодным новым ценам. Вначале мы проверяем ордер на возможность трейлинг-стопа, попутно собирая сведения для следующей функции — минимальный профит, применение которой описывалось ранее. Затем идет функция закрытия ордера при возникновении условия в обратном направлении и открытие в противоположную сторону.

Функции, рассматриваемые в статье

Теперь рассмотрим функции, призванные помочь нам укоротить код и объединить в блоки часто используемые команды, чтобы вызывать потом целый блок. Рассмотрим, как задавать условия и проверять их:

//+------------------------------------------------------------------+
//|  возвращает сигнал на покупку или продажу                        |
//+------------------------------------------------------------------+
int U()
  {
      if((U1()==2 && Condition1==1)
       || (U2()==2 && Condition2==1)){return(2);}
      if((U1()==1 && Condition1==1)
       || (U2()==1 && Condition2==1)){return(1);}
   return(0);
  }
//+------------------------------------------------------------------+
//|  возвращает сигнал на основании значений стохастика              |
//+------------------------------------------------------------------+
int U1()
  {
   if(iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing, Method,PriceUsing,MODE_SIGNAL,1)>=80)
     {
      if(iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing,Method,PriceUsing,MODE_SIGNAL,2)
           <=iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing, Method,PriceUsing,MODE_MAIN,2))
        {
         if(iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing,Method,PriceUsing,MODE_SIGNAL,1)
           >=iStochastic(Symbol(),Period(),
              Kperiod,Dperiod,Slowing,Method,PriceUsing,MODE_MAIN,1))
           {
            return(2);
           }
        }
     }
   if(iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing,Method,PriceUsing,MODE_SIGNAL,1)<=20)
     {
      if(iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing,Method,PriceUsing,MODE_SIGNAL,2)
           >=iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing,Method,PriceUsing,MODE_MAIN,2))
        {
         if(iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing, Method,PriceUsing,MODE_SIGNAL,1)
              <=iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing,Method,PriceUsing,MODE_MAIN,1))
           {
            return(1);
           }
        }
     }
   return(0);
  }
//+------------------------------------------------------------------+
//| выясним направление тренда с помощью фракталов                   |
//+------------------------------------------------------------------+
int U2()
  {
   double fu=0,fd=0;
   int f=0,shift=2;
   while(f<2)
     {
      if(iFractals(Symbol(),Period(),MODE_UPPER,shift)>0)
        {
         fu=fu+1;
         f=f+1;
        }
      if(iFractals(Symbol(),Period(),MODE_LOWER,shift)>0)
        {
         fd=fd+1;
         f=f+1;
        }
      shift=shift+1;
     }
   if(fu==2){return(2);}
   if(fd==2){return(1);}
   return(0);
  }

Первая функция просто проверяет условия, две следующих задают условия. А теперь рассмотрим функцию, которая высчитывает уровни стопов, если они заданы неправильно, и определяет размер лота:

//+------------------------------------------------------------------+
//| предварительная инициализация переменных                         |
//+------------------------------------------------------------------+
int preinit()
  {
   Lot=NormalizeDouble(MathFloor(LotSpliter*AccountBalance()*AccountLeverage()
      /Ask/MathPow(10,Digits+1)*10)/10,1);
   if(MaxLot>0 && Lot>MaxLot){Lot=MaxLot;}
   if(Lot>MarketInfo(Symbol(),MODE_MAXLOT)){Lot=MarketInfo(Symbol(),MODE_MAXLOT);}
   PP=0;
   StopLoss=sl;
   TakeProfit=tp;
   if(TakeProfit!=0 && TakeProfit<(MarketInfo(Symbol(),MODE_STOPLEVEL)))
     {
      TakeProfit=MarketInfo(Symbol(),MODE_STOPLEVEL);
     }
   if(StopLoss!=0 && StopLoss<(MarketInfo(Symbol(),MODE_STOPLEVEL)))
     {
      StopLoss=MarketInfo(Symbol(),MODE_STOPLEVEL);
     }
   return(0);
  }

Теперь зададим функции, открывающие ордеры в зависимости от установленных уровней стопов:

//+------------------------------------------------------------------+
//| возвращает true в случае успешного открытия Buy                  |
//+------------------------------------------------------------------+
bool OrderBuy()
  {
   bool res=false;
   if(StopLoss!=0 && TakeProfit!=0)
     {
      res=OrderSend(Symbol(), 0, NormalizeDouble(Lot,1), Ask, Slippage,
       NormalizeDouble(Ask-StopLoss,4),
        NormalizeDouble(Ask+TakeProfit,4), 0, 0, 0, 0);
      return(res);
     }
   if(StopLoss==0 && TakeProfit!=0)
     {
      res=OrderSend(Symbol(), 0, NormalizeDouble(Lot,1), Ask, Slippage, 0,
       NormalizeDouble(Ask+TakeProfit,4), 0, 0, 0, 0);
      return(res);
     }
   if(StopLoss==0 && TakeProfit==0)
     {
      res=OrderSend(Symbol(), 0, NormalizeDouble(Lot,1), Ask,
       Slippage, 0, 0, 0, 0, 0, 0);
      return(res);
     }
   if(StopLoss!=0 && TakeProfit==0)
     {
      res=OrderSend(Symbol(), 0, NormalizeDouble(Lot,1), Ask, Slippage,
       NormalizeDouble(Ask-StopLoss,4), 0, 0, 0, 0, 0);
      return(res);
     }
   return(res);
  }
//+------------------------------------------------------------------+
//|   возвращает true в случае успешного открытия Sell               |
//+------------------------------------------------------------------+
bool OrderSell()
  {
   bool res=false;
   if(StopLoss!=0 && TakeProfit!=0)
     {
      res=OrderSend(Symbol(), OP_SELL, NormalizeDouble(Lot,1), Bid, Slippage,
       NormalizeDouble(Bid+StopLoss,4),
        NormalizeDouble(Bid-TakeProfit,4), 0, 0, 0, 0);
      return(res);
     }
   if(StopLoss==0 && TakeProfit!=0)
     {
      res=OrderSend(Symbol(), OP_SELL, NormalizeDouble(Lot,1), Bid, Slippage,
       NormalizeDouble(Bid+StopLoss,4),
        NormalizeDouble(Bid-TakeProfit,4), 0, 0, 0, 0);
      return(res);
     }
   if(StopLoss==0 && TakeProfit==0)
     {
      res=OrderSend(Symbol(), OP_SELL, NormalizeDouble(Lot,1), Bid, Slippage,
       NormalizeDouble(Bid+StopLoss,4),
        NormalizeDouble(Bid-TakeProfit,4), 0, 0, 0, 0);
      return(res);
     }
   if(StopLoss!=0 && TakeProfit==0)
     {
      res=OrderSend(Symbol(), OP_SELL, NormalizeDouble(Lot,1), Bid, Slippage,
       NormalizeDouble(Bid+StopLoss,4),
        NormalizeDouble(Bid-TakeProfit,4), 0, 0, 0, 0);
      return(res);
     }
   return(res);
  }

Следующая функция закрывает ордер с указанным тикетом, размером и по указанной цене:

//+------------------------------------------------------------------+
//|  возвращает true при успешном закрытии ордера с тикетом Ticket   |
//+------------------------------------------------------------------+
bool CloseOnlyOrder(int Ticket, double Lots ,double priceClose)
  {
   bool res=false;
   res=OrderClose(Ticket, Lots, priceClose, Slippage, 0);
   return(res);

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

//+------------------------------------------------------------------+
//| возвращает true в случае успешного выбора ордера на позиции pos  |
//+------------------------------------------------------------------+
bool SelectOnlyOrder(int pos)
  {
   bool res=false;
   res=OrderSelect(pos,SELECT_BY_POS,MODE_TRADES);
   return(res);
  }
//+------------------------------------------------------------------+

Несколько советов по написанию

Во-первых, задавайте опции в виде 0 и 1 вместо true и false. Это поможет Вам лучше и качественней оптимизировать советника. Во-вторых, не пренебрегайте стоп-лоссом, чтобы ограничить возможные убытки, когда рынок идет в ту сторону, которая противоречит условиям. В-третьих, не тестируйте экспертов без уровня стоп-лосса — это черевато быстрым проигрышем депозита. В-четвертых, используйте функции и блоки, которые помогают облегчить понимание кода.

Заключение

Экспертов создавать очень легко, а чтобы было еще легче, прикладываю эксперт, которого разбирал в статье.

Прикрепленные файлы:
 template.mq4 (8.1 Kb)
Источник: mql4.com

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

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

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