English 日本語
preview
Entwicklung eines Toolkit zur Analyse von Preisaktionen (Teil 19): ZigZag Analyzer

Entwicklung eines Toolkit zur Analyse von Preisaktionen (Teil 19): ZigZag Analyzer

MetaTrader 5Beispiele |
156 5
Christian Benjamin
Christian Benjamin

Einführung

Trendlinien bilden das Rückgrat der technischen Analyse und der modernen Kursentwicklung. Sie bilden das Gerüst der Kursmuster, auf die sich Devisen-, Kryptowährungs-, Rohstoff-, Aktien- und Derivatehändler verlassen. Richtig gezeichnet, zeigen Trendlinien effizient Markttrends auf und helfen Händlern, potenzielle Chancen zu erkennen.

Unabhängig davon, ob Sie ein Daytrader oder ein kurzfristiger Händler sind, Trendlinien spielen in vielen Handelssystemen und -strategien eine wichtige Rolle. In unserer Entwicklungsserie des Price Action Analysis Toolkit stellen wir ein Tool namens ZigZag Analyzer vor. Dieses Tool konzentriert sich auf das Zeichnen von Trendlinien unter Verwendung des ZigZag-Indikators, um Umkehrpunkte zu identifizieren, die die Grundlage für die Konstruktion von Trendlinien bilden. MQL5 ist eine leistungsstarke Sprache für die Automatisierung von Handelssystemen und ermöglicht es uns, fortschrittliche Tools wie den ZigZag Analyzer zu entwickeln, die sich den Marktbedingungen anpassen und die Entscheidungsfindung in Echtzeit unterstützen.

Wir beginnen mit der Erforschung von Trendlinien, untersuchen dann den Zigzag-Indikator, skizzieren den Systemalgorithmus, stellen den MQL5-Code vor, überprüfen die Ergebnisse und schließen mit unseren abschließenden Erkenntnissen. Nachstehend finden Sie das Inhaltsverzeichnis:



Trendlinien

Eine Trendlinie ist eine schräg verlaufende Linie, die wichtige Kurspunkte, in der Regel höhere Tiefst- oder niedrigere Höchststände, miteinander verbindet und in die Zukunft als Unterstützungs- oder Widerstandsniveau projiziert. Er zeigt die wahrscheinliche Richtung und Dynamik der Kursbewegungen an. Um eine Trendlinie zu zeichnen, müssen Sie zunächst die allgemeine Marktrichtung bestimmen. Ein Aufwärtstrend ist durch eine Abfolge von höheren Hochs und höheren Tiefs gekennzeichnet, während ein Abwärtstrend durch niedrigere Hochs und niedrigere Tiefs gekennzeichnet ist. Zur Veranschaulichung betrachten Sie ein Chart, das ein Abwärtsmuster zeigt, bei dem Sie die fallenden hohen Umkehrpunkte verbinden würden, um die Trendlinie festzulegen. Während der Preiskonsolidierung kann die Bildung mehrerer Trendlinien Muster aufzeigen, die Handelssignale verstärken. Nachstehend finden Sie eine bildliche Darstellung.

Aufwärtstrend

Abb. 1. Trendlinien

Das Chart veranschaulicht zwei Schlüsselkonzepte: Unterstützung und Widerstand. Ein Unterstützungsniveau ist ein Bereich, in dem die Abwärtsbewegung häufig zum Stillstand kommt, weil die Käufer aktiv genug werden, um den Verkaufsdruck aufzufangen. Bei der Anwendung von Trendlinien wird die Unterstützung in der Regel durch aufwärts gerichtete Linien angezeigt, die wichtige Tiefpunkte verbinden. Im Gegensatz dazu ist ein Widerstandsniveau ein Bereich, in dem die Aufwärtsbewegung aufgrund eines verstärkten Verkaufsdrucks häufig pausiert. Bei Trendlinien wird der Widerstand durch abwärts gerichtete Linien dargestellt, die wichtige Hochpunkte miteinander verbinden. Händler zeichnen häufig Trendlinien über mehrere Zeithorizonte hinweg, um festzustellen, ob sich ein Markt über kurze, mittlere oder lange Zeiträume aufwärts oder abwärts bewegt.
Trendlinien sind ein wertvolles Instrument der technischen Analyse, da sie den Marktteilnehmern helfen, die Gesamtrichtung des Preises eines Vermögenswerts abzuschätzen. Durch die Verbindung signifikanter Höchst- oder Tiefststände in einem ausgewählten Zeitrahmen stellen diese Linien visuell dar, ob sich der Markt aufwärts, abwärts oder seitwärts bewegt. Diese Erkenntnis ist besonders nützlich für Händler und kurzfristige Anleger, die sich bei ihren Entscheidungen auf Preistrends verlassen.



Zickzack-Indikator

Der genaue Ursprung des Zig-Zag-Indikators ist zwar nicht eindeutig belegt, aber einige Quellen schreiben seine Entdeckung Bill Wolfe zu, einem S&P 500-Händler, der für die Entwicklung der Wolfe-Wellen bekannt ist, einer Methode, die den Elliott-Wellen ähnelt, aber über andere Charttechniken verfügt. Die Wolfe-Wellen bestehen aus fünf Wellen, die veranschaulichen, wie sich Angebot und Nachfrage auf einen Gleichgewichtspreis zubewegen. Der Zig Zag-Indikator hebt signifikante Kursumkehrungen hervor, die einen bestimmten Schwellenwert überschreiten, der in der Regel als Prozentsatz ausgedrückt wird. Wenn der Kurs diese Schwelle überschreitet, setzt der Indikator einen neuen Punkt und zieht eine gerade Linie vom vorherigen Punkt aus, wodurch kleinere Schwankungen herausgefiltert werden. Auf diese Weise lassen sich die zugrunde liegenden Trends über verschiedene Zeiträume hinweg leichter erkennen.

Händler können den prozentualen Schwellenwert (z. B. 4 % oder 5 %) anpassen, um mehr oder weniger Kursschwankungen zu erfassen, je nach Volatilität des Vermögenswerts oder ihrem persönlichen Handelsstil. Diese Flexibilität trägt dazu bei, dass der Zig-Zag-Indikator potenzielle Wendepunkte besser erkennen kann. In der wellenbasierten Analyse, wie z. B. der Elliot-Wellentheorie, kann das Zig Zag helfen, die Struktur jeder Welle zu verdeutlichen. Letztendlich ist es oft notwendig, mit verschiedenen Einstellungen zu experimentieren, um das optimale Gleichgewicht zwischen dem Herausfiltern von Rauschen und dem Erkennen aussagekräftiger Kursbewegungen zu finden.

Zickzack-Indikator

Abb. 2. Zick-Zack-Indikator

Abbildung 2 oben zeigt ein Chart mit dem Zig Zag-Indikator. Sie zeigt, wie aus den Umkehrpunkten Trendlinien konstruiert werden können. Der Zig-Zag-Indikator vereinfacht die Trendanalyse, indem er kleinere Kursschwankungen herausfiltert und wichtige Wendepunkte hervorhebt. Er markiert signifikante Höchst- und Tiefststände, die als Ankerpunkte für die Zeichnung von Trendlinien dienen. In einem Aufwärtstrend bildet die Verbindung dieser Schwungtiefs eine Unterstützungslinie, während in einem Abwärtstrend die Verbindung der hohen Umkehrpunkte eine Widerstandslinie bildet. Diese Methode hebt die Gesamtrichtung des Marktes hervor, indem sie das Rauschen eliminiert. Durch die Anpassung der Sensitivität des Indikators kann die Genauigkeit dieser Trendlinien weiter verfeinert werden, um bessere Handelseinblicke zu erhalten.



System-Algorithmus

1. Globale Deklarationen und Eingabeparameter

