![Múltiplas recontagens de barra nula em alguns indicadores](https://c.mql5.com/i/articles/overlay.png)
Múltiplas recontagens de barra nula em alguns indicadores
Geralmente, os autores deste tipo de indicador, tendo se deparado com o problema, acabam por optar pela solução mais fácil, mas não pela mais sábia: Eles simplesmente fazem com que os seus indicadores recalculem o valor do indicador em relação a todas as barras do gráfico durante todas as inicializações da função int start(), a fim de calcular apenas o valor da última, a barra nula!
Em um primeiro momento, esta solução parece resolver todos os problemas. Mas, na realidade, os problemas são simplesmente movidos para outra área. Um indicador do tipo absorve recursos, e isso faz com que o computador fique obstruído e travado!
Para resolver este problema, é preciso primeiramente pensar na ideia geral de como o indicador é construído. Todo indicador é uma função de algumas variáveis:
Todas os indicadores podem ser divididos em dois grandes grupos:
- Grupo 1 - indicadores nos quais todas as variáveis são determinadas apenas pelos preços dos títulos e por variáveis externas; essas variáveis podem ser calculadas em relação a qualquer barra, sem relacioná-las a valores das mesmas variáveis em barras anteriores.
- Grupo 2 - indicadores nos quais ao menos uma variável depende do seu próprio valor, obtido como resultado do cálculo do indicador em barras anteriores:
VariávelN(i) = FunçãoN(VariávelN(i+1)),
sendo que o valor à esquerda foi obtido na barra i, e que o valor entre colchetes no lado direito foi obtido na barra i+1. Ou pelo menos uma variável depende de outra variável, cujo valor foi obtido através do cálculo do indicador em barras anteriores:
VariávelN(i) = FunçãoR(VariávelX(i+1)),
sendo que, de modo semelhante, o valor à esquerda foi obtido na barra i, e que o valor entre colchetes no lado direito foi obtido na barra i+1.
Nós estamos interessados nos indicadores do grupo 2, pois estes são os indicadores que criam o problema supracitado. Ao passo que o indicador é recontado multiplamente na barra nula, variáveis tais que logicamente deveriam ter os mesmos valores em relação a outras barras começam a ser recontadas multiplamente em relação a todas as barras, mesmo se o indicador tiver sido escrito corretamente de modo a recontar apenas a barra nula através do uso da função IndicatorCounted(). Um indicador do tipo se mostra completamente inútil para o trabalho no mercado em tempo real. Após todas estas explicações, vamos ao indicador específico:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
Neste caso, a forma mais simples de resolver o problema seria substituir, no código do indicador, as variáveis mencionadas por matrizes do indicador:
//+------------------------------------------------------------------+ //| 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); } //+----------------------------------------------------------------+
O problema foi resolvido, mas, neste caso, se trata de uma solução particular para este problema específico: pode haver um número muito maior de variáveis, e é por isso que nem sempre todas as variáveis podem ser escritas como buffers do indicador. Em tais situações, a solução mais geral ao problema seria o seguinte: Para realizar um recálculo múltiplo normal de um indicador, nós precisamos apenas daqueles valores de variáveis obtidos após o cálculo do indicador na segunda barra. Então é melhor e mais abrangente recontar não apenas a última barra, mas também a penúltima.
Portanto, os valores destas variáveis ao fim do ciclo na segunda barra devem ser memorizados em algumas variáveis de memória que não sejam locais a nenhum bloco de programa de indicador, ou seja, declaradas no início do código do indicador. Estas variáveis de memória podem ser tornadas estatísticas, e então introduzidas na função int start() no início do texto. E em toda inicialização da função start(), antes do ciclo de cálculo do indicador, caso a quantidade de barras contadas não seja igual a zero (se (IndicatorCounted()!=0), atribua valores destas variáveis de memória às variáveis do indicador presentes. Em seguida, as barras não contadas podem ser calculadas, desde o início, no mesmo código que todas as barras! Às vezes é melhor memorizar estas variáveis não no fim do ciclo da segunda barra, mas no início da primeira barra. É isso que faremos nos exemplos a seguir! Abaixo temos o mesmo indicador, agora escrito considerando estas ideias.
//+-------------------------------------------------------------------------+ //| 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); } //+-----------------------------------------------------------------+
Em comparação com o anterior, este indicador precisa de muito menos informações para restaurar variáveis na memória. Mas ele possui uma aparência muito mais complicada!
A parte do código do mesmo indicador apresentada abaixo dentro da função int start() serve aos desenvolvedores mais avançados de expert advisors, que combinam EA com indicadores. Neste código, o EA sempre irá calcular o valor do indicador apenas na barra nula. É natural que esta variante do código seja adequada apenas ao expert de teste em dados históricos. Para a operação online do expert advisor, é preciso possuir outra variante do código do indicador que nós consideramos no nosso último exemplo. Supõe-se que, caso uma barra nula nova tenha começado a se formar, o valor do indicador na primeira barra é contado completamente, não devendo ser recontado. O mesmo se aplica a variáveis que são memorizadas quando a barra muda. Deve-se notar aqui que, caso um código complexo do tipo não for escrito para o expert, será impossível saber o que o expert irá contar e com que base ele irá realizar transações! Se, ao invés deste código, usarmos a variante testada que realiza a recontagem completa do indicador a cada tick em todas as barras apenas para se obter o valor da última barra, a nula, nós poderíamos esperar pelos resultados por um mês!
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); } //+----------------------------------------------------------------+
O código, é claro, fica um pouco mais complicado!
Abaixo temos o indicador exemplar, no qual, para o seu funcionamento correto, apenas uma variável lógica deve ser restaurada a cada inicialização da função int start(). Mas sem essa mudança quase imperceptível, o indicador não irá funcionar corretamente:
//+------------------------------------------------------------------+ //| 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); }
A situação abaixo é bastante semelhante:
//+------------------------------------------------------------------+ //| 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); }
Para que o indicador abaixo funcione corretamente, é necessário restaurar não apenas as variáveis normais, mas também o 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); }
E, finalmente, o popular indicador ZigZag que, como podemos ver a partir da análise, também é recontado em todas as barras e, portanto, representa o problema em questão! Suponho que seja até mesmo desnecessário incluir o código deste indicador no presente artigo, dado que ele sempre pode ser extraído da pasta "indicadores" do terminal do cliente MetaTrader 4.
É claro que, em relação a este indicador, um código para o uso mais econômico dos recursos do computador que fosse escrito levando em consideração todas as ideias acima seria bastante atraente, incrível e trabalhoso. Neste caso, nós podemos fazer diferente. Se, após o recálculo do indicador, registrarmos as coordenadas e os valores da última e penúltima inflexões da linha quebrada do indicador ZigZag, nós seremos capazes de, no futuro, na próxima inicialização da função int start(), recontar com bastante precisão os valores não contados do indicador a partir da coordenada mais próxima entre essas duas. E a contagem incompleta dos dois últimos picos pode ser tirada da memória. Devemos adicionar que este indicador não funciona com total correção, e periodicamente cria elevações completamente anormais que devem ser descartadas, e seria bastante desejável combinar essa tarefa com a anterior. Dado que ao menos três picos do indicador ZigZag são sempre necessários para a remoção de elevações do gráfico, nós começaremos o cálculo do indicador precisamente a partir do penúltimo, começando da inflexão da linha quebrada do indicador. O código deve ser alterado deste modo, em um caso do tipo:
//+------------------------------------------------------------------+ //| 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); } //---+ +----------------------------------------------------------+
Atualmente, o ZigZag consome uma quantidade muito menor dos preciosos recursos do computador que, como sabemos, sempre acabam se mostrando insuficientes! Eu alterei o nome do buffer do indicador para o mais óbvio "ZigZagBuffer". Eu retirei do indicador o segundo buffer com dados temporários, pois ele não é necessário ali, e alterei o seu nome para "TempBuffer". E, em três ciclos de cálculo do indicador, eu introduzi a variável "limite" como o número inicial da barra, a partir do qual a recontagem apenas das barras não contadas deve começar.
É natural que todo indicador seja único. E é quase impossível criar uma abordagem capaz de trabalhar igualmente bem em todos os indicadores. Mas eu acredito que as ideias gerais de uma abordagem do tipo estão bastante claras:
1. A parte mais difícil é determinar todas as variáveis que possuem valores acumulados em ticks anteriores. Deve-se levar em consideração que às vezes é necessário memorizar algumas variáveis e números de barra, e a barra pode mudar no próximo tick, tornando esses valores salvos inúteis. Neste tipo de caso, o tempo da abertura da barra deve ser memorizado (MEMORY_bar_time = Time[lastlowBar]). Então o estado atual da barra pode ser restaurado através do uso deste tempo memorizado (iBarShift(NULL,0,MEMORY_bar_time, TRUE)). Pode ocorrer de haver vários ciclos do cálculo do indicador, e cada loop conter variáveis a serem memorizadas, a mesma variável em ciclos diferentes tendo que ser memorizada separadamente ao fim da segunda e da primeira barras ou no início do ciclo na primeira barra e na barra nula.
2. É desejável introduzir variáveis com os nomes que correspondam à variável inicial. É melhor declarar estas variáveis como não-locais no início do código do indicador. Frequentemente estas variáveis podem ser declaradas estáticas no próprio código do indicador imediatamente após o operador do start().
3. O código para a restauração de variáveis deve ser introduzido antes de todos os ciclos do cálculo do indicador.
4. Em todos os ciclos contendo variáveis reais, deve ser adicionado o código para a memorização dessas variáveis.
Finalmente, eu preciso apenas adicionar que todos os indicadores usados como exemplos neste artigo foram extraídos de fontes abertas em vários fóruns na internet. Eu os forneci aqui apenas como exemplos de correção de erros contidos neles, e não sou responsável pela sua distribuição, cópia, ou recompilação, ou por quaisquer violações de direitos autorais que possam ocorrer caso alguém os coloque em websites públicos.
Nikolay Kositsin
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/1411
![Meu primeiro "graal"](https://c.mql5.com/2/13/144_2.png)
![O MQL4 como uma ferramenta do trader, ou a análise técnica avançada](https://c.mql5.com/2/13/137_1.png)
![Como usar registros de parada de funcionamento para depurar os seus próprios DLLs](https://c.mql5.com/2/13/153_6.gif)
![Algoritmos genéticos vs. busca simples no otimizador do MetaTrader 4](https://c.mql5.com/2/13/135_1.gif)
![MQL5 - Linguagem para estratégias de negociação inseridas no terminal do cliente MetaTrader 5](https://c.mql5.com/i/registerlandings/logo-2.png)
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso