请 [注册] 或 [登录]  | 返回主站

量化交易吧 /  数理科学 帖子:3352790 新帖:65

液态图表

专门套利发表于:4 月 17 日 16:03回复(1)

介绍

有一次,我注意到每个经纪商的 H4 时间帧以及更高的图表都有所不同。这背后的原因是因为经纪商分别位于不同的时区。在某些情况下,虽然时区之间的差别很小,同一图表的某些部分也会有显著不同。在某一个图表上有一个明显的反转形态,但另一个图表上的相同部位却没有表现出任何精确的形态。

此后,有个想法掠过我的脑海,写一款指标重绘 H1 图表,以便在右侧总会有一根完整的收盘柱线。选择 M1 周期作为价格的源头。作为结果, 小时图表每分钟重绘, 在一小时内我得到了 60 个变化的同一小时图表。它的形式以平滑、流动的方式变化,揭示一些初始情况下不曾被提示的隐藏形态。

我把此指标称为 "液态图表",因为它的表现很特别。根据不同的绘图模式,或是在基准周期的新柱线出现时,或是在静态位移值改变时,图表 "流动" (被重绘) 。在本文中我们将研究绘制 "液态图表" 的原理,然后编写指标,并比较 EA 使用此技术与 EA 根据形态进行交易的效率。



1. 绘制原理

在我们开始之前, 我们来定义术语。

位移 结果图表的柱线开盘价与源图表柱线开盘价之间的差异。

当前时间帧 是源图表时间帧。

基准时间帧 是我们将要在结果图表里形成价格柱线的时间帧。

基准周期不能超过当前的。当前周期必须能够被基准周期切分且无剩余。当前时间帧与基准的比率越大,我们可以得到的结果图表的变化也就越多。然而,如果该比率过大,则用于绘制基准时间帧的结果图表柱线的必要历史数据数量可能不足。

图表绘图有三种类型。

  • 带有静态位移的图表 (Static ShiftSS)。
  • 在开盘模式带有动态位移的图表 (Dynamic Shift, 仅开盘DSO)。
  • 在收盘模式带有动态位移的图表 (Dynamic Shift, 期望收盘DSC)。

在静态位移模式, 柱线的开盘时间按照设置时间位移。在开盘模式的动态位移令一根柱线好像刚刚开盘,而且在收盘模式令柱线看上去像即将收盘。

让我们靠近一些观察。


1.1. 静态位移图表

在此模式,每根柱线的开盘时间会按照基准时间帧设置的数量的等价分钟数位移。我们称其为 位移。这种方式,如果设置的位移等于 0, 则图表会准确的与原始的相同。位移 1, 与基准时间帧相差 15 分钟, 即等于 15 分钟。位移 2 等于 30 分钟,以此类推。

位移不能超过 (k-1), 此处 k 是当前时间帧与基准时间帧的比率。它意味着,当前时间帧 H1 和基准的 M1, 基准时间帧最大许可位移是 60/1 - 1 = 59, 即是 59 分钟。如果基准时间帧是 M5, 则基准时间帧最大许可位移是 60/5 - 1 = 11, 即是 55 分钟。

当前时间帧 H1 的柱线开盘时间位移15 分钟, 即 00:15, 01:15, 02:15 以此类推。当前时间帧 M15 且位移 1 分钟, 柱线开盘时间为 00:16, 00:31, 00:46, 01:01 以此类推。

当位移接近极限值时,此图表与源图区别很小。显著差异出现在位移值接近允许范围的中间。

静态位移图表

图例. 1. 小时图与基准时间帧 M15,位移等于 1 的例子


1.2. 开盘模式动态位移图表

在此模式里, 基准时间帧里每出现新柱线时位移会重新计算。与此同时,计算位移,以便图表末尾存在的柱线时间 (最后的价格) 不能超过基准时间帧的值。如果当前时间帧是 H1,且基准是 M5,则右边柱线的开盘看上去像是早于五分钟之前。

动态位移图表, 柱线开始

图例. 2. 小时图形成在基准时间帧 M15,开盘模式动态位移的例子


1.3. 收盘模式动态位移图表

在此模式里, 基准时间帧里每出现新柱线时位移会重新计算,就像开盘模式。仅有的不同在于计算位移的方式,图表末尾存在的柱线时间 (最后的价格) 大于或等于当前和基准时间帧之间的差值。如果当前时间帧是 H1,且基准是 M5,则右边柱线的收盘看上去像不晚于五分钟。

动态位移图表, 完整柱线

图例. 3. 小时图形成在基准时间帧 M15,收盘模式动态位移的例子


2. 数据转换

编写 GetRatesLC() 函数参考账户设置的位移来转换历史数据。它将修改后的历史数据写入 MqlRates 类型的结构数组, 类似于 CopyRates() 函数。

int GetRatesLC(
   int             start_pos    // source for copying
   int             len,         // amount to copy
   MqlRates&       rates[],     // target array
   ENUM_TIMEFRAMES base_period, // basic timeframe
   int&            shift        // shift
   );

参数

  start_pos

   [in]  在当前时间帧里第一个元素索引。它是数据转换和拷贝至缓存区的起始点。

  len

   [in]  元素拷贝的数量。

  rates[]

   [out]  MqlRates 类型的数组。

  base_period

   [in]  基准时间帧。 

  shift

   [in] [out]  位移。它可以接受以下数值:

数值描述
 -2
 按开盘模式计算位移 (柱线开始形成)
 -1
 按收盘模式计算位移 (柱线结束形成)
 0 ... N
 应用设置的位移。可接受的数值从 0 至 N。
 N = Tcur/Tbase - 1。此处 Tcur 是当前时间帧, Tbase 是基准时间帧。

表.1。参数 shift 的允许值

如果函数实现成功, shift 将接收计算的位移值, 如果值为 -2 或 -1 则忽略。

返回值

元素拷贝数量或错误代码:

代码描述
 -1
 基准时间帧指定有误
 -2
 位移指定有误

表格 2. 返回错误代码

以下是函数 GetRatesLC() 的代码,来自 liquidchart.mqh 文件。