In diesem ersten Abschnitt richten wir Schlüsseleingaben und globale Variablen ein, mit denen Sie den Analyzer anpassen können, ohne in den Code einzugreifen. Wir definieren Parameter wie den Chart-Zeitrahmen und spezifische Eigenschaften für den ZigZag-Indikator wie Tiefe, Abweichung und Rückschritt. Diese Einstellungen legen fest, wie der Analysator Umkehrpunkte auswählt. Wir deklarieren auch Arrays, um die ZigZag-Daten zu speichern und um die Zeit und den Preis der wichtigsten Pivots aufzuzeichnen.

Wir schätzen diese Einrichtung wegen ihrer Einfachheit und ihres modularen Aufbaus. So können Sie beispielsweise durch Ändern des Zeitrahmenparameters problemlos zwischen kurzfristigen und langfristigen Trends wechseln. Mit den ZigZag-Eigenschaften können Sie die Empfindlichkeit des Indikators einstellen, sodass Sie die Analyse an unterschiedliche Marktbedingungen oder Vermögenswerte anpassen können. Wir verwenden globale Variablen und Arrays als zentralen Knotenpunkt für alle dynamischen Daten. Dieser Ansatz verbessert die Leistung und macht den Code einfacher zu pflegen. Wenn neue Daten eintreffen, werden sie effizient gespeichert und stehen für die Analyse bereit, was die Anpassung und Fehlersuche erheblich vereinfacht.

Insgesamt schaffen wir durch die Zentralisierung dieser kritischen Eingaben und Erklärungen ein flexibles und klares Werkzeug, das es Ihnen ermöglicht, den Analysator an Ihre Bedürfnisse anzupassen, während die zugrunde liegenden Prozesse robust und zuverlässig bleiben.

// Input parameters
input ENUM_TIMEFRAMES InpTimeFrame    = PERIOD_CURRENT; // Timeframe to analyze
input int             ZZ_Depth         = 12;  // ZigZag depth
input int             ZZ_Deviation     = 5;   // ZigZag deviation
input int             ZZ_Backstep      = 3;   // ZigZag backstep
input int             LookBackBars     = 200; // Bars to search for pivots
input int             ExtendFutureBars = 100; // Bars to extend trendlines into the future

// Global indicator handle for ZigZag
int zzHandle;

// Arrays for ZigZag data and pivot storage
double   zzBuffer[];
datetime pivotTimes[];
double   pivotPrices[];
bool     pivotIsPeak[];

// Variable to detect new bars
datetime lastBarTime = 0;

  • InpTimeFrame: Der Zeitrahmen für die Analyse.
  • ZZ_Depth, ZZ_Deviation, ZZ_Backstep: Parameter, die die Empfindlichkeit und das Verhalten des ZigZag-Indikators beeinflussen.

Arrays wie zzBuffer speichern die Ausgabe des ZigZag-Indikators. Zusätzliche Arrays (pivotTimes, pivotPrices, pivotIsPeak) sind für die Speicherung von Details zu jedem erkannten Pivot reserviert. Eine Variable (lastBarTime) hilft bei der Feststellung, ob ein neuer Balken begonnen hat, und stellt sicher, dass die Analyse nur bei Bedarf aktualisiert wird.

2. Die Initialisierungsfunktion (OnInit)

In der Initialisierungsfunktion führen wir den Code einmal aus, wenn der Indikator geladen wird. Unser Hauptziel ist es hier, den ZigZag-Indikator anhand der Nutzereingaben zu erstellen und zu konfigurieren. Wir rufen die Funktion iCustom auf, um zu versuchen, den ZigZag-Indikator zu instanziieren und sein Handle zu speichern. Wenn die Initialisierung des Indikators fehlschlägt und ein ungültiges Handle zurückgegeben wird, protokollieren wir einen Fehler und halten die weitere Verarbeitung an.

Wir verwenden diese Funktion, um sicherzustellen, dass alles korrekt eingerichtet ist, bevor eine Analyse stattfindet. Sie fungiert als Torwächter und verhindert, dass der restliche Code ausgeführt wird, wenn es ein Problem mit dem Indikator-Setup gibt. Diese frühzeitige Prüfung spart Zeit und vermeidet unnötige Fehler im weiteren Verlauf der Ausführung. Indem wir die Initialisierung hier zentralisieren, erleichtern wir die Verwaltung und Fehlersuche im System, falls etwas schief geht. Die Funktion stellt außerdem sicher, dass alle nutzerdefinierten Einstellungen von Anfang an angewendet werden, was eine solide Grundlage für die nachfolgende Analyse darstellt.

int OnInit()
  {
   zzHandle = iCustom(_Symbol, InpTimeFrame, "ZigZag", ZZ_Depth, ZZ_Deviation, ZZ_Backstep);
   if(zzHandle == INVALID_HANDLE)
     {
      Print("Error creating ZigZag handle");
      return(INIT_FAILED);
     }
   return(INIT_SUCCEEDED);
  }

  • Erstellung von Indikatoren: Verwendet wird iCustom, um den ZigZag-Indikator mit bestimmten Parametern zu laden.
  • Fehlerbehandlung: Prüft, ob das zurückgegebene Handle gültig ist. Protokolliert eine Fehlermeldung und bricht ab, wenn die Initialisierung fehlschlägt.

3. Die Deinitialisierungsfunktion (OnDeinit)

Wenn der Indikator entfernt oder die Plattform geschlossen wird, ist es wichtig, alle Objekte zu bereinigen und die zugewiesenen Ressourcen freizugeben. Die Funktion OnDeinit sorgt dafür, dass alle grafischen Objekte (wie Trendlinien oder horizontale Linien), die auf dem Chart gezeichnet wurden, gelöscht werden und der Handle des ZigZag-Indikators freigegeben wird. Auf diese Weise wird sichergestellt, dass keine unerwünschten Elemente auf der Chart verbleiben und dass die Ressourcen des Systems ordnungsgemäß verwaltet werden.

Ressourcenbereinigung: Löscht alle erstellten Chartobjekte, um Unordnung zu vermeiden.

Freigabe des Handles: Gibt das Handle des Indikators ZigZag mit IndicatorRelease frei.

void OnDeinit(const int reason)
  {
   ObjectDelete(0, "Downtrend_HighLine");
   ObjectDelete(0, "Uptrend_LowLine");
   ObjectDelete(0, "Major_Resistance");
   ObjectDelete(0, "Major_Support");
   ObjectDelete(0, "Minor_Resistance");
   ObjectDelete(0, "Minor_Support");
   IndicatorRelease(zzHandle);
  }

4. Die Hauptausführungsfunktion (OnTick)

Dies ist das Herzstück des Algorithmus, der bei jedem neuen Tick abläuft. Die Funktion prüft zunächst, ob sich ein neuer Balken gebildet hat, indem sie den Zeitstempel des aktuellen Balkens mit der zuletzt gespeicherten Zeit vergleicht. Wird kein neuer Balken erkannt, wird die Funktion vorzeitig beendet, um Rechenleistung zu sparen. Sobald ein neuer Balken bestätigt wird, werden alte Chartobjekte entfernt, die neuesten ZigZag-Daten mit CopyBuffer abgerufen und dann zwei Hilfsfunktionen aufgerufen: eine zum Zeichnen von Trendlinien und eine weitere zum Zeichnen von Unterstützungs- und Widerstandsniveaus.

