Multiple Null Bar Re-Count in Some Indicators
In this article, I would like to discuss the problem of multiple re-counting of the indicator value in the MetaTrader 4 Client Terminal when the null bar changes. Its core consits in that you can find in the web so many rather good indicators that can work normally only on historical data, but, when the trading platform is connected to the server, they give results that, to put it mildly, bear no relation to algorithms set on these indicators!
Usually, authors of such indicators, after having wrestled with the problem, finally find the easiest but not the wisest solution: They just make their indicators recalculate indicator's value for all bars of the chart at each launch of the int start() function in order to calculate the value on only one last, null bar!
At the first glance, all problems seem to be solved by this, but, in the reality,
the problems just move to another area. Such indicator absorbs resources, and this
results in that computer hampers and hangs!
To get outside of this problem, one should first of all think of the general idea of how the indicator is built. Every indicator is a function of some variables:
All indicators can be divided into two large groups:
- Group 1 - indicators, in which all variables are determined only by security prices
and by external variables; these variables can be calculated for any bar without
concerning them with values of the same variables on preceding bars.
- Group 2 - indicators, in which at least one variable depends on its own value obtained
as a result of indicator calculation on preceding bars:
VariableN(i) = FunctionN(VariableN(i+1)),
where the left value was obtained on the i-th bar and the value in brackets in the right part was obtained on bar i+1. Or at least one variable depends on another variable, the value of which was obtained at calculation of the indicator on preceding bars:
VariableN(i) = FunctionR(VariableX(i+1)),
where, similarly, the left value was obtained on the i-th bar and the value in brackets in the right part was obtained on bar i+1.
We are interested in indicators from Group 2 since these are these indicators that
create the problem above. Where indicator is multiply re-counted on the null bar,
such variables that, logically, should have the same values for other bars start
to be multiply re-counted for all bars, even if the indicator has been written
in due form to re-count only null bar using the IndicatorCounted() function. Such
an indicator proves to be absolutely useless for working on the real-time market.
Having explained all this, let us go to the specific indicator:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
In this case, the most simple way to solve the problem would be replacing of the variables I mentioned in the indicator code with indicator arrays:
//+------------------------------------------------------------------+ //| 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); } //+----------------------------------------------------------------+
The problem has been solved, but, in this case, it is a particular solution of this specific problem: there can be much more variables, and this is why by no means always all variables can be written as indicator buffers. In such situations, the most general solution of the problem could be the following actions. To make a normal multiple recalculation of an indicator, we need only those variables values that are obtained after calculation of the indicator on the second bar, so it is better and more comprehensive to re-count not only the last, but also the last but one bar!
Therefore, values of these variables at the end of the loop on the second bar must be memorized in some memory variables that are not local in any indicator program block, i.e. declared at the beginning of the indicator code. These memory variables can be made statistical and then introduced into the int start() function at the beginning of the text. And at every launch of the start() function before the indicator calculation loop, if the amount of counted bars is not equal to zero (if (IndicatorCounted()!=0), assign values from these memory variables to the actual indicator's variables. After that, the uncounted bars can be calculated on the same code as all bars from the beginning! It is sometimes better to memorize these variables not at the end of the loop on the second bar, but at the beginning on the first bar. This is how we will act in our further examples! Below is the same indicator written considering these ideas:
//+-------------------------------------------------------------------------+ //| 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); } //+-----------------------------------------------------------------+
Being compared to the previous one, this indicator needs much less information to restore variables in the memory. But it looks more complicated than the previous one!
The part of the code of the same indicator given below inside of the int start() function for the most advanced developers of expert advisors who combine an EA with indicators. In this code, the EA will always calculate the indicator value only on the null bar. It is natural that this variation of the code suits only to test expert on historical data. For expert advisor's online operation, one has to have another variation of the code from the indicator that we have considered in our last example. It is supposed that, if a new null bar has started to form, the indicator value on the first bar is completely counted and should not be re-counted. The same is applicable to variables that are memorized when the bar changes. It must be noted here that, if such a complicated code is not written for the expert, it will be impossible to understand what such an expert will count and on what basis it will trade! If, instead of this code, to use the proved variation with the complete re-count of the indicator on every tick on all bars only to get the value on the last, null bar, we can wait for results during a month!
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); } //+----------------------------------------------------------------+
Of course, the code becomes some more complicated!
Below is the exemplary indicator, in which, for it to work correctly, only one logical variable must be restored at every launch of the int start() function. But, without this almost imperceivable change, indicator will not work properly:
//+------------------------------------------------------------------+ //| 3LineBreak.mq4 | //| Copyright © 2004, Poul_Trade_Forum | //| Aborigen | //+------------------------------------------------------------------+ #property copyright "Poul Trade Forum" #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); }
Situation below is quite the same:
//+------------------------------------------------------------------+ //| 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); }
For the indicator below to work correctly, it is necessary to restore not only normal variables, but also the buffer:
//+------------------------------------------------------------------+ //| 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); }
Well, and finally, the well-beloved indicator ZigZag that, as we can see from analysis, is re-counted on all bars, too, and, therefore, represents the problem in question! I suppose it to be even unnecessary to put th code of this indicator in this present article since it can always be taken from the "indicators" folder of the MetaTrader 4 Client Terminal.
Of course, in this indicator, the code for more saving use of computer resources written considering all the above ideas would look rather catchy, awesome and cumbersome. In this situation, we can act differently. If, after recalculation of the indicator, we register coordinates and values of the last and the next to last inflection of the ZigZag indicator broken line, we will be able in future, at the next launch of the int start() function quite correctly re-count the non-counted values of the indicator from the nearest of these two coordinates. And the incomplete count of the last two peaks can be taken from memory. It must be added that this indicator does not work quite correctly and periodically creates absolutely nonnormal hills to do away with, and it would be highly desirable to combine thios task with the previous one. Since at least three peaks of the ZigZag indicator are always required to remove hills from the chart, we will start calculation of the indicator exactly from the туче to last from the beginning of the indicator's broken line inflection. this is how the code should be changed, in such a case:
//+------------------------------------------------------------------+ //| 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); } //---+ +----------------------------------------------------------+
As it stands now, ZigZag is much less voracious of precious computer resources that,
from the previous experience, are unfotunately always insufficient no matter how
many of them are available! I changed the name of the indicator buffer for the
more transparent "ZigZagBuffer". I took the second buffer with temporary
data off the indicator buffers since there is no necessity to have it there and
changed its name for "TempBuffer". And in three loops of indicator calculation,
I introduced variable "limit" as the start bar number, from which re-count
of only uncounted bars will start.
It is natural that every indicator is unique. And it is hardly possible to create one approach that would work equally well on all indicators. But I suppose that general ideas of such an approach are quite clear:
1. The most difficult is to determine all variables that have values accumulated
on previous ticks. It must be taken into consideration that it is sometimes necessary
to memorize some variables and bar numbers, the bar can change on the next ticks
and these saved values will not have any sense then. In such a case, the time of
bar opening must be memorized (MEMORY_bar_time = Time[lastlowBar]). Then the current
state of the bar can be restored using this memorized time (iBarShift(NULL,0,MEMORY_bar_time,
TRUE)). It can happen that there are several loops of indicator calculation and
every loop contains variables to be memorized, the same variable in different loops
having to be memorized separately at the end on the second and the first bar or
at the beginning of the loop on the first and null bar.
2. It is desirable to introduce variables with the names that correspond with the
initial variables. It is better to declare these variables as non-local at the
beginning of the indicator code. These variables can often be declared as static
ones in the indicator code itself immediately after the start() operator.
3. The code of restoring of variables must be introduced before all loops of the
indicator calculation.
4. In every loop containing actual variables, the code of memorizing these variables
should be added.
At the end, I just have to add that all indicators used as examples in this article
were taken from open sources at various forums in internet. I gave them here only
as examples to correct errors they contin and am not responsible for distribution,
copying, recompiling thereof, or for any copyright violations possibly occuring
due to somebody's placing thereof on public websites.
Nikolay Kositsin
Original article: http://articles.mql4.com/ru/articles/1411
Translated from Russian by MetaQuotes Ltd.
Original article: https://www.mql5.com/ru/articles/1411
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use