int GetRatesLC(int start_pos,int len,MqlRates &rates[],ENUM_TIMEFRAMES base_period,int& shift)
  {
   //--- number of basic timeframes contained in the current one  
   int k=PeriodSeconds()/PeriodSeconds(base_period);
   if(k==0)
      return(-1);//basic timeframe specified incorrectly
   //---
   MqlRates r0[];
   ArrayResize(rates,len);
   if(CopyRates(_Symbol,_Period,start_pos,1,r0)<1)
      return(0);// no data
   //---
   int sh;
   if(shift>=0)
     {
      //--- fixed shift
      if(shift<k)
         sh=shift;
      else
         return(-2);//--- shift specified incorrectly   
     }
   else if(shift==-1)
     {
      //--- shift to be calculated (dynamic, beginning of the bar formation)
      sh=int((TimeCurrent()-r0[0].time)/PeriodSeconds(base_period));
     }
   else if(shift==-2)
     {
      //--- shift to be calculated (dynamic, end of the bar formation)
      sh=1+int((TimeCurrent()-r0[0].time)/PeriodSeconds(base_period));
      if(sh>=k)
         sh = 0;
     }
   else
      return(-2);//shift specified incorrectly       
   //--- opening time of the basic period bar, which is the beginning of the current period bar formation
   //--- synchronization of the time of opening bars takes place relative to the tO time
   datetime tO;
   //--- closing time of the bar under formation, i.e. opening time of the last bar of basic timeframe in the series
   datetime tC;
   tO=r0[0].time+sh*PeriodSeconds(base_period);
   if(tO>TimeCurrent())
      tO-=PeriodSeconds();
   tC=tO+PeriodSeconds()-PeriodSeconds(base_period);
   if(tC>TimeCurrent())
      tC=TimeCurrent();
   int cnt=0;
   while(cnt<len)
     {
      ArrayFree(r0);
      int l=CopyRates(_Symbol,base_period,tC,k,r0);
      if(l<1)
         break;
      //--- time of the bar with the (l-1) index does not have to be equal to tC
      //--- if there is no bar with the tC time, it can be the nearest bar
      //--- in any case its time is assigned to the tC time
      tC=r0[l-1].time;
      //--- check if tO has the correct value and modify if needed.
      while(tO>tC)
         tO-=PeriodSeconds();
      //--- the time values of tO and tC have actual meaning for the bar under formation  
      int index=len-1-cnt;
      rates[index].close=0;
      rates[index].open=0;
      rates[index].high=0;
      rates[index].low=0;
      rates[index].time=tO;
      for(int i=0; i<l; i++)
         if(r0[i].time>=tO && r0[i].time<=tC)
           {
            if(rates[index].open==0)
              {
               rates[index].open= r0[i].open;
               rates[index].low = r0[i].low;
               rates[index].high= r0[i].high;
                 }else{
               if(rates[index].low > r0[i].low)
                  rates[index].low=r0[i].low;
               if(rates[index].high < r0[i].high)
                  rates[index].high=r0[i].high;
              }
            rates[index].close=r0[i].close;
           }
      //--- specifying closing time of the next bar in the loop
      tC=tO-PeriodSeconds(base_period);
      //
      cnt++;
     }
   if(cnt<len)
     {
      //-- less data than required, move to the beginning of the buffer
      int d=len-cnt;
      for(int j=0; j<cnt; j++)
         rates[j]=rates[j+d];
      for(int j=cnt;j<len;j++)
        {
         //--- fill unused array elements with zeros
         rates[j].close=0;
         rates[j].open=0;
         rates[j].high=0;
         rates[j].low=0;
         rates[j].time=0;
        }
     }
   shift = sh;  
   return(cnt);
  }

几个应加以强调的要点。

  • 函数不返回报价的交易量。而原因是,在 DSC 模式下,柱线开盘时从不返回交易量。这是很合乎逻辑的。如果您的 EA 使用即时报价交易量作为一根新柱线形成的信号,它将永远不会收到信号。此方法用于 移动均线 EA。您可以在函数里添加即时报价交易量的计数器,但它应该不能正确工作。为了避免混淆,我根本不会度量即时报价的交易量。
  • 函数返回请求的柱线数量,但它并非意味着,第一根和最后一根柱线之间的时间与源图上相应的时间间隔相称。在一段连续的历史数据中,虽然有时会对应。如果指定的段落包含周末,"幻影柱线" 可能会出现在边缘。

以下图解表现了一个 "幻影柱线" 的例子。这根柱线在 10 月 27 日的第一分钟形成, 其一并包含了 10 月 26 日 23:01 的柱线开盘时间。应当指出,这样的柱线之后,指标图表将被顺移到相对应的源图表的左侧。柱线时间对应于初始时间 (例如, 21:00 -> 21:01), 将有不同的索引。

幻影柱线

图例. 4. 幻影柱线 2014.10.26 于 23:01



3. 指标实现

让我们来编写指标,在单独的窗口里显示 "液态图表"。指标可以工作在全部三种模式: 静态位移模式, 柱线开盘动态位移模式和柱线收盘动态位移模式。指标也有控制元素来改变模式和位移值,而无需调用指标参数对话框。

一开始我们使用来自 liquidchart.mqh 文件的 GetRatesLC() 函数。我们应该从 RefreshBuffers() 函数调用, 而它本身, 会在 OnCalculate 函数里调用。它也在 OnChartEvent 中被调用, 在模式里作为替代或者位移,并且指标的缓存区需要重新计算。OnChartEvent 函数处理按下按钮,改变位移值和模式。

指标的输入参数:

input ENUM_TIMEFRAMES   BaseTF=PERIOD_M1;       // LC Base Period
input int               Depth=100;              // Depth, bars
input ENUM_LC_MODE      inp_LC_mode=LC_MODE_SS; // LC mode
input int               inp_LC_shift=0;         // LC shift

此处 Depth 是结果图表的柱线数量,ENUM_LC_MODE 是指标绘制模式的描述类型。

enum ENUM_LC_MODE
  {//plotting mode
   LC_MODE_SS=0,  // Static Shift
   LC_MODE_DSO=1, // Dynamic Shift, just Open
   LC_MODE_DSC=2  // Dynamic Shift, expected Close
  };
