Двухэтапный вариант модификации открытых позиций

Genkov | 9 мая, 2008


Введение

В статье "Подход Т. Демарка к техническому анализу" есть рекомендованные коэффициенты длины коррекции, в частности 0,382 и 0,618. Применяя эти коэффициенты при отслеживании открытых позиций, можно избежать ненужных ситуаций закрытия и переоткрытия позиций в ситуациях близких к трендовым. Функция хорошо работает особенно в ситуациях возникновения дивергенций.

Этот подход с учетом переустановки величины профита помогает уловить и возникновение "хорошего" тренда. Например, как показано на рис1 по сравнению с рис2.




Алгоритм функции

1-ая модификация ордера по заданному значению TrailingStop, последующие - устанавливают StopLoss на 1 или 2 пункта ниже возможного уровня коррекции (в данном случае коэффициент коррекции = 0.382 "Coeff_ "). Значение TakeProfit при каждом шаге увеличиваем, например на половину величины TrailingStop-а (можно выбрать и другую величину!). Можно так же и не менять величину TakeProfit. Для этого в начале программы в операторе extern double March = 0; установить значение ноль.

Для тех трейдеров, которые предпочитают адресный анализ-поддержку выполнения конкретных действий программы непосредственно в ходе торгов, целесообразнее будет переменную MagicNumber перенести в код самого советника в то место, где происходит открытие позиции. Более подробно о конкретной адресной поддержке можно прочитать в Учебнике, опубликованного на сайте MQL4.com (автор С.Ковалев).


Рассмотрим поподробнее предлагаемый код и комментарии к нему будущей функции в советнике:

//+------------------------------------------------------------------+
//|      Двухэтапный вариант TrailingStop        Modify_2step v5.mq4 |
//|  Модификация ордеров: переустановка StopLoss и TakeProfit        |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2008, GenKov"
#property link      Genkov@bk.ru
//+------------------------------------------------------------------+
/* Magic=N

Magic=N - такой оператор надо вставлять при открытии позиции сразу же после операторов контроля выполнения условий в самой программе (советнике), и в функцию! Наверное, в связи с непредсказуемостью рынка, как мне кажется, универсального модификатора мне создать не удалось, а поэтому для каждого вида условий открытия позиций (по Magic=N) надо писать функцию отслеживания (передвижения S/L и T/P) и условия закрытия позиции.

extern double    March         =  1;  // шаг увеличения TakeProfit-а 
                                      // "0" шаг не увеличивает T/P.

S/L должен быть на 1 пункт меньше TrailingStop-а, чтобы при первом же срабатывании S/L оказался на безубыточном уровне. Таким образом мы страхуем себя от возможных потерь (управление капиталом).

extern double    StopLoss      = 15;  
extern double    TrailingStop  = 16;  
extern double    TakeProfit    = 60;  // подбор по тестеру
//+------------------------------------------------------------------+
//void TrailingStop()
  int start()                                   
   {
   //----------------------------------------------------------------+
   int point  = MarketInfo(Symbol(),MODE_POINT);      // Размер пункта 
   int StopLev= MarketInfo(Symbol(),MODE_STOPLEVEL);  
   double half_Trail = MathRound(TrailingStop/2);//половина TrailingStop-а
   double Step = March*half_Trail;  //величина увеличения TakeProfit-а
  if (TrailingStop<0) return;
   { 
   for (int i=0; i<OrdersTotal(); i++)
    {
    if (OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
    if (OrderSymbol()!=Symbol() || OrderMagicNumber()!=Magic) continue;
    if (OrderType()==OP_BUY)
     {

Первый этап модификации позиций BUY

if(OrderStopLoss()<OrderOpenPrice())//если S/L ниже цены открытия ордера
      {   // и если разность между текущей ценой и ценой открытия поз больше T/S
      if(Bid-OrderOpenPrice()>TrailingStop*Point) // && 
       {     // и если OrderStopLoss() меньше разницы текущей цены и T/S
       if(OrderStopLoss()<Bid-TrailingStop*Point)
        {    // расчитаем новое значение T/P
        double Now_T_P=(OrderTakeProfit()+Step*Point);
       { 
       OrderModify(OrderTicket(),OrderOpenPrice(),
       OrderStopLoss()+TrailingStop*Point,
       OrderTakeProfit()+Step*Point,0,Aqua); // повышаем значение T/P 
      return;
      }
     }
    }
   }

Однако, может возникнуть ситуация, когда передвигаемый TakeProfit станет на 2-3 пункта выше ранее запланированного уровня прибыли, остановится и

начнет медленно снижаться.


Чтобы избежать упущенной прибыли, введем оператор контроля над этой ситуацией, который и закроет ордер на запланированном уровне прибыли. Если же цена продолжит рост, то будет продолжено продвижение стоп-лоса и тейк-профита.

if(Bid-OrderOpenPrice()>=TakeProfit*Point && (Pr_Op_1-Pr_Op_0)>2*Point) 
   {
    // Print(" Bid= ",Bid," >= ",OrderTakeProfit()," Magic= ",Magic);
    OrderClose(OrderTicket(),Lots,Bid,2,Red);
    }
// второй этап модификации поз.BUY
  if(OrderStopLoss()>=OrderOpenPrice()) // Стор лос на безубыточном уровне
   {    // посчитаем коэффициент коррекции
    double Coeff_up = NormalizeDouble((Bid-OrderOpenPrice())*0.382,Digits);
    // и если разность между текущей ценой и ценой открытия поз больше коэфф. коррекции 
    if(Bid-OrderOpenPrice()>Coeff_up) 
     {    // посчитаем значение нового StopLoss с запасом в 2-а пункта
      double New_S_Loss = Bid-Coeff_up-2*Point;
      // и если значение нового StopLoss-a выше текущего значения 
      if(New_S_Loss-OrderStopLoss()>3*Point)
       {     // передвинем S/L и T/P
        OrderModify(OrderTicket(),OrderOpenPrice(),
        New_S_Loss,OrderTakeProfit()+Step*Point,0,Yellow);
        }
//        Print(" Bid-OrderOpenPrice()= ",Bid-OrderOpenPrice());
//        Print("  2   Coeff_up= ",Coeff_up," Order_S_Los= ",New_S_Loss," Bid= ",Bid);
       return;
       }
      }
     }

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

// ---------------------------- 1 этап модификации -----SELL-------------&
   else  if(OrderType()==OP_SELL) 
    {
   if(OrderStopLoss()>OrderOpenPrice())//если S/L выше цены открытия ордера
     {
     if(OrderOpenPrice()-Ask>TrailingStop*Point && 
        OrderStopLoss()>Ask+TrailingStop*Point)
     { 
      OrderModify(OrderTicket(),OrderOpenPrice(),
      Ask+TrailingStop*Point,OrderTakeProfit()-Step*Point,0,SkyBlue);
      return;
      }
     }
if(OrderOpenPrice()-Ask>=TakeProfit*Point && (Pr_Op_0-Pr_Op_1)>2*Point) 
   {
    OrderClose(OrderTicket(),Lots,Bid,2,Red);
    }     
// ---------------------------- 2 этап модификации -----SELL-------------&
   if(OrderStopLoss()<=OrderOpenPrice()) // Стор лос на безубыточном уровне
    { // посчитаем коэффициент коррекции
     double Coeff_down = NormalizeDouble((OrderOpenPrice()-Ask)*0.382,Digits);
     // и если разность между ценой открытия поз и текущей ценой больше коэфф. коррекции 
    if(OrderOpenPrice()-Ask>Coeff_down) 
     {    // посчитаем значение нового StopLoss с запасом в 2-а пункта
      New_S_Loss = Ask+Coeff_down+2*Point; 
      // и если значение нового StopLoss-a ниже текущего значения 
      if(New_S_Loss-OrderStopLoss()>3*Point)
       {     // передвинем S/L и T/P   
       OrderModify(OrderTicket(),OrderOpenPrice(),
       New_S_Loss,OrderTakeProfit()-Step*Point,0,Khaki);
      return;
      }
     }
    }
   }
  } 
 //  -----------------------------------------------------------------------------------

Для превращения этого советника в функцию надо закомментировать специальную функцию int start(), стоящую в начале программы, заменив ее на раскомментированное определение функции TrailingStop() в начале программы, закомментированный вызов функции в конце программы

//TrailingStop();

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


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

// --------------------------------------------------------------------------------
  
   double Macd_m15_0= iMACD(NULL,PERIOD_M15,12,26,9,PRICE_CLOSE,MODE_MAIN,0);
   double Macd_m15_1= iMACD(NULL,PERIOD_M15,12,26,9,PRICE_CLOSE,MODE_MAIN,1);
   
   if(OrdersTotal()<2)
    {
    if(Macd_m15_0<Macd_m15_1)
     {
     OrderSend(Symbol(),OP_SELL,0.1,Bid,3,Ask+StopLoss*Point,Bid-TakeProfit*Point,"",Magic,0,Red);
     }
    if(Macd_m15_0>Macd_m15_1)
     {
     OrderSend(Symbol(),OP_BUY,0.1,Ask,3,Bid-StopLoss*Point,Ask+TakeProfit*Point,"",Magic,0,Blue);
     }
    return(0);
   }
// --------------------------------------------------------------------------------
//  TrailingStop();
  }
   return(0);
  }
// --- end --- &

Теперь убираем из вышеприведенного текста кода подробные комментарии, и оформляем код в виде исполнительной функции: получим следующий фай, который рекомендуется хранить в директории каталог_терминал\experts\include с расширением .mqh или каталог_терминал\libraries с расширением mq4.


//+------------------------------------------------------------------+
//|                                             Modify_2_Step v5.mq4 |
//|                                         Copyright © 2008, GenKov |
//|                                                     Genkov@bk.ru |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2008, GenKov"
#property link      "Genkov@bk.ru"
extern double    March         =  1;  // шаг увеличения TakeProfit-а 
                                      // "0" шаг не увеличивает T/P.
// S/L должен быть на 1 пункт меньше TrailingStop-а, чтобы при 
// первом же срабатывании S/L оказался на безубыточном уровне  
extern double    StopLoss      = 15;  
extern double    TrailingStop  = 16;
extern double Lots             = 0.1;  
extern double    TakeProfit    = 60;  // подобрать по тестеру
void TrailingStop()
  {
   int Magic=3090;  //  номер условия открывшего позицию
   int point  = MarketInfo(Symbol(),MODE_POINT);      // Размер пункта 
   int StopLev= MarketInfo(Symbol(),MODE_STOPLEVEL);  
   double half_Trail = MathRound(TrailingStop/2);//половина TrailingStop-а
   double Step = March*half_Trail;  //величина увеличения TakeProfit-а
  if (TrailingStop<0) return;
   { 
   for (int i=0; i<OrdersTotal(); i++)
    {//1 +цикл по перебору ордеров
    if (OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
    if (OrderSymbol()!=Symbol() || OrderMagicNumber()!=Magic) continue;
    if (OrderType()==OP_BUY)
     {
// --------------------------- 1 этап модификации -----BUY-------------&     
    if(OrderStopLoss()<OrderOpenPrice())//если S/L ниже цены открытия ордера
      {   // и если разность между текущей ценой и ценой открытия поз больше T/S
      if(Bid-OrderOpenPrice()>TrailingStop*Point) // && 
       {     // и если OrderStopLoss() меньше разницы текущей цены и T/S
       if(OrderStopLoss()<Bid-TrailingStop*Point)
        {    // расчитаем новое значение T/P
        double Now_T_P=(OrderTakeProfit()+Step*Point);
       { 
       OrderModify(OrderTicket(),OrderOpenPrice(),
       OrderStopLoss()+TrailingStop*Point,
       OrderTakeProfit()+Step*Point,0,Aqua); // повышаем значение T/P 
      return;
      }
     }
    }
   }
  if(Bid-OrderOpenPrice()>=TakeProfit*Point) 
   {
    OrderClose(OrderTicket(),Lots,Bid,2,Red);
    }
//------------------------- 2-ой этап модификации -----BUY---------------&
  if(OrderStopLoss()>=OrderOpenPrice()) // Стор лос на безубыточном уровне
   {    // посчитаем коэффициент коррекции
    double Coeff_up = NormalizeDouble((Bid-OrderOpenPrice())*0.382,Digits);
    // и если разность между текущей ценой и ценой поз. больше коэфф. коррекции 
    if(Bid-OrderOpenPrice()>Coeff_up) 
     {    // посчитаем значение нового StopLoss с запасом в 6-и пункта
      double New_S_Loss = Bid-Coeff_up-6*Point-StopLev*Point;
      // и если значение нового StopLoss-a выше текущего значения 
      if((New_S_Loss-OrderStopLoss())<2*Point)
       {     // передвинем S/L и T/P
        OrderModify(OrderTicket(),OrderOpenPrice(),
        OrderStopLoss(),OrderTakeProfit()+Step*Point/2,0,Yellow);
        }
        else
        {
         OrderModify(OrderTicket(),OrderOpenPrice(),
        New_S_Loss+1*Point,OrderTakeProfit()+Step*Point,0,Yellow);
        }
       return;
       }
      }
     }
// ---------------------------- 1 этап модификации -----SELL-------------&
  else if(OrderType()==OP_SELL)
    {
   if(OrderStopLoss()>OrderOpenPrice())//если S/L выше цены открытия ордера
     {
     if(OrderOpenPrice()-Ask>TrailingStop*Point && 
        OrderStopLoss()>Ask+TrailingStop*Point)
     { 
      OrderModify(OrderTicket(),OrderOpenPrice(),
      Ask+TrailingStop*Point,OrderTakeProfit()-Step*Point,0,SkyBlue);
      return;
      }
     }
if(OrderOpenPrice()-Ask>=TakeProfit*Point) 
   {
    OrderClose(OrderTicket(),Lots,Bid,2,Red);
    }     
// ---------------------------- 2 этап модификации -----SELL-------------&
   if(OrderStopLoss()<=OrderOpenPrice()) // Стор лос на безубыточном уровне
    if(OrderOpenPrice()-Ask>=OrderTakeProfit()) OrderClose(OrderTicket(),Lots,Ask,2,Red);   
    { // посчитаем коэффициент коррекции
     double Coeff_down = NormalizeDouble((OrderOpenPrice()-Ask)*0.382,Digits);
     // и если разность между ценой открытия поз и текущей ценой больше коэффициента коррекции 
    if(OrderOpenPrice()-Ask>Coeff_down) 
     {   // посчитаем значение нового StopLoss с запасом в 6-и пункта
      New_S_Loss = Ask+Coeff_down+6*Point; 
      // и если значение нового StopLoss-a ниже текущего значения 
      if((OrderStopLoss()-New_S_Loss-StopLev*Point)>=10*Point)
       {    // передвинем S/L и T/P
       OrderModify(OrderTicket(),OrderOpenPrice(),
       New_S_Loss-5*Point,OrderTakeProfit()-Step*Point,0,Khaki);
      return;
      }
     }
    }
   }
  } 
return(0);
}
}
// ---end----- void TrailingStop()--------------------------------&
  // этот блок только для контроля ошибок в коде функции
  //  int start()  
  //   {
  //    if(25>26) TrailingStop();
  //    }
  // --------------------------------


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

Прикреплены варианты версий:

v4 - с закрытием по S/L; v5 - с упреждающим закрытием по T/P; v6 - с учетом упреждения и адресной поддержке по Magic померу.