void OnTick()
  {
   datetime currentBarTime = iTime(_Symbol, InpTimeFrame, 0);
   if(currentBarTime == lastBarTime)
      return;
   lastBarTime = currentBarTime;

   // Remove previous objects
   ObjectDelete(0, "Downtrend_HighLine");
   ObjectDelete(0, "Uptrend_LowLine");
   ObjectDelete(0, "Major_Resistance");
   ObjectDelete(0, "Major_Support");
   ObjectDelete(0, "Minor_Resistance");
   ObjectDelete(0, "Minor_Support");

   if(CopyBuffer(zzHandle, 0, 0, LookBackBars, zzBuffer) <= 0)
     {
      Print("Failed to copy ZigZag data");
      return;
     }
   ArraySetAsSeries(zzBuffer, true);

   DrawZigZagTrendlines();
   DrawSupportResistance();
  }

  • Neuer Bar-Check: Verwendet iTime, um eine Änderung des Balkens zu erkennen.
  • Puffer-Update: Aktualisiert zzBuffer mit den neuesten Daten des ZigZag.
  • Chart-Updates: Löscht frühere grafische Objekte, um neue Objekte vorzubereiten. Ruft Funktionen zum Zeichnen von Trendlinien und Unterstützungs-/Widerstandslinien auf.

5. Zeichnen von ZigZag-basierten Trendlinien (DrawZigZagTrendlines)

Diese Funktion ist dafür verantwortlich, die signifikanten Umkehrpunkte aus den ZigZag-Daten zu identifizieren und sie zur Berechnung von Trendlinien zu verwenden. Er durchläuft den Puffer, um Hochs und Tiefs zu sammeln, je nachdem, ob der aktuelle ZigZag-Wert mit dem Hoch oder Tief des Balkens übereinstimmt. Sobald die Umkehrpunkte gesammelt sind, verwendet der Code eine lineare Regression, um die Trendlinie für jeden Satz von Punkten zu bestimmen. Bei der Regressionsberechnung werden die folgenden Formeln verwendet:

1. Steigung (m)

Abb. 3. Regressionsformel

2. Achsenabschnitt (b)

Achsenabschnitt (b)

Abb. 4. Achsenabschnitt

  • (t) steht für die Zeitwerte (oder die unabhängige Variable).
  • (p) steht für die Preiswerte (oder die abhängige Variable).
  • (N) ist die Anzahl der in der Regression verwendeten Datenpunkte.

Extraktion der Umkehrpunkte: Durchläuft in einer Schleife zzBuffer, um bis zu 10 Höchst- und Tiefstwerte zu erfassen.                                                        
Ausschluss des letzten Umkehrpunktes: Verwirft den letzten Umkehrpunkt, um das Rauschen zu reduzieren.                                                                      
Regressionsanalyse: Berechnet die Steigung (m) und den Achsenabschnitt (b) anhand der obigen Formeln.

void DrawZigZagTrendlines()
  {
   double highPrices[10], lowPrices[10];
   datetime highTimes[10], lowTimes[10];
   int highCount = 0, lowCount = 0;

   // Extract swing points from the ZigZag buffer
   for(int i = 0; i < LookBackBars - 1; i++)
     {
      if(zzBuffer[i] != 0)
        {
         if(iHigh(_Symbol, InpTimeFrame, i) == zzBuffer[i] && highCount < 10)
           {
            highPrices[highCount] = zzBuffer[i];
            highTimes[highCount] = iTime(_Symbol, InpTimeFrame, i);
            highCount++;
           }
         else if(iLow(_Symbol, InpTimeFrame, i) == zzBuffer[i] && lowCount < 10)
              {
               lowPrices[lowCount] = zzBuffer[i];
               lowTimes[lowCount] = iTime(_Symbol, InpTimeFrame, i);
               lowCount++;
              }
        }
     }

   // Exclude the most recent swing if possible
   int usedHighCount = (highCount >= 4) ? highCount - 1 : highCount;
   int usedLowCount  = (lowCount  >= 4) ? lowCount - 1  : lowCount;

   double mHigh = 0, bHigh = 0, mLow = 0, bLow = 0;
   bool validHigh = false, validLow = false;

   // Regression for highs
   if(usedHighCount >= 3)
     {
      double sumT = 0, sumP = 0, sumTP = 0, sumT2 = 0;
      for(int i = 0; i < usedHighCount; i++)
        {
         double t = (double)highTimes[i];
         double p = highPrices[i];
         sumT += t;
         sumP += p;
         sumTP += t * p;
         sumT2 += t * t;
        }
      int N = usedHighCount;
      double denominator = N * sumT2 - sumT * sumT;
      if(denominator != 0)
        {
         mHigh = (N * sumTP - sumT * sumP) / denominator;
         bHigh = (sumP - mHigh * sumT) / N;
        }
      else
         bHigh = sumP / N;
      validHigh = true;
     }

   // Regression for lows
   if(usedLowCount >= 3)
     {
      double sumT = 0, sumP = 0, sumTP = 0, sumT2 = 0;
      for(int i = 0; i < usedLowCount; i++)
        {
         double t = (double)lowTimes[i];
         double p = lowPrices[i];
         sumT += t;
         sumP += p;
         sumTP += t * p;
         sumT2 += t * t;
        }
      int N = usedLowCount;
      double denominator = N * sumT2 - sumT * sumT;
      if(denominator != 0)
        {
         mLow = (N * sumTP - sumT * sumP) / denominator;
         bLow = (sumP - mLow * sumT) / N;
        }
      else
         bLow = sumP / N;
      validLow = true;
     }

   // Define time limits for trendlines
   datetime pastTime   = iTime(_Symbol, InpTimeFrame, LookBackBars - 1);
   datetime futureTime = lastBarTime + ExtendFutureBars * PeriodSeconds();

   // Draw trendlines if both regressions are valid
   if(validHigh && validLow)
     {
      // When slopes have the same sign, use average slope for parallel lines
      if(mHigh * mLow > 0)
        {
         double mParallel = (mHigh + mLow) / 2.0;
         double bHighParallel = highPrices[0] - mParallel * (double)highTimes[0];
         double bLowParallel  = lowPrices[0] - mParallel * (double)lowTimes[0];

         datetime highStartTime = pastTime;
         double highStartPrice  = mParallel * (double)highStartTime + bHighParallel;
         double highEndPrice    = mParallel * (double)futureTime + bHighParallel;
         if(!ObjectCreate(0, "Downtrend_HighLine", OBJ_TREND, 0, highStartTime, highStartPrice, futureTime, highEndPrice))
            Print("Failed to create High Trendline");
         else
           {
            ObjectSetInteger(0, "Downtrend_HighLine", OBJPROP_COLOR, clrRed);
            ObjectSetInteger(0, "Downtrend_HighLine", OBJPROP_RAY_LEFT, true);
            ObjectSetInteger(0, "Downtrend_HighLine", OBJPROP_RAY_RIGHT, true);
           }

         datetime lowStartTime = pastTime;
         double lowStartPrice  = mParallel * (double)lowStartTime + bLowParallel;
         double lowEndPrice    = mParallel * (double)futureTime + bLowParallel;
         if(!ObjectCreate(0, "Uptrend_LowLine", OBJ_TREND, 0, lowStartTime, lowStartPrice, futureTime, lowEndPrice))
            Print("Failed to create Low Trendline");
         else
           {
            ObjectSetInteger(0, "Uptrend_LowLine", OBJPROP_COLOR, clrGreen);
            ObjectSetInteger(0, "Uptrend_LowLine", OBJPROP_RAY_LEFT, true);
            ObjectSetInteger(0, "Uptrend_LowLine", OBJPROP_RAY_RIGHT, true);
           }
        }
      else // Draw separate trendlines if slopes differ
        {
         datetime highStartTime = pastTime;
         double highStartPrice  = mHigh * (double)highStartTime + bHigh;
         double highEndPrice    = mHigh * (double)futureTime + bHigh;
         if(!ObjectCreate(0, "Downtrend_HighLine", OBJ_TREND, 0, highStartTime, highStartPrice, futureTime, highEndPrice))
            Print("Failed to create High Trendline");
         else
           {
            ObjectSetInteger(0, "Downtrend_HighLine", OBJPROP_COLOR, clrRed);
            ObjectSetInteger(0, "Downtrend_HighLine", OBJPROP_RAY_LEFT, true);
            ObjectSetInteger(0, "Downtrend_HighLine", OBJPROP_RAY_RIGHT, true);
           }

         datetime lowStartTime = pastTime;
         double lowStartPrice  = mLow * (double)lowStartTime + bLow;
         double lowEndPrice    = mLow * (double)futureTime + bLow;
         if(!ObjectCreate(0, "Uptrend_LowLine", OBJ_TREND, 0, lowStartTime, lowStartPrice, futureTime, lowEndPrice))
            Print("Failed to create Low Trendline");
         else
           {
            ObjectSetInteger(0, "Uptrend_LowLine", OBJPROP_COLOR, clrGreen);
            ObjectSetInteger(0, "Uptrend_LowLine", OBJPROP_RAY_LEFT, true);
            ObjectSetInteger(0, "Uptrend_LowLine", OBJPROP_RAY_RIGHT, true);
           }
        }
     }
   else
     {
      // Draw only available regression if only one set of points is valid
      if(validHigh)
        {
         datetime highStartTime = pastTime;
         double highStartPrice  = mHigh * (double)highStartTime + bHigh;
         double highEndPrice    = mHigh * (double)futureTime + bHigh;
         if(!ObjectCreate(0, "Downtrend_HighLine", OBJ_TREND, 0, highStartTime, highStartPrice, futureTime, highEndPrice))
            Print("Failed to create High Trendline");
         else
           {
            ObjectSetInteger(0, "Downtrend_HighLine", OBJPROP_COLOR, clrRed);
            ObjectSetInteger(0, "Downtrend_HighLine", OBJPROP_RAY_LEFT, true);
            ObjectSetInteger(0, "Downtrend_HighLine", OBJPROP_RAY_RIGHT, true);
           }
        }
      if(validLow)
        {
         datetime lowStartTime = pastTime;
         double lowStartPrice  = mLow * (double)lowStartTime + bLow;
         double lowEndPrice    = mLow * (double)futureTime + bLow;
         if(!ObjectCreate(0, "Uptrend_LowLine", OBJ_TREND, 0, lowStartTime, lowStartPrice, futureTime, lowEndPrice))
            Print("Failed to create Low Trendline");
         else
           {
            ObjectSetInteger(0, "Uptrend_LowLine", OBJPROP_COLOR, clrGreen);
            ObjectSetInteger(0, "Uptrend_LowLine", OBJPROP_RAY_LEFT, true);
            ObjectSetInteger(0, "Uptrend_LowLine", OBJPROP_RAY_RIGHT, true);
           }
        }
     }
  }

Trendlinien-Zeichnung (wenn beide Trends gültig sind)

Gleiches Vorzeichen der Steigung: Es wird eine gemittelte Steigung für parallele Linien verwendet.                                                                                                                  Verschiedene Zeichen: Zeichnen der einzelnen Trendlinien. Verwendet wird ObjectCreate und ObjectSetInteger um die Linien zu platzieren und zu gestalten.

6. Zeichnen von Unterstützungs- und Widerstandsniveaus (DrawSupportResistance)

Der Unterstützungs- und Widerstandsteil des Codes dient der dynamischen Identifizierung wichtiger horizontaler Kursniveaus auf der Grundlage der vom ZigZag-Indikator gelieferten bestätigten Umkehrpunkte. Der Algorithmus bestimmt nicht nur das höchste bestätigte Hoch als Hauptwiderstand und das niedrigste bestätigte Tief als Hauptunterstützung, sondern geht noch weiter, indem er signifikante Hochs und Tiefs herausfiltert, um sowohl Haupt- als auch Nebenwerte zu bestimmen. Dieser Prozess ist von entscheidender Bedeutung, da Unterstützung und Widerstand grundlegende Konzepte in der technischen Analyse sind; Unterstützung stellt ein Niveau dar, bei dem der Preis aufgrund einer erhöhten Nachfrage dazu neigt, nicht weiter zu fallen, während Widerstand ein Niveau angibt, bei dem der Preis aufgrund des Angebotsdrucks typischerweise Schwierigkeiten hat, sich nach oben zu bewegen.

Bei dieser Implementierung untersucht der Code alle bestätigten Umkehrpunkte, sortiert und vergleicht sie sorgfältig, um die extremsten Werte zu isolieren. Dadurch wird sichergestellt, dass die auf dem Chart eingezeichneten Niveaus nicht nur vorübergehende Schwankungen sind, sondern aussagekräftige Zonen darstellen, die in der Vergangenheit Preisumkehrungen beeinflusst haben. Indem der Algorithmus den zweithöchsten und zweitniedrigsten Wert als geringfügigen Widerstand und Unterstützung identifiziert, bietet er zusätzliche Einblicke. Diese kleineren Niveaus können als frühe Signale oder sekundäre Ziele dienen und Händlern eine nuancierte Sicht auf mögliche Kursreaktionen bieten, bevor sie die kritischeren Hauptniveaus erreichen.

Dieser Ansatz ist in einem sich ständig wandelnden Markt von großem Nutzen. Sobald neue Kursdaten eintreffen, nimmt der ZigZag-Indikator neue Umkehrpunkte auf und aktualisiert automatisch die Unterstützungs- und Widerstandsniveaus, um die aktuelle Marktstruktur widerzuspiegeln. Diese Echtzeitanpassung ist für Händler von entscheidender Bedeutung, da sie ihnen hilft, sich an sich verändernde Preisbarrieren anzupassen, die ihre Ein- oder Ausstiegsentscheidungen beeinflussen könnten. Diese Ebenen werden auf dem Chart als horizontale Linien in unterschiedlichen Farben dargestellt, sodass sie auf einen Blick zu erkennen sind. Diese zusätzliche Klarheit ermöglicht es Händlern, schnell zu erkennen, in welchen Schlüsselbereichen der Preis reagieren könnte, und hilft ihnen, Stop-Loss-Aufträge zu platzieren oder Profit Targets mit mehr Vertrauen festzulegen. Letztendlich berechnet dieser Teil des Codes nicht nur Unterstützung und Widerstand, sondern wandelt die rohen Marktdaten in klare, umsetzbare Erkenntnisse um, was ihn zu einem unverzichtbaren Werkzeug für jeden Händler macht, der Charttechnik verwendet.

