谈到了当交易货币篮子时,会有形态出现,我们精力集中在组合的震荡指标上。我们使用组合的WPR指标作为例子,结果我们取得了一些形态,分析了它们的优点和缺点,并且对在真实交易中使用它们的实用性得出了结论。赫兹股票量化软件
但是,这还不够。基于震荡指标的组合指标不能满足所有交易者对货币篮子进行技术分析的需要,交易者的工具箱应该要加强,加上组合的跟随趋势的指标以及赫兹股票量化软件它们自己的形态。只有在研究它们之后,我们才能确定技术工具是否已经完备。
让我们开发一个测试指标来解决这个问题。我们已经进行过这个任务,所以我们可以使用前面文章中的代码来做最小的修改。但是,我们首先应该探讨组合跟随趋势指标的一些特点,我们将使用前面文章中读者已经熟悉的术语。赫兹股票量化软件
组合跟随趋势指标的特点
组合跟随趋势指标不能基于任何趋势跟随的父指标,因为有某些限制。
限制 #1. 组合指标应该放到单独的窗口中,在价格图表窗口中显示此指标没有意义。因为平均的原则就是用于构建组合指标,而不清楚它们在这种情况下应该如何显示。另外,使用的测量单位和在图表上使用的是不同的。所以,不管是移动平均,还是布林带,再或者是其它的图表指标都无法用作父指标。
限制 #2. 组合的指标只能显示一个货币的状态;所以,您需要两个组合指标来显示一个货币对的当前状态。它们中的每一个都位于独立窗口中,我们需要两个额外的窗口。这样分开的原因是缩放尺度的差别。基于震荡指标的组合指标永远在预先定义的限制之内变化,然而,对于跟随趋势指标就不是这样,它们没有已知的最大值或者最小值。这就意味着之前描述过的方法,包括把移动平均应用到两个组合指标的读数上是没有意义的。这样的联合计算在组合跟随趋势指标的时候是不适合的。
父指标列表的限制使我们在最大程度上使用组合的跟随趋势指标,例如,根据预先的检验,在 赫兹股票量化软件 菜单中的跟随趋势指标列表中,只有 ADX 和 StdDev 符合我们的需要,赫兹股票量化软件
但是这不是我们放弃任务的理由,我们将使用提供的工具并开始使用我们已经知道的组合指标 — 篮子货币指数。赫兹股票量化软件
使用移动平均的篮子货币指数
让我们开发 testIndexMA.mq5 测试指标,和在这里描述的指标类似,并且加上了移动平均:
//+------------------------------------------------------------------+//| testDistance.mq5 |//| 2016 MetaQuotes Software Corp. |//| http://www.mql5.com |//+------------------------------------------------------------------+#property copyright "Copyright 2016, MetaQuotes Software Corp."#property link "http://www.mql5.com"#property version "1.00"#property indicator_separate_window#property indicator_buffers 2#property indicator_plots 2input color clr= clrGreen;input color clrMA = clrMagenta;input int maperiod = 10; //MA 周期数double ind[],ma[];//+------------------------------------------------------------------+//| 自定义指标初始化函数 |//+------------------------------------------------------------------+//int h,h1;int OnInit() {//--- 指标缓冲区映射 ArraySetAsSeries(ind,true); SetIndexBuffer(0,ind); IndicatorSetString(INDICATOR_SHORTNAME,"testdistance"); IndicatorSetInteger(INDICATOR_DIGITS,2); 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,"_tstdistance_"); 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, "_tstdistance_MA" ); //--- return(INIT_SUCCEEDED); } string pair[]={"EURUSD","GBPUSD","AUDUSD","NZDUSD","USDCAD","USDCHF","USDJPY"};bool bDirect[]={false,false,false,false,true,true,true};int iCount=7; double GetValue(int shift) { double res=1.0,t; double dBuf[1]; for(int i=0; i<iCount; i++) { t=CopyClose(pair[i],PERIOD_CURRENT,shift,1,dBuf); if(!bDirect[i]) dBuf[0]=1/dBuf[0]; res*=dBuf[0]; }//end for (int i = 0; i < iCount; i++) return (NormalizeDouble(MathPow (res, 1/(double)iCount), _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; 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); } } else { ind[0]= GetValue(0); ma[0] = GetMA(ind, 0, maperiod, _Digits); }//--- 返回 prev_calculated 的值用于下一次调用 return(rates_total); }void OnDeinit(const int reason) { 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)); }
使用这组输入数据,指标画出了带有移动平均的美元指数。把第49行和第50行这样修改:
赫兹股票量化软件
string pair[]={"EURUSD", "EURJPY", "EURCHF", "EURGBP", "EURNZD", "EURCAD", "EURAUD"}; bool bDirect[]={true,true,true,true,true,true,true};
再次编译文件 testIndexMA2.mq5. 结果我们会得到类似的指标,显示了欧元指数。把它放到 EURUSD H1:
编辑搜图
我们对指标的绝对值并不感兴趣。让我们对移动平均指标的交叉点来计数,计算潜在的入场点。就像在前面的文章中所说的,这些点应该在烛形关闭的时候固定,我们正是这样做的。使用垂直线标记侦测到的进场点: 蓝色表示买入而红色表示卖出,结果明显是正面的,但是,利润相对较小并且不稳定,所以应该增加获利的能力。首先,不要忘记货币对的第二个货币,并把美元指数指标加到一个独立的窗口中:赫兹股票量化软件
编辑搜图
用垂直线标记移动平均和美元指数图的交叉。让我们分析结果,
-
指数图与移动平均的交叉显示了可能的趋势反转,如果在货币对的第二个货币中也有类似(或者反转)的交叉,那就会利润更高。例如,对于 EURUSD, 如果美元指数向上与移动平均交叉,欧元指数应该向下与移动平均交叉。这种情况的信号就是一个货币走强而同时另一个货币走弱。赫兹股票量化软件
-
如果两个货币的交叉点是在同一个方向,就不要进入市场。在那种情况下,很可能是平盘。赫兹股票量化软件
-
交叉点应该清晰可见。我们在前面的文章中已经探讨过。赫兹股票量化软件
这样就得到了第一个实用的结论: 当进入市场时要考虑到两种货币的指数。推荐当一个货币走弱,而另一个货币走强的时候进入市场,其中一个信号就是指数图与赫兹股票量化软件移动平均交叉。但是,这个信号还不够: 首先,要等待第二个货币走向相反方向。
还是有延迟的问题: 对于货币对中的两个货币,在指数图和移动平均交叉点之间可能的最大距离是多少?显然,最小(并且最佳)距离是0。很难使用最大延迟来给出清楚的答案,尽管很明显应该使用某个距离。如果一个货币走弱和另一个货币的走强时间相差较远,进入市场就是危险的,在这种情况下,我们会面对背离和趋势的走弱。赫兹股票量化软件
所以,我们应该考虑根据组合的跟随趋势指标来进入市场。为了能够更准确的评估潜在入场点,让我们转到上面谈到的指标绝对值的问题。 赫兹股票量化软件
使用之字转向(ZigZag)快速分析
对于我们未来的工作, 让我们使用来自这篇文章的之字转向指标,它是由我很尊敬的同僚Dmitry Fedoseev写的。让我们把 iUniZigZagPriceSW.mq5 放置到美元指数图上:赫兹股票量化软件
编辑搜图
在这里,之字转向显示为一条蓝色的粗线。我们的目标是分析和组织之字转向片段的长度。使用这种方法,我们可能就可以得到美元指数的"摆动幅度",赫兹股票量化软件
让我们修改一点指标的代码:
//+------------------------------------------------------------------+//| iUniZigZagSW.mq5 |//| Copyright 2016, 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_buffers 6#property indicator_plots 3//--- 最高点绘图#property indicator_label1 "High"#property indicator_type1 DRAW_LINE#property indicator_color1 clrGreen#property indicator_style1 STYLE_SOLID#property indicator_width1 1//--- 最低点绘图#property indicator_label2 "Low"#property indicator_type2 DRAW_LINE#property indicator_color2 clrGreen#property indicator_style2 STYLE_SOLID#property indicator_width2 1//--- 之字转向绘图#property indicator_label3 "ZigZag"#property indicator_type3 DRAW_SECTION#property indicator_color3 clrRed#property indicator_style3 STYLE_SOLID#property indicator_width3 1//--- 方向绘图#property indicator_label4 "Direction"#property indicator_type4 DRAW_LINE#property indicator_style4 STYLE_SOLID#property indicator_width4 1//--- LastHighBar(最近的高点柱形) 绘图#property indicator_label5 "LastHighBar"#property indicator_type5 DRAW_LINE#property indicator_style5 STYLE_SOLID#property indicator_width5 1//--- LastLowBar(最近的低点柱形) 绘图#property indicator_label6 "LastLowBar"#property indicator_type6 DRAW_LINE#property indicator_style6 STYLE_SOLID#property indicator_width6 1#include <ZigZag\CSorceData.mqh>#include <ZigZag\CZZDirection.mqh>#include <ZigZag\CZZDraw.mqh>//+------------------------------------------------------------------+//| |//+------------------------------------------------------------------+enum EDirection { Dir_NBars=0, Dir_CCI=1 };//--- 输入参数input EDirection DirSelect=Dir_NBars;input int CCIPeriod = 14;input ENUM_APPLIED_PRICE CCIPrice = PRICE_TYPICAL;input int ZZPeriod=14;input string name="index-usd-zz.txt";CZZDirection*dir; CZZDraw*zz;//--- 指标缓冲区double HighBuffer[];double LowBuffer[];double ZigZagBuffer[];double DirectionBuffer[];double LastHighBarBuffer[];double LastLowBarBuffer[];//+------------------------------------------------------------------+//| 自定义指标初始化函数 |//+------------------------------------------------------------------+int h;//+------------------------------------------------------------------+//| |//+------------------------------------------------------------------+int OnInit() { switch(DirSelect) { case Dir_NBars: dir=new CNBars(ZZPeriod); break; case Dir_CCI: dir=new CCCIDir(CCIPeriod,CCIPrice); break; } if(!dir.CheckHandle()) { Alert("指标 2 下载错误"); return(INIT_FAILED); } zz=new CSimpleDraw();//--- 指标缓冲区映射 SetIndexBuffer(0,HighBuffer,INDICATOR_DATA); SetIndexBuffer(1,LowBuffer,INDICATOR_DATA); SetIndexBuffer(2,ZigZagBuffer,INDICATOR_DATA); SetIndexBuffer(3,DirectionBuffer,INDICATOR_CALCULATIONS); SetIndexBuffer(4,LastHighBarBuffer,INDICATOR_CALCULATIONS); SetIndexBuffer(5,LastLowBarBuffer,INDICATOR_CALCULATIONS); h=FileOpen(name,FILE_CSV|FILE_WRITE|FILE_ANSI,',');//--- return(INIT_SUCCEEDED); }//+------------------------------------------------------------------+//| |//+------------------------------------------------------------------+void OnDeinit(const int reason) { if(CheckPointer(dir)==POINTER_DYNAMIC) { delete(dir); } if(CheckPointer(zz)==POINTER_DYNAMIC) { delete(zz); } }//+------------------------------------------------------------------+//| 自定义指标迭代函数 |//+------------------------------------------------------------------+int ind=0;//+------------------------------------------------------------------+//| |//+------------------------------------------------------------------+int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[] ) { int start; if(prev_calculated==0) { start=0; } else { start=prev_calculated-1; } for(int i=start;i<rates_total;i++) { HighBuffer[i]=price[i]; LowBuffer[i]=price[i]; } int rv; rv=dir.Calculate(rates_total, prev_calculated, HighBuffer, LowBuffer, DirectionBuffer); if(rv==0)return(0); zz.Calculate(rates_total, prev_calculated, HighBuffer, LowBuffer, DirectionBuffer, LastHighBarBuffer, LastLowBarBuffer, ZigZagBuffer); if(ind<= 10) ind++; if(ind == 10) { double mx=0,mn=1000000; double lg; for(int i=0;i<rates_total;i++) { if(ZigZagBuffer[i]==0 || ZigZagBuffer[i]==EMPTY_VALUE) continue; if(ZigZagBuffer[i] > mx) mx = ZigZagBuffer[i]; if(ZigZagBuffer[i] < mn) mn = ZigZagBuffer[i]; } lg=mx-mn; PrintFormat("Min index: %.05f Max index: %.05f Length: %.05f",mn,mx,lg); lg/=100; double levels[100]; int count[100]; ArrayInitialize(count,0); for(int i=1; i<101; i++) levels[i-1]=NormalizeDouble(lg*i,_Digits); mn=0; for(int i=0;i<rates_total;i++) { if(ZigZagBuffer[i]==0 || ZigZagBuffer[i]==EMPTY_VALUE) continue; if(mn==0) mn=ZigZagBuffer[i]; else { lg=MathAbs(mn-ZigZagBuffer[i]); for(int j=0; j<100; j++) { if(lg<levels[j]) { count[j]++; break; } } mn=ZigZagBuffer[i]; } } for(int i=0; i<100; i++) { PrintFormat("%d level: %.05f count: %d",i,levels[i],count[i]); FileWrite(h,i,levels[i],count[i]); } FileClose(h); } return(rates_total); }//+------------------------------------------------------------------+