AM2
Андрей

 
Уровень 34

  Торгую в компаниях:


Группа "Программирование на MQL"

Рейтинг 280



Как написать тестер для бинарных опционов

В сети есть великое множество стратегий для бинарных опционов, но при всем при этом тестирование выбранной стратегии в тестере вызывает некоторые затруднения. На примере простого советника разберем написание тестера для БО.

Пусть у нас есть код, который покупает ниже уровня перепроданности и продает выше уровня перекупленности индикатора RSI:




//+------------------------------------------------------------------+
//|                                                          RSI.mq4 |
//|                                              Copyright 2016, AM2 |
//|                                      http://www.forexsystems.biz |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, AM2"
#property link      "http://www.forexsystems.biz"
#property version   "1.00"
#property strict  

//--- Inputs
extern int StopLoss      = 222;      // лось
extern int TakeProfit    = 222;      // язь
extern int Shift         = 1;        // на каком баре сигнал индикатора
extern int Slip          = 100;      // реквот
extern int Magic         = 123;      // магик
extern double Lots       = 0.1;      // лот
extern int RSIPeriod     = 14;       // период RSI 
extern int RSILevel      = 20;       // уровень RSI 

datetime t=0;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {

   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   Comment("");
  }
//+------------------------------------------------------------------+
//| Установка ордера                                                 |
//+------------------------------------------------------------------+
void PutOrder(int type,double price)
  {
   int r=0;
   color clr=Green;
   double sl=0,tp=0;

   if(type==1 || type==3 || type==5)
     {
      clr=Red;
      if(StopLoss>0)   sl=NormalizeDouble(price+StopLoss*Point,Digits);
      if(TakeProfit>0) tp=NormalizeDouble(price-TakeProfit*Point,Digits);
     }

   if(type==0 || type==2 || type==4)
     {
      clr=Blue;
      if(StopLoss>0)   sl=NormalizeDouble(price-StopLoss*Point,Digits);
      if(TakeProfit>0) tp=NormalizeDouble(price+TakeProfit*Point,Digits);
     }

   r=OrderSend(NULL,type,Lots,NormalizeDouble(price,Digits),Slip,sl,tp,"",Magic,0,clr);
   return;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int CountTrades()
  {
   int count=0;
   for(int i=OrdersTotal()-1;i>=0;i--)
     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
        {
         if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic)
           {
            if(OrderType()<2) count++;
           }
        }
     }
   return(count);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OpenPos()
  {
   double rsi=iRSI(NULL,0,RSIPeriod,0,Shift);

   if(rsi<RSILevel)
     {
      PutOrder(0,Ask);
     }

   if(rsi>100-RSILevel)
     {
      PutOrder(1,Bid);
     }
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(CountTrades()<1)
     {
      OpenPos();
      t=Time[0];
     }
  }
//+------------------------------------------------------------------+



Чтобы данную стратегию протестировать на истории установим стопы в 0 и добавим в настройки следующие параметры:


extern string Настроки_Опционов="";
extern double KLot       = 2;        // увеличение лота
extern double MaxLot     = 5000;     // максимальный лот
extern string Expiration = "60";     // истечение в минутах

extern string Настройки_Тестирования="";
extern double WinPercent = 75;       // процент при выигрыше
extern double Stavka     = 50;       // ставка
extern double KStavka    = 2;        // увеличение ставки
extern double MaxStavka  = 5000;     // максимальная ставка


Немного изменится функция установки ордера:


//+------------------------------------------------------------------+
//| Установка ордера                                                 |
//+------------------------------------------------------------------+
void PutOrder(int type,double price)
  {
   int r=0;
   color clr=Green;
   double sl=0,tp=0;
   double lot=Lot();
   if(IsTesting()) lot=Lots;

   if(type==1 || type==3 || type==5)
     {
      clr=Red;
      if(StopLoss>0)   sl=NormalizeDouble(price+StopLoss*Point,Digits);
      if(TakeProfit>0) tp=NormalizeDouble(price-TakeProfit*Point,Digits);
     }

   if(type==0 || type==2 || type==4)
     {
      clr=Blue;
      if(StopLoss>0)   sl=NormalizeDouble(price-StopLoss*Point,Digits);
      if(TakeProfit>0) tp=NormalizeDouble(price+TakeProfit*Point,Digits);
     }

   r=OrderSend(NULL,type,lot,NormalizeDouble(price,Digits),Slip,sl,tp,Expiration,Magic,0,clr);
   return;
  }


Также для торговли бинариками нам нужно будет подсчитывать количество лосей:


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int Losses()
  {
   int losses=0;
   for(int i=OrdersHistoryTotal()-1;i>=0;i--)
     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY))
        {
         if(OrderProfit()>0) break;
         if(OrderProfit()<0) losses++;
        }
     }
   return(losses);
  }


и затем рассчитывать лот:


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double Lot()
  {
   double lot=0;
   lot=Lots*MathPow(KLot,Losses());
   if(lot>MaxLot) lot=Lots;
   return(lot);
  }


Результаты на экран будем выводить с помощью меток:


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void PutLabel(string text,string n,int x,int y)
  {
//--- создадим текстовую метку
   ObjectCreate(0,n,OBJ_LABEL,0,0,0);

//--- установим координаты метки
   ObjectSetInteger(0,n,OBJPROP_XDISTANCE,x);
   ObjectSetInteger(0,n,OBJPROP_YDISTANCE,y);
//--- установим угол графика, относительно которого будут определяться координаты точки
   ObjectSetInteger(0,n,OBJPROP_CORNER,CORNER_RIGHT_UPPER);
//--- установим текст
   ObjectSetString(0,n,OBJPROP_TEXT,text);
//--- установим шрифт текста
   ObjectSetString(0,n,OBJPROP_FONT,"Arial");
//--- установим размер шрифта
   ObjectSetInteger(0,n,OBJPROP_FONTSIZE,12);
//--- установим цвет
   ObjectSetInteger(0,n,OBJPROP_COLOR,Red);
  }


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


//+------------------------------------------------------------------+
//| Закрытие позиции по типу ордера                                  |
//+------------------------------------------------------------------+
void CloseAll(int ot=-1)
  {
   bool cl;
   for(int i=OrdersTotal()-1;i>=0;i--)
     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
        {
         if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic)
           {
            if(OrderType()==0 && (ot==0 || ot==-1))
              {
               RefreshRates();
               cl=OrderClose(OrderTicket(),OrderLots(),NormalizeDouble(Bid,Digits),Slip,White);
              }
            if(OrderType()==1 && (ot==1 || ot==-1))
              {
               RefreshRates();
               cl=OrderClose(OrderTicket(),OrderLots(),NormalizeDouble(Ask,Digits),Slip,White);
              }
           }
        }
     }
  }


и вычисление времени открытия позиции:


//+------------------------------------------------------------------+
//| Время открытия позиции                                           |
//+------------------------------------------------------------------+
datetime OrderTime()
  {
   datetime tm=0;
   for(int i=OrdersTotal()-1;i>=0;i--)
     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
        {
         if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic)
           {
            if(OrderType()<2) tm=OrderOpenTime();
           }
        }
     }
   return(tm);
  }


Также только в режиме тестирования будем рассчитывать ставку:


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double Stavim()
  {
   double s=Stavka;
   s=NormalizeDouble(Stavka*MathPow(KStavka,Losses()),2);
   if(s>MaxStavka) s=Stavka;
   return(s);
  }


и профит с учетом вознаграждения:


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double Profit()
  {
   double pr=0;
   int losses=0;

   for(int i=OrdersHistoryTotal()-1;i>=0;i--)
     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY))
        {
         if(OrderProfit()>0)
           {
            pr+=NormalizeDouble(Stavka*MathPow(KStavka,losses),2)*WinPercent*0.01;
            losses=0;
           }
         if(OrderProfit()<0)
           {
            pr-=NormalizeDouble(Stavka*MathPow(KStavka,losses),2);
            losses++;
           }
        }
     }
   return(pr);
  }


