Mehrmalige Neuberechnungen des nullwertigen Bars in einigen Indikatoren

Nikolay Kositsin | 18 Januar, 2016

In diesem Artikel möchte ich das Problem der mehrmaligen Neuberechnungen des Indikator-Wertes betrachten, wenn das nullwertige Bar sich im Client-Terminal MetaTrader 4 ändert. Der Kern des Problems besteht darin, dass es im Internet zahlreiche und meistens gute Indikatoren gibt, die nur in History-Intervallen normal funktionieren, aber wenn die Handelsplattform zum Server verbunden ist, geben sie wenig gesagt die Ergebnisse, die mit den Algorithmen dieser Indikatoren nichts zu tun haben!

Normalerweise nach der langen Überlegungen finden die Programmiere, die diese Variablen erstellt haben, eine gar keine kluge Lösung zu diesem Problem: Sie erstellen ihre Indikatoren nur für die Wert-Berechnung des letzten nullwertigen Bars, und die Funktion int start() muss dann bei jedem neuen Start die Indikatoren-Werte für alle Bars im Chart neuberechnen!


Es scheint auf dem ersten Blick, es seien mit dieser Lösung alle Probleme weg, aber in der Tat werden diese Probleme einfach in eine andere Dimension verschoben, solche Indikatoren werden nur mehr die Computer-Ressourcen verbrauchen, was folgendermaßen bei einer Menge von unkorrekt funktionierenden Indikatoren zum "hängen bleiben" des Computers führen kann!


Um das Problem besser zu verstehen, muss man zuerst besser die allgemeine Idee des Indikatorenaufbaus betrachten. Jeder Indikator ist vor allem eine Funktion aus einigen Variablen:


Indikator = Funktion (Variable 1, Variable 2, Variable 3, .... u.s.w.).

Alle Indikatoren kann man zu zwei Gruppen teilen:

  • Die Erste- sind Indikatoren, in denen alle Variablen nur von den Preisen des Finanzinstrumentes und externen Variablen bestimmt werden, und dabei kann man diese Variablen für jedes Bar ohne Zusammenhang der Variablen mit den Werten der gleichen Variablen berechnen, die in den vorherigen Bars berechnet wurden.

  • Die Zweite - sind Indikatoren, in denen wenigstens eine Variable von ihren Wert abhängig ist, der bei der Berechnung der Indikatoren in den letzten Bars erhalten wurde:

    Die Variable N(i) = Die Funktion N( Die Variable N(i+1)),

    Wo der linke Wert auf i-ten Bars erhalten wurde, und der Wert in Klammern im rechten Teil wurde auf i+1 Bars erhalten. Oder eine Variable muss wenigstens von einer anderen Variable abhängig sein, deren Wert bei der Berechnung der Indikatoren in den letzten Bars erhalten wurde:

    Die Variable N(i) = Die Funktion R( Die Variable X(i+1)),

    Wo der linke Wert auf i-ten Bars erhalten wurde, und der Wert in Klammern im rechten Teil wurde auf i+1 Bars erhalten.

Uns werden Indikatoren aus der zweiten Gruppe interessieren, weil eben diese Variablen dieses Problem bereiten, welches in diesem Artikel aktuell betrachtet ist. Bei mehrmaligen Neuberechnungen des Indikators im nullwertigen Bar gibt es solche Variablen, die logischerweise nur einige die selben Werte für andere Bars haben müssen, sie fangen aber an, mehrmalige Neuberechnungen für alle Bars durchzuführen, wenn sogar der Indikator nach allen Regeln nur für die Berechnung des nullwertigen Bars mit der Funktion IndicatorCounted()geschrieben ist. Ein solcher Indikator wird dann absolut untauglich für die Online-Arbeit auf dem Markt sein, nach allen diesen Erklärungen lassen Sie uns bitte einen konkreten Indikator betrachten:

//+------------------------------------------------------------------+
//|                                                           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 diesem Fall wird die Indikatoren-Werten 
    // auf allen Bars bei jedem Start der Funktion start() ganz neuberechnet
    for(int bar = Bars-1; bar >= 0; bar--)
    /*
          Wenn die Zeile "for(int bar=Bars-1; bar>=0; bar--)" mit 
          den 4 unten kommenden Zeilen wechseln, um den Indikator nur auf letzten Bars bei jedem Start der Funktion start() neuzuberechnen 
          , dann wird dieser Indikator nur  
          in der History gut arbeiten:
 
         int  limit,counted_bars=IndicatorCounted();
         if(counted_bars>0) counted_bars--;
         limit=Bars-1-counted_bars;
         for(int bar=limit; bar>=0; bar--)
         */
      {
        // Variablen e1,e2,e3,e4,e5,e6 sind Funktionen von sich selbst, 
        // die in den vorherigen Bars berechnet wurden  
        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 diesem Fall ist die einfachste Lösung des Problems, die Variablen zu wechseln, auf die ich im Indikatortext hingewiesen habe, mit Indikatoren-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[];
//---- Die Verwaltung der Variablen in Puffern
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);
//---- Die Einschreibung der Variablen in Indikatorpuffern
   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()
  {
//----+ Die Überprüfung der Anzahl der Bars , damit sie ausreichend für die richtige 
//      Berechnung des Indikators wären
   if(Bars - 1 < T3_Period)
       return(0);
//----+ Eingabe der ganzen Variablen und erhalten dadurch bereits berechneten Bars
   int MaxBar, limit, counted_bars = IndicatorCounted();
//---- Überprüfung auf mögliche Fehler
   if(counted_bars < 0)
       return(-1);
//---- das letzte berechnete Bar muss neuberechnet werden
   if(counted_bars > 0) 
       counted_bars--;
//---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung  
//     Bars beginnt
   MaxBar = Bars - 1 - T3_Period;
//---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung  
//     nur neuen Bars beginnt
   limit = (Bars - 1 - counted_bars);
//---- Initialisieren der Null
   if(limit > MaxBar)
     {
       for(int bar = Bars - 1; bar >= limit; bar--)
           MapBuffer[bar] = 0.0;
       limit = MaxBar; 
     }
//+--- Die Hauptloop der Berechnung des Indikators
   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];
     } 
