测试当交易货币对篮子时出现的形态第二部分

8 一月 2018, 08:55
Andrei Novichkov
0
3 042

简介

我们继续测试当交易货币对篮子时出现的形态,在前面的文章中, 我们测试了超买/超卖水平突破形态,对水平突破的探讨是使用组合 WPR 指标作为实例的。这个经验可以扩展到其他基于振荡指标的组合指标中,我们假定结果将是类似的。

所进行测试的结果,是估算超卖/超买水平的位置,对于超买水平,数值范围从 60% 到 70%, 而对于超卖水平,它的范围从 -60% 到 -70%. 在所有货币对篮子的H4周期中测试该模式都展示出它的获利能力,D1 周期只能看到较少的交易数量,而 H1 则出现明显亏损。

在本文中,我们将尝试把移动平均(MA)应用到组合指标图中,并且在交易中使用它,我们将继续依赖标准的技术分析和我们自己的方法。

研究工具

我们的主要工具是著名的周期数为20的组合 WPR 指标,在它的指标图中加载周期数为10的 МА 指标。我们选择了这么小的周期数是因为我们将不会监控全局的处理:我们只对局部的趋势感兴趣,所以,就没有考虑长的周期数。

让我们在 H1, H4 和 D1 时段上做验证, 就像在前一篇文章中一样。我们记得它们中第一个形态的结果,所以,觉得和之前时段的结果一样也是有理由的,另外,当然我们也不要忘记积累的经验可以用于在任何其他时段和货币篮子中做研究。

基本的术语和规则可以在这里找到。

研究形态

这个形态在经典技术分析中非常为人熟知,我们已经描述过它,所以让我们回忆一下交易货币篮子的主要特性:

  • 交易者在统一指标图与移动平均交叉时收到一个进场信号,

这里有两种信号:

  • 货币对买入信号 — 当 МА 在图中向上与统一指标交叉时.
  • 货币对卖出信号 — 当 МА 在图中向下与统一指标交叉时.
  • 交易者通过接收到的信号,买入或者卖出货币篮子而进入市场,
  • 交易者再通过接收到与入场信号相反的信号而退出市场。

另外,要记住根据移动平均进入市场的信号通常有延迟,

我们记得,把 MA 应用于通常的货币对图表时,对于快速移动平均会有很多空的进场信号,我们想在这种情况下也会有足够的信号,为了检查这一点,我们已经开发了附在下面的 testWPR&MA.mq5 。

//+------------------------------------------------------------------+
//|                                                      testWPR.mq5 |
//|                                        MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_minimum -100
#property indicator_maximum 100


#define LG 7

#property indicator_buffers 2
#property indicator_plots   2

input int WPR       = 20; //WPR 周期数
input int maperiod  = 10; //MA 周期数
input color   clr   = clrGreen;
input color   clrMA = clrMagenta;

string pair[]={"EURUSD","GBPUSD","AUDUSD","NZDUSD","USDCAD","USDCHF","USDJPY"};
bool bDirect[]={false,false,false,false,true,true,true};

int h[LG];
double ind[],ma[];