И вот все необходимые функции у нас есть остается только добавить их в советник, чтобы они посчитали нам профит:


   if(TimeCurrent()-OrderTime()>=(int)Expiration*60 && IsTesting())
     {
      CloseAll();
     }

   PutLabel("Profit: "+(string)Profit(),"P",120,20);
   PutLabel("Stavka: "+(string)Stavim(),"S",120,40);
   PutLabel("Losses: "+(string)Losses(),"L",120,60);


Теперь соберем все это в советник:


//+------------------------------------------------------------------+
//|                                                          RSI.mq4 |
//|                                              Copyright 2016, AM2 |
//|                                      http://www.forexsystems.biz |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, AM2"
#property link      "http://www.forexsystems.biz"
#property version   "1.00"
#property strict  

//--- Inputs
extern int StopLoss      = 222;      // лось
extern int TakeProfit    = 222;      // язь
extern int Shift         = 1;        // на каком баре сигнал индикатора
extern int Slip          = 100;      // реквот
extern int Magic         = 123;      // магик
extern double Lots       = 0.1;      // лот
extern int RSIPeriod     = 14;       // период RSI 
extern int RSILevel      = 20;       // уровень RSI 

extern string Настроки_Опционов="";
extern double KLot       = 2;        // увеличение лота
extern double MaxLot     = 5000;     // максимальный лот
extern string Expiration = "60";     // истечение в минутах

extern string Настройки_Тестирования="";
extern double WinPercent = 75;       // процент при выигрыше
extern double Stavka     = 50;       // ставка
extern double KStavka    = 2;        // увеличение ставки
extern double MaxStavka  = 5000;     // максимальная ставка

datetime t=0;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {

   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   Comment("");
  }
//+------------------------------------------------------------------+
//| Установка ордера                                                 |
//+------------------------------------------------------------------+
void PutOrder(int type,double price)
  {
   int r=0;
   color clr=Green;
   double sl=0,tp=0;
   double lot=Lot();
   if(IsTesting()) lot=Lots;

   if(type==1 || type==3 || type==5)
     {
      clr=Red;
      if(StopLoss>0)   sl=NormalizeDouble(price+StopLoss*Point,Digits);
      if(TakeProfit>0) tp=NormalizeDouble(price-TakeProfit*Point,Digits);
     }

   if(type==0 || type==2 || type==4)
     {
      clr=Blue;
      if(StopLoss>0)   sl=NormalizeDouble(price-StopLoss*Point,Digits);
      if(TakeProfit>0) tp=NormalizeDouble(price+TakeProfit*Point,Digits);
     }

   r=OrderSend(NULL,type,lot,NormalizeDouble(price,Digits),Slip,sl,tp,Expiration,Magic,0,clr);
   return;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double Lot()
  {
   double lot=0;
   lot=Lots*MathPow(KLot,Losses());
   if(lot>MaxLot) lot=Lots;
   return(lot);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int Losses()
  {
   int losses=0;
   for(int i=OrdersHistoryTotal()-1;i>=0;i--)
     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY))
        {
         if(OrderProfit()>0) break;
         if(OrderProfit()<0) losses++;
        }
     }
   return(losses);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int CountTrades()
  {
   int count=0;
   for(int i=OrdersTotal()-1;i>=0;i--)
     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
        {
         if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic)
           {
            if(OrderType()<2) count++;
           }
        }
     }
   return(count);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OpenPos()
  {
   double rsi=iRSI(NULL,0,RSIPeriod,0,Shift);

   if(rsi<RSILevel)
     {
      PutOrder(0,Ask);
     }

   if(rsi>100-RSILevel)
     {
      PutOrder(1,Bid);
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void PutLabel(string text,string n,int x,int y)
  {
//--- создадим текстовую метку
   ObjectCreate(0,n,OBJ_LABEL,0,0,0);

//--- установим координаты метки
   ObjectSetInteger(0,n,OBJPROP_XDISTANCE,x);
   ObjectSetInteger(0,n,OBJPROP_YDISTANCE,y);
//--- установим угол графика, относительно которого будут определяться координаты точки
   ObjectSetInteger(0,n,OBJPROP_CORNER,CORNER_RIGHT_UPPER);
//--- установим текст
   ObjectSetString(0,n,OBJPROP_TEXT,text);
//--- установим шрифт текста
   ObjectSetString(0,n,OBJPROP_FONT,"Arial");
//--- установим размер шрифта
   ObjectSetInteger(0,n,OBJPROP_FONTSIZE,12);
//--- установим цвет
   ObjectSetInteger(0,n,OBJPROP_COLOR,Red);
  }
//+------------------------------------------------------------------+
//| Закрытие позиции по типу ордера                                  |
//+------------------------------------------------------------------+
void CloseAll(int ot=-1)
  {
   bool cl;
   for(int i=OrdersTotal()-1;i>=0;i--)
     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
        {
         if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic)
           {
            if(OrderType()==0 && (ot==0 || ot==-1))
              {
               RefreshRates();
               cl=OrderClose(OrderTicket(),OrderLots(),NormalizeDouble(Bid,Digits),Slip,White);
              }
            if(OrderType()==1 && (ot==1 || ot==-1))
              {
               RefreshRates();
               cl=OrderClose(OrderTicket(),OrderLots(),NormalizeDouble(Ask,Digits),Slip,White);
              }
           }
        }
     }
  }