//+--- Das Ende der Hauptloop
   return(0);
  }
//+----------------------------------------------------------------+

Das Problem ist gelöst, aber es ist in diesem Fall nur eine spezielle Lösung dieses spezifischen Problems: Es können mehr Variablen sein, und aus diesem Grund ist es nicht immer möglich, alle Variablen als Indikatorpuffer einzuschreiben. In solchen Situationen können die folgenden Aktionen als die allgemeine Lösung des Problems werden. Um eine normale Neuberechnung des Indikators durchzuführen, braucht man den Wert der Variablen, die nach der Indikatorberechnung im zweiten Bar erhalten wurden, deshalb ist es immer besser und sachlicher, nicht nur das letzte Bar neuzuberechnen, sondern auch das vorletzte Bar!

Von daher muss man den Werte dieser Variablen am Ende der Loop des zweiten Bars in einigen Speichervariablen speichern, die nicht lokal in einem Programmblock eines Indikators bleiben, das heisst, die schon am Textanfang des Indikators angezeigt sind. Man kann diese Speichervariablen auch statistisch machen und dann kann man sie in die Funktion int start() am Textanfang eintragen. Und es wird bei jedem Start der Funktion start () sein, bevor die Loop der Indikatorberechnung kommt, wenn die Anzahl der gezählten Bars nicht Null ist,
if(IndicatorCounted()!=0)
werden die aktuellen Variablen des Indikators mit den Werten aus diesen Speichervariablen zugeordnet. Danach kann man die Berechnung dieser ungezählten Bars nach dem gleichen Code, genauso wie von Anfang alle Bars, durchführen! Es ist jedoch manchmal besser, die Variablen nicht am Ende der Loop im zweiten Bar zu speichern, sondern am Anfang in ersten Bar. In weiterem Beispiel machen wir es genauso! Hier ist eine Variante zum gleichen Indikator, der nach dieser Art geschrieben wurde:
//+------------------------------------------------------------------+
//|                                                           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;
//---- Eingabe der Variablen, um die Variablen zu speichern   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;
//---- Das Ende des Initialisierens 
   return(0);
  }
//+------------------------------------------------------------------+
//| T3 iteration function                                            |
//+------------------------------------------------------------------+
int start()
  {
//----+ Die Überprüfung der Anzahl der Bars , damit sie ausreichend für die richtige 
//      Berechnung des Indikators wären
   if(Bars-1 < T3_Period)
       return(0);
//----+ Eingabe der ganzen Variablen und erhalten dadurch bereits berechneten Bars
   int MaxBar, limit, counted_bars = IndicatorCounted();
//---- Überprüfung auf mögliche Fehler
   if(counted_bars < 0)
       return(-1);
//---- das letzte berechnete Bar muss neuberechnet werden
   if(counted_bars > 0) 
       counted_bars--;
//---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung  
//     aller Bars beginnt
   MaxBar = Bars - 1 - T3_Period;
//---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung  
//     nur der neuen Bars beginnt
   limit = (Bars - 1 - counted_bars);
//---- Initialisieren der Null
   if(limit > MaxBar)
     {
       for(int bar = Bars - 1; bar >= MaxBar; bar--)
           MapBuffer[bar] = 0.0;
       limit = MaxBar; 
     }
//+--- bis zur Hauptloop der Berechnung des Indikators stellen wir den Wert
//     der Variablen wieder, wie sie nach der Berechnung im zweiten Bar waren
//+--- Wiederherstellung der Werte der Variablen  +=======+
   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);
     }
//+--- +==========================================+
//+--- Die Hauptloop der Berechnung des Indikators
   for(bar = limit; bar >= 0; bar--)
     {
       //+--- Speichern wir den Wert der Variablen, wie sie nach der Berechnung  
       //     im zweiten Bar waren
       //+--- Speichern wir den Wert der Variablen +=============+ 
       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;
     } 
   //+--- Das Ende der Hauptloop
   return(0);
  }
//+-----------------------------------------------------------------+