inp_LC_modeinp_LC_shift 参数则会被 LC_modeLC_shift 覆盖。这种设计允许通过按下按钮来改变它们的值。不打算讨论绘制按钮和按钮操作,因为它们与本文的主题无关。让我们来研究 RefreshBuffers() 函数的详情。
bool RefreshBuffers(int total,
                    double &buff1[],
                    double &buff2[],
                    double &buff3[],
                    double &buff4[],
                    double &col_buffer[])
  {
   MqlRates rates[];
   ArrayResize(rates,Depth);
//---
   int copied=0;
   int shift=0;
   if(LC_mode==LC_MODE_SS)
      shift = LC_shift; //static shift
   else if(LC_mode==LC_MODE_DSO)
      shift = -1;       //calculate shift (beginning of the bar formation)
   else if(LC_mode==LC_MODE_DSC)
      shift = -2;       //calculate shift (end of the bar formation)
   else
      return(false);
//---
   copied=GetRatesLC(0,Depth,rates,BaseTF,shift);
//---
   if(copied<=0)
     {
      Print("No data");
      return(false);
     }
   LC_shift = shift;
   refr_keys();
//--- initialize buffers with empty values
   ArrayInitialize(buff1,0.0);
   ArrayInitialize(buff2,0.0);
   ArrayInitialize(buff3,0.0);
   ArrayInitialize(buff4,0.0);
//---
   int buffer_index=total-copied;
   for(int i=0;i<copied;i++)
     {
      buff1[buffer_index]=rates[i].open;
      buff2[buffer_index]=rates[i].high;
      buff3[buffer_index]=rates[i].low;
      buff4[buffer_index]=rates[i].close;
      //---
      if(rates[i].open<=rates[i].close)
         col_buffer[buffer_index]=1;//bullish or doji
      else
         col_buffer[buffer_index]=0;//bearish
      //
      buffer_index++;
     }
//
   return(true);
  }

首先, shift 变量的相关数值,根据模式传递到 GetRatesLC() 函数。在静态模式,它是 LC_shift 参数的拷贝,且在柱线的开盘或收盘模式它相应的是 -1 或 -2。函数成功执行之后, GetRatesLC() 返回位移的当前数值至 shift 变量。它要么重新计算或保持原样。在任何情况下, 我们分配其值至 LC_shift 变量, 并通过 refr_keys() 函数调用图形元素的重绘。

此后, 我们在指标缓存区里更新 OHLC 的数值和柱线颜色。

指标的完整代码可在 liquid_chart.mq5 文件里找到。在启动之后, 指标如下所示:

液态图表指标, 位移 0

图例. 5. 液态图表指标

关于控制元素的几句话

  • SS 按钮切换指标至静态位移模式。带箭头的按钮在此模式激活,它们可以用来设置所需的位移值。
  • DSO 按钮切换指标至动态模式, 柱线开始形成。在此模式下,计算出的位移值不能手工修改。
  • DSC 按钮切换指标至动态位移模式, 柱线结束形成。在此模式下,手工修改位移值也不可用。

SS 模式, 当位移值为 0, 指标用初始图表的数值覆盖。如果您改变此值, 您将看到图表重绘。一个明显的区别已经在值 28 的位置出现。替代软弱的 "轨道", 此处是一个独特的 "锤头"。这是做多时机?

液态图表指标, 位移 28液态

图例. 6. 液态图表指标, 位移 28

切换指标至 DSO 模式, 一根新形成的柱线始终处于右边。在 DSC 模式,一根柱线即将在不迟于基准时间帧时间间隔内收盘。


4. 创建 EA

我们继续创建两个 EA。第一个按照移动均线进行交易,第二个按照 "夹针柱线" 形态。

让我们以标准例程 Moving Average EA (在 Experts\Examples\Moving Average 文件夹) 作为模板。这样我们就能比较两种基础不同的策略的优化结果,来理解使用静态或动态移位相关的一些意义。


4.1. EA 遵照移动均线进行交易

首先要定义输入参数。它们有四个:

input double MaximumRisk    = 0.1// Maximum Risk in percentage
input double DecreaseFactor = 3;    // Decrease factor
input int    MovingPeriod   = 12;   // Moving Average period
input int    MovingShift    = 6;    // Moving Average shift

在改编之后新增了三个参数:

input ENUM_TIMEFRAMES  BaseTF=PERIOD_M1;  // LC Base Period
input bool             LC_on = true;      // LC mode ON
input int              LC_shift = 0;      // LC shift

LC_on 参数对于检查 GetRatesLC() 是否工作正常很有用处。组合条件 (LC_on == true && LC_shift == 0) 必须与 (LC_on == false) 结果相同

对于将现成的 EA Moving Average 改编为带位移的,要包含文件 liquidchart.mqh,且在启用位移功能 (输入参数 LC_ontrue) 的情况下,要用 CopyRates() 函数取代 GetRatesLC() 函数:

   int copied;
   if(LC_on==true)
     {
      int shift = LC_shift;
      copied=GetRatesLC(0,2,rt,BaseTF,shift);
     }
   else
      copied = CopyRates(_Symbol,_Period,0,2,rt);
   if(copied!=2)
     {
      Print("CopyRates of ",_Symbol," failed, no history");
      return;
     }

它需要在 CheckForOpen()CheckForClose() 两个函数内都完成。我们不得不放弃使用指标句柄,并手工计算移动均值。为此,我们添加 CopyMABuffer() 函数:

int CopyMABuffer(int len,double &ma[])
  {
   if(len<=0)
      return(0);
   MqlRates rates[];
   int l=len-1+MovingPeriod;
   int copied;
   if(LC_on==true)
     {
      int shift = LC_shift;
      ArrayResize(rates,l);
      copied=GetRatesLC(MovingShift,l,rates,BaseTF,shift);
     }
   else
      copied=CopyRates(_Symbol,_Period,MovingShift,l,rates);
//      
   if(copied<l)
      return(0);
//
   for(int i=0;i<len;i++)
     {
      double sum=0;
      for(int j=0;j<MovingPeriod;j++)
        {
         if(LC_on==true)
            sum+=rates[j+i].close;
         else
            sum+=rates[copied-1-j-i].close;
        }
      ma[i]=sum/MovingPeriod;
     }
   return(len);
  }

它返回所需的在 ma[] 缓存区里的数值数量,或由于某种原因出错则为 0。

柱线开盘的控制是要考虑的另一个重要问题。在原始的 Moving Average EA 版本里,它是用即时报价数据来实现的:

   if(rt[1].tick_volume>1)
      return;

在我们的例子中没有即时报价交易量,因此我们将要直接编写 newbar() 函数来控制开盘:

bool newbar(datetime t)
  {
   static datetime t_prev=0;
   if(t!=t_prev)
     {
      t_prev=t;
      return(true);
     }
   return(false);
  }

其操作工作原理在于,与前根柱线的开盘时间进行比较。替代检查即时报价的交易量,让我们在 CheckForOpen()CheckForClose() 函数里调用 newbar() 函数:

   if(newbar(rt[1].time)==false)
      return;

现成的完整代码可以在 moving_average_lc.mq5 文件里找到。


4.2. EA 按照 "夹针柱线" 进行交易

夹针柱线匹诺曹 是由三根柱线构成的形态。中间柱线带有长影线或 "鼻子", 指出价格行情可能的反转。两侧柱线称为 "眼睛"。它们的极值点不能超过相邻柱线的影线。这个形态在根据蜡烛条模型进行操作的交易者之中十分流行。

我们的夹针柱线必须满足下列价格反转下行的条件:

  • 柱线 r[0] 必须为阳。
  • 柱线 r[2] 必须为阴。
  • AC 之间的最大价格不应超过 B, 此处 AC 分别是柱线 r[0]r[2]最高值B 是柱线 r[1]最高价
  • 中间柱线的实体, 即柱线 r[1]开盘价 收盘价 之间的差价 (图解中的 OC), 不应超过外部参数设置的点数。
  • 中间柱线的影线, 即柱线 r[1]最高价 开盘价收盘价 之间较大的数值的差价, 不应小于外部参数设置的点数。
  • 中间柱线的影线与其实体的比率,不应小于外部参数设置的数值。

形态检查将在柱线 r[3] 开盘时进行。

夹针柱线

图例. 7. "夹针柱线" 形态

下行反转的夹针柱线存在的定义代码如下:

   if(r[0].open<r[0].close && r[2].open>r[2].close && r[1].high>MathMax(r[0].high,r[2].high))
     {
     //--- eyes of the upper pin bar
      double oc=MathAbs(r[1].open-r[1].close)/_Point;
      if(oc>inp_pb_max_OC)
         return(0);
      double shdw=(r[1].high-MathMax(r[1].open,r[1].close))/_Point;
      if(shdw<inp_pb_min_shdw)
         return(0);
      if(oc!=0)
        {
         if((shdw/oc)<inp_pb_min_ratio)
            return(0);
        }
      return(1);
     }

上行反转类似。所以, 检查夹针柱线存在的函数如下所示:

int IsPinbar(MqlRates &r[])
  {
   //--- there must be 4 values in the r[] array
   if(ArraySize(r)<4)
      return(0);
   if(r[0].open<r[0].close && r[2].open>r[2].close && r[1].high>MathMax(r[0].high,r[2].high))
     {
      //--- eyes of the upper pin bar
      double oc=MathAbs(r[1].open-r[1].close)/_Point;
      if(oc>inp_pb_max_OC)
         return(0);
      double shdw=(r[1].high-MathMax(r[1].open,r[1].close))/_Point;
      if(shdw<inp_pb_min_shdw)
         return(0);
      if(oc!=0)
        {
         if((shdw/oc)<inp_pb_min_ratio)
            return(0);
        }
      return(1);
     }
   else if(r[0].open>r[0].close && r[2].open<r[2].close && r[1].low<MathMin(r[0].low,r[2].low))
     {
      //--- eyes of the lower pin bar
      double oc=MathAbs(r[1].open-r[1].close)/_Point;
      if(oc>inp_pb_max_OC)
         return(0);
      double shdw=(MathMin(r[1].open,r[1].close)-r[1].low)/_Point;
      if(shdw<inp_pb_min_shdw)
         return(0);
      if(oc!=0)
        {
         if((shdw/oc)<inp_pb_min_ratio)
            return(0);
        }
      return(-1);
     }
   return(0);
  }

传递的历史数据数组不应小于四个元素。在检测到上部夹针柱线时 (即夹针柱线指示反转向下), 函数返回数值 1。在检测到下部夹针柱线时 (即夹针柱线指示反转向上), 函数返回数值 -1。如果根本没有夹针柱线,函数返回 0。函数也使用以下输入参数:

input uint   inp_pb_min_shdw     = 40;    // Pin bar min shadow, point
input uint   inp_pb_max_OC       = 20;    // Pin bar max OC, point
input double inp_pb_min_ratio    = 2.0;   // Pin bar shadow to OC min ratio

我们将使用最简单的依据夹针柱线的交易策略进行交易。我们将在反转向下时做空,并且在反转向上时做多。通常情况下,指标需要确认,但此刻我们不打算采用它们,以便保持实验的完整性。我们将只用夹针柱线。

此 EA 交易采用的 "夹针柱线" 形态,基于移动均线 EA。函数 CopyMABuffer() 最终被删除,因为此函数会在 CheckForOpen()CheckForClose() 函数里调用。请求的历史数据数量可以增至二到四小时。柱线 r[3] 的时间用于检查新柱线的开盘。

   int copied;
   if(LC_on==true)
   {
      int shift = LC_shift;
      copied=GetRatesLC(0,4,rt,BaseTF,shift);
   }
   else
      copied = CopyRates(_Symbol,_Period,0,4,rt);
   if(copied!=4)
     {
      Print("CopyRates of ",_Symbol," failed, no history");
      return;
     }
   if(newbar(rt[3].time)==false)
      return;

开仓信号检查如下所示:

   int pb=IsPinbar(rt);
   if(pb==1)       // upper pin bar
      signal=ORDER_TYPE_SELL; // sell conditions
   else if(pb==-1) // lower pin bar
      signal=ORDER_TYPE_BUY// buy conditions

