Как написать простейший советник на MQL4? - Такси №1

Как написать простейший советник на MQL4?

Подобным вопросом наверняка задается любой новичок желающий освоить написание экспертов для торговли на рынке FOREX. При желании и некоторой сноровке эту задачу можно решить за один вечер.

Для начала сформулируем правила открытия и закрытия позиций. 

Торговать будем по валютной паре евродоллар на пятиминутке используя сигналы индикаторов Moving Average и Stochastic. Покупаем, когда Moving Average растет и Stochastic снизился ниже уровня перепроданности. Продаем, когда Moving Average убывает и Stochastic вырос выше уровня перекупленности.

Чтобы облегчить задачу написания советника воспользуемся кодом советника Moving Average.mq4 из стандартной библиотеки MetaTrader 4. 

//+------------------------------------------------------------------+//|                                         Moving Average.mq4       |//|                      Copyright © 2005, MetaQuotes Software Corp. |//|                                       http://www.metaquotes.net  |//+------------------------------------------------------------------+#define MAGICMA  20050610extern double Lots               = 0.1;extern double MaximumRisk        = 0.02;extern double DecreaseFactor     = 3;extern double MovingPeriod       = 12;extern double MovingShift        = 6;//+------------------------------------------------------------------+//| Calculate open positions                                         |//+------------------------------------------------------------------+int CalculateCurrentOrders(string symbol)  {   int buys=0,sells=0;//----   for(int i=0;i<OrdersTotal();i++)     {      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;      if(OrderSymbol()==Symbol() && OrderMagicNumber()==MAGICMA)        {         if(OrderType()==OP_BUY)  buys++;         if(OrderType()==OP_SELL) sells++;        }     }//---- return orders volume   if(buys>0) return(buys);   else       return(-sells);  }//+------------------------------------------------------------------+//| Calculate optimal lot size                                       |//+------------------------------------------------------------------+double LotsOptimized()  {   double lot=Lots;   int    orders=HistoryTotal();     // history orders total   int    losses=0;                       // number of losses orders without a break//---- select lot size   lot=NormalizeDouble(AccountFreeMargin()*MaximumRisk/1000.0,1);//---- calcuulate number of losses orders without a break   if(DecreaseFactor>0)     {      for(int i=orders-1;i>=0;i--)        {         if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==false) { Print("Error in history!"); break; }         if(OrderSymbol()!=Symbol() || OrderType()>OP_SELL) continue;         //----         if(OrderProfit()>0) break;         if(OrderProfit()<0) losses++;        }      if(losses>1) lot=NormalizeDouble(lot-lot*losses/DecreaseFactor,1);     }//---- return lot size   if(lot<0.1) lot=0.1;   return(lot);  }//+------------------------------------------------------------------+//| Check for open order conditions                                  |//+------------------------------------------------------------------+void CheckForOpen()  {   double ma;   int    res;//---- go trading only for first tiks of new bar   if(Volume[0]>1) return;//---- get Moving Average    ma=iMA(NULL,0,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE,0);//---- sell conditions   if(Open[1]>ma && Close[1]<ma)       {      res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,0,0,"",MAGICMA,0,Red);      return;     }//---- buy conditions   if(Open[1]<ma && Close[1]>ma)       {      res=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,0,0,"",MAGICMA,0,Blue);      return;     }//----  }//+------------------------------------------------------------------+//| Check for close order conditions                                 |//+------------------------------------------------------------------+void CheckForClose()  {   double ma;//---- go trading only for first tiks of new bar   if(Volume[0]>1) return;//---- get Moving Average    ma=iMA(NULL,0,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE,0);//----   for(int i=0;i<OrdersTotal();i++)     {      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false)        break;      if(OrderMagicNumber()!=MAGICMA || OrderSymbol()!=Symbol()) continue;      //---- check order type       if(OrderType()==OP_BUY)        {         if(Open[1]>ma && Close[1]<ma) OrderClose(OrderTicket(),OrderLots(),Bid,3,White);         break;        }      if(OrderType()==OP_SELL)        {         if(Open[1]<ma && Close[1]>ma) OrderClose(OrderTicket(),OrderLots(),Ask,3,White);         break;        }     }//----  }//+------------------------------------------------------------------+//| Start function                                                   |//+------------------------------------------------------------------+void start()  {//---- check for history and trading   if(Bars<100 || IsTradeAllowed()==false) return;//---- calculate open orders by current symbol   if(CalculateCurrentOrders(Symbol())==0) CheckForOpen();   else                                    CheckForClose();//----  }//+------------------------------------------------------------------+

Немного изменим шапку эксперта и укажем свои внешние переменные:

//+------------------------------------------------------------------+//|                                                     alya-bob.mq4 |//|                                           Copyright © 2011, AM2. |//|                                             www.forexsystems.biz |//+------------------------------------------------------------------+#property copyright "Copyright © 2011, AM2."#property link      "www.forexsystems.biz"#define MAGICMA  20110426extern double StopLoss           = 0.0035;extern double TakeProfit         = 0.007;extern double MovingPeriod     = 20;extern double MovingShift        = 0;extern int StochOversold         = 30;extern int StochOverbought      = 70;

Так как советник у нас простейший убираем из кода функции LotsOptimized() для расчета лота и CheckForClose() предназначенную для закрытия позиций при определенном условии.

Далее запишем значения необходимых индикаторов и условия открытия позиций в функции CheckForOpen():

 double ma0=iMA(NULL,0,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE,0);   double ma1=iMA(NULL,0,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE,1);   double ma2=iMA(NULL,0,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE,2);   double st=iStochastic(NULL,0,5,3,3,MODE_SMA,0,MODE_MAIN,0);//---- buy    if(ma1>ma2 && ma0>ma1  && Close[1]>ma0 && st<StochOversold)       {      res=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,Ask-StopLoss,Ask+TakeProfit,"",MAGICMA,0,Blue);      return;     }      //---- sell      if(ma1<ma2 && ma0<ma1 && Close[1]<ma0 && st>StochOverbought)       {      res=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,Bid+StopLoss,Bid-TakeProfit,"",MAGICMA,0,Red);      return;     }     

И в завершение нашего задания подкорректируем содержание функции start():

//+------------------------------------------------------------------+//|              Start function                                      |//+------------------------------------------------------------------+void start()  {//---- check for history and trading   if(Bars<100 || IsTradeAllowed()==false) return;//---- calculate open orders by current symbol   if(CalculateCurrentOrders(Symbol())==0) CheckForOpen();  }//+------------------------------------------------------------------+

Вот и весь эксперт!

//+------------------------------------------------------------------+//|                                                     alya-bob.mq4 |//|                                           Copyright © 2011, AM2. |//|                                             www.forexsystems.biz |//+------------------------------------------------------------------+#property copyright "Copyright © 2011, AM2."#property link      "www.forexsystems.biz"#define MAGICMA  20110426extern double StopLoss           = 0.0035;extern double TakeProfit         = 0.007;extern double MovingPeriod       = 20;extern double MovingShift        = 0;extern int StochOversold         = 30;extern int StochOverbought       = 70;extern double Lots               = 0.1;//+------------------------------------------------------------------+//| Calculate open positions                                         |//+------------------------------------------------------------------+int CalculateCurrentOrders(string symbol)  {   int buys=0,sells=0;//----   for(int i=0;i<OrdersTotal();i++)     {      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;      if(OrderSymbol()==Symbol() && OrderMagicNumber()==MAGICMA)        {         if(OrderType()==OP_BUY)  buys++;         if(OrderType()==OP_SELL) sells++;        }     }//---- return orders volume   if(buys>0) return(buys);   else       return(-sells);  }//+------------------------------------------------------------------+//| Check for open order conditions                                  |//+------------------------------------------------------------------+void CheckForOpen()  {//---- go trading only for first tiks of new bar   if(Volume[0]>1) return;//---- get Moving Average      int    res;  //----    double ma0=iMA(NULL,0,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE,0); // Значение Moving  Average на текущем баре   double ma1=iMA(NULL,0,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE,1); // Значение Moving  Average на предыдущем баре   double ma2=iMA(NULL,0,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE,2); // Значение Moving  Average на предпредыдущем баре   double st=iStochastic(NULL,0,5,3,3,MODE_SMA,0,MODE_MAIN,0);//---- buy    if(ma1>ma2 && ma0>ma1  && Close[1]>ma0 && st<StochOversold)  // Moving  Average растет, Stochastic ниже уровня перепроданности и цена выше Moving  Average     {      res=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,Ask-StopLoss,Ask+TakeProfit,"",MAGICMA,0,Blue);      return;     }      //---- sell      if(ma1<ma2 && ma0<ma1 && Close[1]<ma0 && st>StochOverbought)  // Moving  Average убывает, Stochastic выше уровня перекупленности и цена ниже Moving  Average     {      res=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,Bid+StopLoss,Bid-TakeProfit,"",MAGICMA,0,Red);      return;     }       }  //+------------------------------------------------------------------+//| Start function                                                   |//+------------------------------------------------------------------+void start()  {//---- check for history and trading   if(Bars<100 || IsTradeAllowed()==false) return;//---- calculate open orders by current symbol   if(CalculateCurrentOrders(Symbol())==0) CheckForOpen();  }//+----------------------------------------------------------------