Im Vergleich mit dem letzten Indikator, benutzt dieser Indikator weniger Information bei der Wiederherstellung der Variablen im Speicher! Aber er sieht komplizierter aus als der vorhergehende!

Und da ist eine Variante zum Teil des gleichen Indikators in der Funktion int start(), das ist für die fortgeschrittenen Programmiere des Advisors, die den Advisor mit Indikatoren verbinden, in diesem Code wird der Advisor den Wert des Indikators im nullwertigen Bar berechnen. Natürlich passt diese Variation des Codes nur für den Test des Advisors in der History, und für die Arbeit des Advisors im verbundenen Terminal muss man noch eine Variation des Codes aus dem Indikator haben, den wir im letzten Beispiel betrachtet haben. Es wird angenommen, dass ein neuer nullwertige Bar begonnen hat, zu bilden, und der Indikatorwert wird im ersten Bar vollständig berechnet, und kann nicht mehr neuberechnet werden. Das gleiche gilt auch für die Variablen, die gespeichert werden, wenn der bar sich ändert. Dabei muss man beachten, wenn der Code für Advisors nicht so kompliziert geschrieben wird, wird es überhaupt unklar, was ein solcher Advisor berechnen wird, und auf welcher Grundlage er handeln wird! Und wenn statt einem solchen Code, eine Variation mit der kompletten Berechnung des Indikators in jedem Tick auf allen Bars verwendet wird, nur um den Wert auf dem letzten nullwertigen Bar zu erhalten, dann wird man auf das Testergebnis des Advisors ein Monat lange warten!

int start()
  {
//----+ Die Überprüfung der Anzahl der Bars , damit sie ausreichend für die richtige 
//      Berechnung des Indikators wären
   if(Bars-1 < T3_Period)
       return(0);
//---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung  
//     aller Bars beginnt
   int MaxBar = Bars - 1 - T3_Period;
//---- Initialisieren der Null
   if(MaxBar = 0)
       for(int bar = Bars - 1; bar > 0; bar--)
           MapBuffer[bar] = 0.0;
//+--- bis zur Hauptberechnung des Indikators stellen wir den Wert  
//     der Variablen wieder, wie sie nach der Berechnung im ersten Bar waren
//+--- Wiederherstellung der Werte der Variablen  +=======+
   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);
         }
//+--- +==========================================+
//+--- Speichern wir den Wert der Variablen, wie sie nach der Berechnung  
//     ersten Bar waren
//+--- Speichern wir den Wert der Variablen +=============+ 
   if(Tnew0 != time2)
     {
       time2 = Tnew0;
       E1 = e1; 
       E2 = e2; 
       E3 = e3; 
       E4 = e4; 
       E5 = e5; 
       E6 = e6;
     }
//+---+============================================+
 
//+--- Die Berechnung des Indikators (Die Berechnung wird die ganze Zeit nur im nillwertigen 
//     Bar durchgeführt)
   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;
//----+ ------------------------------------------------------+
//----+ Hier müssen Sie den Code ihres Experten eintragen     |
//----+ ------------------------------------------------------+
   return(0);
  }
//+----------------------------------------------------------------+

Natürlich wird der Code etwas komplizierter!

Unten ist ein Beispiel für den Indikator, in dem für die richtige Funktionalität muss man nur eine logische Variable bei jedem Start der Funktion int start() wiederherstellen. Aber ohne diese fast unsichtbare Kleinigkeit, wird der Indikator nicht richtig funktionieren:

//+------------------------------------------------------------------+
//|                                                   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 [];
//---- Eingabe der Variablen , um die mehrmalige Neuberechnung des nullwertigen Bars durchzuführen 
int time2;bool SWING;
//+------------------------------------------------------------------+
//| 3LineBreak initialization function                               |
//+------------------------------------------------------------------+ 
int init()
  {   
//---- Chart wird als Histogramm durchgeführt 
   SetIndexStyle(0,DRAW_HISTOGRAM);
   SetIndexStyle(1,DRAW_HISTOGRAM);
//---- 2 Indikatorpuffer werden für die Zählung verwendet.
   SetIndexBuffer(0,HighBuffer);
   SetIndexBuffer(1,LowBuffer );
//---- Die Einstellung der Indikator-Werten, die im Chart unsichtbar 
//     werden
   SetIndexEmptyValue(0,0);
   SetIndexEmptyValue(1,0);
//---- Die Namen für Datenfenster und Labels für Unterfenster.
   IndicatorShortName("3LineBreak");
   SetIndexLabel   (0,"3LineBreak");
//---- Die Bestimmung der Nummer des Bars, von der der Indikator
//     entsteht  
   SetIndexDrawBegin(0,Lines_Break);
   SetIndexDrawBegin(1,Lines_Break);
//---- Das Ende des Initialisierens 
 
   return(0);
  }