根据反向夹针柱线平仓:

   if(type==(long)POSITION_TYPE_BUY && pb==1)
      signal=true;
   if(type==(long)POSITION_TYPE_SELL && pb==-1)
      signal=true;

请注意,在输入参数的严格条件下,夹针柱线 极少 发生。因此,若只通过反向夹针柱线平仓,则有错失利润或亏损平仓的风险。

为此, 我们添加了 止盈止损 级别。它们可分别通过外部参数设置 inp_tp_pp 和  inp_sl_pp:

   double sl=0,tp=0,p=0;
   double ask=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
   double bid=SymbolInfoDouble(_Symbol,SYMBOL_BID);
   if(signal==ORDER_TYPE_SELL)
   {
     p=bid;
     if(inp_sl_pp!=0)
       sl=NormalizeDouble(ask+inp_sl_pp*_Point,_Digits);
     if(inp_tp_pp!=0)
       tp=NormalizeDouble(ask-inp_sl_pp*_Point,_Digits);
   } else {
     p=ask;
     if(inp_sl_pp!=0)
       sl=NormalizeDouble(bid-inp_sl_pp*_Point,_Digits);
     if(inp_tp_pp!=0)
       tp=NormalizeDouble(bid+inp_sl_pp*_Point,_Digits);
   }
   CTrade trade;
   trade.PositionOpen(_Symbol,signal,TradeSizeOptimized(),p,sl,tp);

如果 inp_tp_ppinp_sl_pp 的数值为零, 则相对应的 止盈止损 级别将不会设置。

改编完成。EA 准备就绪。完整代码可在 pinbar_lc.mq5 文件里找到。


5. EA 优化

为了评估位移图表在不同策略中的效能,我们将利用 EA 优化进一步比较最佳结果。此处最重要的参数是盈利, 回撤和交易数量。依据移动均线交易的 EA 将作为指标策略的样本,而根据 "夹针柱线" 交易的EA 表现为非指标策略。

优化将在 MetaQuotes-Demo 服务器上采用最近半年的历史数据展开。此实验将针对 EURUSD, GBPUSD 和 USDJPY 进行。起始资金是 3000 美元, 杠杆 1:100。测试模式是 "所有报价"。优化模式 - 快速 (遗传算法), 最大余额。


5.1. 以移动均线进行交易的优化结果分析

让我们来比较 EA 工作在不同模式下的优化结果: 零位移, 静态位移和动态位移 (DSODSC)。

测试将针对 EURUSD, GBPUSD 和 USDJPY, 期间为 2014.04.01 - 2014.10.25 (最后六个月)。周期 H1。

EA 的输入参数:

参数
数值
 Maximum Risk in percentage
 0.1
 Descrease factor
 3.0
 Moving Average period
 12
 Moving Average shift
 6
 BaseTF
 1 分钟
 LC_on
 true
 LC_shift
 0

表 3. 移动均线 LC EA 的输入参数

5.1.1. 禁用位移模式的 EA 优化

优化参数:

参数
 开始 步长终止
 Moving Average period
 12
 1
 90
 Moving Average shift
 6
 1
 30

表 4. 移动均线 LC EA 零位移模式的优化参数

图中描绘了禁用位移模式的 EA 优化, EURUSD:

零位移模式优化, EURUSD

图例. 8. 移动均线 LC EA 零位移模式的优化, EURUSD

最佳结果:

 结果
 获利回撤 %
交易数量
均线周期 均线位移
 3796,43 796,43 16,18 111 24 12
 3776,98 776,98 17,70 77 55
 22
 3767,45 767,45 16,10 74 59
 23
 3740,38 740,38 15,87 78 55
 17
 3641,16 641,16 15,97 105 12
 17

表 5. 移动均线 LC EA 零位移模式的最佳结果

图中描绘了禁用位移模式的 EA 优化, GBPUSD:

零位移模式优化, GBPUSD

图例. 9. 移动均线 LC EA 零位移模式的优化, GBPUSD

最佳结果:

 结果 获利回撤 %
 交易数量
 均线周期均线位移
 4025,75 1025,75 8,08 80 18
 22
 3857,90 857,90 15,04 74 55
 13
 3851,40 851,40 18,16 80 13
 24
 3849,48 849,48 13,05 69 34
 29
 3804,70 804,70 16,57 137 25
 8

表 6. 移动均线 LC EA 零位移模式 GBPUSD 的最佳结果

图中描绘了禁用位移模式的 EA 优化, USDJPY:

零位移模式优化, USDJPY

图例. 10. 移动均线 LC EA 零位移模式的优化, USDJPY

最佳结果:

结果
获利
回撤 %
交易数量
 均线周期 均线位移
5801,632801,6311,5448
65
23
5789,172789,1714,0350
44
27
5539,062539,0617,1446
67
27
5331,342331,3415,0561
70
9
5045,192045,1912,6148
83
15

表 7. 移动均线 LC EA 零位移模式 USDJPY 的最佳结果

5.1.2. 静态位移模式的 EA 优化

优化参数:

参数
 开始 步长终止
 Moving Average period
 12
 1
 90
 Moving Average shift
 6
 1
 30
 LC_shift 1 1 59

表 8. 移动均线 LC EA 静态位移模式的优化参数

图中描绘了静态位移模式的 EA 优化, EURUSD:

静态位移模式优化, EURUSD

图例. 11. 移动均线 LC EA 静态位移模式的优化, EURUSD

最佳结果:

结果
获利
 回撤 %
 交易数量
均线周期
均线位移
LC_shift
 4385,06
 1385,06
 12,87 100 32 11 8
 4149,63
 1149,63
 14,22 66 77 25 23
 3984,92
 984,92
 21,52 122 12 11 26
 3969,35
 969,35
 16,08 111 32 11 24
 3922,95
 922,95
 12,29 57 77 25 10

表 9. 移动均线 LC EA 静态位移模式 EURUSD 的最佳结果

图中描绘了静态位移模式的 EA 优化, GBPUSD:

静态位移模式优化, GBPUSD

图例. 12. 移动均线 LC EA 静态位移模式的优化, GBPUSD

最佳结果:

 结果 获利回撤 %
