• Registre-se

Múltiplas recontagens de barra nula em alguns indicadores

18 fevereiro 2016, 12:34
Nikolay Kositsin
0
524

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:


Indicador = Função (variável1, variável2, variável3, .... etc.).

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 Software Corp.
Artigo original: https://www.mql5.com/ru/articles/1411

Arquivos anexados |
NullBarReCount.zip (12.86 KB)
O MQL4 como uma ferramenta do trader, ou a análise técnica avançada O MQL4 como uma ferramenta do trader, ou a análise técnica avançada

As transações comerciais são, antes de tudo, um cálculo de probabilidades. O ditado que diz que o ócio é um motivador do progresso revela a razão pela qual todos os indicadores e sistemas de transações que conhecemos foram desenvolvidos. O fato é que a maioria dos novatos no mundo das transações estuda teorias "prontas" de transação. Mas, por sorte, há ainda mais segredos de mercado a serem descobertos, e as ferramentas usadas na análise de movimentos de preços existem, basicamente, sob a forma de indicadores técnicos e conjuntos matemáticos ou estatísticos não realizados. Devemos agradecer a Bill Williams por sua contribuição à teoria dos movimentos de mercado. Mas talvez ainda seja cedo para descansar.

Algoritmos genéticos vs. busca simples no otimizador do MetaTrader 4 Algoritmos genéticos vs. busca simples no otimizador do MetaTrader 4

O artigo compara o tempo e os resultados obtidos pela otimização dos Expert Advisors usando algoritmos genéticos e aqueles obtidos por buscas simples.

Meu primeiro "graal" Meu primeiro "graal"

Aqui são examinados os erros mais comuns que levam programadores de primeira viagem a criar sistemas de transações "super lucrativos" (durante testes). São apresentados experts exemplificadores que apresentam resultados fantásticos no verificador, mas resultam em perdas em transações reais.

Como usar registros de parada de funcionamento para depurar os seus próprios DLLs Como usar registros de parada de funcionamento para depurar os seus próprios DLLs

De 25 a 30% de todos os registros de parada de funcionamento recebidos de usuários surgem por conta de erros ocorridos quando funções importadas de dlls personalizados são executadas.