//+------------------------------------------------------------------+
//| 3LineBreak iteration function                                    |
//+------------------------------------------------------------------+ 
int start()
{
//---- Eingabe der Variablen mit Gleitkomma
double VALUE1,VALUE2;
//---- Eingabe der logischen Variablen
bool Swing=true,OLDSwing;
//----+ Eingabe der ganzen Variablen und erhalten dadurch bereits berechneten Bars
int MaxBar,limit,counted_bars=IndicatorCounted();
//---- Überprüfung auf mögliche Fehler
if (counted_bars<0)return(-1);
//---- das letzte berechnete Bar muss neuberechnet werden )
if (counted_bars>0) counted_bars--;
//---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung 
//     aller Bars beginnt
MaxBar=Bars-1-Lines_Break;
//---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung 
//     nur der neuen Bars beginnt
limit=(Bars-1-counted_bars);
//---- Initialisieren der Null
if (limit>MaxBar)
 {
  for (int bar=limit; bar>MaxBar;bar--)
   { 
    HighBuffer[bar]=0.0; 
    LowBuffer [bar]=0.0; 
   }
  limit=MaxBar;
 }
//----
//+--- Wiederherstellung der Werte der Variablen +================+
int Tnew=Time[limit+1];
if (limit<MaxBar)
 if (Tnew==time2)Swing=SWING; 
 else
  {
   if (Tnew>time2)Print("ERROR01");
   else Print("ERROR02");
   return(-1);  
  }
//+--- +==================================================+
 
//+--- Die Hauptloop der Berechnung des Indikators
for (bar=limit; bar>=0;bar--)
 {
  //+--- Speichern wir den Wert der Variablen +=============+ 
  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 &&  Low [bar]<VALUE2) Swing=false;
  if (!OLDSwing &&  High[bar]>VALUE1) Swing=true;
  //----
  if (Swing)
   { 
    HighBuffer[bar]=High[bar]; 
    LowBuffer [bar]=Low [bar]; 
   }
 
  if (!Swing)
   { 
    LowBuffer [bar]=High[bar]; 
    HighBuffer[bar]=Low [bar]; 
   }   
 }
//+--- Das Ende der Hauptloop
   return(0);
}


Unten ist auch eine ziemlich ähnliche Situation:

//+------------------------------------------------------------------+
//|                                                  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;
//---- Das Ende des Initialisierens 
   return(0);
  }
//+------------------------------------------------------------------+
//| BrainTrend1 iteration function                                   |
//+------------------------------------------------------------------+
int start()
  {
//---- Die Überprüfung der Anzahl der Bars , damit sie ausreichend für die Berechnung wären
   if(Bars < 11)
       return(0);
//---- Eingabe der statistischen Speichervariablen für mehrere Neuberechnung  
//     des nullwertigen Bars 
   static int MEMORY, time2;
//----+ Eingabe der ganzen Variablen und erhalten dadurch bereits berechneten Bars
   int limit, MaxBar,bar, counted_bars = IndicatorCounted();
//---- Überprüfung auf mögliche Fehler
   if(counted_bars < 0)
       return(-1);
//---- das letzte berechnete Bar muss neuberechnet werden 
   if(counted_bars > 0) 
       counted_bars--;
//---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung  
//     aller Bars beginnt
   MaxBar = Bars - 1 - 10;
//---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung  
//     nur der neuen Bars beginnt
   limit = Bars - counted_bars - 1; 
   if(limit > MaxBar)
   limit = MaxBar;
   Comment("BrainTrading Inc. System 7.0");
//+--- Wiederherstellung der Werte der Variablen +================+
   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)
     {
       //+--- Speichern wir den Wert der Variablen +====+ 
      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--;
     } 
//+--- Das Ende der Hauptloop
   return(0);
  }

Im nächsten Indikator für die richtige Funktionalität muss man nicht nur normale Variablen wiederherstellen, sondern noch die Puffer wiederherstellen:

//+------------------------------------------------------------------+
//|                                                  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;
//---- Eingabe der Variablen , um die mehrmalige Neuberechnung des nullwertigen Bars durchzuführen 
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;  
//---- Die Änderung der Große des Puffers bis zum erforderten 
   ArrayResize(Values, artp);
//---- Die ähnliche Änderung der Große des Speicherpuffers in der ersten Dimension 
//     bis zum erforderten
   ArrayResize(VALUES, artp);
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| BrainTrend2 iteration function                                   |
//+------------------------------------------------------------------+
int start()
  {
//---- Die Überprüfung der Anzahl der Bars , damit sie ausreichend für die Berechnung wären
   if(Bars < 11)
       return(0);
//----+ Eingabe der ganzen Variablen und erhalten dadurch bereits berechneten Bars
   int limit, MaxBar, bar, J, counted_bars = IndicatorCounted();
//---- Überprüfung auf mögliche Fehler
   if(counted_bars < 0)
      return(-1);
//---- das letzte berechnete Bar muss neuberechnet werden 
   if(counted_bars > 0) 
       counted_bars--;
//---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung  
//     aller Bars beginnt
   MaxBar = Bars - 3;
//---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung  
//     nur der neuen Bars beginnt
   limit = (Bars - 1 - counted_bars);
//---- Initialisieren der 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;        
         }
     } 
//----
//+--- Wiederherstellung der Werte der Variablen +================+
   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);  
         }
//+--- +==================================================+
//+--- Die Hauptloop der Berechnung des Indikators 
   bar = limit;
   while(bar >= 0)      
     {  
       //+--- Speichern wir den Wert der Variablen +=============+ 
       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--;
     }  
