已打开头寸的两步修改

Genkov | 18 三月, 2016

简介

“T.DeMark 的技术分析方法”一文中,包含了推荐的修正长度系数,具体为 0.382 和 0.618。在打开头寸时使用这些系数,可以避免邻近趋势时不必要的关闭和重新打开头寸。该功能效果很好,尤其在出现偏离的情况下。

在重新设置获利值的情况下,这种方法帮助检测“有利”趋势的出现。例如,图 1 和图 2 所示。




功能算法

对订单的第一个改动由指定 TrailingStop 值执行,随后的改动设置的 StopLoss 比可能的修正水平低 1 到 2 个点(在这种情况,修正系数=0,382 "Coeff_")。在每个步长上按照,例如,TrailingStop 值的一半(你也可以选择其他值!)增加 TakeProfit 值。TakeProfit 的值也可以更改。为此,在程序开始时应该设置 extern double March = 0; 的零值。

对于喜欢在交易时直接执行特定程序的地址分析支持操作的交易者,最好将 MagicNumber 变量转移到 Expert Advisor 自身打开头寸的代码中。关于具体的地址支持,可以在 MQL4.com 网站上发布的 S. Kovalyov 的书籍 中阅读更多详情。


我们来仔细检查 EA 中预期函数的建议代码和其中的注释:

//+------------------------------------------------------------------+
//|      Two-stage variant of TrailingStop       Modify_2step v5.mq4 |
//|   Orders modification: re-placing StopLoss and TakeProfit        |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2008, GenKov"
#property link      Genkov@bk.ru
//+------------------------------------------------------------------+
/* Magic=N

Magic=N - 此运算符应在建仓时于程序自身(Expert Advisor)中的条件依从控制运算符之后插入,以及在函数中插入。或许鉴于市场的不可预测性,我无法创建一个通用修饰符,所以应该为每种类型的头寸打开条件(按 Magic=N)编写跟踪函数(S/L 和 T/P 的走势)以及头寸关闭条件。

extern double    March         =  1;  // step of increasing TakeProfit 
                                      // step 0 doesn't increase T/P.

S/L 必须小于 TrailingStop 1 个点,以在第一次触发时使 S/L 处于安全水平。利用这种方式,我们可以确保免于可能的损失(资本管理)。

extern double    StopLoss      = 15;  
extern double    TrailingStop  = 16;  
extern double    TakeProfit    = 60;  // fitting with the tester
//+------------------------------------------------------------------+
//void TrailingStop()
  int start()                                   
   {
   //----------------------------------------------------------------+
   int point  = MarketInfo(Symbol(),MODE_POINT);      // Point size 
   int StopLev= MarketInfo(Symbol(),MODE_STOPLEVEL);  
   double half_Trail = MathRound(TrailingStop/2);//half TrailingStop
   double Step = March*half_Trail;  //value of TakeProfit increase
  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)
     {

买入头寸改动的第一步

if(OrderStopLoss()<OrderOpenPrice())//if S/L is less than the order open price
      {   // and if the difference between the current price and the position opening price is greater than T/S
      if(Bid-OrderOpenPrice()>TrailingStop*Point) // && 
       {     // and if OrderStopLoss() is less than the difference between the current price and T/S
       if(OrderStopLoss()<Bid-TrailingStop*Point)
        {    // calculate new T/P value
        double Now_T_P=(OrderTakeProfit()+Step*Point);
       { 
       OrderModify(OrderTicket(),OrderOpenPrice(),
       OrderStopLoss()+TrailingStop*Point,
       OrderTakeProfit()+Step*Point,0,Aqua); // increasing T/P value
      return;
      }
     }
    }
   }

但是,可能发生以下情形:TakeProfit 偏移高于之前计划的获利水平 2-3 个点,停止并开始慢慢下降。



为避免损失获利,我们输入情形控制的运算符,以在计划的获利水平关闭订单。如果价格持续增长,则 StopLoss 和 TakeProfit 的偏移将继续。

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);
    }
// Second stage of BUY position modification

  if(OrderStopLoss()>=OrderOpenPrice()) // StopLoss is on a lossless level
   {    // calculate correction coefficient
    double Coeff_up = NormalizeDouble((Bid-OrderOpenPrice())*0.382,Digits);
    // and if the differnece between the current and the open price of the position is greater than corr. coefficient 
    if(Bid-OrderOpenPrice()>Coeff_up) 
     {    // calculate the value of new StopLoss with the margin of 2 points
      double New_S_Loss = Bid-Coeff_up-2*Point;
      // and if the value of new StopLoss is higer than the current one
      if(New_S_Loss-OrderStopLoss()>3*Point)
       {     // move S/L and 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 stage of modification -----SELL-------------&
   else  if(OrderType()==OP_SELL) 
    {
   if(OrderStopLoss()>OrderOpenPrice())//if S/L is greater than order open price
     {
     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 stage of modification -----SELL-------------&
   if(OrderStopLoss()<=OrderOpenPrice()) // StopLoss is on a lossless level
    { // calculate correction coefficient
     double Coeff_down = NormalizeDouble((OrderOpenPrice()-Ask)*0.382,Digits);
     // and if the difference between the price of position opening and the current price is greater than corr. coefficient 
    if(OrderOpenPrice()-Ask>Coeff_down) 
     {    // calculate the value of new StopLoss with the margin of 2 points
      New_S_Loss = Ask+Coeff_down+2*Point; 
      // and if the value of new StopLoss is less than the current value
      if(New_S_Loss-OrderStopLoss()>3*Point)
       {     // move S/L and T/P   
       OrderModify(OrderTicket(),OrderOpenPrice(),
       New_S_Loss,OrderTakeProfit()-Step*Point,0,Khaki);
      return;
      }
     }
    }
   }
  } 
 //  -----------------------------------------------------------------------------------

为将该 EA 变为函数,有必要对位于程序开头的特殊 int start() 函数添加注释,并用位于程序开头的 TrailingStop() 函数的未注释描述替换。对函数调用取消注释:

//TrailingStop();

在程序的最后。

如果添加下面的程序块,可以将其用作测试程序中的 EA 来检验函数的有效性。

// --------------------------------------------------------------------------------
  
   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 --- &

现在从上述的代码文本中移除详细的注释,形成可执行的函数:我们将得到可执行文件,建议将其保存在 Terminal_folder\experts\include 目录下,扩展名为 .mqh 或者在 terminal_folder\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;  // the step of TakeProfit increase
                                      // "0" step doesn't increase T/P.
// S/L must be less than TrailingStop by 1 point to bring the S/L  
// on a safe level in the time of the very first triggering
extern double    StopLoss      = 15;  
extern double    TrailingStop  = 16;
extern double Lots             = 0.1;  
extern double    TakeProfit    = 60;  // fitting with the tester
void TrailingStop()
  {
   int Magic=3090;  //  number of condition that opens position
   int point  = MarketInfo(Symbol(),MODE_POINT);      // Point size 
   int StopLev= MarketInfo(Symbol(),MODE_STOPLEVEL);  
   double half_Trail = MathRound(TrailingStop/2);//half TrailingStop
   double Step = March*half_Trail;  //TakeProfit-а increase size
  if (TrailingStop<0) return;
   { 
   for (int i=0; i<OrdersTotal(); i++)
    {//1 +cycle by orders search
    if (OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
    if (OrderSymbol()!=Symbol() || OrderMagicNumber()!=Magic) continue;
    if (OrderType()==OP_BUY)
     {
// --------------------------- 1 stage of modification -----BUY-------------&     
    if(OrderStopLoss()<OrderOpenPrice())//if the S/L is less than the order open price
      {   // and if the difference between the current and the open price is greater than T/S
      if(Bid-OrderOpenPrice()>TrailingStop*Point) // && 
       {     // and if OrderStopLoss() is less than the difference between current price andT/S
       if(OrderStopLoss()<Bid-TrailingStop*Point)
        {    // calculate new T/P value
        double Now_T_P=(OrderTakeProfit()+Step*Point);
       { 
       OrderModify(OrderTicket(),OrderOpenPrice(),
       OrderStopLoss()+TrailingStop*Point,
       OrderTakeProfit()+Step*Point,0,Aqua); // increase T/P value
      return;
      }
     }
    }
   }
  if(Bid-OrderOpenPrice()>=TakeProfit*Point) 
   {
    OrderClose(OrderTicket(),Lots,Bid,2,Red);
    }
//------------------------- 2 stage of modification -----BUY---------------&
  if(OrderStopLoss()>=OrderOpenPrice()) // StopLoss is on the lossless level
   {    // calculate correction coefficient
    double Coeff_up = NormalizeDouble((Bid-OrderOpenPrice())*0.382,Digits);
    // and if the difference between the current and the position price is greater than correction coefficient
    if(Bid-OrderOpenPrice()>Coeff_up) 
     {    // clculate new StopLoss value with the margin of 6 points
      double New_S_Loss = Bid-Coeff_up-6*Point-StopLev*Point;
      // if the value of new StopLoss is greater than the current value
      if((New_S_Loss-OrderStopLoss())<2*Point)
       {     // move S/L and 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 stage of modification -----SELL-------------&
  else if(OrderType()==OP_SELL)
    {
   if(OrderStopLoss()>OrderOpenPrice())//if S/L is greater than the order open price
     {
     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 stage of modification -----SELL-------------&
   if(OrderStopLoss()<=OrderOpenPrice()) // StopLoss is on the lossless level
    if(OrderOpenPrice()-Ask>=OrderTakeProfit()) OrderClose(OrderTicket(),Lots,Ask,2,Red);   
    { // calculate correction coefficient
     double Coeff_down = NormalizeDouble((OrderOpenPrice()-Ask)*0.382,Digits);
     // and if the difference between the position open price and the current price is greater than corr. coefficient
    if(OrderOpenPrice()-Ask>Coeff_down) 
     {   // calculate the value of new StopLoss with the margin of 6 points
      New_S_Loss = Ask+Coeff_down+6*Point; 
      // and if the value of new StopLoss is less than the current value
      if((OrderStopLoss()-New_S_Loss-StopLev*Point)>=10*Point)
       {    // move S/L and T/P
       OrderModify(OrderTicket(),OrderOpenPrice(),
       New_S_Loss-5*Point,OrderTakeProfit()-Step*Point,0,Khaki);
      return;
      }
     }
    }
   }
  } 
return(0);
}
}
// ---end----- void TrailingStop()--------------------------------&
  // this block is only for error controlling in the function code
  //  int start()  
  //   {
  //    if(25>26) TrailingStop();
  //    }
  // --------------------------------

总结

应该说,跟 Sergey Kravchuk 在 “一种跟踪止损和退出市场的模式”(A Pattern Trailing Stop and Exit the Market 一文中描述的“典型跟踪止损”相比,这个版本更容易理解,而且它在我的 EA 中(实际是在模拟账户上)效果良好,我认为,它适合激进和稳健跟踪。

随附的版本:

v4 - 按止损关闭;v5 - 按获利的预测关闭;v6 - 考虑了预测和幻数的地址支持。