void DrawSupportResistance()
  {
   double confirmedHighs[10], confirmedLows[10];
   int confHighCount = 0, confLowCount = 0;

   for(int i = 0; i < LookBackBars - 1; i++)
     {
      if(zzBuffer[i] != 0)
        {
         if(iHigh(_Symbol, InpTimeFrame, i) == zzBuffer[i] && confHighCount < 10)
           {
            confirmedHighs[confHighCount] = zzBuffer[i];
            confHighCount++;
           }
         else if(iLow(_Symbol, InpTimeFrame, i) == zzBuffer[i] && confLowCount < 10)
              {
               confirmedLows[confLowCount] = zzBuffer[i];
               confLowCount++;
              }
        }
     }

   int usedHighCount = (confHighCount >= 4) ? confHighCount - 1 : confHighCount;
   int usedLowCount  = (confLowCount  >= 4) ? confLowCount - 1  : confLowCount;

   double majorResistance = -1e9, majorSupport = 1e9;
   double minorResistance = -1e9, minorSupport = 1e9;
   double tempHigh = -1e9, tempLow = -1e9;
   for(int i = 0; i < usedHighCount; i++)
     {
      if(confirmedHighs[i] > majorResistance)
        {
         tempHigh = majorResistance;
         majorResistance = confirmedHighs[i];
        }
      else if(confirmedHighs[i] > tempHigh)
           {
            tempHigh = confirmedHighs[i];
           }
     }
   if(tempHigh > -1e9)
      minorResistance = tempHigh;
   for(int i = 0; i < usedLowCount; i++)
     {
      if(confirmedLows[i] < majorSupport)
        {
         tempLow = majorSupport;
         majorSupport = confirmedLows[i];
        }
      else if(confirmedLows[i] < tempLow)
           {
            tempLow = confirmedLows[i];
           }
     }
   if(tempLow < 1e9)
      minorSupport = tempLow;

   if(usedHighCount > 0)
     {
      if(!ObjectCreate(0, "Major_Resistance", OBJ_HLINE, 0, 0, majorResistance))
         Print("Failed to create Major Resistance");
      else
         ObjectSetInteger(0, "Major_Resistance", OBJPROP_COLOR, clrMagenta);

      if(minorResistance > -1e9 && minorResistance < majorResistance)
        {
         if(!ObjectCreate(0, "Minor_Resistance", OBJ_HLINE, 0, 0, minorResistance))
            Print("Failed to create Minor Resistance");
         else
            ObjectSetInteger(0, "Minor_Resistance", OBJPROP_COLOR, clrFuchsia);
        }
     }
   if(usedLowCount > 0)
     {
      if(!ObjectCreate(0, "Major_Support", OBJ_HLINE, 0, 0, majorSupport))
         Print("Failed to create Major Support");
      else
         ObjectSetInteger(0, "Major_Support", OBJPROP_COLOR, clrAqua);

      if(minorSupport < 1e9 && minorSupport > majorSupport)
        {
         if(!ObjectCreate(0, "Minor_Support", OBJ_HLINE, 0, 0, minorSupport))
            Print("Failed to create Minor Support");
         else
            ObjectSetInteger(0, "Minor_Support", OBJPROP_COLOR, clrBlue);
        }
     }
  }

Die Datenerfassung iteriert durch den Puffer, um bestätigte Höchst- und Tiefstwerte zu extrahieren. Die Niveaubestimmung verwendet Vergleiche, um die Extremwerte zu isolieren. Große Widerstände/Unterstützungen werden als die extremsten Werte festgelegt, während die nächstgrößeren Werte zu kleinen Werten werden. Die grafische Darstellung erzeugt horizontale Linien (OBJ_HLINE) für jede identifizierte Ebene. Zur leichteren Unterscheidung sind die einzelnen Zeilen farbig hinterlegt.


MQL5 Code

//+------------------------------------------------------------------+
//|                                               ZigZag Analyzer.mq5|
//|                                   Copyright 2025, MetaQuotes Ltd.|
//|                           https://www.mql5.com/en/users/lynnchris|
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link      "https://www.mql5.com/en/users/lynnchris"
#property version   "1.0"
#property strict

// Input parameters
input ENUM_TIMEFRAMES InpTimeFrame    = PERIOD_CURRENT; // Timeframe to analyze
input int             ZZ_Depth         = 12;  // ZigZag depth
input int             ZZ_Deviation     = 5;   // ZigZag deviation
input int             ZZ_Backstep      = 3;   // ZigZag backstep
input int             LookBackBars     = 200; // Bars to search for pivots
input int             ExtendFutureBars = 100; // Bars to extend trendlines into the future

// Global indicator handle for ZigZag
int zzHandle;

// Arrays for ZigZag data and pivot storage
double   zzBuffer[];
datetime pivotTimes[];
double   pivotPrices[];
bool     pivotIsPeak[];

// Variable to detect new bars
datetime lastBarTime = 0;

//+------------------------------------------------------------------+
//| Initialization function                                          |
//+------------------------------------------------------------------+
int OnInit()
  {
   zzHandle = iCustom(_Symbol, InpTimeFrame, "ZigZag", ZZ_Depth, ZZ_Deviation, ZZ_Backstep);
   if(zzHandle == INVALID_HANDLE)
     {
      Print("Error creating ZigZag handle");
      return(INIT_FAILED);
     }
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Deinitialization function                                        |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   ObjectDelete(0, "Downtrend_HighLine");
   ObjectDelete(0, "Uptrend_LowLine");
   ObjectDelete(0, "Major_Resistance");
   ObjectDelete(0, "Major_Support");
   ObjectDelete(0, "Minor_Resistance");
   ObjectDelete(0, "Minor_Support");
   IndicatorRelease(zzHandle);
  }

//+------------------------------------------------------------------+
//| Tick function                                                    |
//+------------------------------------------------------------------+
void OnTick()
  {
   datetime currentBarTime = iTime(_Symbol, InpTimeFrame, 0);
   if(currentBarTime == lastBarTime)
      return;
   lastBarTime = currentBarTime;

// Remove previous objects
   ObjectDelete(0, "Downtrend_HighLine");
   ObjectDelete(0, "Uptrend_LowLine");
   ObjectDelete(0, "Major_Resistance");
   ObjectDelete(0, "Major_Support");
   ObjectDelete(0, "Minor_Resistance");
   ObjectDelete(0, "Minor_Support");

   if(CopyBuffer(zzHandle, 0, 0, LookBackBars, zzBuffer) <= 0)
     {
      Print("Failed to copy ZigZag data");
      return;
     }
   ArraySetAsSeries(zzBuffer, true);

   DrawZigZagTrendlines();
   DrawSupportResistance();
  }