//+--- Das Ende der Hauptloop
   return(0);
  }
Na und schließlich der geliebte Indikator ZigZag, wie uns Analyse zeigt, wird der auch immer wieder auf allen Bars neuberechnet, und deshalb hat auch in sich ein Problem, welchem der Artikel sich widmet! Mir scheint es, der Code dieses Indikators brauchen wir nicht in den Text dieses Artikels einzufügen, weil den man immer in der Datei "Indicators" des Client-Terminals Metatrader 4 finden kann.

Natürlich ist der Code in diesem Indikator mehr sparsamer bezüglich für Computerressourcen und mit der Rücksicht auf alle oben genannten Forderungen konnte er fantastisch und grausam aussehen. Aber in dieser Situation kann man einen anderen Weg nehmen. Wenn wir nach der Neuberechnung des Indikators Koordinaten und Werte der letzten und der vorletzten Wende des ZigZag festlegen, können wir künftig beim nächsten Start der Funktion int start() richtig die Indikator-Werte neuberechnen, die noch nicht von der nächstgelegenen beiden Koordinaten legen. Und die unvollständige Zähle der letzten beiden Spitze aus dem Speicher nehmen. Dazu muss man noch sagen, dass dieser Indikator nicht immer korrekt funktioniert, ab und zu macht er absolut anormale Hügel, die man auch zugleich mit der letzten Aufgabe gelöst haben sollte. Weil die Löschung der Hügel aus dem Chart immer minimal drei Spitzen des ZigZags benötigt, dazu noch werden wir die Berechnung des Indikators auf neue Bars eben mit dem vorletzten Bar beginnen, welcher von dem Anfang der Indikatorenwende liegt. In diesem Fall ist es hier eine Variation der Korrektur des Indikatorencodes:

//+------------------------------------------------------------------+
//|                                                       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()
  {
    //+ Die Überprüfung der Anzahl der Bars , damit sie ausreichend für die richtige
    //  Berechnung des Indikators wären
    if(Bars - 1 < ExtDepth)
        return(0);
    //+ Eingabe der ganzen Speichervariablen für die Neuberechnung des Indikators 
    //  nur auf noch nicht berechneten Bars
    static int time2, time3, time4;  
    //+ Eingabe der Variablen mit Gleitkomma für die Neuberechnung des Indikators 
    //  nur auf noch nicht berechneten Bars
    static  double ZigZag2, ZigZag3, ZigZag4;
    //+ Eingabe der ganzen Variablen für die Neuberechnung des Indikators
    //  nur auf noch nicht berechneten Bars und erhalten dadurch bereits berechneten Bars
    int MaxBar, limit, supr2_bar, supr3_bar, supr4_bar;
    int counted_bars = IndicatorCounted();
    //  Überprüfung auf mögliche Fehler
    if(counted_bars < 0)
        return(-1);
    // das letzte berechnete Bar muss neuberechnet werden
    if(counted_bars > 0) 
        counted_bars--;
    //----+ Eingabe der Variablen    
    int shift, back, lasthighpos, lastlowpos;
    double val, res, TempBuffer[1];
    double curlow, curhigh, lasthigh, lastlow;
    //---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung 
    // aller Bars beginnt
    MaxBar = Bars - ExtDepth; 
    // Die Bestimmung der Nummer des ersten  Bars in der Loop, von dem die Neuberechnung  
    // der neuen  Bars beginnt
    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("Der erste Bar ist noch nicht gefunden,",
            " die Neuberechnung des Indikators wird auf allen Bars durchgeführt" );
          }
      }
    // Initialisieren der Null
    if(limit >= MaxBar) 
      {
        for(shift = Bars - 1; shift >= MaxBar; shift--)
            ZigZagBuffer[shift] = 0.0; 
        limit = MaxBar; 
      } 
    // Die Änderung der Große des vorübergehenden Puffers
    if(ArrayResize(TempBuffer, Limit + ExtBackstep + 1)!=
       limit + ExtBackstep + 1)
        return(-1);
    //+ der Anfang der ersten großen 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;
      }
    //+ das Ende der ersten großen Loop 
    // final cutting 
    lasthigh = -1; 
    lasthighpos = -1;
    lastlow = -1; 
    lastlowpos = -1;
    //----+ der Anfang der zweiten großen 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;
          }
      }
    //+ das Ende der zweiten großen Loop
    //+ der Anfang der dritten Loop
    for(shift = limit; shift >= 0; shift--)
      {
        res = TempBuffer[shift];
        if(res != 0.0) 
            ZigZagBuffer[shift] = res;
      }
    //+ das Ende der dritten Loop
    //+ Wiederherstellung der Werte des Indikatorpuffers,  
    //  die verloren sein könnten 
    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;
      }
    //+ Korrektur der entstehenden Hügel  
    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;      
          }
      } 
    //+ Zeitspeicherung der 3 letzten Wenden des ZigZags und Speicherung 
    //  der Indikator-Werte an diesen Punkten 
    time2 = Time[bar2];
    time3 = Time[bar3];
    time4 = Time[bar4];
    ZigZag2 = vel2;  
    ZigZag3 = vel3; 
    ZigZag4 = vel4; 
    //---- Das Ende der Berechnung der Indikator-Werte
    return(0);
  }
 //---+ +----------------------------------------------------------+