交易数量
 均线周期 均线位移LC_shift
 4571,07 1571,07 14,90 79 12
 25
 42
 4488,90 1488,90 15,46 73 12
 25
 47
 4320,31 1320,31 9,59 107 12
 16
 27
 4113,47 1113,47 10,96 75 12
 25
 15
 4069,21 1069,21 15,27 74 12
 25
 50

表 10. 移动均线 LC EA 静态位移模式 GBPUSD 的最佳结果

图中描绘了静态位移模式的 EA 优化, USDJPY:

静态位移模式优化, USDJPY

图例. 13. 移动均线 LC EA 静态位移模式的优化, USDJPY

最佳结果:

结果
获利
回撤 %
交易数量
均线周期
 均线位移LC_shift
 6051,39 3051,39 15,94 53
 76
 12
 31
 5448,98 2448,98 10,71 54
 44
 30
 2
 5328,15 2328,15 11,90 50
 82
 13
 52
 5162,82 2162,82 10,46 71
 22
 26
 24
 5154,71 2154,71 14,34 54
 75
 14
 58

表 11. 移动均线 LC EA 静态位移模式 USDJPY 的最佳结果

5.1.3. 动态位移模式的 EA 优化

优化参数:

参数
 开始 步长终止
 Moving Average period
 12
 1
 90
 Moving Average shift
 6
 1
 30
 LC_shift -2 1 -1

表 12. 移动均线 LC EA 动态位移模式的优化参数

图中描绘了动态位移模式的 EA 优化, EURUSD:

动态位移模式优化, EURUSD

图例. 14. 移动均线 LC EA 动态位移模式的优化, EURUSD

最佳结果:

结果
获利
回撤 %
交易数量
均线周期
均线位移
LC_shift
 3392,64 392,64 27,95 594 15 13 -2
 3140,26 140,26 23,35 514 12 17 -2
 2847,12 -152,88 17,04 390 79 23 -1
 2847,12 -152,88 17,04 390 79 12 -1
 2826,25 -173,75 20,12 350 85 22 -1

表 13. 移动均线 LC EA 动态位移模式 EURUSD 的最佳结果

图中描绘了动态位移模式的 EA 优化, GBPUSD:

动态位移模式优化, GBPUSD

图例. 15. 移动均线 LC EA 动态位移模式的优化, GBPUSD

最佳结果:

 结果获利
 回撤 %
交易数量
均线周期
 均线位移LC_shift
 5377,58 2377,58 19,73 391 12
 26
 -2
 3865,50 865,50 18,18 380 23
 23
 -2
 3465,63 465,63 21,22 329 48
 21
 -2
 3428,99 428,99 24,55 574 51
 16
 -1
 3428,99 428,99 24,55 574 51
 15
 -1

表 14. 移动均线 LC EA 动态位移模式 GBPUSD 的最佳结果

图中描绘了动态位移模式的 EA 优化, USDJPY:

动态位移模式优化, USDJPY

图例. 16. 移动均线 LC EA 动态位移模式的优化, USDJPY

最佳结果:

结果
获利
回撤 %
 交易数量
均线周期
均线位移
 LC_shift
 6500,19 3500,19 17,45 244
 42
 28
 -2
 6374,18 3374,18 19,91 243
 54
 24
 -2
 6293,29 3293,29 19,30 235
 48
 27
 -2
 5427,69 2427,69 17,65 245
 90
 8
 -2
 5421,83 2421,83 16,30 301
 59
 12
 -2

表 15. 移动均线 LC EA 动态位移模式 USDJPY 的最佳结果

5.2. 以 "夹针柱线" 进行交易的优化结果分析

让我们来比较 EA 工作在不同模式下的优化结果: 零位移, 静态位移和动态位移 (DSODSC)。测试将针对 EURUSD, GBPUSD 和 USDJPY, 期间为 2014.04.01 - 2014.10.25。周期 H1。

EA 的输入参数:

 参数数值
Maximum Risk in percentage
0.1
Decrease factor
3.0
夹针最小影线点数
40
夹针最大实体点数
110
夹针至实体的最小比率
1.4
止损点数 (0 为禁用)
150
止盈点数 (0 为禁用)
300
LC Base Period
1 分钟
LC mode ON
true
LC 位移
0

表 16. 夹针柱线 LC EA 的输入参数

我们要优化夹针柱线形状定义的参数: "鼻子" 长度, 中间柱线的 "鼻子" 与实体的比率, 和最大实体大小。级别 止盈止损 也一并优化。


5.2.1. 禁用位移模式的 EA 优化

优化参数:

 参数 开始 步长 终止
夹针最小影线点数
100
20
400
夹针最大实体点数
20
20
100
夹针至实体的最小比率
1
0.2
3
止损点数 (0 为禁用)
150
50
500
止盈点数 (0 为禁用)
150
50
500

表 17. 夹针 LC EA 静态位移模式的优化参数

图中描绘了禁用位移模式的 EA 优化, EURUSD:

零位移模式优化, EURUSD

图例. 17. 夹针 LC EA 零位移模式的优化, EURUSD

最佳结果:

结果
获利
 回撤 %
 交易数量
 夹针最小影线
 夹针最大实体
 夹针影线
至实体的最小比率
 止损 止盈
 3504,59
 504,59
 9,82
 33
 100
 60
 1.8
 450
 500
 3428,89
 428,89
 8,72
 21
 120
 60
 2.8
 450
 350
 3392,37
 392,37
 9,94
 30
 100
 60
 2,6
 450
 250
 3388,54
 388,54
 9,93
 31
 100
 80
 2,2
 450
 300
 3311,84
 311,84
 6,84
 13
 140
 60
 2,2
 300
 450

表 18. 夹针 LC EA 零位移模式 EURUSD 的最佳结果

图中描绘了禁用位移模式的 EA 优化, GBPUSD:

零位移模式优化, EURUSD

图例. 18. 夹针 LC EA 零位移模式的优化, GBPUSD

最佳结果:

结果
获利
 回撤 %
 交易数量
 夹针最小影线
 夹针最大实体
 夹针影线