int iUp,iDw;
//+------------------------------------------------------------------+
//| 自定义指标初始化函数                                                 |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- 指标缓冲区映射
   for(int i=0; i<LG; i++)
     {
      h[i]=iWPR(pair[i],0,WPR);
     }

   IndicatorSetString(INDICATOR_SHORTNAME,"testWPRusd");
   IndicatorSetInteger(INDICATOR_DIGITS,2);
   IndicatorSetInteger(INDICATOR_LEVELS,2);
   IndicatorSetInteger(INDICATOR_LEVELSTYLE,0,STYLE_SOLID);
   IndicatorSetInteger(INDICATOR_LEVELSTYLE,1,STYLE_SOLID);
   IndicatorSetInteger(INDICATOR_LEVELCOLOR,0,clrRed);
   IndicatorSetInteger(INDICATOR_LEVELCOLOR,1,clrRed);
   IndicatorSetInteger(INDICATOR_LEVELWIDTH,0,1);
   IndicatorSetInteger(INDICATOR_LEVELWIDTH,1,1);
   IndicatorSetDouble(INDICATOR_LEVELVALUE,0,-60);
   IndicatorSetDouble(INDICATOR_LEVELVALUE,1,60);

   ArraySetAsSeries(ind,true);
   SetIndexBuffer(0,ind);
   PlotIndexSetInteger(0,PLOT_DRAW_TYPE,DRAW_LINE);
   PlotIndexSetInteger(0,PLOT_LINE_STYLE,STYLE_SOLID);
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,2);
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,clr);
   PlotIndexSetString(0,PLOT_LABEL,"_tstWPRusd_");

   ArraySetAsSeries(ma,true);
   SetIndexBuffer(1,ma);
   PlotIndexSetInteger(1,PLOT_DRAW_TYPE,DRAW_LINE);
   PlotIndexSetInteger(1,PLOT_LINE_STYLE,STYLE_SOLID);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,1);
   PlotIndexSetInteger(1,PLOT_LINE_COLOR,clrMA);
   PlotIndexSetString(1,PLOT_LABEL,"Middle_Basket_line_MA");

   iUp=iDw=0;
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double GetValue(int shift)
  {
   double dBuf[1];
   double res=0.0;
   for(int i=0; i<LG; i++)
     {
      CopyBuffer(h[i],0,shift,1,dBuf);
      if(bDirect[i]==true)
         res+=dBuf[0];
      else
         res+=-(dBuf[0]+100);
     }//end for (int i = 0; i < iCount; i++)      
   res=res/LG;
   return (NormalizeDouble((res + 50) * 2, _Digits) );
  }
//+------------------------------------------------------------------+
//| 自定义指标迭代函数                                                   |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---
   if(prev_calculated==0 || rates_total>prev_calculated+1)
     {
      int rt=rates_total-WPR;
      for(int i=1; i<rt; i++)
        {
         ind[i]=GetValue(i);
        }
      rt-=maperiod;
      for(int i=1; i<rt; i++)
        {
         ma[i]=GetMA(ind,i,maperiod,_Digits);
        }
      rt--;
      for(int i=1; i<rt; i++)
        {
         if(ind[i] > ma[i] && ind[i+1] < ma[i+1]) {iUp++; continue;}
         if(ind[i] < ma[i] && ind[i+1] > ma[i+1]) {iDw++; continue;}
        }
      PrintFormat("买入数量: %d 卖出数量: %d",iUp,iDw);
     }
   else
     {
     }
//--- 返回 prev_calculated 的值用于下一次调用
   return(rates_total);
  }
//+------------------------------------------------------------------+

void OnDeinit(const int reason)
  {
   for(int i=0; i<LG; i++)
     {
      if(h[i]!=INVALID_HANDLE) IndicatorRelease(h[i]);
     }
   string text;
   switch(reason)
     {
      case REASON_PROGRAM:
         text="指标通过调用 ExpertRemove() 函数终止运行";break;
      case REASON_INITFAILED:
         text="这个数值表示 OnInit() 处理函数 "+__FILE__+" 返回了非零数值";break;
      case REASON_CLOSE:
         text="终端已经被关闭"; break;
      case REASON_ACCOUNT:
         text="账户已经改变";break;
      case REASON_CHARTCHANGE:
         text="交易品种或者时段已经改变";break;
      case REASON_CHARTCLOSE:
         text="图表被关闭";break;
      case REASON_PARAMETERS:
         text="输入参数已经改变";break;
      case REASON_RECOMPILE:
         text="程序 "+__FILE__+" 被重新编译";break;
      case REASON_REMOVE:
         text="程序 "+__FILE__+" 被从图表上删除";break;
      case REASON_TEMPLATE:
         text="图表上应用了新的模板";break;
      default:text="其它原因";
     }
   PrintFormat("%s",text);
  }
//+------------------------------------------------------------------+

double GetMA(const double &arr[],int index,int period,int digit) 
  {
   double m=0;
   for(int j=0; j<period; j++) m+=arr[index+j];
   m/=period;
   return (NormalizeDouble(m,digit));
  }
//+------------------------------------------------------------------+

这个指标会对整个可用历史中统一指标与移动平均的交叉次数进行计数。让我们把指标放置在 EURUSD 上,来在我们想要的时段中取得 USD 篮子的数据:

  取得的信号