Diese Form benötigt ZigZag weniger wertvolle Computer-Ressourcen, die Erfahrungsgemäß immer knapp sind, egal wie viele von ihnen zur Verfügung stehen! Den Namen des Indikatorpuffers habe ich auf den mehr verständlichen "ZigZagBuffer" geändert, der zweite Puffer mit den vorübergehenden Daten habe ich aus dem Indikatorpuffer weggenommen, denn er wird da nicht benötigt und seinen Namen habe ich auch auf "TempBuffer" geändert. Und in drei Loops der Indikatorberechnung fügte ich die Variable "limit" als die Nummer des ersten Bars hinzu, von dem die Neuberechnung nur auf noch nicht berechneten Bars beginnt.

Es ist natürlich klar, dass jeder Indikator einzigartig ist und deshalb ist es kaum möglich, ein Prinzip zu schaffen, das genauso gut auf allen Indikatoren funktionieren würde. Aber ich nehme an, dass die allgemeinen Ideen eines solchen Prinzips durchaus klar sind:

1. Der komplizierteste Hauptteil ist die Bestimmung aller Variablen, die einen Wert von den vorherigen Ticks haben. Es muss berücksichtigt werden, dass Variablen und irgendwelche Bars-Nummer manchmal gespeichert werden müssen, aber eine Bar kann in den kommenden Ticks mit einer anderen Bar gewechselt werden und dann braucht man diese gespeicherten Werte nicht mehr. In einem solchen Fall muss die Öffnungszeit des Bars gespeichert werden

MEMORY_bar_time = Time[lastlowBar]
und weiter den aktuellen Zustand des Bars nach dieser gespeicherten Zeit wiederherstellen
iBarShift(NULL, 0, MEMORY_bar_time, TRUE).

Es kann eine Situation herrschen, in der ein paar Loops der Indikatorberechnung sein können, und in jeder Loop werden Variablen sein, die gespeichert werden müssen, es kann auch noch sein, dass eine und die gleiche Variable in unterschiedlichen Loops eine extra Speicherung am Ende des zweiten Bars oder am Loopanfang auf dem ersten Bar benötigen wird;
2. Es ist empfohlen, Variablen mit den Namen einzugeben, die den Anfangsnamen entsprechen. Es ist besser, diese Variablen am Textanfang des Indikators als nicht lokale zu erklären. Diese Variablen können oft auch im Code des Indikators nach dem Operator start() als statistische bestimmt werden;
3. Für alle Loops der Berechnung des Indikators muss man den Wiederherstellungscode hinzufügen.
4. In jeder Loop, wo auch eine aktuelle Variable gibt, muss man noch den Code hinzufügen, der diese Variablen speichert.

Ich kann noch zum Schluss sagen, dass ich alle betrachteten Indikatoren im Internet aus zahlreichen Foren genommen habe. Ich habe sie nur als Beispiel verwendet, um ihre Fehler zu korrigieren, aber ich trage keine Verantwortung für Verteilen, Kopieren, Neukompiliereen, und für Urheberrechtsverletzungen, wenn jemand sowas bei dem Codeangebot dieser Indikatoren im Internet bekommt.