//+------------------------------------------------------------------+
//| Время открытия позиции                                           |
//+------------------------------------------------------------------+
datetime OrderTime()
  {
   datetime tm=0;
   for(int i=OrdersTotal()-1;i>=0;i--)
     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
        {
         if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic)
           {
            if(OrderType()<2) tm=OrderOpenTime();
           }
        }
     }
   return(tm);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double Stavim()
  {
   double s=Stavka;
   s=NormalizeDouble(Stavka*MathPow(KStavka,Losses()),2);
   if(s>MaxStavka) s=Stavka;
   return(s);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double Profit()
  {
   double pr=0;
   int losses=0;

   for(int i=OrdersHistoryTotal()-1;i>=0;i--)
     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY))
        {
         if(OrderProfit()>0)
           {
            pr+=NormalizeDouble(Stavka*MathPow(KStavka,losses),2)*WinPercent*0.01;
            losses=0;
           }
         if(OrderProfit()<0)
           {
            pr-=NormalizeDouble(Stavka*MathPow(KStavka,losses),2);
            losses++;
           }
        }
     }
   return(pr);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(CountTrades()<1)
     {
      OpenPos();
      t=Time[0];
     }

   if(TimeCurrent()-OrderTime()>=(int)Expiration*60 && IsTesting())
     {
      CloseAll();
     }

   PutLabel("Profit: "+(string)Profit(),"P",120,20);
   PutLabel("Stavka: "+(string)Stavim(),"S",120,40);
   PutLabel("Losses: "+(string)Losses(),"L",120,60);
  }
//+------------------------------------------------------------------+



И посмотрим на результаты:



Скачать советник можно по ссылке: www.opentraders.ru/downloads/1436/
  • +9
  • Просмотров: 6873
  • 25 декабря 2016, 20:51
  • AM2
Понравилcя материал? Не забудьте поставить плюс и поделиться в социальной сети!

Вступите в группу "Программирование на MQL", чтобы следить за обновлениями
ПРИСОЕДИНИТЬСЯ К ГРУППЕ
присоединиться
26 сентября 2016
09 сентября 2017

Комментарии (3)

+
0
а если надо узнать соотношение прибыльных к убыточным сделкам?*???* 
avatar

  8  Kudryashov Сообщений: 129

  • 26 июля 2018, 21:42
+
0
при желании тоже можно посчитать
avatar

  34  AM2 Автор Сообщений: 15826 - Андрей

  • 26 июля 2018, 21:46
+
0
потестил это… не айс*rabota*  бывает что цена закрытие выше цены открытия но советник считает ее проигрышной*???* 
avatar

  8  Kudryashov Сообщений: 129

  • 16 августа 2018, 22:22

Зарегистрируйтесь или авторизуйтесь, чтобы оставить комментарий
Начать торговлю с Альпари