H1 H4 D1
买入 卖出 买入 卖出 买入 卖出
EURUSD 8992 8992 2448 2449 550 551
历史深度 2005.09.08 2004.10.11 2000.02.28

我们看到,这里有足够的信号. 让我们假定,在其他货币篮子中的情况也是类似的,我们就不需要验证它们了。

下面的屏幕截图显示了指标的运行:

我们很快就发现很多潜在信号,很明显,它们中有很多是假信号,但是现在考虑这一点还过早。我们将使用蓝色绘制买入信号,而使用红色绘制卖出信号。

我们研究的操作逻辑如下:

  • 得到进场信号,就进入市场;在得到反向信号之后退出市场,反向进入市场。取得对应信号的时候重复这个过程。

如果没有任何额外的过滤,这个方法表明我们持续保持在市场中。我们将很可能需要这样一种过滤,但是我们将会晚些时候再探讨这个问题。同时,在屏幕截图中信号质量的差别是显而易见的:

  • 在点 7 和 8 (蓝色) 有明确的信号;
  • 点 5 (红色)信号很好;
  • 在点 2, 3 和 4 (红色)有一系列不同方向的信号.

让我们引入用于区分信号“好”与“坏”的规则,在下面的两幅图片中,我们看到真正“好”信号的特点:

我们找的"好"形态(信号)
无形态,“坏”信号





USD 上的组合 WPR 图以绿色显示,深红色线表示移动平均,而垂直蓝色线显示形态的边界。

我们假定 Delta1 和 Delta2 的距离值不应小于入场形态的 5%,

尽管如此,我们还是使用像右边的图片那样表示“坏”形态,它们没有退出信号,而是警告可能有趋势的改变或者变缓。这样,它们就可以用于退出市场或者被排除(这正是我们将要做的)。

开始测试

对于进一步的工作,我们需要在下面附加的 testEAbasket.mq5 文件中提供的 EA 交易:

//+------------------------------------------------------------------+
//|                                                 testEAbasket.mq5 |
//|                        Copyright 2017, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include <Trade\\Trade.mqh>

#define LG 7

enum BSTATE 
  {
   BCLOSE = 0,
   BBUY   = 1,
   BSELL  = 2
  };
//+------------------------------------------------------------------+
//| EA交易初始化函数                                                    |
//+------------------------------------------------------------------+
input int wpr = 20;
input int ma  = 10;
input double lt = 0.01; //lot

string pair[]={"EURUSD","GBPUSD","AUDUSD","NZDUSD","USDCAD","USDCHF","USDJPY"};
bool bDirect[]={false,false,false,false,true,true,true};

int h;
ulong  Ticket[LG];

double m[1],ml;
double w[1],wl;

BSTATE g_state;

double g_dMinSize = 5.0;

int OnInit()
  {
   h = iCustom(NULL,0,"testWPR&MA",wpr,ma);
   if (h == INVALID_HANDLE) {
      Print("当创建 testWPReur 时出错");
      return (INIT_FAILED);
   }
   
   g_state = BCLOSE;
   
   EventSetTimer(1);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| EA 交易终止函数                                                    |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   IndicatorRelease(h);
   EventKillTimer();
      
  }
//+------------------------------------------------------------------+
//| EA交易订单分时函数                                                  |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   
  }
//+------------------------------------------------------------------+
//| 计时器函数                                                        |
//+------------------------------------------------------------------+
void OnTimer()
  {
   if(IsNewCandle()) 
     {
         wl = w[0];
         CopyBuffer(h,0,1,1,w);
         ml = m[0];
         CopyBuffer(h,1,1,1,m);
         if ( w[0] > m[0] && wl < ml) {
            if (g_state != BCLOSE) CloseAllPos();
            if ( w[0] - m[0] >= g_dMinSize && ml - wl >= g_dMinSize) {
               EnterBuy(lt);
               g_state = BBUY;
            }   
         }     
         if ( w[0] < m[0] && wl > ml) {
            if (g_state != BCLOSE) CloseAllPos();
            if ( m[0] - w[0] >= g_dMinSize && wl - ml >= g_dMinSize) {
               EnterSell(lt);
               g_state = BSELL;
            }   
         }            
     }      
  }