至实体的最小比率
 止损 止盈
 3187,13
 187,13
 11,10
 13
 160
 60
 2,6
 500
 350
 3148,73
 148,73
 3,23
 4
 220
 40
 2,8
 400
 400
 3142,67
 142,67
 11,27
 17
 160
 100
 1,8
 500
 350
 3140,80
 140,80
 11,79
 13
 180
 100
 2
 500
 500
 3094,20
 94,20
 1,62
 1
 260
 60
 1,6
 500
 400

表 19. 夹针 LC EA 零位移模式 GBPUSD 的最佳结果

图中描绘了禁用位移模式的 EA 优化, USDJPY:

零位移模式优化, USDJPY

图例. 19. 夹针 LC EA 零位移模式的优化, USDJPY

最佳结果:

结果
获利
 回撤 %
 交易数量
 夹针最小影线
 夹针最大实体
 夹针影线
至实体的最小比率
 止损 止盈
 3531,99
 531,99
 9,00
 6
 160
 60
 2.2
 450
 500
 3355,91
 355,91
 18,25
 16
 120
 60
 1,6
 450
 400
 3241,93
 241,93
 9,11
 4
 160
 40
 2,8
 450
 500
 3180,43
 180,43
 6,05
 33
 100
 80
 1,8
 150
 450
 3152,97
 152,97
 3,14
 6
 160
 80
 2,8
 150
 500

表 20. 夹针 LC EA 零位移模式 USDJPY 的最佳结果

5.2.2. 静态位移模式的 EA 优化

优化参数:

 参数 开始 步长 终止
 夹针最小影线点数
 100
 20
 400
 夹针最大实体点数
 20
 20
 100
 夹针至实体的最小比率
 1
 0.2
 3
 止损点数 (0 为禁用)
 150
 50
 500
 止盈点数 (0 为禁用)
 150
 50
 500
 LC 位移
 1 1 59

表 21. 夹针 LC EA 静态位移模式的优化参数

图中描绘了静态位移模式的 EA 优化, EURUSD:

静态位移模式优化, EURUSD

图例. 20. 夹针 LC EA 静态位移模式的优化, EURUSD

最佳结果:

结果
获利
 回撤 %
 交易数量
 夹针最小影线
 夹针最大实体
 夹针影线
至实体的最小比率
 止损 止盈 LC 位移
 4843,54
 1843,54
 10,14
 19
 120
 80
 1,6
 500
 500
 23
 4714,81
 1714,81
 10,99
 28
 100
 100
 1,6
 500
 500
 23
 4672,12
 1672,12
 10,16
 18 120
 80
 1,8
 500
 500
 23
 4610,13
 1610,13
 9,43
 19
 120
 80
 1,6
 450
 450
 23
 4562,21
 1562,21
 13,94
 27
 100
 100
 1,6
 500
 400
 25

表 22. 夹针 LC EA 静态位移模式 EURUSD 的最佳结果

图中描绘了静态位移模式的 EA 优化, GBPUSD:

静态位移模式优化, GBPUSD

图例. 21. 夹针 LC EA 静态位移模式的优化, GBPUSD

最佳结果:

结果
获利
 回撤 %
 交易数量
 夹针最小影线
 夹针最大实体
 夹针影线
至实体的最小比率
 止损 止盈 LC 位移
 4838,10
 1838,10
 5,60
 34
 100
 40
 2,4
 450
 500
 24
 4797,09
 1797,09
 5,43
 35
 100
 40
 2,6
 400
 500
 24
 4755,57
 1755,57
 7,36
 42
 100
 100
 2
 400
 500
 24
 4725,41
 1725,41
 8,35
 45
 100
 80
 1
 400
 500
 24
 4705,61
 1705,61
 8,32
 41
 100
 100
 2
 450
 500
 24

表 23. 夹针 LC EA 静态位移模式 GBPUSD 的最佳结果

图中描绘了静态位移模式的 EA 优化, USDJPY:

静态位移模式优化, USDJPY

图例. 22. 夹针 LC EA 静态位移模式的优化, USDJPY

最佳结果:

结果
获利
 回撤 %
 交易数量
 夹针最小影线
 夹针最大实体
 夹针影线
至实体的最小比率
 止损 止盈 LC 位移
 4108,83
 1108,83
 6,45
 9
 140
 40
 1,4
 500
 450
 55
 3966,74
 966,74
 7,88
 12
 140
 60
 2,8
 450
 500
 45
 3955,32
 955,32
 9,91
 21
 120
 80
 2
 500
 500
 45
 3953,80
 953,80
 6,13
 10
 140
 60
 2,8
 450
 450
 47
 3944,33
 944,33
 6,42
 6
 160
 100
 2,6
 500
 400
 44

表 24. 夹针 LC EA 静态位移模式 USDJPY 的最佳结果

5.2.3. 动态位移模式的 EA 优化

优化参数:

 参数 开始 步长 终止
 夹针最小影线点数
 100
 20
 400
 夹针最大实体点数
 20
 20
 100
 夹针至实体的最小比率
 1
 0.2
 3
 止损点数 (0 为禁用)
 150
 50
 500
 止盈点数 (0 为禁用)
 150
 50
 500
 LC 位移
 -2 1 -1

表 25. 夹针 LC EA 动态位移模式的优化参数

图中描绘了动态位移模式的 EA 优化, EURUSD:

动态位移模式优化, EURUSD

图例. 23. 夹针 LC EA 动态位移模式的优化, EURUSD

最佳结果:

结果
获利
 回撤 %
 交易数量
 夹针最小影线
 夹针最大实体
 夹针影线
至实体的最小比率
 止损 止盈 LC 位移
 4185,65
 1185,65
 13,22
 49
 200
 100
 1,8
 450
 500
 -2
 4011,80
 1011,80
 13,75
 49
 200
 100
 2
 400
 500
 -2
 3989,28
 989,28
 12,01
 76
 140
 20
 1,2
 350
 200
 -1
 3979,50
 979,50
 16,45
 157
 100
 20
 1
 450
 500
 -1
 3957,25
 957,25
 16,68
 162
 100
 20
 1
 400
 500
 -1

表 26. 夹针 LC EA 静态位移模式 EURUSD 的最佳结果

图中描绘了动态位移模式的 EA 优化, GBPUSD:

动态位移模式优化, GBPUSD

图例. 24. 夹针 LC EA 动态位移模式的优化, GBPUSD

最佳结果:

结果
获利
 回撤 %
 交易数量
 夹针最小影线
 夹针最大实体
 夹针影线
至实体的最小比率
 止损 止盈 LC 位移
 4906,84
 1906,84
 10,10
 179
 120
 40
 1,8
 500
 500
 -2
 4316,46
 1316,46
 10,71
 151
 120
 20
 2,4
 450
 500
 -1
 4250,96
 1250,96
 12,40
 174
 120
 40
 1,8
 500
 500
 -1
 4040,82
 1040,82
 12,40
 194
 120
 60
 2
 500
 200
 -2
 4032,85
 1032,85
 11,70
 139
 140
 40
 2
 400
 200
 -1

表 27. 夹针 LC EA 动态位移模式 GBPUSD 的最佳结果

图中描绘了动态位移模式的 EA 优化, USDJPY:

动态位移模式优化, USDJPY

图例. 25. 夹针 LC EA 动态位移模式的优化, USDJPY

最佳结果:

结果
获利
 回撤 %
 交易数量
 夹针最小影线
 夹针最大实体
 夹针影线
至实体的最小比率
 止损 止盈 LC 位移
 5472,67
 2472,67
 13,01
 138
 100
 20
 2,4
 500
 500
 -1
 4319,84
 1319,84
 15,87
 146
 100
 20
 2,2
 400
 500
 -1
 4259,54
 1259,54
 19,71
 137
 100
 20
 2,4
 500
 500
 -2
 4197,57
 1197,57
 15,98
 152
 100
 20
 1
 350
 500
 -1
 3908,19
 908,19
 16,79
 110
 120
 40
 3
 400
 400
 -1

表 28. 夹针 LC EA 动态位移模式 USDJPY 的最佳结果


6. 优化结果比较

为了制作一张对照表,让我们从最好结果的每一个表中选择利润,回撤和交易数量的最大值。下一个是在静态或动态位移模式的接收数值, 我们记录此数值的变化 (百分比),或者相对于零位移模式相同的数值。


6.1. EA 遵照移动均线进行交易

利润:

 无位移
 静态
发位移
动态
发位移
 EURUSD
 796,43
 1385,06 (+74%)
 392,64 (-51%)
 GBPUSD
 1025,75
 1571,07 (+53%)
 2377,58 (+132%)
 USDJPY
 2801,63
 3051,39 (+9%)
 3500,19 (+25%)

Table 29. 从移动均线 LC EA 的最佳优化结果中比较最大盈利数值

回撤:

 无位移
 静态
发位移
动态
位移
 EURUSD
 17,7
 21,52 (+22%)   
 27,95 (+58%)      
 GBPUSD
 18,16
 15,46 (-15%)
 24,55 (+35%)
 USDJPY
 17,14
 15,94 (-7%)
 19,91 (+16%)

表 30. 从移动均线 LC EA 的最佳优化结果中比较最大回撤数值

交易数量:

 无位移
 静态
发位移
动态
发位移
 EURUSD
 111
 122 (+10%)     
 594 (+435%)       
 GBPUSD
 137
 107 (-22%)
 574 (+319%)
 USDJPY
 61
 71 (+16%)
 301 (+393%)

表 31. 从移动均线 LC EA 的最佳优化结果中比较最大交易量数值

吸引您的目光的第一件事,总是动态位移模式入场点的显著增加。与此同时, 回撤明显增加, 且对于 EURUSD 利润降低两倍。

对于此 EA 来说,静态模式更有利可图。此处我们可以看到 GBPUSD 和 USDJPY 的回撤降低,而 EURUSD 和 GBPUSD 的盈利显著增加。


6.2. EA 按照 "夹针柱线" 进行交易

利润:

 无位移
 静态
发位移
动态
发位移
 EURUSD
504,59
1843,54 (+265%)
1185,65 (+135%)
 GBPUSD
187,13
1838,10 (+882%)
1906,84 (+919%)
 USDJPY
531,99
1108,83 (+108%)2472,67 (+365%)

表 32. 从夹针 LC EA 的最佳优化结果中比较最大盈利数值

回撤:

 无位移
 静态
发位移
动态
发位移
 EURUSD
9,94
13,94 (+40%)
16,68 (+68%)
 GBPUSD
11,79
8,35 (-29%)
12,4 (+5%)
 USDJPY
18,25
9,91 (-46%)
19,71 (+8%)

表 33. 从夹针 LC EA 的最佳优化结果中比较最大回撤数值

交易数量:

 无位移
 静态
发位移
动态
发位移
 EURUSD
33
28 (-15%)
162 (+391%)
 GBPUSD
17
45 (+165%)
194 (+1041%)
 USDJPY
33
21 (-36%)
152 (+361%)

表 34. 从夹针 LC EA 的最佳优化结果中比较最大交易量数值

此处,我们也看到在动态移位模式里交易量大幅增加。在此情况下, 回撤明显增加, 与在移动均线 LC EA 的情况类似, 仅针对 EURUSD。对于其它货币对回撤增加不明显, 大约 5-8 个百分点。

在静态位移模式,优化对于 GBPUSD 和 USDJPY 的盈利有限。不过,我们可以看到对于同样的货币对,回撤显著降低,但对于 EURUSD 它是增加的。对于此 EA,静态位移模式看上去盈利较低。


结论

在本文中,我们研究了"液态图表" 的绘制原理,并在指标和非指标策略实现的 EA 优化结果基础上,比较了其运作模式的影响。

因此得出以下结论:

  • 对于使用指标的策略 (例如按移动均线交易) 的 EA, 静态位移模式更适合。它确保更精准的入场,结果是回撤降低且利润增加。
  • 动态位移模式更适合按形态交易的 EA。此模式增加入场点数量,同时回撤降低。
  • 动态位移模式与组织良好的资金管理结合,可以得到更出色的结果。
  • 虽然指标策略看着非常有前途,但静态位移模式有一个显著的缺点。位移值所提供的最佳结果,必须要准确猜测输入参数列表里的其它变量的数值。

全部回复

0/140

量化课程

    移动端课程