在这篇文章中,我想讨论一下 MetaTrader 4 客户端中当基础柱体改变时多次重新计算指标值。它的核心问题是,你能够在网上找到许多好的指标,他们只对于历史数据运作正常,但当交易平台连接上服务器时,它们得出的结果,说得婉转一些,就是不能实现设置在这些指标中的运算规则!
通常,这些指标的作者,在斟酌了这个问题后,最终找到了一个简单但不聪明得解决方法:他们重新计算他们的指标图表中所有的柱体在每次运行 int start() 函数时的值,来得出最后那个基础柱体的值。
第一眼看上去所有问题好象都这样解决了,但是事实上,问题转移到了另一个范畴。这样的指标占用系统资源,结果会导致电脑死机。
为了解决这个问题,我们首先应该考虑指标被建立的一般思路。每个指标都是含有一些变量的函数:
所有的指标可以被分成两大类:
我们对第二类指标感兴趣,因为它引出了上面的问题。指标在哪里需要在基础柱体上被多次重算,这些变量在逻辑上应该和另一些柱体开始对所有柱体多次重新计算的值一样,即使这个指标是用 IndicatorCounted() 函数只依靠对基础柱体重新计算而编制的。这种指标被证明对于实时行情是完全没用的。为了解释这些,让我们来看一下这个特殊的指标:
//+------------------------------------------------------------------+ //| T3.mq4 | //| MojoFX | //| http://groups.yahoo.com/group/MetaTrader_Experts_and_Indicators/ | //+------------------------------------------------------------------+ #property copyright "MojoFX - Conversion only" #property link "http://groups.yahoo.com/group/MetaTrader_Experts_and_Indicators/" //---- #property indicator_chart_window #property indicator_buffers 1 #property indicator_color1 Red //---- extern int MA_Period = 14; extern double b = 0.7; //---- double MapBuffer[]; double e1, e2, e3, e4, e5, e6; double c1, c2, c3, c4; double n, w1, w2, b2, b3; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int init() { SetIndexStyle(0, DRAW_LINE); IndicatorDigits(MarketInfo(Symbol(), MODE_DIGITS)); IndicatorShortName("T3" + MA_Period); SetIndexBuffer(0, MapBuffer); b2 = b * b; b3 = b2 * b; c1 = -b3; c2 = (3 * (b2 + b3)); c3 = -3 * (2 * b2 + b + b3); c4 = (1 + 3 * b + b3 + 3 * b2); n = MA_Period; if(n < 1) n=1; n = 1 + 0.5 * (n - 1); w1 = 2 / (n + 1); w2 = 1 - w1; //---- return(0); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int start() { // In this case, indicator's values are fully recalculated // on all bars at every launch of the start() function for(int bar = Bars-1; bar >= 0; bar--) /* If the line named "for(int bar=Bars-1; bar>=0; bar--)" is replaced with the four lines below for recounting of the indicator on only last bars at each launch of the start() function, this indicator will work properly only on historical data: int limit,counted_bars=IndicatorCounted(); if(counted_bars>0) counted_bars--; limit=Bars-1-counted_bars; for(int bar=limit; bar>=0; bar--) */ { // Variables e1,e2,e3,e4,e5,e6 are functions of themselves // calculated on the preceding bar e1 = w1 * Close[bar] + w2 * e1; e2 = w1 * e1 + w2 * e2; e3 = w1 * e2 + w2 * e3; e4 = w1 * e3 + w2 * e4; e5 = w1 * e4 + w2 * e5; e6 = w1 * e5 + w2 * e6; MapBuffer[bar]=c1 * e6 + c2 * e5 + c3 * e4 + c4 * e3; } //---- return(0); } //+------------------------------------------------------------------+
在这个案例中,最简单的解决方法是用我曾经在指标代码中提到过的数组来代替变量:
//+------------------------------------------------------------------+ //| T3.mq4 | //| MojoFX | //| http://groups.yahoo.com/group/MetaTrader_Experts_and_Indicators/ | //+------------------------------------------------------------------+ #property copyright "MojoFX - Conversion only" #property link "http://groups.yahoo.com/group/MetaTrader_Experts_and_Indicators/" #property indicator_chart_window #property indicator_buffers 1 #property indicator_color1 Red extern int T3_Period = 14; extern double b = 0.7; double MapBuffer[]; //---- Turning of variables into buffers double e1[], e2[], e3[], e4[], e5[], e6[]; //---- double c1, c2, c3, c4; double n, w1, w2, b2, b3; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int init() { //---- SetIndexStyle(0, DRAW_LINE); IndicatorDigits(MarketInfo(Symbol(), MODE_DIGITS)); IndicatorShortName("T3" + T3_Period); SetIndexBuffer(0, MapBuffer); //---- Writing of variables into indicator buffers IndicatorBuffers(7); SetIndexBuffer(1, e1); SetIndexBuffer(2, e2); SetIndexBuffer(3, e3); SetIndexBuffer(4, e4); SetIndexBuffer(5, e5); SetIndexBuffer(6, e6); //---- b2=b*b; b3=b2*b; c1=-b3; c2=(3*(b2+b3)); c3=-3*(2*b2+b+b3); c4=(1+3*b+b3+3*b2); n=T3_Period; if (n<1) n=1; n = 1 + 0.5*(n-1); w1 = 2 / (n + 1); w2 = 1 - w1; //---- return(0); } //+-----------------------------------------------------------------------+ //| Custom indicator iteration function | //+-----------------------------------------------------------------------+ int start() { //----+ check whether the amount of bars is sufficient for correct // calculation of the indicator if(Bars - 1 < T3_Period) return(0); //----+ Entering of integer variables and obtaining of bars already counted int MaxBar, limit, counted_bars = IndicatorCounted(); //---- check for possible errors if(counted_bars < 0) return(-1); //---- the last counted bar must be re-counted if(counted_bars > 0) counted_bars--; //---- determining of the oldest bar number, starting from which // all bars will be re-counted MaxBar = Bars - 1 - T3_Period; //---- determining of the oldest bar number, starting from which // only new bars will be re-counted limit = (Bars - 1 - counted_bars); //---- initialization of null if(limit > MaxBar) { for(int bar = Bars - 1; bar >= limit; bar--) MapBuffer[bar] = 0.0; limit = MaxBar; } //+--- basic loop of indicator calculation for(bar = limit; bar >= 0; bar--) { e1[bar] = w1*Close[bar] + w2*e1[bar+1]; e2[bar] = w1*e1[bar] + w2*e2[bar+1]; e3[bar] = w1*e2[bar] + w2*e3[bar+1]; e4[bar] = w1*e3[bar] + w2*e4[bar+1]; e5[bar] = w1*e4[bar] + w2*e5[bar+1]; e6[bar] = w1*e5[bar] + w2*e6[bar+1]; MapBuffer[bar] = c1*e6[bar] + c2*e5[bar] + c3*e4[bar] + c4*e3[bar]; } //+--- termination of the basic loop return(0); } //+----------------------------------------------------------------+
//+-------------------------------------------------------------------------+ //| T3.mq4 | //| Copyright 2005, MojoFX | //| http://groups.yahoo.com/group/MetaTrader_Experts_and_Indicators | //+-------------------------------------------------------------------------+ #property copyright "MojoFX - Conversion only" #property link "http://groups.yahoo.com/group/MetaTrader_Experts_and_Indicators/" #property indicator_chart_window #property indicator_buffers 1 #property indicator_color1 Yellow //---- extern int T3_Period = 8; extern double b = 0.7; //---- //---- double MapBuffer[]; //---- double e1, e2, e3, e4, e5, e6; double n, c1, c2, c3, c4, w1, w2, b2, b3; //---- introduction of variables to save variables e1,e2,e3,e4,e5,e6 int time2; double E1, E2, E3, E4, E5, E6; //+--------------------------------------------------------------------------+ //| T3 initialization function | //+--------------------------------------------------------------------------+ int init() { //---- indicators setting SetIndexStyle(0, DRAW_LINE); IndicatorDigits(MarketInfo(Symbol(), MODE_DIGITS)); IndicatorShortName("T3" + T3_Period); SetIndexBuffer(0, MapBuffer); b2 = b*b; b3 = b2*b; c1 = -b3; c2 = (3*(b2 + b3)); c3 = -3*(2*b2 + b + b3); c4 = (1 + 3*b + b3 + 3*b2); if(T3_Period < 1) T3_Period = 1; n = 1 + 0.5*(T3_Period - 1); w1 = 2 / (n + 1); w2 = 1 - w1; //---- initialization complete return(0); } //+---------------------------------------------------------------------------+ //| T3 iteration function | //+---------------------------------------------------------------------------+ int start() { //----+ check whether the amount of bars is enough for correct // indicator calculation if(Bars-1 < T3_Period) return(0); //----+ introduction of integer variables and getting of bars already counted int MaxBar, limit, counted_bars = IndicatorCounted(); //---- check for possible errors if(counted_bars < 0) return(-1); //---- the last counted bar must be re-counted if(counted_bars > 0) counted_bars--; //---- determining of the oldest bar number, starting from which // all bars will be re-counted MaxBar = Bars - 1 - T3_Period; //---- determining of the oldest bar number, starting from which // only new bars will be re-counted limit = (Bars - 1 - counted_bars); //---- initialization of null if(limit > MaxBar) { for(int bar = Bars - 1; bar >= MaxBar; bar--) MapBuffer[bar] = 0.0; limit = MaxBar; } //+--- before the basic loop of indicator calculation, restore values // of variables as they were after counting on the second bar //+--- restore values of the variables +=======+ int Tnew = Time[limit+1]; if(limit < MaxBar) if(Tnew == time2) { e1 = E1; e2 = E2; e3 = E3; e4 = E4; e5 = E5; e6 = E6; } else { if(Tnew > time2) Print("ERROR01"); else Print("ERROR02"); return(-1); } //+--- +==========================================+ //+--- Basic loop to calculate the indicator for(bar = limit; bar >= 0; bar--) { //+--- Memorize values of variables as they were after // the second bar //+--- Save values of the variables +=============+ if(bar == 1) if(((limit == 1)&&(time2 != Time[2])) || (limit > 1)) { time2 = Time[2]; E1 = e1; E2 = e2; E3 = e3; E4 = e4; E5 = e5; E6 = e6; } //+---+============================================+ e1 = w1*Close[bar] + w2*e1; e2 = w1*e1 + w2*e2; e3 = w1*e2 + w2*e3; e4 = w1*e3 + w2*e4; e5 = w1*e4 + w2*e5; e6 = w1*e5 + w2*e6; MapBuffer[bar]=c1*e6 + c2*e5 + c3*e4 + c4*e3; } //+--- terminate the basic loop return(0); } //+-----------------------------------------------------------------+
和前面的比较,这个指标需要更少的信息存储在内存中的变量里。但它看上去比前一个更复杂!
下面这段代码是同一个指标的,使用了 int start() 函数,提供给能够将智能交易程序和代码结合的高级开发者。在这段代码里,智能交易程序只在基础柱体上计算指标。当然代码里的这个变量只适合作为历史数据的测试程序。对于智能交易程序的在线运作,我们不得不使用另一个代码里的变量,来自于我们在最后的例子中研究的指标。假设,如果一个新的基础柱体开始形成,在第一个柱体上的指标值完全被计算出并且不应该被重新计算。同样也适用于柱体变化时被储存的变量。这里需要强调,如果这样一段复杂的代码没有写入智能交易程序,就不可能明白这样的程序怎么样进行计算,在什么基础上来进行交易!如果代替这段代码,用被证实的变量,每个价位都在所有的柱体上重新进行计算指标,最后得出基础柱体,我们可能用一个月的时间来等结果!
int start() { //----+ check whether the amount of bars is enough for correct // indicator calculation if(Bars-1 < T3_Period) return(0); //---- determine the oldest bar number, starting from which // all bars will be re-counted int MaxBar = Bars - 1 - T3_Period; //---- initialization of null if(MaxBar = 0) for(int bar = Bars - 1; bar > 0; bar--) MapBuffer[bar] = 0.0; //+--- before basic indicator calculation, restore values // of variables as they were after calculation on the first bar //+--- restoring values of variables +=======+ int Tnew0 = Time[2]; int Tnew1 = Time[2+1]; if(Tnew0 == time2) { e1 = E1; e2 = E2; e3 = E3; e4 = E4; e5 = E5; e6 = E6; } else if(Tnew1 != time2) { if(Tnew1 > time2) Print("ERROR01"); else Print("ERROR02"); return(-1); } //+--- +==============================================+ //+--- Memorize values of variables as they were after // the first bar //+--- Saving of values of variables +================+ if(Tnew0 != time2) { time2 = Tnew0; E1 = e1; E2 = e2; E3 = e3; E4 = e4; E5 = e5; E6 = e6; } //+---+============================================+ //+--- indicator calculation (calculation is made always // only on the null bar) e1 = w1*Close[0] + w2*e1; e2 = w1*e1 + w2*e2; e3 = w1*e2 + w2*e3; e4 = w1*e3 + w2*e4; e5 = w1*e4 + w2*e5; e6 = w1*e5 + w2*e6; MapBuffer[0] = c1*e6 + c2*e5 + c3*e4 + c4*e3; //----+ ------------------------------------------------+ //----+ The code of your expert must be placed here | //----+ ------------------------------------------------+ return(0); } //+----------------------------------------------------------------+
当然,这段代码变得复杂了一些!
下面是个可仿效的指标,在这个指标里,为了运作正常,当运行 int start() 函数时,只有一个逻辑变量必须被储存。但是如果没有这个几乎不被察觉的变化,指标不能适当地运作:
//+------------------------------------------------------------------+ //| 3LineBreak.mq4 | //| Copyright 2004, Poul_Trade_Forum | //| Aborigen | //+------------------------------------------------------------------+ #property indicator_chart_window #property indicator_buffers 2 #property indicator_color1 Gold #property indicator_color2 Magenta //---- extern int Lines_Break = 3; //---- double HighBuffer[]; double LowBuffer []; //---- double VALUE1, VALUE2, Swing = 1, OLDSwing; //---- Introduction of variables for multiple re-count of bar int time2, SWING; //+---------------------------------------------------------------------+ //| 3LineBreak initialization function | //+---------------------------------------------------------------------+ int init() { //---- Chart is performed as a hystogram SetIndexStyle(0, DRAW_HISTOGRAM); SetIndexStyle(1, DRAW_HISTOGRAM); //---- 2 indicator buffers are used for counting. SetIndexBuffer(0, HighBuffer); SetIndexBuffer(1, LowBuffer ); //---- setting of indicator values that will not be visible on the chart SetIndexEmptyValue(0, 0); SetIndexEmptyValue(1, 0); //---- names for data windows and labels for subwindows. IndicatorShortName("3LineBreak"); SetIndexLabel (0, "3LineBreak"); //---- setting of the bar number, starting from which the indicator // will be drawn SetIndexDrawBegin(0, Lines_Break); SetIndexDrawBegin(1, Lines_Break); //---- termination of the initialization return(0); } //+------------------------------------------------------------------+ //| 3LineBreak iteration function | //+------------------------------------------------------------------+ int start() { //----+ Introduction of integer variables and getting of bars already counted int MaxBar, limit, counted_bars = IndicatorCounted(); //---- check for possible errors if(counted_bars < 0) return(-1); //---- the last counted bar must be re-counted ) if(counted_bars > 0) counted_bars--; //---- determining of the oldest bar number, starting from which // all bars will be re-counted MaxBar = Bars - 1 - Lines_Break; //---- determining of the oldest bar number, starting from which // only new bars will be re-counted limit = (Bars - 1 - counted_bars); //---- initialization of null if(limit > MaxBar) { for(int bar = limit; bar > MaxBar; bar--) { HighBuffer[bar] = 0.0; LowBuffer[bar] = 0.0; } limit=MaxBar; } //---- //+--- restoring of values of variables +================+ int Tnew = Time[limit+1]; if(limit < MaxBar) if(Tnew == time2) Swing = SWING; else { if(Tnew > time2) Print("ERROR01"); else Print("ERROR02"); return(-1); } //+--- +==================================================+ //+--- basic loop of indicator calculation for(bar = limit; bar >= 0; bar--) { //+--- Saving of values of variables +=============+ if(bar == 1) if(((limit == 1) && (time2 != Time[2]))||(limit > 1)) { time2 = Time[2]; SWING = Swing; } //+---+============================================+ OLDSwing = Swing; //---- VALUE1 = High[Highest(NULL, 0, MODE_HIGH, Lines_Break, bar + 1)]; VALUE2 = Low[Lowest(NULL, 0, MODE_LOW, Lines_Break, bar + 1)]; //---- if(OLDSwing == 1 && Low [bar] < VALUE2) Swing = -1; if(OLDSwing == -1 && High[bar] > VALUE1) Swing = 1; //---- if(Swing == 1) { HighBuffer[bar] = High[bar]; LowBuffer [bar] = Low [bar]; } if(Swing == -1) { LowBuffer[bar] = High[bar]; HighBuffer[bar] = Low[bar]; } } //+--- termination of the basic loop return(0); }
//+------------------------------------------------------------------+ //| BrainTrend1.mq4 | //| BrainTrading Inc. System 7.0 | //| http://www.braintrading.com | //+------------------------------------------------------------------+ #property copyright "BrainTrading Inc. System 7.0" #property link "http://www.braintrading.com" #property indicator_chart_window #property indicator_buffers 2 #property indicator_color1 Red #property indicator_color2 Lime //---- double Ind_Buffer1[]; double Ind_Buffer2[]; double value2, Range, val1, val2, d, val3; int f, p, x1, x2, value11; //+------------------------------------------------------------------+ //| BrainTrend1 initialization function | //+------------------------------------------------------------------+ int init() { //---- SetIndexStyle(0, DRAW_HISTOGRAM); SetIndexBuffer(0, Ind_Buffer1); //---- SetIndexStyle(1, DRAW_HISTOGRAM); SetIndexBuffer(1, Ind_Buffer2); //---- string short_name; short_name = "BrainTrend1"; IndicatorShortName(short_name); SetIndexLabel(0, "" + short_name + "_Down"); SetIndexLabel(1, "" + short_name + "_Up"); IndicatorDigits(MarketInfo(Symbol(), MODE_DIGITS)); //---- f = 7; d = 2.3; x1 = 53; x2 = 47; value11 = 9; //---- termination of the initialization return(0); } //+------------------------------------------------------------------+ //| BrainTrend1 iteration function | //+------------------------------------------------------------------+ int start() { //---- check whether the amount of bars is enough to calculate if(Bars < 11) return(0); //---- Introduction of statistical memory variables for multiple // recalculation of the null bar static int MEMORY, time2; //----+ Introduction of integer variables and getting of counted bars int limit, MaxBar,bar, counted_bars = IndicatorCounted(); //---- check for possible errors if(counted_bars < 0) return(-1); //---- the last counted bar must be re-counted if(counted_bars > 0) counted_bars--; //---- determining of the oldest bar number, starting from which // all bars will be re-counted MaxBar = Bars - 1 - 10; //---- determining of the oldest bar number, starting from which // only new bars will be re-counted limit = Bars - counted_bars - 1; if(limit > MaxBar) limit = MaxBar; Comment("BrainTrading Inc. System 7.0"); //+--- restoring of values of variables +================+ int Tnew = Time[limit+1]; if(limit < MaxBar) if(Tnew == time2) p=MEMORY; else { if(Tnew > time2) Print("ERROR01"); else Print("ERROR02"); return(-1); } //+--- +===================================================+ bar = limit; while(bar >= 0) { //+--- Saving of values of variables +====+ if(bar == 1) if(((limit == 1) && (time2 != Time[2])) || (limit > 1)) { time2 = Time[2]; MEMORY = p; } //+---+====================================+ Range = iATR(NULL, 0, f, bar) / d; value2 = iStochastic(NULL, 0, value11, value11, 1, 0, 0, 0, bar); val1 = 0.0; val2 = 0.0; val3 = MathAbs(Close[bar] - Close[bar+2]); if(value2 < x2 && val3 > Range) p = 1; if(value2 > x1 && val3 > Range) p = 2; if(value2 < x2 && (p == 1||p == 0)) { if(val3 > Range) { val1 = High[bar]; val2 = Low [bar]; } } if(value2 > x1 && (p == 2||p == 0)) { val2 = High[bar]; val1 = Low [bar]; } Ind_Buffer1[bar] = val1; Ind_Buffer2[bar] = val2; bar--; } //+--- termination of the basic loop return(0); }
//+------------------------------------------------------------------+ //| BrainTrend2.mq4 | //| BrainTrading Inc. System 7.0 | //| http://www.braintrading.com | //+------------------------------------------------------------------+ #property copyright "BrainTrading Inc. System 7.0" #property link "http://www.braintrading.com" #property indicator_chart_window #property indicator_buffers 2 #property indicator_color1 Blue #property indicator_color2 Red //---- double Ind_Buffer1[]; double Ind_Buffer2[]; double spread; //---- bool river = True; int artp, limit, Curr, glava; double dartp, cecf, Emaxtra, widcha, TR; double Values[1], ATR, Weight, val1, val2, low, high, Series1; //---- Introduction of variables for multiple re-counting of the null bar bool RIVER; int time2, GLAVA; double EMAXTRA,VALUES[1]; //+------------------------------------------------------------------+ //| BrainTrend2 initialization function | //+------------------------------------------------------------------+ int init() { //---- SetIndexStyle(0, DRAW_HISTOGRAM); SetIndexBuffer(0, Ind_Buffer1); SetIndexStyle(1, DRAW_HISTOGRAM); SetIndexBuffer(1, Ind_Buffer2); spread = MarketInfo(Symbol(), MODE_SPREAD)*Point; //---- dartp = 7.0; cecf = 0.7; artp = 7; //---- change of the buffer size to the required size ArrayResize(Values, artp); //---- similar change of the memory buffer size in the first measuring // to the required size ArrayResize(VALUES, artp); //---- return(0); } //+------------------------------------------------------------------+ //| BrainTrend2 iteration function | //+------------------------------------------------------------------+ int start() { //---- check whether the amount of bars is enough to calculate if(Bars < 11) return(0); //----+ Introduction of integer variables and getting of bars already counted int limit, MaxBar, bar, J, counted_bars = IndicatorCounted(); //---- check for possible errors if(counted_bars < 0) return(-1); //---- the last counted bar must be re-counted if(counted_bars > 0) counted_bars--; //---- determining of the oldest bar number, starting from which // all bars will be re-counted MaxBar = Bars - 3; //---- determining of the oldest bar number, starting from which // only new bars will be re-counted limit = (Bars - 1 - counted_bars); //---- initialization of null if(limit >= MaxBar) { limit = MaxBar; Emaxtra = Close[limit+1]; glava = 0; double T_Series2 = Close[limit+2]; double T_Series1 = Close[limit+1]; if(T_Series2 > T_Series1) river = True; else river = False; for(int ii = Bars - 1; ii > MaxBar; ii--) { Ind_Buffer1[ii] = 0.0; Ind_Buffer2[ii] = 0.0; } } //---- //+--- restoring of values of variables +================+ int Tnew = Time[limit+1]; if(limit < MaxBar) if(Tnew == time2) { for(int xx = 0;xx <= artp - 1; xx++) Values[xx] = VALUES[xx]; glava = GLAVA; Emaxtra = EMAXTRA; river = RIVER; } else { if(Tnew > time2) Print("ERROR01"); else Print("ERROR02"); return(-1); } //+--- +==================================================+ //+--- Basic loop of the indicator calculation bar = limit; while(bar >= 0) { //+--- Saving values of variables +================+ if(bar == 1) if(((limit == 1) && (time2 != Time[2])) || (limit > 1)) { for(int kk = 0;kk <= artp - 1; kk++) VALUES[kk] = Values[kk]; GLAVA = glava; EMAXTRA = Emaxtra; RIVER = river; time2 = Time[2]; } //+---+============================================+ Series1 = Close[bar+1]; low = Low[bar]; high = High[bar]; TR = spread + high - low; if(MathAbs(spread + high - Series1) > TR ) TR = MathAbs(spread + high - Series1); if(MathAbs(low - Series1) > TR) TR = MathAbs(low - Series1); if(bar == MaxBar) for(J = 0; bar <= artp - 1; J++) Values[J] = TR; Values[glava] = TR; ATR = 0; Weight = artp; Curr = glava; for(J = 0; J <= artp - 1; J++) { ATR += Values[Curr]*Weight; Weight -= 1.0; Curr--; if(Curr == -1) Curr = artp - 1; } ATR = 2.0*ATR / (dartp*(dartp + 1.0)); glava++; if(glava == artp) glava = 0; widcha = cecf*ATR; if(river && low < Emaxtra - widcha) { river = False; Emaxtra = spread + high; } if(!river && spread + high > Emaxtra + widcha) { river = True; Emaxtra = low; } if(river && low > Emaxtra) { Emaxtra = low; } if(!river && spread + high < Emaxtra ) { Emaxtra = spread + high; } //Range1 = iATR(NULL,0,10,bar); if(river==true ) { val1 = high; val2 = low; } else { val1 = low; val2 = high; } Ind_Buffer1[bar] = val1; Ind_Buffer2[bar] = val2; bar--; } //+--- termination of the basic loop return(0); }
好了,最后很招人爱的 ZigZag 指标,如我们在技术分析里看到的,也是在所有的柱体上重新计算的,因此,提出这个问题!我想没必要在这篇文章中将这个指标的代码贴出来,因为可以在 MetaTrader 4 客户端的 "indicators" 文件夹中将其打开。
当然,在这个指标中,综合上述思路编写的更多使用电脑资源的存储代码看起来非常易使人上当的,可怕的和麻烦的。此时,我们可以表现得不同。如果重新计算指标后,我们对最后版本的 ZigZag 指标虚线记录坐标和最后两个值,我们将在将来,下一次运行 int start() 函数完全正确的重算没有计算过的,与这两个坐标最近的指标值。而这两个最后的没有计算的的高点可以从内存中取值。必须说的是,这个指标不能完全正常的运作,并且周期性的会偏离正确的运作,但用来和前面的指标组合,它还是受人喜欢的。既然 ZigZag 指标至少有三个最高点总是会与图表偏离,我们将开始严密地指标计算,从这个类型到指标的虚线变形开始的最后处。在这个案例里,代码应该这样改变:
//+------------------------------------------------------------------+ //| ZigZag.mq4 | //| Copyright 漏 2005, MetaQuotes Software Corp.| //| https://www.metaquotes.net/ | //+------------------------------------------------------------------+ #property copyright "Copyright 漏 2005, MetaQuotes Software Corp." #property link "https://www.metaquotes.net/" #property indicator_chart_window #property indicator_buffers 1 #property indicator_color1 Red #property indicator_width1 0 #property indicator_style1 1 //---- extern int ExtDepth = 12; extern int ExtDeviation = 5; extern int ExtBackstep = 3; //---- double ZigZagBuffer[]; //+------------------------------------------------------------------+ //| ZigZag initialization function | //+------------------------------------------------------------------+ int init() { //---- SetIndexBuffer(0, ZigZagBuffer); SetIndexStyle(0, DRAW_SECTION); SetIndexEmptyValue(0, 0.0); IndicatorShortName("ZigZag(" + ExtDepth + "," + ExtDeviation + "," + ExtBackstep + ")"); //---- return(0); } //+------------------------------------------------------------------+ //| ZigZag iteration function | //+------------------------------------------------------------------+ int start() { //+ check whether the amount of bars is sufficient for correct // calculation of the indicator if(Bars - 1 < ExtDepth) return(0); //+ Introduction of integer memory variables to re-count the indicator // on uncounted bars only static int time2, time3, time4; //+ Introduction of floating-point variables to re-count // the indicator on uncounted bars only static double ZigZag2, ZigZag3, ZigZag4; //+ Introduction of integer variables to re-count the indicator only // on uncounted bars and getting of indicators already counted int MaxBar, limit, supr2_bar, supr3_bar, supr4_bar; int counted_bars = IndicatorCounted(); // check for possible errors if(counted_bars < 0) return(-1); // the last counted bar must be re-counted if(counted_bars > 0) counted_bars--; //----+ Introduction of variables int shift, back, lasthighpos, lastlowpos; double val, res, TempBuffer[1]; double curlow, curhigh, lasthigh, lastlow; // determining of the oldest bar number, starting from which // all bars will be fully re-counted MaxBar = Bars - ExtDepth; // determining of the start bar number in the loop, starting from // which new bars will be re-counted if(counted_bars == 0) limit = MaxBar; else { //---- supr2_bar = iBarShift(NULL, 0, time2, TRUE); supr3_bar = iBarShift(NULL, 0, time3, TRUE); supr4_bar = iBarShift(NULL, 0, time4, TRUE); //---- limit = supr3_bar; if((supr2_bar < 0) || (supr3_bar < 0) || (supr4_bar < 0)) { limit = MaxBar; Print("Start bar was not found,", " the indicator will be re-counted on all bars" ); } } // initialization of null if(limit >= MaxBar) { for(shift = Bars - 1; shift >= MaxBar; shift--) ZigZagBuffer[shift] = 0.0; limit = MaxBar; } // change of the temporary buffer size if(ArrayResize(TempBuffer, Limit + ExtBackstep + 1)!= limit + ExtBackstep + 1) return(-1); //+ start of the first large loop for(shift = limit; shift >= 0; shift--) { //--- val = Low[Lowest(NULL, 0, MODE_LOW, ExtDepth, shift)]; if(val == lastlow) val = 0.0; else { lastlow = val; if((Low[shift] - val) > (ExtDeviation*Point)) val = 0.0; else { for(back = 1; back <= ExtBackstep; back++) { res = ZigZagBuffer[shift+back]; if((res !=0 ) && (res > val)) ZigZagBuffer[shift+back] = 0.0; } } } ZigZagBuffer[shift] = val; //--- val = High[Highest(NULL, 0, MODE_HIGH, ExtDepth, shift)]; if(val == lasthigh) val = 0.0; else { lasthigh = val; if((val - High[shift]) > (ExtDeviation*Point)) val = 0.0; else { for(back = 1; back <= ExtBackstep; back++) { res = TempBuffer[shift+back]; if((res != 0) && (res < val)) TempBuffer[shift+back] = 0.0; } } } TempBuffer[shift] = val; } //+ end of the first large loop // final cutting lasthigh = -1; lasthighpos = -1; lastlow = -1; lastlowpos = -1; //----+ start of the second large loop for(shift = limit; shift >= 0; shift--) { curlow = ZigZagBuffer[shift]; curhigh = TempBuffer[shift]; if((curlow == 0) && (curhigh == 0)) continue; //--- if(curhigh != 0) { if(lasthigh > 0) { if(lasthigh < curhigh) TempBuffer[lasthighpos] = 0; else TempBuffer[shift] = 0; } if(lasthigh < curhigh || lasthigh < 0) { lasthigh = curhigh; lasthighpos = shift; } lastlow = -1; } //---- if(curlow != 0) { if(lastlow > 0) { if(lastlow > curlow) ZigZagBuffer[lastlowpos] = 0; else ZigZagBuffer[shift] = 0; } //--- if((curlow < lastlow) || (lastlow < 0)) { lastlow = curlow; lastlowpos = shift; } lasthigh = -1; } } //+ end of the second large loop //+ start of the third loop for(shift = limit; shift >= 0; shift--) { res = TempBuffer[shift]; if(res != 0.0) ZigZagBuffer[shift] = res; } //+ end of the third loop //+ Restoring of values of the indicator buffer that // could be lost if(limit < MaxBar) { ZigZagBuffer[supr2_bar] = ZigZag2; ZigZagBuffer[supr3_bar] = ZigZag3; ZigZagBuffer[supr4_bar] = ZigZag4; for(int qqq = supr4_bar - 1; qqq > supr3_bar; qqq--) ZigZagBuffer[qqq] = 0; for(int ggg=supr3_bar - 1; ggg > supr2_bar; ggg--) ZigZagBuffer[ggg] = 0; } //+ correction of hills double vel1, vel2, vel3, vel4; int bar1, bar2, bar3, bar4; int count; if(limit == MaxBar) supr4_bar = MaxBar; for(int bar = supr4_bar; bar >= 0; bar--) { if(ZigZagBuffer[bar] != 0) { count++; vel4 = vel3; bar4 = bar3; vel3 = vel2; bar3 = bar2; vel2 = vel1; bar2 = bar1; vel1 = ZigZagBuffer[bar]; bar1 = bar; if(count < 3) continue; if((vel3 < vel2) && (vel2 < vel1)) ZigZagBuffer[bar2] = 0; if((vel3 > vel2) && (vel2 > vel1)) ZigZagBuffer[bar2] = 0; if((vel2 == vel1) && (vel1 != 0)) ZigZagBuffer[bar1] = 0; } } //+ memorizing of the last three inflections of the ZigZag and // the indicator values at these points time2 = Time[bar2]; time3 = Time[bar3]; time4 = Time[bar4]; ZigZag2 = vel2; ZigZag3 = vel3; ZigZag4 = vel4; //---- completion of calculating the indicator values return(0); } //---+ +----------------------------------------------------------+
按照现在的情况,ZigZag 占用的宝贵的电脑资源少了,从以前的经验来看,不管其可用性多高,总是不足的。我为指标缓冲改了个更明显的名字 "ZigZagBuffer"。 我把第二个缓冲用来存储临时数据,替代了指标缓存因为这儿并不需要它,并且改名为 "TempBuffer"。在三个指标计算的循环里,我把变量 "limit" 作为开始的柱体数,只有没计算过的柱体值从这儿开始重新计算。
每个指标都是唯一的,几乎不可能创建一个在全部指标中都能同样运行的方法。但是我假设这样的方法的通常思路是相当清楚的:
1. 在先前的价位上确定所有的变量是最难的。我们必须考虑到,有时需要记录一些变量和柱体数,这个柱体可以在下一个价位改变,而保存的值却没有任何改变。在这个案例中,柱体开始的时间必须被记录(MEMORY_bar_time = Time[lastlowBar])。然后当前的柱体状态可以通过被记录的时间重建(iBarShift(NULL,0,MEMORY_bar_time,TRUE))。指标计算了几个循环后,每个循环都有变量要储存,同样的变量在不同的循环里必须被分开来储存。
2. 初始化的变量要与申明的变量名字一致。最好在指标代码的开始处申明全局变量。在 start() 运作后,在指标代码里,这些变量经常被立即申明作为静态变量。
3. 在所有指标计算的循环前,必须写变量重建的代码。
4. 在每一个包含当前变量的循环里,应该添加存储这些变量的代码。
最后,我想说的是所有在本文中作为例子的指标,都可以在网络的不同论坛里获得源代码。 我把它们只作为例子分享,纠正其中的错误,如果有任何侵权的责任应归于把他们放到网站上的人。
Nikolay Kositsin
本社区仅针对特定人员开放
查看需注册登录并通过风险意识测评
5秒后跳转登录页面...
移动端课程