//+------------------------------------------------------------------+
//| Draw ZigZag-based Trendlines                                     |
//+------------------------------------------------------------------+
void DrawZigZagTrendlines()
  {
   double highPrices[10], lowPrices[10];
   datetime highTimes[10], lowTimes[10];
   int highCount = 0, lowCount = 0;

// Extract swing points from the ZigZag buffer
   for(int i = 0; i < LookBackBars - 1; i++)
     {
      if(zzBuffer[i] != 0)
        {
         if(iHigh(_Symbol, InpTimeFrame, i) == zzBuffer[i] && highCount < 10)
           {
            highPrices[highCount] = zzBuffer[i];
            highTimes[highCount] = iTime(_Symbol, InpTimeFrame, i);
            highCount++;
           }
         else
            if(iLow(_Symbol, InpTimeFrame, i) == zzBuffer[i] && lowCount < 10)
              {
               lowPrices[lowCount] = zzBuffer[i];
               lowTimes[lowCount] = iTime(_Symbol, InpTimeFrame, i);
               lowCount++;
              }
        }
     }

// Exclude the most recent swing if possible
   int usedHighCount = (highCount >= 4) ? highCount - 1 : highCount;
   int usedLowCount  = (lowCount  >= 4) ? lowCount - 1  : lowCount;

   double mHigh = 0, bHigh = 0, mLow = 0, bLow = 0;
   bool validHigh = false, validLow = false;

// Regression for highs
   if(usedHighCount >= 3)
     {
      double sumT = 0, sumP = 0, sumTP = 0, sumT2 = 0;
      for(int i = 0; i < usedHighCount; i++)
        {
         double t = (double)highTimes[i];
         double p = highPrices[i];
         sumT += t;
         sumP += p;
         sumTP += t * p;
         sumT2 += t * t;
        }
      int N = usedHighCount;
      double denominator = N * sumT2 - sumT * sumT;
      if(denominator != 0)
        {
         mHigh = (N * sumTP - sumT * sumP) / denominator;
         bHigh = (sumP - mHigh * sumT) / N;
        }
      else
         bHigh = sumP / N;
      validHigh = true;
     }

// Regression for lows
   if(usedLowCount >= 3)
     {
      double sumT = 0, sumP = 0, sumTP = 0, sumT2 = 0;
      for(int i = 0; i < usedLowCount; i++)
        {
         double t = (double)lowTimes[i];
         double p = lowPrices[i];
         sumT += t;
         sumP += p;
         sumTP += t * p;
         sumT2 += t * t;
        }
      int N = usedLowCount;
      double denominator = N * sumT2 - sumT * sumT;
      if(denominator != 0)
        {
         mLow = (N * sumTP - sumT * sumP) / denominator;
         bLow = (sumP - mLow * sumT) / N;
        }
      else
         bLow = sumP / N;
      validLow = true;
     }

// Define time limits for trendlines
   datetime pastTime   = iTime(_Symbol, InpTimeFrame, LookBackBars - 1);
   datetime futureTime = lastBarTime + ExtendFutureBars * PeriodSeconds();

// Draw trendlines if both regressions are valid
   if(validHigh && validLow)
     {
      // When slopes have the same sign, use average slope
      if(mHigh * mLow > 0)
        {
         double mParallel = (mHigh + mLow) / 2.0;
         double bHighParallel = highPrices[0] - mParallel * (double)highTimes[0];
         double bLowParallel  = lowPrices[0] - mParallel * (double)lowTimes[0];

         datetime highStartTime = pastTime;
         double highStartPrice  = mParallel * (double)highStartTime + bHighParallel;
         double highEndPrice    = mParallel * (double)futureTime + bHighParallel;
         if(!ObjectCreate(0, "Downtrend_HighLine", OBJ_TREND, 0, highStartTime, highStartPrice, futureTime, highEndPrice))
            Print("Failed to create High Trendline");
         else
           {
            ObjectSetInteger(0, "Downtrend_HighLine", OBJPROP_COLOR, clrRed);
            ObjectSetInteger(0, "Downtrend_HighLine", OBJPROP_RAY_LEFT, true);
            ObjectSetInteger(0, "Downtrend_HighLine", OBJPROP_RAY_RIGHT, true);
           }

         datetime lowStartTime = pastTime;
         double lowStartPrice  = mParallel * (double)lowStartTime + bLowParallel;
         double lowEndPrice    = mParallel * (double)futureTime + bLowParallel;
         if(!ObjectCreate(0, "Uptrend_LowLine", OBJ_TREND, 0, lowStartTime, lowStartPrice, futureTime, lowEndPrice))
            Print("Failed to create Low Trendline");
         else
           {
            ObjectSetInteger(0, "Uptrend_LowLine", OBJPROP_COLOR, clrGreen);
            ObjectSetInteger(0, "Uptrend_LowLine", OBJPROP_RAY_LEFT, true);
            ObjectSetInteger(0, "Uptrend_LowLine", OBJPROP_RAY_RIGHT, true);
           }
        }
      else
        {
         datetime highStartTime = pastTime;
         double highStartPrice  = mHigh * (double)highStartTime + bHigh;
         double highEndPrice    = mHigh * (double)futureTime + bHigh;
         if(!ObjectCreate(0, "Downtrend_HighLine", OBJ_TREND, 0, highStartTime, highStartPrice, futureTime, highEndPrice))
            Print("Failed to create High Trendline");
         else
           {
            ObjectSetInteger(0, "Downtrend_HighLine", OBJPROP_COLOR, clrRed);
            ObjectSetInteger(0, "Downtrend_HighLine", OBJPROP_RAY_LEFT, true);
            ObjectSetInteger(0, "Downtrend_HighLine", OBJPROP_RAY_RIGHT, true);
           }

         datetime lowStartTime = pastTime;
         double lowStartPrice  = mLow * (double)lowStartTime + bLow;
         double lowEndPrice    = mLow * (double)futureTime + bLow;
         if(!ObjectCreate(0, "Uptrend_LowLine", OBJ_TREND, 0, lowStartTime, lowStartPrice, futureTime, lowEndPrice))
            Print("Failed to create Low Trendline");
         else
           {
            ObjectSetInteger(0, "Uptrend_LowLine", OBJPROP_COLOR, clrGreen);
            ObjectSetInteger(0, "Uptrend_LowLine", OBJPROP_RAY_LEFT, true);
            ObjectSetInteger(0, "Uptrend_LowLine", OBJPROP_RAY_RIGHT, true);
           }
        }
     }
   else
     {
      if(validHigh)
        {
         datetime highStartTime = pastTime;
         double highStartPrice  = mHigh * (double)highStartTime + bHigh;
         double highEndPrice    = mHigh * (double)futureTime + bHigh;
         if(!ObjectCreate(0, "Downtrend_HighLine", OBJ_TREND, 0, highStartTime, highStartPrice, futureTime, highEndPrice))
            Print("Failed to create High Trendline");
         else
           {
            ObjectSetInteger(0, "Downtrend_HighLine", OBJPROP_COLOR, clrRed);
            ObjectSetInteger(0, "Downtrend_HighLine", OBJPROP_RAY_LEFT, true);
            ObjectSetInteger(0, "Downtrend_HighLine", OBJPROP_RAY_RIGHT, true);
           }
        }
      if(validLow)
        {
         datetime lowStartTime = pastTime;
         double lowStartPrice  = mLow * (double)lowStartTime + bLow;
         double lowEndPrice    = mLow * (double)futureTime + bLow;
         if(!ObjectCreate(0, "Uptrend_LowLine", OBJ_TREND, 0, lowStartTime, lowStartPrice, futureTime, lowEndPrice))
            Print("Failed to create Low Trendline");
         else
           {
            ObjectSetInteger(0, "Uptrend_LowLine", OBJPROP_COLOR, clrGreen);
            ObjectSetInteger(0, "Uptrend_LowLine", OBJPROP_RAY_LEFT, true);
            ObjectSetInteger(0, "Uptrend_LowLine", OBJPROP_RAY_RIGHT, true);
           }
        }
     }
  }