//+------------------------------------------------------------------+
  
void CloseAllPos() 
  {

   CTrade Trade;
   Trade.LogLevel(LOG_LEVEL_NO);

   for(int i=0; i<LG; i++) 
     {

      Trade.PositionClose(Ticket[i]);
     }

     g_state = BCLOSE;

  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void EnterBuy(double lot) 
  {

   CTrade Trade;
   Trade.LogLevel(LOG_LEVEL_NO);

   for(int i=0; i<LG; i++) 
     {
      if(bDirect[i]) 
        { //发送买入订单
         Trade.Buy(lot,pair[i]);
         Ticket[i]=Trade.ResultDeal();
        }
      else 
        { //发送卖出订单
         Trade.Sell(lot,pair[i]);
         Ticket[i]=Trade.ResultDeal();
        }
     }
     g_state = BBUY;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void EnterSell(double lot) 
  {

   CTrade Trade;
   Trade.LogLevel(LOG_LEVEL_NO);

   for(int i=0; i<LG; i++) 
     {
      if(bDirect[i]) 
        { //发送卖出订单
         Trade.Sell(lot,pair[i]);
         Ticket[i]=Trade.ResultDeal();
        }
      else 
        { //发送买入订单
         Trade.Buy(lot,pair[i]);
         Ticket[i]=Trade.ResultDeal();
        }
     }
     g_state = BSELL;
  }
  
bool IsNewCandle() 
  {

   static int candle=-1;

   int t1=0;
   switch(_Period)
     {
      case PERIOD_H1:  t1 = Hour();   break;
      case PERIOD_H4:  t1 = Hour4();  break;
      case PERIOD_D1:  t1 = Day();    break;
     }
   if(t1 != candle) {candle=t1; return(true);}
   return (false);
  }
int Hour4(){return((int)Hour()/4);}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int Day()
  {
   MqlDateTime tm;
   TimeCurrent(tm);
   return(tm.day);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int Hour()
  {
   MqlDateTime tm;
   TimeCurrent(tm);
   return(tm.hour);
  }  

让我们在策略测试器中使用去年的数据,分别在H1, H4 和 D1时段测试它。我们将会分析USD货币对篮子。

分析结果可以在附件中的 testEAbasket.zip 档案中找到,它的格式是标准报告。我们可以马上说结果是负面的。使用现有的设置,该EA交易在所有三个时段都是亏损的。这是个负面的结果,但也是符合我们预料的。很难假定您可以从这样大量早期就确定的交易中取得很大的利润,下面的情况也会影响到结果:

  • 移动平均形态总是会有延迟 (根据定义).
  • 在标准技术分析中,进场决定不能基于单独一个快速移动平均的行为。
  • 该 EA 交易只是根据形态的“质量”最小程度地排除了一些信号,这显然是不够的,特别是形态“质量”只是预先确定而可能是不正确的。

然而,尽管都是负面结果,还是有一点希望的曙光。在文章的第一部分, 我们看到问题中的形态在 H4 上工作得很好,我们现在谈论的形态在 H1 上相对工作得也不错。结果是负面的,但是它也显示出获利。利润的减少不是很迅猛:

可以假定,如果这个EA和它的设置能够修改一点,我们可能会得到好的结果,我们在测试中看到余额显示出利润,有很多交易,但是曲线会有很陡峭的山谷,指示了连续的亏损结果,但是也显示了连续获利的结果的存在!让我们尝试修改EA交易的代码,在这个时段增加形态的获利能力。

修改形态的形式

我们想到的第一件事就是修改形态的格式 (Delta1 和 Delta2 参数). 最初,我们选择的是 5%. 我们应该怎样修改它呢?该数值越小,EA就会越频繁地进入市场,更高的数值会使入场次数减少,从而使形态更加“健壮”和快速,并且增加了“趋势改变的脉搏”。

我强烈相信我们不应当增加或者减少这个数值,但这并不是说这是最优的。但是如果我们在这个阶段就开始优化,我们可能会取得在某个独立时间段,某个时段和某个货币对上好的结果。换句话说,我们不能确保取得的数值是通用的。

但是,在这个方向上做些发展还是合理的。我们应当通过设置最大值来限制 Delta1 和 Delta2 数值。这是根据逻辑判断的,因为太“大”的形态可能因为转向太大而没有动力,而导致平盘或者趋势的反转而不是进一步移动。另外,一个“大”形态可能接近组合 WPR 范围的反向边界,在现有趋势的方向上,它不是一个进场的好位置。

所以,让我们把 Delta1 和 Delta2 数值的最大值设为 10%. 在这种情况下,形态“大小”为 Delta1 + Delta2 = 20%. 这不算很多。我们应当在 EA 中做下面的修改:

1. 增加全局变量:

double g_dMaxSize = 10.0;

2. 修改计时器事件处理函数:

void OnTimer()
  {
   if(IsNewCandle())
     {
      wl=w[0];
      CopyBuffer(h,0,1,1,w);
      ml=m[0];
      CopyBuffer(h,1,1,1,m);
      double d1 = MathAbs(w[0] - m[0]);
      double d2 = MathAbs(ml - wl);
      if(w[0]>m[0] && wl<ml) 
        {
         if(g_state!=BCLOSE) CloseAllPos();
         if(d1 >= g_dMinSize && d2 >= g_dMinSize &&
            d1 <= g_dMaxSize && d2 <= g_dMaxSize) 
           {
            EnterBuy(lt);
            g_state=BBUY;
           }
        }
      if(w[0]<m[0] && wl>ml) 
        {
         if(g_state!=BCLOSE) CloseAllPos();
         if(d1 >= g_dMinSize && d2 >= g_dMinSize &&
            d1 <= g_dMaxSize && d2 <= g_dMaxSize) 
           {
            EnterSell(lt);
            g_state=BSELL;
           }
        }
     }
  }


让我们继续使用修改过的EA交易在H1上进行测试,您可以在附件中的 testEAbasket1.zip 档案中找到它的结果。相应的图表显示如下:


很明显,有正面的改变,结果依然是负面的,但是亏损绝对少了很多。造成亏损的趋势变得不稳定和随机了,很深的回撤之后会有所恢复。当然,这个测试对于最终结论还是不够的,但是在 Delta1 和 Delta2 最大值上应用过滤器看起来是有益的。让我们在 EA 代码中实现这些改变。

从现在开始,我们将不会修改 Delta1 和 Delta2 的值,再次说明,这并不是说这些值是最佳的。记住我们在转换到其他时段和货币篮子时应当改变它们,我暂时更想继续使用它们。

第二个过滤器

下一步很明显了,

  • 我们在趋势的方向上,当组合 WPR (以及其它震荡指标) 接近它的边界时很谨慎地进入市场,

这是使用标准技术指标的一个为人熟知的原则,这也可以扩展到组合指标中。在前面的文章中,我们已经指出,在这种情况下可能会有趋势的反转,变换或者转向平盘。现在,我们必须在 EA 的第二个过滤器中实现这些考量。

组合 WPR 的范围是从 -100% 到 +100%,我们不能直接依靠这些数值,因为指标会接近这些边界但是将永远不会达到它们,我们拥有的是超卖/超买边界。在前面的文章中, 我们检验了这些边界的突破,并且我们知道了它们的位置,让我们就使用它们。

我们需要更加明确地定义目标,

  • 如果组合 WPR 指标图接触或者向上突破了超买边界时,交易者不会买入货币篮子。
  • 如果组合 WPR 指标图接触或者向下突破了超卖边界时,交易者不会卖出货币篮子。

我们把超买区域设置在 60-70%, 而超卖区域设置在 -60% ... -70%. 我们将使用较低的边界值(60% 和 -60%)来作为新的过滤器。让我们假定, 组合 WPR 曲线在买入货币篮子时应当低于过滤的边界,而在卖出时要高于边界。换句话说,我们不会全范围搜索移动平均交叉的形态,我们会在标准技术分析中自己定义过滤,

  • 我们将会考虑移动平均和指标图的相对位置,比较它们的高低类型。

让我们像这样修改代码块来处理进入市场的条件:

       if(w[0]>m[0] && wl<ml) 
        {
         if(g_state!=BCLOSE) CloseAllPos();
         if(d1 >= g_dMinSize && d2 >= g_dMinSize &&
            d1 <= g_dMaxSize && d2 <= g_dMaxSize && w[0] < 60) 
           {
            EnterBuy(lt);
            g_state=BBUY;
           }
        }
      if(w[0]<m[0] && wl>ml) 
        {
         if(g_state!=BCLOSE) CloseAllPos();
         if(d1 >= g_dMinSize && d2 >= g_dMinSize &&
            d1 <= g_dMaxSize && d2 <= g_dMaxSize && w[0] > -60) 
           {
            EnterSell(lt);
            g_state=BSELL;
           }
        }


让我们在之前所选的时间段和 H1 时段中测试EA交易,这里是结果:


在附件中的 testEAbasket2.zip 文件中可以找到完整档案,结果和之前的差别不是很大,尽管它们稍微好了一些。

可能是什么原因呢?这可能是因为没有准确设置超买/超卖水平,或者过滤掉的交易不够,或者两者兼有。

得到的结果是否说明应用的过滤器没有用呢?不,不是这样的,我们只能在把这个过滤器应用到所有的货币篮子中,所有选择的时段中,以及时间段明显超过一年才能下结论。所以,让我们把这个过滤器保留在 EA 代码中,尽管它的相关性还有疑问。

使用形态完成工作

我们在 USD 货币篮子中实现我们的计划,最终版本的 EA 交易就位于附件中的 testEAbasketFinal.mq5 文件中,根据进行的测试,主要结论如下:

  • 这个形态不能用作市场入场信号。

在其余的货币篮子中是否还有必要进行测试呢?结果很可能是预料得到的。

这种主要考虑使我们在其它货币中使用该形态和单个移动平均的突破时,在真正的交易中使用标准技术分析时不能用作完全的市场进场信号,echnical analysis. 所以,我们将试着把组合 WPR 指标图与移动平均的交叉用作一个过滤器。组合指标突破超买/超卖水平用作主要的入场信号。我们的目标是发现这样的过滤器是否会影响获利能力。

把形态用作过滤器

让我们定义初始问题,

  • 组合 WPR 指标图向上突破超卖区域,突破在柱形关闭时依然保持。交易者只有在移动平均“低于”组合指标图时才能买入货币篮子。
  • 如需卖出货币篮子,情况应当和上面描述的相反,
  • 组合 WPR 指标图达到 0% 区域时用于退出市场。

您可以很容易地看到,这个形态的“简化”版本(高低过滤器)被再次使用,而不是用的完整功能版本。过滤器用在移动平均和组合WPR指标图的相对位置中。

让我们修改 testEAbasket.mq5 EA 来用于测试,我们需要加入源数据来描述超买/超卖水平,以及把该形态用作过滤的条件:

input int SELLPROFIT =   0;
input int SELL1LIMIT =  70;
input int SELL2FROM  =  60;
input int SELL2TO    =  50;

input int BUYPROFIT  =   0;
input int BUY1LIMIT  = -70;
input int BUY2FROM   = -60;
input int BUY2TO     = -50;

//...................................................................

//+------------------------------------------------------------------+
//| 计时器函数                                                         |
//+------------------------------------------------------------------+
void OnTimer()
  {
   if(IsNewCandle())
     {
      wl=w[0];
      CopyBuffer(h,0,1,1,w);
      ml=m[0];
      CopyBuffer(h,1,1,1,m);

      if(g_state==BBUY && (w[0]>=BUYPROFIT))
        {
         CloseAllPos();
        }
      if(g_state==BSELL && (w[0]<=SELLPROFIT))
        {
         CloseAllPos();
        }
      if(g_state==BCLOSE && w[0]>=BUY2FROM && w[0]<=BUY2TO && wl<=BUY1LIMIT && w[0] > m[0])
        {
            EnterBuy(lt);
            return;        
        }
        
       
      if(g_state==BCLOSE && w[0]<=SELL2FROM && w[0]>=SELL2TO && wl>=SELL1LIMIT && w[0] < m[0])
        {
            EnterSell(lt);
            return;        
        }
    }
  }

在附加的 testEAbasket1.mq5 文件中可以找到完整的 EA 交易代码。

使用 H1 时段来进行测试. 在其中会发现最多数量的负面结果的交易,结果可以在前面的文章中找到,我们这里就将不会重复,

我们使用这篇文章中的形态来用作过滤器,在一年的时间段中进行测试,结果如下:

使用来自这篇文章的形态作为过滤器取得了正面的结果!我们已经得到了相对平滑的曲线,看到了清晰的获利趋势。不幸的是,交易的数量没有我们想要的那么多。当在更大的时段中应用这个EA时,交易数量会进一步降低。

在附件中的 Tester_EURUSD_Filter.zip 档案中可以找到完整的测试报告。

结论

我们已经完成了在某个货币篮子中使用基于振荡指标的组合指标构成形态的测试,我们使用组合 WPR 作为基础,但是结果可以被扩展到 RSI 和随机振荡指标中。

然而,我们必须承认,我们还不能把这个形态应用到实际交易中,积累的统计数据明显还是不够的。这有关于测试的时间段,以及形态参数本身。选择 MA 周期数仍然有待讨论。

与此同时,我们已经得到了有趣的结果,

  1. 我们已经评估了超卖/超买水平的位置,并且使用了它们。
  2. 我们已经检验了组合指标图与移动平均交叉的实用性。
  3. 我们已经评估了包含两个点的联合应用形态。

换句话说,我们已经在把这种方法引入实际引用中迈出了第一步。

文章中使用的程序:

 # 名称
类型
 描述
1 testWPR&MA.mq5 指标
检查组合指标图与移动平均交叉次数的指标。
2
testEAbasket.mq5 EA 交易
用于测试的 EA 交易。
 3
testEAbasket.zip 档案 关于 testEABasket.mq5 EA 在 USD 货币篮子中运行的标准 html 报告。
 4 testEAbasket1.zip 档案 关于 testEABasket.mq5 EA 在 USD 货币篮子中与第一个过滤器一起运行的标准 html 报告。
 5
testEAbasket2.zip EA 交易 关于 testEABasket.mq5 EA 在 USD 货币篮子和两个过滤器运行的标准 html 报告。
 6 testEAbasketFinal.mq5 EA 交易
最终版本的 testEAbasket.mq5 EA.
 7 testEAbasket1.mq5
EA 交易 用于测试的 EA 交易。
 8 Tester_EURUSD_Filter.zip 档案 测试 testEAbasket1.mq5 EA 的报告档案。


本文译自 MetaQuotes Software Corp. 撰写的俄文原文
原文地址: https://www.mql5.com/ru/articles/3818

附加的文件 |
testWPRuMA.mq5 (6.02 KB)
Tester_EURUSD.zip (276.97 KB)
testEAbasket1.mq5 (5.14 KB)
testEAbasket.mq5 (5.29 KB)
testEAbasket1.zip (148.42 KB)
testEAbasket2.zip (145.62 KB)
testEAbasket.zip (581.26 KB)
利用迪纳波利 (DiNapoli) 等级进行交易 利用迪纳波利 (DiNapoli) 等级进行交易

本文研究使用 MQL5 标准工具依据迪纳波利 (DiNapoli) 等级进行实际交易的智能交易系统变种。对其性能进行了测试并得出结论。

利用解析入场点为指标的技术创建新的交易策略 利用解析入场点为指标的技术创建新的交易策略

本文提出了一种技术, 通过汇集一套独立的指标, 以及开发定制的入场信号, 帮助每个人创建定制的交易策略。

用于 MQL5 向导的 NRTR 指标和交易模块 用于 MQL5 向导的 NRTR 指标和交易模块

在本文中, 我们将分析 NRTR 指标, 并基于此指标创建一个交易系统。我们将会开发一个交易信号模块, 此模块可用来创建基于 NRTR 与附加趋势确认指标相结合的策略。

动量弹球交易策略 动量弹球交易策略

在这篇文章中,我们会继续探讨根据 Linda B. Raschke 和 Laurence A. Connors 的 “华尔街智慧: 高胜算短线交易策略(Street Smarts: High Probability Short-Term Trading Strategies)”一书中描述的交易策略来书写代码,这一次我们将研究动量弹球系统(Momentum Pinball system): 我们会描述创建两个指标,交易机器人和一个其中的信号模块。