量化软件下载:赫兹量化峰谷指标新鲜的方法,新颖的解决方案
我们现在来快速了解一下几何学。想像轨道线指标的线池是一个 3D 平面。将一个平面垂直放到价格图表上,并于当前(零)柱处切割平面。
结果,我们得到了呈一条曲线的表面横截面(上图所示是曲线成为直线的一种特殊情况)。要做预测,有曲线上每个点的坐标就足够了,而且它们还会被用于进一步的计算当中。
我们将需要下述横截面特征:最大与最小点,以及横截面的重心(所有点值的算术平均值)。获得的特征点将被投向到当前(零)柱上,相关数据则被存储于历史中。这些特征点将充当当前与下一个峰谷节点的基础。
由于包络带搜索分高峰与低谷执行,所以我们要获取两个横截面:一个为高峰,另一个为低谷。
要获取预测,我们将使用最近的特征点。比如说,搜索某峰谷高峰时,我们取轨道线指标上轨线与某个截平面交叉所产生的横截面的特征点。相反,搜索某低谷时,我们则取轨道线指标下轨线与某个截平面交叉所产生的横截面的特征点。
测试新指标
完成了方法的定义,现在我们来创建指标。我们首先会找到峰谷指标的最后节点,并在图表中完成绘制。为此,我们将采用专为手头任务而编写的 AdvancedZigZag 类:
//+------------------------------------------------------------------+//| AdvancedZigZag.mqh |//| Copyright 2013, DC2008 |//| https://www.mql5.com/ru/users/DC2008 |//+------------------------------------------------------------------+#property copyright "Copyright 2013, DC2008"#property link "https://www.mql5.com/ru/users/DC2008"#property version "1.00"//+------------------------------------------------------------------+//| GetExtremums.mqh |//+------------------------------------------------------------------+#include <GetExtremums.mqh> // author of the code Yurich#property copyright "Copyright 2012, Yurich"#property link "https://www.mql5.com/ru/users/Yurich"//+------------------------------------------------------------------+//| ZigZag node structure |//+------------------------------------------------------------------+struct MqlZigZag { double price; // Node coordinate datetime t; // Time };//+------------------------------------------------------------------+//| The AdvancedZigZag class |//+------------------------------------------------------------------+class AdvancedZigZag {private: MqlRates rt[]; dextremum zz[]; int history; double amplitude;public: dextremum zHL[]; MqlZigZag zzH[],zzL[]; int Count(const double range); int Read(const int nodes); AdvancedZigZag(const int bars); ~AdvancedZigZag(); };//+------------------------------------------------------------------+//| Class constructor |//+------------------------------------------------------------------+AdvancedZigZag::AdvancedZigZag(const int bars) { history=bars; amplitude=0; }//+------------------------------------------------------------------+//| The Read method of the class |//+------------------------------------------------------------------+int AdvancedZigZag::Read(const int nodes) { CopyRates(NULL,0,TimeCurrent(),history,rt); int cnt=GetExtremums(amplitude,rt,zHL,nodes); return(cnt); }//+------------------------------------------------------------------+//| The Count method of the class |//+------------------------------------------------------------------+int AdvancedZigZag::Count(const double range) { amplitude=range; CopyRates(NULL,0,TimeCurrent(),history,rt); int cnt=GetExtremums(amplitude,rt,zz); ArrayResize(zzH,cnt); ArrayResize(zzL,cnt); int h=0; int l=0; for(int i=0; i<cnt; i++) { if(zz[i].type>0) { zzH[h]=(MqlZigZag)zz[i]; h++; } else { zzL[l]=(MqlZigZag)zz[i]; l++; } } ArrayResize(zzH,h); ArrayResize(zzL,l); return(cnt); }//+------------------------------------------------------------------+//| |//+------------------------------------------------------------------+AdvancedZigZag::~AdvancedZigZag() { }
共有两种方法:
计数法会找到某给定时间周期(柱数)内的所有峰谷节点,并将其保存到各种数组中,实现高峰与低谷的区分。如此一来,轨道线的分析和计算就更简单了;
读取法会找到最后的节点,并将其保存到一个单一数组中。我们需要此方法来实现峰谷指标可视化;
GetExtremums 库(由 Yury Kulikov 提供)在搜索节点时亦不可或缺。
我们将该指标放到一个 EA 交易中研究一下。为什么是 EA 交易、而不是指标呢?这当然是个人口味问题,但对我来讲,这种方式似乎更高效。毫无疑问,EA 交易的图形功能是弱了些,但我们收获的却是性能。因为相同交易品种的指标都在一个单一数据流中运行,而每个 EA 都在于自己独立的数据流中运行。我们来看看代码:
//+------------------------------------------------------------------+//| two_Comets.mq5 |//| Copyright 2013, DC2008 |//| https://www.mql5.com/ru/users/DC2008 |//+------------------------------------------------------------------+#property copyright "Copyright 2013, DC2008"#property link "https://www.mql5.com/ru/users/DC2008"#property version "1.00"#include <AdvancedZigZag.mqh>//--- Depth of history for the indicator calculationinput int depth_stories=5000; // Depth stories for calculating the indicator [bars]//--- Minimum ZigZag amplitude valueinput int amplitude=100; // The minimum value of the amplitude of the indicator [points]//--- Declaring the classAdvancedZigZag Azz(depth_stories);//---#define NUMBER_MA 227#define START_MA 5//--- macros#define SIZE(i) (double)i*0.3<1?1:(int)(i*0.25)#define ObjF1 ObjectSetString(0,name,OBJPROP_FONT,"Wingdings")#define ObjF2 ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_CENTER)#define ObjF3(T) ObjectSetInteger(0,name,OBJPROP_TIME,T)#define ObjF4(P) ObjectSetDouble(0,name,OBJPROP_PRICE,P)#define ObjF5(size) ObjectSetInteger(0,name,OBJPROP_FONTSIZE,size)#define ObjF6(code) ObjectSetString(0,name,OBJPROP_TEXT,CharToString(code))#define ObjF7(clr) ObjectSetInteger(0,name,OBJPROP_COLOR,clr)#define ObjF8 ObjectSetInteger(0,name,OBJPROP_COLOR,clrMagenta)#define ObjF9 ObjectSetInteger(0,name,OBJPROP_WIDTH,3)#define ObjF10 ObjectSetInteger(0,name,OBJPROP_BACK,true) #define ObjFont ObjF1;ObjF2;#define ObjCoordinates(T,P) ObjF3(T);ObjF4(P);#define ObjProperty(size,code,clr) ObjF5(size);ObjF6(code);ObjF7(clr);#define ObjZZ ObjF8;ObjF9;ObjF10;//---double MA[1],sumHi[NUMBER_MA],sumLo[NUMBER_MA];int handle_MA_H[NUMBER_MA],handle_MA_L[NUMBER_MA];datetime t[1];int H,L;int t_min,t_max;int err=-1;double sumH[2],maxH[2],minH[2];double sumL[2],maxL[2],minL[2];string name;int count;int shift;//+------------------------------------------------------------------+//| Expert initialization function |//+------------------------------------------------------------------+int OnInit() { shift=PeriodSeconds()/30;//--- calculation of ZigZag nodes using historical data Azz.Count(amplitude*Point()); H=ArraySize(Azz.zzH); L=ArraySize(Azz.zzL); if(H<30 || L<30) { Print("Not enough data to calculate ZigZag nodes: "+ "increase the depth of history; "+ "or decrease the amplitude value."); return(-1); }//--- for(int i=0; i<NUMBER_MA; i++) { handle_MA_H[i]=iMA(NULL,0,i+START_MA,0,MODE_SMA,PRICE_HIGH); handle_MA_L[i]=iMA(NULL,0,i+START_MA,0,MODE_SMA,PRICE_LOW); }//--- return(0); }//+------------------------------------------------------------------+//| Expert deinitialization function |//+------------------------------------------------------------------+void OnDeinit(const int reason) { ObjectsDeleteAll(0,-1,-1); for(int i=0; i<NUMBER_MA; i++) { IndicatorRelease(handle_MA_H[i]); IndicatorRelease(handle_MA_L[i]); }//--- }//+------------------------------------------------------------------+//| Expert tick function |//+------------------------------------------------------------------+void OnTick() {//--- get the current bar's opening time value CopyTime(NULL,0,0,1,t);//--- ZigZag: last 7 nodes count=Azz.Read(7); for(int i=1; i<count; i++) { name="ZZ"+(string)i; ObjectCreate(0,name,OBJ_TREND,0,0,0); ObjectSetInteger(0,name,OBJPROP_COLOR,clrRed); ObjectSetInteger(0,name,OBJPROP_WIDTH,10); ObjectSetInteger(0,name,OBJPROP_BACK,true); ObjectSetDouble(0,name,OBJPROP_PRICE,0,Azz.zHL[i-1].value); ObjectSetInteger(0,name,OBJPROP_TIME,0,Azz.zHL[i-1].time); ObjectSetDouble(0,name,OBJPROP_PRICE,1,Azz.zHL[i].value); ObjectSetInteger(0,name,OBJPROP_TIME,1,Azz.zHL[i].time); }//--- check for integrity of preliminary calculations if(err<0) { //--- calculate the sums of deviations of the nodes from MA for ZigZag peaks ArrayInitialize(sumHi,0.0); for(int j=H-1; j>=0; j--) { for(int i=0; i<NUMBER_MA; i++) { err=CopyBuffer(handle_MA_H[i],0,Azz.zzH[j].t,1,MA); if(err<0) return; sumHi[i]+=Azz.zzH[j].price-MA[0]; } } //--- calculate the sums of deviations of the nodes from MA for ZigZag troughs ArrayInitialize(sumLo,0.0); for(int j=L-1; j>=0; j--) { for(int i=0; i<NUMBER_MA; i++) { err=CopyBuffer(handle_MA_L[i],0,Azz.zzL[j].t,1,MA); if(err<0) return; sumLo[i]+=MA[0]-Azz.zzL[j].price; } } } }//+------------------------------------------------------------------+