Und als Epilog zu dem Artikel möchte ich seit 5 Monaten nach dem Artikel, noch mal den Indikator ZigZag aufrufen, um ihn wegen seiner Popularität und verfügten Möglichkeiten in MQL4 noch besser zu machen! Ich habe entschieden, die Optimierung dieses Indikators mit der Rücksicht auf alle von mir erwähnten Prinzipien durchzuführen. Ich habe nur zwei Indikatorpuffer gelassen (symmetrisch für die Spitzen und Tiefen des Indikators), und habe die Linie des ZIGZAGS in der Art ZIGZAG gemacht(Operatoren


Als Ergebnis hat der Indikator angefangen, seine Spitzen (High und Low) gleichzeitig auf einem und dieselben Bar korrekt anzuzeigen!

//+------------------------------------------------------------------+
//|                                                    ZigZag_NK.mq4 |
//|                      Copyright © 2005, MetaQuotes Software Corp. |
//|                                       https://www.metaquotes.net/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2005, MetaQuotes Software Corp."
#property link      "https://www.metaquotes.net/"
//---- Darstellung des Indikators im Hauptfenster
#property indicator_chart_window
//---- die Anzahl der Indikatorpuffers
#property indicator_buffers  2
//---- die Farbe des Indikators
#property indicator_color1 Aqua
#property indicator_color2 Aqua
//---- die Dicke der Indikator-Linie
#property indicator_width1 0
#property indicator_width2 0
//---- Linienstil  des Indikators
#property indicator_style1 1
#property indicator_style2 1
//---- Eingabeparameter des Indikators 
extern int ExtDepth=12;
extern int ExtDeviation=5;
extern int ExtBackstep=3;
//---- 
//---- die Indikatorpuffers
double LowestBuffer[],HighestBuffer[];
//----+ Eingabe der ganzen Speichervariablen für die Neuberechnung des Indikators
//      nur auf noch nicht berechneten Bars
int    MaxBar,time2,LASTLOWPOS,LASTHIGHPOS,LHTIME,LLTIME,size;  
//----+ Eingabe der Variablen mit Gleitkomma für die Neuberechnung des Indikators 
//      nur auf noch nicht berechneten Bars
double LowestMEMORY[1],HighestMEMORY[1],LASTLOW0,LASTLOW1,LASTHIGH0,
       LASTHIGH1,LASTHIGHEST,LASTLOWEST;
//+------------------------------------------------------------------+
//| ZigZag initialization function                                   |
//+------------------------------------------------------------------+
int init()
  {
//----  Indikatorpuffer werden für die Zählung verwendet 
   SetIndexBuffer(0,LowestBuffer);
   SetIndexBuffer(1,HighestBuffer);
//---- Chart wird als gebrochene ZigZag durchgeführt  
   SetIndexStyle(0,DRAW_ZIGZAG);
   SetIndexStyle(1,DRAW_ZIGZAG);
//---- Die Einstellung der Indikator-Werten, die im Chart unsichtbar werden
   SetIndexEmptyValue(0,0.0);
   SetIndexEmptyValue(1,0.0);
//---- Die Namen für Datenfenster und Labels für Unterfenster
   SetIndexLabel(0,"Low" );
   SetIndexLabel(1,"High");
   IndicatorShortName("ZigZag (ExtDepth="+ExtDepth+", ExtDeviation="+
                      ExtDeviation+", ExtBackstep="+ExtBackstep+" )");
//---- Die Bestimmung der Große der vorübergehenden Puffers 
   size=ExtBackstep+1;
//---- Die Änderung der Große der vorübergehenden Puffers 
   if(ArrayResize(LowestMEMORY,size)!=size)return(-1);
   if(ArrayResize(HighestMEMORY,size)!=size)return(-1);
//---- Das Ende des Initialisierens 
   return(0);
  }
//+------------------------------------------------------------------+
//|  ZigZag iteration function                                       |
//+------------------------------------------------------------------+
int start()
  {
   //----+ Die Überprüfung der Anzahl der Bars , damit sie ausreichend für die richtige 
   //      Berechnung des Indikators wären
   if (Bars-1<ExtDepth)return(0);
   //----+ Eingabe der ganzen Variablen und erhalten dadurch bereits berechneten Bars
   int limit,iii,counted_bars=IndicatorCounted();
   //---- Überprüfung auf mögliche Fehler
   if (counted_bars<0)return(-1);
   //---- das letzte berechnete Bar muss neuberechnet werden 
   if (counted_bars>0) counted_bars--;
   //----+ Eingabe der Variablen    
   int    bar,back,lasthighpos,lastlowpos;
   double curlow,curhigh,lasthigh0,lastlow0,lasthigh1,lastlow1,val,res;
   //---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung 
   //     aller Bars beginnt 
   MaxBar=Bars-ExtDepth; 
   //---- Die Bestimmung der Nummer  des ersten  Bars in der Loop, von dem die Neuberechnung
   //     der neuen Bars  beginnt
   limit=Bars-counted_bars-1;
        
   //+--- Wiederherstellung der Werte der Variablen +======+
   int Tnew=Time[limit+1];
   if (limit<MaxBar)
    {
     if (Tnew==time2)
      {
       lastlow0=LASTLOW0;
       lasthigh0=LASTHIGH0;
       //+---
       lastlow1=LASTLOW1;
       lasthigh1=LASTHIGH1;
       //+---
       lastlowpos=iBarShift(NULL,0,LLTIME,true); 
       lasthighpos=iBarShift(NULL,0,LHTIME,true); 
       //+--- Die Überprüfung der Variablen lasthighpos und lastlowpos um 
       //     die Richtigkeit für die weitere Berechnung
       if ((lasthighpos<0)||(lastlowpos<0))
        {
         Print("Fehler bei der Wiederherstellung der Variablen!!!" + 
            " Die Werte der Variablen lasthighpos und lastlowpos wurden verloren");
         Print("die Neuberechnung des Indikators wird auf allen Bars durchgeführt!");
         return(-1);
        }
       //+---
       LowestBuffer[lastlowpos]=LASTLOWEST;
       HighestBuffer[lasthighpos]=LASTHIGHEST;
       //+---     
       for(iii=size-1; iii>=0; iii--)
        {
         LowestBuffer[iii+limit+1]=LowestMEMORY[iii];
         HighestBuffer[iii+limit+1]=HighestMEMORY[iii];
        }
       //+---    
      } 
     else 
      {
       if (Tnew>time2)
            Print("Fehler bei der Wiederherstellung der Variablen!!! Tnew>time2");
       else Print("Fehler bei der Wiederherstellung der Variablen!!! Tnew");
       Print("die Neuberechnung des Indikators wird auf allen Bars durchgeführt!");
       return(-1);  
      }
    }
   //+--- +==========================================+
   
   //---- Initialisieren der Null
   if (limit>=MaxBar) 
     {
      for (bar=Bars-1; bar>=MaxBar;bar--)
       {
        LowestBuffer [bar]=0.0; 
        HighestBuffer[bar]=0.0; 
       }
      lastlow1=-1; 
      lasthigh1=-1; 
      lastlowpos=-1; 
      lasthighpos=-1;
      limit=MaxBar; 
     }
     
   //----+  <<< der Anfang der ersten großen Loop >>> -----------+  
   for(bar=limit; bar>=0; bar--)
     {
      //+--- Speichern wir den Wert der Variablen +=========+ 
      if (bar==1)
        {
         if(((limit==1)&&(time2==Time[2]))||(limit>1))
          {
           LASTLOW0=lastlow0;
           LASTHIGH0=lasthigh0;
           //+---
           for(iii=size-1; iii>=0; iii--)
            {
             LowestMEMORY[iii]=LowestBuffer[iii+2];
             HighestMEMORY[iii]=HighestBuffer[iii+2];
            }
          }
        }
      //+---+=========================================+     
  
      //--- low
      val=Low[Lowest(NULL,0,MODE_LOW,ExtDepth,bar)];
      if(val==lastlow0) val=0.0;
      else 
        { 
         lastlow0=val; 
         if((Low[bar]-val)>(ExtDeviation*Point))val=0.0;
         else
           {
            for(back=1; back<=ExtBackstep; back++)
              {
               res=LowestBuffer[bar+back];
               if((res!=0)&&(res>val))LowestBuffer[bar+back]=0.0; 
              }
           }
        } 
      LowestBuffer[bar]=val;
      //--- high
      val=High[Highest(NULL,0,MODE_HIGH,ExtDepth,bar)];
      if(val==lasthigh0) val=0.0;
      else 
        {
         lasthigh0=val;
         if((val-High[bar])>(ExtDeviation*Point))val=0.0;
         else
           {
            for(back=1; back<=ExtBackstep; back++)
              {
               res=HighestBuffer[bar+back];
               if((res!=0)&&(res<val))HighestBuffer[bar+back]=0.0; 
              } 
           }
        }
      HighestBuffer[bar]=val;
     }
    //----+ das Ende der ersten großen Loop  
   
   //----+  <<< der Anfang der zweiten großen Loop >>> -----------+  
   for(bar=limit; bar>=0; bar--)
     {
      //+--- Speichern wir den Wert der Variablen +====+ 
      if (bar==1)
       {
        if(((limit==1)&&(time2==Time[2]))||(limit>1))
         {
          time2=Time [2];
          LASTLOW1=lastlow1;
          LASTHIGH1=lasthigh1;
          //+---
          LLTIME=Time[lastlowpos];
          LHTIME=Time[lasthighpos];
          //+---
          LASTLOWEST=LowestBuffer[lastlowpos];
          LASTHIGHEST=HighestBuffer[lasthighpos];
         }
       }
     //+---+====================================+     
     
      curlow=LowestBuffer[bar];
      curhigh=HighestBuffer[bar];
      //---
      if((curlow==0)&&(curhigh==0))continue;
      //---
      if(curhigh!=0)
        {
         if(lasthigh1>0) 
           {
            if(lasthigh1<curhigh)HighestBuffer[lasthighpos]=0;
            else HighestBuffer[bar]=0;
           }
         //---
         if(lasthigh1<curhigh || lasthigh1<0)
           {
            lasthigh1=curhigh;
            lasthighpos=bar;
           }
         lastlow1=-1;
        }
      //----
      if(curlow!=0)
        {
         if(lastlow1>0)
           {
            if(lastlow1>curlow) LowestBuffer[lastlowpos]=0;
            else LowestBuffer[bar]=0;
           }
         //---
         if((curlow<lastlow1)||(lastlow1<0))
           {
            lastlow1=curlow;
            lastlowpos=bar;
           } 
         lasthigh1=-1;
        }
     } 
   //----+ das Ende der zweiten großen Loop 
   //+--------------------------------------------------------+ 
        
 //---- Das Ende der Berechnung der Indikator-Werte
return(0);
}
//+-----------------------------------------------------------+

Mir scheint es, in dieser Form wird es die beste Variante des Indikators sein. Neben der Wiederherstellung der normalen Variablen in Loops, musste man noch die Werte der Indikatorpuffers in diesem Indikator wiederherstellen und immer wieder neuberechnen, (Der Indikator berechnet nicht nur seinen Wert auf dem aktuellen Bar, sondern noch den Wert der vorherigen Bars auf der Tiefe "ExtBackstep"!)

Im Hinblick auf die Vorschläge, die in der "Luft" gehängten ZigZags Spitzen zur Löschung vorschlagen, kann man hier bemerken, dass sie einen gewissen logischen Sinn haben, und deshalb wäre ihre Löschung sinnlos. Natürlich können Sie einen schlaueren Algorithmus zur Korrektur dieser Spitzen-Positionen eingeben, aber es wird dann ein anderer Indikator sein! Und von daher, dass ich ein anderes Thema in meinem Artikels habe, und da gab es erstmal keine Fragen über die Algorithmen-Modifikation des Zickzacks, denke ich, dass dieses Thema völlig erschöpft ist .