//+------------------------------------------------------------------+
//| Draw Support and Resistance Levels                               |
//+------------------------------------------------------------------+
void DrawSupportResistance()
  {
   double confirmedHighs[10], confirmedLows[10];
   int confHighCount = 0, confLowCount = 0;

   for(int i = 0; i < LookBackBars - 1; i++)
     {
      if(zzBuffer[i] != 0)
        {
         if(iHigh(_Symbol, InpTimeFrame, i) == zzBuffer[i] && confHighCount < 10)
           {
            confirmedHighs[confHighCount] = zzBuffer[i];
            confHighCount++;
           }
         else
            if(iLow(_Symbol, InpTimeFrame, i) == zzBuffer[i] && confLowCount < 10)
              {
               confirmedLows[confLowCount] = zzBuffer[i];
               confLowCount++;
              }
        }
     }

   int usedHighCount = (confHighCount >= 4) ? confHighCount - 1 : confHighCount;
   int usedLowCount  = (confLowCount  >= 4) ? confLowCount - 1  : confLowCount;

   double majorResistance = -1e9, majorSupport = 1e9;
   double minorResistance = -1e9, minorSupport = 1e9;
   double tempHigh = -1e9, tempLow = -1e9;
   for(int i = 0; i < usedHighCount; i++)
     {
      if(confirmedHighs[i] > majorResistance)
        {
         tempHigh = majorResistance;
         majorResistance = confirmedHighs[i];
        }
      else
         if(confirmedHighs[i] > tempHigh)
           {
            tempHigh = confirmedHighs[i];
           }
     }
   if(tempHigh > -1e9)
      minorResistance = tempHigh;
   for(int i = 0; i < usedLowCount; i++)
     {
      if(confirmedLows[i] < majorSupport)
        {
         tempLow = majorSupport;
         majorSupport = confirmedLows[i];
        }
      else
         if(confirmedLows[i] < tempLow)
           {
            tempLow = confirmedLows[i];
           }
     }
   if(tempLow < 1e9)
      minorSupport = tempLow;

   if(usedHighCount > 0)
     {
      if(!ObjectCreate(0, "Major_Resistance", OBJ_HLINE, 0, 0, majorResistance))
         Print("Failed to create Major Resistance");
      else
         ObjectSetInteger(0, "Major_Resistance", OBJPROP_COLOR, clrMagenta);

      if(minorResistance > -1e9 && minorResistance < majorResistance)
        {
         if(!ObjectCreate(0, "Minor_Resistance", OBJ_HLINE, 0, 0, minorResistance))
            Print("Failed to create Minor Resistance");
         else
            ObjectSetInteger(0, "Minor_Resistance", OBJPROP_COLOR, clrFuchsia);
        }
     }
   if(usedLowCount > 0)
     {
      if(!ObjectCreate(0, "Major_Support", OBJ_HLINE, 0, 0, majorSupport))
         Print("Failed to create Major Support");
      else
         ObjectSetInteger(0, "Major_Support", OBJPROP_COLOR, clrAqua);

      if(minorSupport < 1e9 && minorSupport > majorSupport)
        {
         if(!ObjectCreate(0, "Minor_Support", OBJ_HLINE, 0, 0, minorSupport))
            Print("Failed to create Minor Support");
         else
            ObjectSetInteger(0, "Minor_Support", OBJPROP_COLOR, clrBlue);
        }
     }
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+



Ergebnisse

Bevor wir die Ergebnisse analysieren, fügen wir zunächst den ZigZag-Indikator in das Chart ein. Um den Prozess besser zu verstehen, sehen Sie sich bitte das nachstehende GIF-Chart an. Diese visuelle Hilfe soll die einzelnen Schritte veranschaulichen. Anhand des Charts können Sie sehen, wie der Indikator integriert und konfiguriert ist. Wenn das klar ist, können wir zur Analyse der Ergebnisse übergehen.

Indikator einfügen

Abb. 5. Initialisierung des ZigZag-Indikators

Diese Reihe von Charts veranschaulicht die Ergebnisse, wobei jedes Chart von ausführlichen Erläuterungen begleitet wird. Das nachstehende Chart zeigt zunächst das Ergebnis, das nach der Ausführung des Zig Zag Analyzer-Tools für den Stufenindex erzielt wurde. Wie beobachtet, werden die Trendlinien genau gezeichnet, wenn der EA auf das Chart angewendet wird. Sowohl die untere als auch die obere Linie sind abwärts gerichtet, was auf einen Abwärtstrend hindeutet. Darüber hinaus zeigen die Charts deutlich die großen und kleinen Unterstützungs- und Widerstandsebenen an.

Trendlinien

Abb. 6. Ergebnis zum Stufenindex

Dieser Screenshot bietet zusätzliche Einblicke in die Analyse. In der Abbildung sehen Sie wichtige Umkehrpunkte wie untere Hochs und untere Tiefs, die für die Konstruktion von Trendlinien verwendet werden. Größere und kleinere Unterstützungs- und Widerstandsniveaus sind deutlich markiert. Vor allem die Schnittpunkte zwischen den Trendlinien und den wichtigsten Kursniveaus markieren starke Umkehrpunkte. Das höchste untere Hoch trifft auf den Hauptwiderstand und das niedrigste untere Tief auf die Hauptunterstützung, wo eine Umkehr stattfindet.

Trendlinien

Abb. 7. Stufenindex

Dieses USDCHF-Chart zeigt eingezeichnete Trendlinien. Sie sind auf dem Markt präsent, aber nicht übermäßig dominant. Der Markt respektiert die Unterstützungs- und Widerstandsniveaus, was die Wirksamkeit des Systems bestätigt. Ich habe die Punkte hervorgehoben, an denen die Trendlinien die Marktschwankungen berühren.

Abb. 8. USDCHF

Schließlich können wir seine Performance im Index Volatility 25 betrachten. Die Trendlinien sind deutlich eingezeichnet und verbinden die Umkehrpunkte. Die Linien verdeutlichen die Bewegungen des Marktes mit Präzision. Diese Klarheit stärkt die Zuverlässigkeit des Systems unter verschiedenen Marktbedingungen. Die Ergebnisse bestätigen die Wirksamkeit unseres Ansatzes.

Abb. 9. Volatilität 25 Index


Schlussfolgerung

Das Tool Zig Zag Analyzer ist eine leistungsstarke Methode zur Automatisierung der Preisaktionsanalyse mit MQL5. Unsere Tests zeigen, dass die Trendlinien in Märkten, die sich im Trend befinden, effektiv gezeichnet werden. Ich glaube, dass dieser Ansatz zur Entwicklung zusätzlicher Tools führen kann, die Muster wie Fahnen- und Dreiecksformationen erkennen. Der Zig Zag Analyzer dient Anfängern im Devisenhandel als Ausgangspunkt, um Trends zu beobachten und potenzielle Unterstützungs- oder Widerstandszonen zu erkennen. Sie ist auch für erfahrene Händler wertvoll, da Trendlinien für die Preisaktionsanalyse von zentraler Bedeutung sind. Dieses Tool eignet sich hervorragend zum Lernen und kann an verschiedene Handelsstrategien angepasst werden, wobei auch andere Bestätigungsmethoden einbezogen werden können.

Datum Name des Werkzeugs  Beschreibung Version  Aktualisierungen  Hinweis
01/10/24 Chart Projector Skript zur Überlagerung der Kursentwicklung des Vortages mit einem Ghost-Effekt. 1.0 Erste Veröffentlichung Toolkit Nummer 1
18/11/24 Analytical Comment Er liefert Informationen zum Vortag in Tabellenform und nimmt die zukünftige Marktentwicklung vorweg. 1.0 Erste Veröffentlichung Toolkit Nummer 2
27/11/24 Analytics Master Reguläre Aktualisierung der Marktmetriken alle zwei Stunden.  1.01 Zweite Veröffentlichung Toolkit Nummer 3
02/12/24 Analytics Forecaster  Reguläre Aktualisierung der Marktmetriken alle zwei Stunden mit Telegram-Integration. 1.1 Dritte Ausgabe Toolkit Nummer 4
09/12/24 Volatility Navigator Der EA analysiert die Marktbedingungen anhand der Indikatoren Bollinger Bands, RSI und ATR. 1.0 Erste Veröffentlichung Toolkit Nummer 5
19/12/24 Mean Reversion Signal Reaper Analysiert den Markt anhand der Strategie „Umkehr zur Mitte“ und liefert Signale.  1.0  Erste Veröffentlichung  Toolkit Nummer 6 
9/01/25  Signal Pulse  Analysator für mehrere Zeitrahmen. 1.0  Erste Veröffentlichung  Toolkit Nummer 7 
17/01/25  Metrics Board  Bedienfeld mit Taste für die Analyse.  1.0  Erste Veröffentlichung Toolkit Nummer 8 
21/01/25 External Flow Analytik durch externe Bibliotheken. 1.0  Erste Veröffentlichung Toolkit Nummer 9 
27/01/25 VWAP Volumengewichteter Durchschnittspreis   1.3  Erste Veröffentlichung  Toolkit Nummer 10 
02/02/25  Heikin Ashi  Trendglättung und Identifizierung von Umkehrsignalen  1.0  Erste Veröffentlichung  Toolkit Nummer 11
04/02/25  FibVWAP  Signalerzeugung durch Python-Analyse  1.0  Erste Veröffentlichung  Toolkit Nummer 12
14/02/25  RSI DIVERGENCE  Kursentwicklung versus RSI-Divergenzen  1.0  Erste Veröffentlichung  Toolkit Nummer 13 
17/02/25  Parabolic Stop and Reverse (PSAR)  Automatisierung der PSAR-Strategie 1.0 Erste Veröffentlichung  Toolkit Nummer 14
20/02/25  Quarters Drawer Script Einzeichnen der Ebenen der Viertel auf dem Chart  1.0  Erste Veröffentlichung  Toolkit Nummer 15 
27/02/25  Intrusion Detector Erkennen und warnen, wenn der Preis ein Viertel-Niveau erreicht 1.0   Erste Veröffentlichung Toolkit Nummer 16 
27/02/25  TrendLoom Tool  Analysepanel für mehrere Zeitrahmen 1.0 Erste Veröffentlichung Toolkit Nummer 17
11/03/25  Quarters Board  Bedienfeld mit Tasten zum Aktivieren oder Deaktivieren der Viertel-Ebenen  1.0  Erste Veröffentlichung Toolkit Nummer 18
26/03/25  ZigZag Analyzer  Zeichnen von Trendlinien mit dem ZigZag-Indikator  1.0  Erste Veröffentlichung  Toolkit Nummer 19 

Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/17625

Beigefügte Dateien |
ZigZag_Analyzer.mq5 (13.44 KB)
Letzte Kommentare | Zur Diskussion im Händlerforum (5)
diego herrera
diego herrera | 9 Apr. 2025 in 21:28
>Hallo Cristina, viele Grüße.

Ich finde diesen Indikator sehr interessant. Er würde mir bei meiner technischen Analyse sehr helfen, da ich die meiste Zeit damit verbringe, um den richtigen Trend, die Unterstützung und den Widerstand zu finden. Ich habe den Code heruntergeladen, und er wurde korrekt kompiliert, aber wenn ich ihn in den Chart einfüge, werden keine Informationen angezeigt. Mache ich etwas falsch? Ich habe wieder ein Video angehängt. Mit freundlichen Grüßen.
Christian Benjamin
Christian Benjamin | 12 Apr. 2025 in 08:18
diego herrera #:
>Hallo Cristina, viele Grüße.

Ich finde diesen Indikator sehr interessant. Er würde mir bei meiner technischen Analyse sehr helfen, da ich die meiste Zeit damit verbringe, um den richtigen Trend, die Unterstützung und den Widerstand zu finden. Ich habe den Code heruntergeladen, und er wurde korrekt kompiliert, aber wenn ich ihn in den Chart einfüge, werden keine Informationen angezeigt. Mache ich etwas falsch? Ich habe wieder ein Video angehängt. Mit freundlichen Grüßen.

Hie diego herrera

Christian Benjamin
Christian Benjamin | 12 Apr. 2025 in 08:26
diego herrera #:
>Hallo Cristina, viele Grüße.

Ich finde diesen Indikator sehr interessant. Er würde mir bei meiner technischen Analyse sehr helfen, da ich die meiste Zeit damit verbringe, um den richtigen Trend, die Unterstützung und den Widerstand zu finden. Ich habe den Code heruntergeladen, und er wurde korrekt kompiliert, aber wenn ich ihn in den Chart einfüge, werden keine Informationen angezeigt. Mache ich etwas falsch? Ich habe wieder ein Video angehängt. Meine Grüße.
Ich glaube, das Problem liegt an der Position des ZigZag-Indikators. Bitte versuchen Sie, ihn in den Hauptordner der Indikatoren zu verschieben. Wenn das Problem weiterhin besteht, teilen Sie uns bitte die MQL5-Protokolle auf der Registerkarte Experten mit, nachdem Sie das Programm ausgeführt haben. Bitte entschuldigen Sie die verspätete Antwort.
linfo2
linfo2 | 13 Apr. 2025 in 21:48
Ich denke, das Problem ist der Zickzack-Indikator ist nicht in der Down-Load enthalten, ich bin nicht sicher, welche Christain bezieht sich auf, aber Sie können den Zickzack-Indikator aus Beispiele verwenden, wenn Sie es als benutzerdefinierte Indikator benötigen
Conor Mcnamara
Conor Mcnamara | 6 Mai 2025 in 22:42
diego herrera #:
>Hallo Cristina, viele Grüße.

Ich finde diesen Indikator sehr interessant. Er würde mir bei meiner technischen Analyse sehr helfen, da ich die meiste Zeit damit verbringe, um den richtigen Trend, die Unterstützung und den Widerstand zu finden. Ich habe den Code heruntergeladen, und er wurde korrekt kompiliert, aber wenn ich ihn in den Chart einfüge, werden keine Informationen angezeigt. Mache ich etwas falsch? Ich habe wieder ein Video angehängt. Mit freundlichen Grüßen.

Versuchen Sie dies

int OnInit()
  {
   zzHandle = iCustom(_Symbol, InpTimeFrame, "Examples\\ZigZag", ZZ_Depth, ZZ_Deviation, ZZ_Backstep);
   if(zzHandle == INVALID_HANDLE)
     {
      Print("Error creating ZigZag handle");
      return(INIT_FAILED);
     }
     
   ChartIndicatorAdd(0, 0, zzHandle);
   return(INIT_SUCCEEDED);
  }
Automatisieren von Handelsstrategien in MQL5 (Teil 13): Aufbau eines Kopf-Schulter-Handelsalgorithmus Automatisieren von Handelsstrategien in MQL5 (Teil 13): Aufbau eines Kopf-Schulter-Handelsalgorithmus
In diesem Artikel automatisieren wir das Muster aus Kopf und Schultern in MQL5. Wir analysieren seine Architektur, implementieren einen EA, um ihn zu erkennen und zu handeln, und führen einen Backtest der Ergebnisse durch. Der Prozess offenbart einen praktischen Handelsalgorithmus, der noch verfeinert werden kann.
Automatisieren von Handelsstrategien in MQL5 (Teil 12): Umsetzung der Strategie der Mitigation Order Blocks (MOB) Automatisieren von Handelsstrategien in MQL5 (Teil 12): Umsetzung der Strategie der Mitigation Order Blocks (MOB)
In diesem Artikel bauen wir ein MQL5-Handelssystem auf, das die Orderblock-Erkennung für den Handel des Smart Money automatisiert. Wir skizzieren die Regeln der Strategie, implementieren die Logik in MQL5 und integrieren das Risikomanagement für eine effektive Handelsausführung. Schließlich führen wir Backtests durch, um die Leistung des Systems zu bewerten und es für optimale Ergebnisse zu verfeinern.
Larry Connors‘ Strategien RSI2 Mean-Reversion im Day-Trading Larry Connors‘ Strategien RSI2 Mean-Reversion im Day-Trading
Larry Connors ist ein renommierter Händler und Autor, der vor allem für seine Arbeit im Bereich des quantitativen Handels und für Strategien wie den 2-Perioden-RSI (RSI2) bekannt ist, der dabei hilft, kurzfristig überkaufte und überverkaufte Marktbedingungen zu erkennen. In diesem Artikel werden wir zunächst die Motivation für unsere Forschung erläutern, dann drei von Connors' berühmtesten Strategien in MQL5 nachbilden und sie auf den Intraday-Handel mit dem S&P 500 Index CFD anwenden.
Erstellen eines Handelsadministrator-Panels in MQL5 (Teil IX): Code Organisation (IV): Handelsmanagement-Panel-Klasse Erstellen eines Handelsadministrator-Panels in MQL5 (Teil IX): Code Organisation (IV): Handelsmanagement-Panel-Klasse
Diese Diskussion behandelt das aktualisierte TradeManagementPanel in unserem New_Admin_Panel EA. Das Update verbessert das Panel durch die Verwendung integrierter Klassen, um eine nutzerfreundliche Schnittstelle für das Handelsmanagement zu bieten. Es enthält Schaltflächen zum Eröffnen von Positionen und Steuerelemente zur Verwaltung bestehender Handelsgeschäfte und ausstehender Aufträge. Ein wichtiges Merkmal ist das integrierte Risikomanagement, das die Einstellung der Werte von Stop-Loss und Take-Profit direkt in der Nutzeroberfläche ermöglicht. Diese Aktualisierung verbessert die Code-Organisation für große Programme und vereinfacht den Zugang zu den Auftragsverwaltungswerkzeugen, die im Terminal oft komplex sind.