English 日本語
preview
Einführung in MQL5 (Teil 14): Ein Anfängerleitfaden zur Erstellung nutzerdefinierter Indikatoren (III)

Einführung in MQL5 (Teil 14): Ein Anfängerleitfaden zur Erstellung nutzerdefinierter Indikatoren (III)

MetaTrader 5Handelssysteme |
76 6
Israel Pelumi Abioye
Israel Pelumi Abioye

Einführung

Willkommen zurück zu unserer MQL5-Serie! In den vorangegangenen Artikeln dieser Serie haben wir untersucht, wie man in MQL5 nutzerdefinierte Indikatoren mithilfe von Puffern und Plots erstellt. In Puffern können wir Indikatorwerte speichern, während Plots helfen, sie auf dem Chart zu visualisieren. Diese Methoden sind für viele Indikatoren geeignet, haben aber ihre Grenzen, wenn es um die Erstellung komplexer visueller Darstellungen geht.

In diesem Artikel werden wir einen neuen Ansatz verfolgen, indem wir Indikatoren mit Hilfe von Meta Trader 5 Chart-Objekten erstellen. Zusätzliche Flexibilität bieten die Chart-Objekte, mit denen sich Beschriftungen, Formen und Trendlinien direkt im Chart erstellen lassen, ohne dass dafür Anzeigepuffer erforderlich sind. Diese Technik eignet sich gut für die Entwicklung von Indikatoren, die einzigartige grafische Komponenten benötigen, die Muster zeigen und wichtige Kursniveaus identifizieren.

Wir werden dazu einen Indikator erstellen, der den Harmonic Patterns, den harmonischen Mustern, ähnelt, um dies umzusetzen. Die Logik, die wir verwenden werden, kann modifiziert werden, um verschiedene harmonische Muster zu identifizieren und darzustellen, auch wenn wir uns nicht auf ein bestimmtes (wie Gartley, Bat oder Butterfly) konzentrieren werden. Das Hauptziel besteht nicht darin, einen effektiven Detektor für die harmonischen Muster zu entwickeln, sondern zu lernen, wie man Chart-Objekte in MQL5 verwendet, um Indikatoren zu entwickeln. In Teil 9 dieser Serie haben wir uns angeschaut, wie man Objekte wie Trendlinien, Rechtecke und Beschriftungen in MQL5 erstellt und damit arbeitet, wo wir zum ersten Mal die Verwendung von Chart-Objekten behandelt haben. Aufbauend auf diesen Kenntnissen wird in diesem Beitrag auf die Entwicklung von Indikatoren eingegangen. Am Ende des Kurses werden Sie wissen, wie Sie einzigartige visuelle Anzeigen entwickeln können, indem Sie dynamisch mit Chart-Elementen arbeiten.

In diesem Artikel erfahren Sie mehr über Folgendes:

  • Wie man einen nutzerdefinierten Indikator mit MetaTrader 5 Chart-Objekten erstellt, anstatt sich auf Puffer und Plots zu verlassen.
  • Verstehen der Struktur von Harmonic Patterns und wie sie in der Kursentwicklung identifiziert werden.
  • Wie man wichtige Umkehrpunkte im Markt erkennt, um potenzielle Harmonic Patterns zu bilden.
  • Verwendung von Fibonacci-Retracement-Levels zur Validierung von Musterformationen.
  • Programmgesteuertes Zeichnen geometrischer Formen (z. B. Dreiecke und Linien) zur Visualisierung von Mustern auf dem Chart.
  • Wie man ungültige Muster herausfiltert, um die Genauigkeit der Handelssignale zu verbessern.

1. Indikator Harmonic Pattern

1.1. Das Verständnis des Harmonic Pattern Indicator

Die als harmonische Muster (Harmonic Pattern) bekannten Kursstrukturen verwenden bestimmte Fibonacci-Verhältnisse, um mögliche Umkehrzonen des Marktes zu ermitteln. Die Gartley-, Bat- und Butterfly-Muster hängen u. a. von Kursschwankungen ab, die geometrische Formen erzeugen, die mit hoher Wahrscheinlichkeit Handelsmöglichkeiten signalisieren.

Harmonische Muster erfordern die Identifizierung kritischer Kurspunkte und die Verwendung von Fibonacci-Verhältnissen zur Validierung ihrer Struktur, während Standardindikatoren Signale mithilfe von Puffern und Plots erzeugen. Daher sind sie schwieriger zu erkennen und anzuzeigen als konventionelle Indikatoren wie RSI oder gleitende Durchschnitte.

Die Logik, die wir verwenden, kann modifiziert werden, um verschiedene Harmonic Patterns zu identifizieren und darzustellen, auch wenn wir uns nicht auf ein bestimmtes konzentrieren (wie Gartley, Bat oder Butterfly). Das Hauptziel besteht nicht darin, einen effektiven Detektor für die harmonischen Muster zu entwickeln, sondern zu lernen, wie man Chart-Objekte in MQL5 verwendet, um Indikatoren zu entwickeln.

Zu diesem Zweck werden wir wichtige Umkehrpunkte (hohe und tiefe) auf dem Chart markieren, Textobjekte (XABCD) verwenden, um wichtige Niveaus anzuzeigen, die Struktur des Musters mit verschiedenen Objekten illustrieren und Fibonacci-Levels anwenden, um die Genauigkeit und Validierung des Musters zu verbessern.

1.2. Das Projekt einrichten

Wie ich oft sage, muss man sich zuerst vorstellen, wie ein Indikator aussehen soll, bevor man ihn entwerfen kann. Die genaue Kenntnis des Aufbaus des Indikators erleichtert den Entwicklungsprozess und garantiert, dass das Endprodukt unseren Anforderungen entspricht.

In diesem Projekt werden wir MetaTrader 5 Chart-Objekte verwenden, um sowohl harmonisch Aufwärts- als auch Abwärts-Muster zu erstellen. Der Indikator zeichnet mehrere grafische Elemente, um die Struktur des Musters zu bilden, lokalisiert wichtige Umkehrpunkte, markiert sie mit Textobjekten (XABCD) und fügt Fibonacci-Ebenen hinzu, um die Darstellung des Musters zu verbessern.

Neben der Erstellung eines Indikators, der harmonischen Mustern sehr ähnlich ist, wird uns diese Methode praktische Erfahrungen mit MQL5-Chart-Objekten vermitteln, was die Erstellung zukünftiger nutzerdefinierter Indikatoren erleichtern wird. Wir besprechen nicht nur, wie diese Muster mit Chart-Objekten erstellt werden können, sondern gehen auch auf mögliche Fehler ein, die auftreten können. Es können Probleme auftreten, wie z. B. falsch ausgerichtete Objekte, falsch platzierte Fibonacci-Ebenen und eine ungenaue Erkennung von Umkehrpunkten. Um eine präzise Musteranzeige und einen reibungslosen Betrieb des Indikators zu gewährleisten, gehen wir auf diese Probleme ein und bieten Lösungen an.

1.2.1. Aufwärts-Muster

Wir werden eine methodische Technik anwenden, um die wichtigen Umkehrpunkte zu identifizieren, die das Muster bilden, um den Indicator Harmonic Pattern für Aufwärts-Muster zu entwickeln. Dabei werden bestimmte Preispunkte festgelegt und es wird sichergestellt, dass sie den Richtlinien für harmonische Muster entsprechen.

Der erste Schritt besteht darin, einen tiefen Umkehrpunk (X) (swing low) als Anfangspunkt des Musters zu identifizieren. Als Nächstes werden wir einen hohen Umkehrpunkt (A) (swing high) und einen tiefen Umkehrpunk (B) (swing low) ermitteln. B muss sich zwischen 61,8 % und 78,6 % des XA-Schenkels zurückbilden, damit das Muster gültig bleibt. Wir suchen dann nach einem hohen Umkehrpunkt (C) und validieren den tiefen Umkehrpunkt (D). Die vollständige Struktur des Aufwärts-Musters entsteht, wenn der letzte Punkt, D, unter X liegt.

Wenn diese Bedingungen erfüllt sind, verwenden wir Chart-Objekte - wie Trendlinien, die die Umkehrpunkte verbinden, Beschriftungen für XABCD-Punkte und Fibonacci-Retracement-Levels zur Bestätigung der Struktur -, um das Muster im Chart grafisch darzustellen. Dies bietet einen methodischen und transparenten Ansatz zur Identifizierung möglicher Aufwärts-Umkehrzonen. Um Ihnen das Erkennen wichtiger Handelszonen innerhalb des Musters zu erleichtern, werden wir auch Chart-Objekte verwenden, um mögliche Einstiegspositionen, Stop-Loss (SL) und Take-Profit (TP) Levels anzuzeigen. Dies hilft bei der Handelsentscheidung, indem es einen methodischen und transparenten Ansatz zur Identifizierung möglicher Aufwärts-Umkehrzonen bietet.

Abbildung 1.  Aufwärts-Muster

Pseudocode:

// Schritt 1: Identifizieren der Umkehrpunkte

  • Erkennen eines tiefen Umkehrpunktes (X)
  • Identifizieren eines hohen Umkehrpunktes (A) nach X
  • Erkennen eines tiefen Umkehrpunktes (B) nach A

WENN das B-Retracement NICHT zwischen 61,8% und 78,6% von XA liegt

  • Muster verwerfen und Neustart der Erkennung  

WENN B-Retracement zwischen 61,8% und 78,6% von XA liegt

  • Identifizieren eines hohen Umkehrpunktes (C) nach B
  • Erkennen eines tiefen Umkehrpunktes (D) nach C

WENN D NICHT kleiner als X ist 

  • DANN Muster verwerfen und die Erkennung neu starten

// Schritt 2: Zeichnen der Chart-Objekte

  • Zeichnen der Objekte, verbinden von X → A → B → C → D 
  •  Beschriften der Punkte mit Textobjekten: X, A, B, C, D
  • Zeichnen der Fibonacci-Retracement von X nach A zur Validierung 

// Schritt 3: Definieren der Handelsstufen 

  • Erstellen der Chart-Objekte, um Eröffnung, SL und TP zu markieren.

1.2.2. Abwärts-Muster

Ähnlich strukturiert wie das Aufwärts-Muster, aber in umgekehrter Richtung, ist das harmonische Abwärts-Muster Indicator. Um sicherzustellen, dass sie den Richtlinien für harmonische Muster folgen, werden wir wichtige Umkehrpunkte festlegen. Das Muster wird identifiziert, indem zunächst ein hoher Umkehrpunkt (X) identifiziert wird, dem ein tiefer Umkehrpunkt (A) folgt. Der hoher Umkehrpunkt (B), der zwischen 61,8 % und 78,6 % des XA-Schenkels zurückgehen muss, wird dann bestimmt. Der endgültige hohe Umkehrpunkt (D) wird dann bestätigt, wenn wir ein tiefer Umkehrpunkt (C) festgestellt haben. D muss über X liegen, wodurch eine mögliche Abwärts-Umkehrzone entsteht, um das Muster zu bestätigen.

Nach der Bestätigung der Struktur werden wir Chart-Objekte wie Trendlinien, XABCD-Labels und Fibonacci-Retracement-Levels verwenden, um das Muster grafisch darzustellen. Um Ihnen bei der Lokalisierung wichtiger Handelszonen innerhalb des Musters zu helfen, werden wir außerdem die Einstiegs-, Stop-Loss- (SL) und Take-Profit- (TP) Niveaus angeben.

Abbildung 2. Abwärts-Muster

Pseudocode:

// Schritt 1: Identifizieren der Umkehrpunkte

  • Erkennen eines hohen Umkehrpunktes (X)
  • Erkennen eines tiefen Umkehrpunktes (A) nach X
  • Erkennen eines hohen Umkehrpunktes (B) nach A

WENN das B-Retracement NICHT zwischen 61,8% und 78,6% von XA liegt

  • Muster verwerfen und Neustart der Erkennung  

WENN B-Retracement zwischen 61,8% und 78,6% von XA liegt

  • Erkennen eines tiefen Umkehrpunktes (C) nach B
  • Erkennen eines hohen Umkehrpunktes (D) nach C

WENN D NICHT größer als X ist

  • Muster verwerfen und Neustart der Erkennung

// Schritt 2: Zeichnen der Chart-Objekte

  • Zeichnen der Objekte, verbinden von X → A → B → C → D 
  • Beschriften der Punkte mit Textobjekten: X, A, B, C, D 
  • Zeichnen der Fibonacci-Retracement von X nach A zur Validierung 

// Schritt 3: Definieren der Handelsstufen 

  • Erstellen der Chart-Objekte, um Eröffnung, SL und TP zu markieren.


2. Aufbau eines harmonischen Aufwärts-Muster

In diesem Abschnitt werden wir damit beginnen, den „Harmonic Pattern Indicator“ in MQL5 umzusetzen. Wir werden die Funktionen spezifizieren, die erforderlich sind, um Umkehrpunkte zu identifizieren, Retracement-Levels zu bestätigen und das Muster auf dem Chart mithilfe von Chart-Objekten zu visualisieren. Außerdem werden wir das Aussehen der gezeichneten Objekte anpassen, um die Übersichtlichkeit und Nutzerfreundlichkeit zu verbessern.

2.1. Erkennen von hohen und tiefen Umkehrpunkten

Um ein harmonisches Muster erkennen zu können, ist eine zuverlässige Technik zur Lokalisierung von hohen und tiefen Umkehrpunkten auf dem Chart erforderlich. Die XABCD-Struktur wird unter Verwendung von Umkehrpunkten als Basis aufgezeichnet. Wir bestimmen, ob das Hoch einer Kerze das höchste innerhalb eines bestimmten Bereichs von benachbarten Kerzen ist, um einen hohen Umkehrpunkt zu identifizieren. In ähnlicher Weise wird ein tiefer Umkehrpunkt identifiziert, wenn das Tief einer Kerze das niedrigste in einem bestimmten Bereich ist. Die Größe dieses Bereichs bestimmt die Empfindlichkeit unserer Erkennung - größere Werte erfassen größere Schwankungen, während kleinere Werte kleinere Schwankungen erkennen. Im nächsten Schritt werden wir einen Algorithmus entwickeln, der historische Kursdaten scannt, wichtige Umkehrpunkte ausfindig macht und garantiert, dass diese mit den Prinzipien der Musterbildung übereinstimmen.

2.1.1. Funktionen für hohe und tiefe Umkehrpunkte

Beispiel:

#property indicator_chart_window

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---

//--- return value of prev_calculated for next call
   return(rates_total);
  }

//+------------------------------------------------------------------+
//| FUNCTION FOR SWING LOW                                           |
//+------------------------------------------------------------------+
bool IsSwingLow(const double &low[], int index, int lookback)
  {
   for(int i = 1; i <= lookback; i++)
     {
      if(low[index] > low[index - i] || low[index] > low[index + i])
         return false; 
     }
   return true; 
  }

//+------------------------------------------------------------------+
//| FUNCTION FOR SWING HIGH                                          |
//+------------------------------------------------------------------+
bool IsSwingHigh(const double &high[], int index, int lookback)
  {
   for(int i = 1; i <= lookback; i++)
     {
      if(high[index] < high[index - i] || high[index] < high[index + i])
         return false; 
     }
   return true; 
  }

Erläuterung:

MetaTrader 5 wird durch die Direktive #property indicator_chart_window informiert, dass der nutzerdefinierte Indikator im primären Kurschart und nicht in einem anderen Unterfenster angezeigt werden soll. Dies ist hilfreich bei der Erstellung von musterbasierten Indikationen wie dem harmonischen Muster oder Indikatoren, die die Preisaktivität überlagern, wie Trendlinien, Unterstützungs- und Widerstandsniveaus usw. Fehlt dieses Merkmal, kann der Indikator standardmäßig in einem anderen Indikatorfenster dargestellt werden, ähnlich wie Oszillatoren wie MACD oder RSI.

Der Zweck der Funktion IsSwingLow besteht darin, die Tiefs der Kurscharts zu identifizieren. Wenn das Tief einer Kerze innerhalb einer bestimmten Spanne unter die Tiefs der umliegenden Kerzen fällt, spricht man von einem tiefen Umkehrpunkt. Die Funktion akzeptiert einen Rückblickswert, der festlegt, wie viele Kerzen davor und danach berücksichtigt werden sollen, ein Array von Tiefstpreisen und den Index der zu bewertenden Kerze. Es wird ermittelt, ob der aktuelle Tiefststand der niedrigste ist, indem die nahegelegenen Kerzen durchlaufen werden. Sie gibt false zurück, wenn es einen niedrigeren Wert im umgebenden Bereich entdeckt, was beweist, dass die aktuelle Kerze kein tiefer Umkehrpunkt ist. Ist dies nicht der Fall, wird „true“ zurückgegeben, was bedeutet, dass ein rechtmäßiger tiefer Umkehrpunkt vorliegt.

In ähnlicher Weise werden hohe Umkehrpunkte, an denen das Hoch einer Kerze die Hochs der benachbarten Kerzen übersteigt - mit der Funktion IsSwingHigh ermittelt. Die Funktion verwendet dieselbe Logik wie IsSwingLow, mit dem Unterschied, dass sie sicherstellt, dass das Hoch am angegebenen Index der höchste Wert im Rückblicksbereich ist, anstatt nach dem niedrigsten Wert zu suchen. Die Funktion gibt false zurück, wenn eine der umgebenden Kerzen einen höheren Wert hat. Ist dies nicht der Fall, bestätigt es einen hohen Umkehrpunkt und gibt true zurück.

Die Erkennung signifikanter Umkehrpunkte der Kurse, die die Grundlage für die Definition des harmonischen Musters bilden, erfordert diese beiden Fähigkeiten. Nach der Identifizierung der Hochs und Tiefs kann die XABCD-Struktur des Musters dargestellt werden, indem man sie mit Trendlinien verbindet und Fibonacci-Retracements zur Bestätigung verwendet. Mit dieser Methode ist gewährleistet, dass sich der Indikator dynamisch an neue Kursinformationen anpasst und die erkannten Muster entsprechend aktualisiert.

Analogie:

Die Funktion IsSwingLow dient dazu, den tiefsten Punkt in einem Tal zu finden. Stellen Sie sich vor, Sie stehen auf einem Wanderweg und versuchen, die tiefste Punkte des Weges zu finden. Während der Rückblickzeit gehen Sie ein paar Schritte vor und ein paar Schritte zurück. Der aktuelle Punkt wird als niedrigster Dip (tiefen Umkehrpunkt) verifiziert, wenn er niedriger ist als jeder andere Punkt in diesem Bereich. Ihr aktueller Standort ist nur ein weiterer fallender Abschnitt und nicht der tatsächliche tiefste Punkt, wenn benachbarte Punkte tiefer liegen. Potenzielle Umkehrzonen, in denen die Preise zu steigen beginnen könnten, werden mit Hilfe dieser Funktion ermittelt.

Die Suche nach dem höchsten Punkt eines Gebirges ähnelt der Verwendung der Funktion IsSwingHigh. Es gilt als hoher Umkehrpunkt, wenn Sie an einem Punkt stehen und ein paar Schritte vor und zurück gehen, um sicherzustellen, dass Ihre aktuelle Position die höchste innerhalb dieses Bereichs ist. Wie weit man prüft, bevor man einen Höchststand oder einen Rückgang anzeigt, hängt von der Rückblickzeit ab; ist sie zu kurz, könnten geringfügige Schwankungen mit wichtigen Punkten verwechselt werden, und ist sie zu groß, könnte man kleinere, aber wichtige Trends übersehen. Dieses Gleichgewicht garantiert, dass die ermittelten Umkehrpunkte signifikant sind und nicht nur willkürliche Kursschwankungen darstellen.

Abbildung 3. Hohe und tiefe Umkehrpunkte

2.1.2. Identifizierung des tiefen Umkehrpunktes (X)

Der nächste Schritt besteht darin, die Funktionen IsSwingLow und IsSwingHigh in die Funktion OnCalculate einzubinden, sobald sie erstellt wurden. Hier werden die Echtzeit-Kursdaten der Logik des Erkennens der Umkehrpunkte unterworfen. Die erste Herausforderung besteht darin, den anfänglichen tiefen Umkehrpunkt (X) zu finden, an dem das harmonische Muster beginnt. Mit der von uns erstellten Funktion können wir iterativ jede Kerze in der Kurshistorie von OnCalculate daraufhin untersuchen, ob sie die Kriterien für einen tiefen Umkehrpunkt erfüllt.

Beispiel:

#property indicator_chart_window

// Input parameters
input int LookbackBars = 10; // Number of bars to look back/forward for swing points
input int bars_check  = 1000; // Number of bars to check for swing points

// CHART ID
long chart_id = ChartID(); // Get the ID of the current chart to manage objects (lines, text, etc.)

//X
double X; // Price of the swing low (X).
datetime X_time; // Time of the swing low (X).
string X_line; // Unique name for the trend line object.
string X_letter; // Unique name for the text label object.

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---

   if(rates_total >= bars_check)
     {

      for(int i = rates_total - bars_check; i < rates_total - LookbackBars; i++)
        {
         if(IsSwingLow(low, i, LookbackBars))
           {
            // If a swing low is found, store its price, time, and create a name for the objects to mark the X.
            X = low[i]; // Price of the swing low (X).
            X_time = time[i]; // Time of the swing low (X).
            X_line = StringFormat("XLow%d", i); // Unique name for the trend line object.
            X_letter = StringFormat("X%d", i); // Unique name for the text label object.

            ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, X_time, X); // Create text object for X
            ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".

            ObjectCreate(chart_id,X_line,OBJ_TREND,0,X_time,X,time[i+LookbackBars],X); // Create line to mark X
           }
        }
     }

//--- return value of prev_calculated for next call
   return(rates_total);
  }

//+------------------------------------------------------------------+
//| FUNCTION FOR SWING LOW                                           |
//+------------------------------------------------------------------+
bool IsSwingLow(const double &low[], int index, int lookback)
  {
 
   for(int i = 1; i <= lookback; i++)
     {
      if(low[index] > low[index - i] || low[index] > low[index + i])
         return false;  
     }
   return true;  
  }

//+------------------------------------------------------------------+
//| FUNCTION FOR SWING HIGH                                          |
//+------------------------------------------------------------------+
bool IsSwingHigh(const double &high[], int index, int lookback)
  {

   for(int i = 1; i <= lookback; i++)
     {
      if(high[index] < high[index - i] || high[index] < high[index + i])
         return false; 
     }
   return true; 
  }
//+------------------------------------------------------------------+

Ausgabe:

Abbildung 4. Tiefer Umkehrpunkt (X)

Erläuterung:

Wir beginnen mit der Angabe einiger wichtiger Eingangsdaten, da die Bestimmung des tiefen Umkehrpunkts (X) der erste Schritt bei der Suche nach einem harmonischen Aufwärts-Muster ist. Die Anzahl der Balken, die vor und nach einem bestimmten Punkt untersucht werden müssen, um sicherzustellen, dass es sich um einen legitimen Umkehrpunkt handelt, wird durch die Variable LookbackBars bestimmt. Dies hilft bei der Beseitigung kleiner Kursschwankungen, die nicht zu nennenswerten Tiefstständen führen. Um sicherzustellen, dass das Skript nur eine überschaubare Anzahl historischer Balken verarbeitet, um die Effizienz zu erhalten, gibt das Argument bars_check an, wie viele Balken analysiert werden sollen.

Außerdem verwenden wir ChartID(), um die chart_id zu erhalten, mit der wir Chart-Objekte wie Trendlinien und Textbeschriftungen erstellen und verwalten können. Wir deklarieren die Variablen „X“, um den Preis des erkannten tiefen Umkehrpunkts (X) zu speichern, „X_time“, um den Zeitpunkt des Auftretens festzuhalten, und „X_line“ und „X_letter“, um den Objekten eindeutige Namen zu geben, die zur Identifizierung dieses Punktes im Chart verwendet werden. Die Textbeschriftung, die den tiefen Umkehrpunktes kennzeichnet, wird mit der Variablen X_letter erstellt, und eine Trendlinie wird zur besseren Darstellung mit der Variablen X_line erstellt.

Anhand dieser vorläufigen Konfigurationen wird dann in der Funktion OnCalculate der tiefe Umkehrpunkt (X) bestimmt. Dank der Bedingung if(rates_total >= bars_check) beginnen wir erst mit der Prüfung, wenn genügend Preisdaten vorhanden sind. Um zu vermeiden, dass unvollständige Preisdaten geprüft werden, durchläuft die Schleife die historischen Balken, beginnend bei rates_total - bars_check und endend bei rates_total - LookbackBars. Die Funktion IsSwingLow in der Schleife erkennt, ob ein bestimmter Punkt ein tiefen Umkehrpunkt ist. Wenn wir einen legitimen tiefen Umkehrpunkt entdeckt haben, zeichnen wir den Zeitpunkt und den Preis auf, denken uns originelle Objektnamen aus und erstellen dann visuelle Komponenten für das Chart.

Mit ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, X_time, X) wird ein Textobjekt erstellt, das den tiefen Umkehrpunkt mit dem Buchstaben „X“ bezeichnet. Zur weiteren Veranschaulichung des identifizierten tiefen Umkehrpunkts verwenden wir ObjectCreate(chart_id, X_line, OBJ_TREND, 0, X_time, X, time[i+LookbackBars], X), um eine Trendlinie auf der X-Ebene zu erstellen. Dadurch wird gewährleistet, dass der erste wichtige Punkt in unserer harmonischen Musterstruktur genau identifiziert und im Chart angezeigt wird, wodurch die Grundlage für die Bestimmung der nachfolgenden Punkte des Musters gelegt wird.

2.1.3. Identifizierung eines hohen Umkehrpunktes (A)

Die Suche nach dem hohen Umkehrpunkt (A) ist der nächste Schritt nach der erfolgreichen Identifizierung des tiefen Umkehrpunkts (X). Dieser Punkt ist für die Bildung des harmonischen Musters von entscheidender Bedeutung, da es sich um die erste nennenswerte Aufwärtsbewegung nach X handelt. Auf die gleiche Weise, wie wir X entdeckt haben, werden wir die Funktion IsSwingHigh verwenden, um A zu finden, aber dieses Mal werden wir nach einem Hoch und nicht nach einem Tief suchen.

Es wird nach einem Punkt in den Kursdaten nach X gesucht, an dem das Hoch die Hochs der umliegenden Balken innerhalb des festgelegten LookbackBars-Bereichs übersteigt. Nachdem wir einen legitimen hohen Umkehrpunkt identifiziert haben, werden wir seinen Preis und seinen Zeitstempel aufzeichnen, ihm einen unverwechselbaren Namen geben und Chart-Objekte verwenden, um es richtig zu beschreiben.

Beispiel:

#property indicator_chart_window

// Input parameters
input int LookbackBars = 10; // Number of bars to look back/forward for swing points
input int bars_check  = 1000; // Number of bars to check for swing points

// CHART ID
long chart_id = ChartID(); // Get the ID of the current chart to manage objects (lines, text, etc.)

//X
double X; // Price of the swing low (X).
datetime X_time; // Time of the swing low (X).
string X_line; // Unique name for the trend line object.
string X_letter; // Unique name for the text label object.

//A
double A; // Price of the swing high (A).
datetime A_time; // Time of the swing high (A).
string A_line; // Unique name for the trend line object.
string A_letter; // Unique name for the text label object.

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---

   if(rates_total >= bars_check)
     {

      for(int i = rates_total - bars_check; i < rates_total - LookbackBars; i++)
        {
         if(IsSwingLow(low, i, LookbackBars))
           {
            // If a swing low is found, store its price, time, and create a name for the objects to mark the X.
            X = low[i]; // Price of the swing low (X).
            X_time = time[i]; // Time of the swing low (X).
            X_line = StringFormat("XLow%d", i); // Unique name for the trend line object.
            X_letter = StringFormat("X%d", i); // Unique name for the text label object.

            ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, X_time, X); // Create text object for X
            ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".
            ObjectCreate(chart_id,X_line,OBJ_TREND,0,X_time,X,time[i+LookbackBars],X); // Create line to mark X

            for(int j = i; j < rates_total - LookbackBars; j++)
              {
               if(IsSwingHigh(high, j, LookbackBars)  && time[j] > X_time)
                 {

                  A = high[j]; // Price of the swing high (A).
                  A_time = time[j]; // Time of the swing high (A).
                  A_line = StringFormat("AHigh%d", j); // Unique name for the trend line object.
                  A_letter = StringFormat("A%d", j); // Unique name for the text label object.

                  ObjectCreate(chart_id, A_letter, OBJ_TEXT, 0, A_time, A); // Create text object for A
                  ObjectSetString(chart_id, A_letter, OBJPROP_TEXT, "A"); // Set the text to "A".
                  ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                  ObjectCreate(chart_id,A_line,OBJ_TREND,0,A_time,A,time[j+LookbackBars],A); // Create line to mark A
                  ObjectSetInteger(chart_id,A_line,OBJPROP_COLOR,clrGreen); // Set line color to green

                  break;
                 }
              }
           }
        }
     }

//--- return value of prev_calculated for next call
   return(rates_total);
  }

//+------------------------------------------------------------------+
//| FUNCTION FOR SWING LOW                                           |
//+------------------------------------------------------------------+
bool IsSwingLow(const double &low[], int index, int lookback)
  {
   for(int i = 1; i <= lookback; i++)
     {
      if(low[index] > low[index - i] || low[index] > low[index + i])
         return false;  
     }
   return true;  
  }

//+------------------------------------------------------------------+
//| FUNCTION FOR SWING HIGH                                          |
//+------------------------------------------------------------------+
bool IsSwingHigh(const double &high[], int index, int lookback)
  {
   for(int i = 1; i <= lookback; i++)
     {
      if(high[index] < high[index - i] || high[index] < high[index + i])
         return false; 
     }
   return true; 
  }
//+------------------------------------------------------------------+

Ausgabe:

Abbildung 5. Hoher Umkehrpunkt (A)

Erläuterung:

Zunächst definieren wir die Variablen, die zur Bestimmung des hohen Umkehrpunktes (A) erforderlich sind. A_time protokolliert den genauen Zeitpunkt, zu dem der hohen Umkehrpunkt auftritt, während A des Kurswert speichert. Wir verwenden A_line als Namen für das Trendlinienobjekt und A_letter als Textbeschriftung, um sicherzustellen, dass jeder erkannte A-Punkt eine eindeutige visuelle Darstellung hat. Diese Variablen helfen bei der Erstellung von Chart-Objekten, die den A-Punkt hervorheben, was die Visualisierung der Struktur des harmonischen Musters erleichtert.

Sobald X identifiziert wurde, durchläuft der Code die Preisdaten, beginnend an der Position von X, um A zu finden. Die Funktion IsSwingHigh, die feststellt, ob ein Balken ein lokales Hoch innerhalb des festgelegten LookbackBars-Bereichs ist, wird zur Überprüfung jedes Balkens verwendet. Die Bedingung time[j] > X_time wird verwendet, um zu garantieren, dass der Swing High A nach X kommt. 

Dadurch wird sichergestellt, dass die richtige Reihenfolge im harmonischen Muster beibehalten wird, indem A nur ausgewählt wird, wenn sein Zeitstempel größer als X_time ist. Der Preis und der Zeitpunkt einen legitimen hohen Umkehrpunkts werden aufgezeichnet, und die Objekte Trendlinie und Textbeschriftung erhalten eindeutige Identitäten, wenn eine solche entdeckt wird. Eine grüne Trendlinie wird konstruiert, um den identifizierten hohen Umkehrpunkt hervorzuheben, und eine Textbeschriftung mit dem Buchstaben „A“ wird dort platziert. Sobald der erste legitime hohe Umkehrpunkt (A) identifiziert wurde, wird die Schleife mit dem Ausdruck break; unterbrochen. Die Schleife würde weiterhin nach weiteren hohen Umkehrpunkten ohne Pause suchen und dabei vielleicht A mit einem späteren hohen Umkehrpunkt überschreiben. Da wir nur die erste Instanz von A nach X haben wollen, sorgt das break; dafür, dass die Schleife die Iteration beendet, sobald ein hoher Umkehrpunkt erkannt wird, wodurch das erste gültige A geschützt und sinnlose Berechnungen vermieden werden. 

2.1.4. Identifizierung des tiefen Umkehrpunktes (B)

Die Suche nach B beginnt, sobald A identifiziert ist, da B nach A kommen muss. Dies wird erreicht, indem die Kursdaten ab der Position A durchlaufen werden und die Funktion IsSwingLow verwendet wird, um einen Balken mit den benachbarten Balken im Bereich LookbackBars zu vergleichen, um festzustellen, ob es sich um einen tiefen Umkehrpunktes handelt. Darüber hinaus wird erwartet, dass B unter ein bestimmtes Fibonacci-Retracement-Niveau von XA in der harmonischen Musteridentifikation fällt. Auf die Fibonacci-Validierung soll an dieser Stelle jedoch nicht eingegangen werden; es geht lediglich um die Identifizierung von B.

Der Preis und die Zeit eines tiefen Umkehrpunktes werden in B bzw. B_time aufgezeichnet, sobald er erkannt wird. Wir geben der Trendlinie (B_line) und der Textbeschriftung (B_letter) unverwechselbare Namen, um diese Position im Chart zu kennzeichnen. Es wird eine Trendlinie erstellt, um das Textobjekt mit der Bezeichnung „B“, das am tiefen Umkehrpunkt erstellt wurde, visuell zu verbinden und hervorzuheben. Dieser Schritt garantiert, dass die drei Hauptpunkte - X, A und B -, die nun als Rahmen für unsere harmonische Musterstruktur dienen, vorhanden sind.

Beispiel:

#property indicator_chart_window

// Input parameters
input int LookbackBars = 10; // Number of bars to look back/forward for swing points
input int bars_check  = 1000; // Number of bars to check for swing points

// CHART ID
long chart_id = ChartID(); // Get the ID of the current chart to manage objects (lines, text, etc.)

//X
double X; // Price of the swing low (X).
datetime X_time; // Time of the swing low (X).
string X_line; // Unique name for the trend line object.
string X_letter; // Unique name for the text label object.

//A
double A; // Price of the swing high (A).
datetime A_time; // Time of the swing high (A).
string A_line; // Unique name for the trend line object.
string A_letter; // Unique name for the text label object.

//B
double B; // Price of the swing low (B).
datetime B_time; // Time of the swing low (B).
string B_line; // Unique name for the trend line object.
string B_letter; // Unique name for the text label object.

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
// This function is called when the indicator is removed or the chart is closed.
// Delete all objects (lines, text, etc.) from the chart to clean up.
   ObjectsDeleteAll(chart_id);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---

   if(rates_total >= bars_check)
     {

      for(int i = rates_total - bars_check; i < rates_total - LookbackBars; i++)
        {
         if(IsSwingLow(low, i, LookbackBars))
           {
            // If a swing low is found, store its price, time, and create a name for the objects to mark the X.
            X = low[i]; // Price of the swing low (X).
            X_time = time[i]; // Time of the swing low (X).
            X_line = StringFormat("XLow%d", i); // Unique name for the trend line object.
            X_letter = StringFormat("X%d", i); // Unique name for the text label object.

            ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, X_time, X); // Create text object for X
            ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".
            ObjectCreate(chart_id,X_line,OBJ_TREND,0,X_time,X,time[i+LookbackBars],X); // Create line to mark X


            for(int j = i; j < rates_total - LookbackBars; j++)
              {
               if(IsSwingHigh(high, j, LookbackBars) && time[j] > X_time)
                 {

                  A = high[j]; // Price of the swing high (A).
                  A_time = time[j]; // Time of the swing high (A).
                  A_line = StringFormat("AHigh%d", j); // Unique name for the trend line object.
                  A_letter = StringFormat("A%d", j); // Unique name for the text label object.

                  ObjectCreate(chart_id, A_letter, OBJ_TEXT, 0, A_time, A); // Create text object for A
                  ObjectSetString(chart_id, A_letter, OBJPROP_TEXT, "A"); // Set the text to "A".
                  ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                  ObjectCreate(chart_id,A_line,OBJ_TREND,0,A_time,A,time[j+LookbackBars],A); // Create line to mark A
                  ObjectSetInteger(chart_id,A_line,OBJPROP_COLOR,clrGreen); // Set line color to green


                  for(int k = j; k < rates_total - LookbackBars; k++)
                    {
                     if(IsSwingLow(low, k, LookbackBars) && time[k] > A_time)
                       {

                        // If a swing low is found, store its price, time, and create a name for the object.
                        B = low[k]; // Price of the swing low (B).
                        B_time = time[k]; // Time of the swing low (B).
                        B_line = StringFormat("BLow%d", k); // Unique name for the trend line object.
                        B_letter = StringFormat("B%d", k); // Unique name for the text label object.

                        ObjectCreate(chart_id, B_letter, OBJ_TEXT, 0, B_time, B); // Create text object for B
                        ObjectSetString(chart_id, B_letter, OBJPROP_TEXT, "B"); // Set the text to "B".
                        ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                        ObjectCreate(chart_id,B_line,OBJ_TREND,0,B_time,B,time[k+LookbackBars],B); // Create line to mark B
                        ObjectSetInteger(chart_id,B_line,OBJPROP_COLOR,clrMidnightBlue); // Set line color to green


                        break;

                       }
                    }

                  break;
                 }
              }
           }
        }
     }

//--- return value of prev_calculated for next call
   return(rates_total);
  }

//+------------------------------------------------------------------+
//| FUNCTION FOR SWING LOW                                           |
//+------------------------------------------------------------------+
bool IsSwingLow(const double &low[], int index, int lookback)
  {
   for(int i = 1; i <= lookback; i++)
     {
      if(low[index] > low[index - i] || low[index] > low[index + i])
         return false;  
     }
   return true; 
  }

//+------------------------------------------------------------------+
//| FUNCTION FOR SWING HIGH                                          |
//+------------------------------------------------------------------+
bool IsSwingHigh(const double &high[], int index, int lookback)
  {

   for(int i = 1; i <= lookback; i++)
     {
      if(high[index] < high[index - i] || high[index] < high[index + i])
         return false;  
     }
   return true;  
  }
//+------------------------------------------------------------------+

Ausgabe:

Abbildung 6. Tiefer Umkehrpunkt (B)

Erläuterung:

Der Preis des auf A folgenden tiefen Umkehrpunktes wird durch die Variable B dargestellt. Eine Schleife, die am Punkt A beginnt und die Funktion IsSwingLow verwendet, um den nächsten tiefen Umkehrpunkt zu finden, wird verwendet, um es zu identifizieren. Der Preis, die Zeit und die eindeutigen Namen für die Trendlinie und die Textbeschriftung werden gespeichert, nachdem sie identifiziert wurden. Um B auf dem Chart anzuzeigen, erzeugt der Computer eine Trendlinie in nachtblau und eine Textbeschriftung („B“) in grün. Um die richtige Reihenfolge der Umkehrpunkte für die Mustergenerierung einzuhalten, sorgt eine Break-Anweisung dafür, dass nur das erste gültige B ausgewählt wird. Da X und B während der gesamten Schleifeniteration als Tiefstwerte erkannt werden, können sie sich in der aktuellen Implementierung gelegentlich überschneiden. Da das Programm jeden Umkehrpunkt nacheinander bewertet, ist dieses Verhalten zu erwarten. Dies könnte jedoch zu überflüssigen Anmerkungen im Chart führen, wenn X und B identisch sind.

Sie können eine Bedingung einfügen, um sicherzustellen, dass B ein separater tiefer Umkehrpunkt ist, der auf A folgt, aber B ist nicht derselbe wie X, wenn Sie verhindern möchten, dass sich X und B überschneiden. Ich werde eine Option in den Code einfügen, mit der Sie wählen können, ob sich X und B überschneiden können. Der Indikator funktioniert wie bisher, wobei X und B derselbe tiefe Umkehrpunkt sein können, wenn eine Überschneidung zulässig ist. Der Indikator stellt jedoch sicher, dass B ein anderer tiefer Umkehrpunkt als X ist, wenn eine Überschneidung verboten ist.

Da B ein separates Tief sein muss und nicht mit X identisch sein kann, führt die Vermeidung von Überschneidungen dazu, dass weniger harmonische Muster entdeckt werden. Je nach Vorliebe des Nutzers für die Mustererkennung bietet diese Option Flexibilität.

Beispiel:

input bool overlap = false; //Allow Overlaping
for(int k = j; k < rates_total - LookbackBars; k++)
  {
   if(IsSwingLow(low, k, LookbackBars) && time[k] > A_time)
     {

      // If a swing low is found, store its price, time, and create a name for the object.
      B = low[k]; // Price of the swing low (B).
      B_time = time[k]; // Time of the swing low (B).
      B_line = StringFormat("BLow%d", k); // Unique name for the trend line object.
      B_letter = StringFormat("B%d", k); // Unique name for the text label object.

      ObjectCreate(chart_id, B_letter, OBJ_TEXT, 0, B_time, B); // Create text object for B
      ObjectSetString(chart_id, B_letter, OBJPROP_TEXT, "B"); // Set the text to "B".
      ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
      ObjectCreate(chart_id,B_line,OBJ_TREND,0,B_time,B,time[k+LookbackBars],B); // Create line to mark B
      ObjectSetInteger(chart_id,B_line,OBJPROP_COLOR,clrMidnightBlue); // Set line color to green

      if(overlap == false)
        {
         i = k;
        }
      if(overlap == true)
        {
         i = i;
        }

      break;

     }
  }
Ausgabe:


Abbildung 7. Überlappung von X und B

Erläuterung:

Ob X und B den gleichen tiefen Umkehrpunkt haben können, hängt von der Überschneidung der Eingangsparameter ab. Die Zeile i = k; garantiert, dass die Iteration vorwärts springt, sobald B gefunden ist, und verhindert, dass B mit X identisch ist, wenn „overlap“ auf false gesetzt ist. Dies schränkt die Anzahl der erkennbaren harmonischen Muster ein und minimiert gleichzeitig die Redundanz, indem eine deutliche Trennung zwischen den Umkehrpunkten beibehalten wird.

Die Zeile i = i; zeigt jedoch an, dass die Schleife regelmäßig weiterläuft, ohne dass ein Sprung erforderlich ist, wenn Überlappung wahr ist. Auf diese Weise können mehr harmonische Muster entdeckt werden, da sich X und B überschneiden können, wenn sie natürlicherweise auf demselben Kursniveau auftreten. Es könnte jedoch auch eine gewisse Wiederholung der Mustermarkierungen bewirken. Indem der Code erfolgreich verhindert, dass sich X und B überschneiden, hat er sichergestellt, dass es sich um getrennte Umkehrpunkte handelt. Wie die Abbildung zeigt, manifestiert sich B nun unabhängig von X, wobei eine deutlichere Musterstruktur erhalten bleibt.

2.1.5. Identifizierung des hohen Umkehrpunktes (C)

Die Ermittlung des hohen Umkehrpunkts (C) erfolgt nach der Bestimmung des tiefen Umkehrpunkts (X), des hohen Umkehrpunkts (A) und des folgenden tiefen Umkehrpunkts (B). Dieser Punkt ist wesentlich für den Aufbau der Struktur eines harmonischen Musters, da er die Gesamtform des Musters und die mögliche Umkehrzone bestimmt.

Sowohl die Trendlinie (C_line) als auch die Textbeschriftung (C_letter) erhalten unterschiedliche Namen, um diesen Punkt visuell zu kennzeichnen. Eine Trendlinie wird erstellt, um ein Textelement mit der Bezeichnung „C“, das sich am hohen Umkehrpunkt im Chart befindet, visuell zu verbinden und hervorzuheben. Dieser Schritt garantiert, dass die vier Hauptpunkte - X, A, B und C -, die die Struktur des harmonischen Musters ausmachen, nun an ihrem Platz sind.

Beispiel:

//C
double C; // Price of the swing high (C).
datetime C_time; // Time of the swing high (C).
string C_line; // Unique name for the trend line object.
string C_letter; // Unique name for the text label object.
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---

   if(rates_total >= bars_check)
     {

      for(int i = rates_total - bars_check; i < rates_total - LookbackBars; i++)
        {
         if(IsSwingLow(low, i, LookbackBars))
           {
            // If a swing low is found, store its price, time, and create a name for the objects to mark the X.
            X = low[i]; // Price of the swing low (X).
            X_time = time[i]; // Time of the swing low (X).
            X_line = StringFormat("XLow%d", i); // Unique name for the trend line object.
            X_letter = StringFormat("X%d", i); // Unique name for the text label object.

            ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, X_time, X); // Create text object for X
            ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".
            ObjectCreate(chart_id,X_line,OBJ_TREND,0,X_time,X,time[i+LookbackBars],X); // Create line to mark X

            for(int j = i; j < rates_total - LookbackBars; j++)
              {
               if(IsSwingHigh(high, j, LookbackBars) && time[j] > X_time)
                 {

                  A = high[j]; // Price of the swing high (A).
                  A_time = time[j]; // Time of the swing high (A).
                  A_line = StringFormat("AHigh%d", j); // Unique name for the trend line object.
                  A_letter = StringFormat("A%d", j); // Unique name for the text label object.

                  ObjectCreate(chart_id, A_letter, OBJ_TEXT, 0, A_time, A); // Create text object for A
                  ObjectSetString(chart_id, A_letter, OBJPROP_TEXT, "A"); // Set the text to "A".
                  ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                  ObjectCreate(chart_id,A_line,OBJ_TREND,0,A_time,A,time[j+LookbackBars],A); // Create line to mark A
                  ObjectSetInteger(chart_id,A_line,OBJPROP_COLOR,clrGreen); // Set line color to green

                  for(int k = j; k < rates_total - LookbackBars; k++)
                    {
                     if(IsSwingLow(low, k, LookbackBars) && time[k] > A_time)
                       {

                        // If a swing low is found, store its price, time, and create a name for the object.
                        B = low[k]; // Price of the swing low (B).
                        B_time = time[k]; // Time of the swing low (B).
                        B_line = StringFormat("BLow%d", k); // Unique name for the trend line object.
                        B_letter = StringFormat("B%d", k); // Unique name for the text label object.

                        ObjectCreate(chart_id, B_letter, OBJ_TEXT, 0, B_time, B); // Create text object for B
                        ObjectSetString(chart_id, B_letter, OBJPROP_TEXT, "B"); // Set the text to "B".
                        ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                        ObjectCreate(chart_id,B_line,OBJ_TREND,0,B_time,B,time[k+LookbackBars],B); // Create line to mark B
                        ObjectSetInteger(chart_id,B_line,OBJPROP_COLOR,clrMidnightBlue); // Set line color to MidnightBlue

                        for(int l = j ; l < rates_total - LookbackBars; l++)
                          {
                           if(IsSwingHigh(high, l, LookbackBars) && time[l] > B_time)
                             {
                              C = high[l]; // Price of the swing high (C).
                              C_time = time[l]; // Time of the swing high (C).
                              C_line = StringFormat("CHigh%d", l); // Unique name for the trend line object.
                              C_letter = StringFormat("C%d", l); // Unique name for the text label object.

                              ObjectCreate(chart_id, C_letter, OBJ_TEXT, 0, C_time, C); // Create text object for C
                              ObjectSetString(chart_id, C_letter, OBJPROP_TEXT, "C"); // Set the text to "C".
                              ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                              ObjectCreate(chart_id,C_line,OBJ_TREND,0,C_time,C,time[l+LookbackBars],C); // Create line to mark C
                              ObjectSetInteger(chart_id,C_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

                              if(overlap == false)
                                {
                                 i = l;
                                }
                              if(overlap == true)
                                {
                                 i = i;
                                }

                              break;

                             }
                          }

                        break;

                       }
                    }

                  break;
                 }
              }
           }
        }
     }

//--- return value of prev_calculated for next call
   return(rates_total);
  }
Ausgabe:


Abbildung 8. Hoher Umkehrpunkt (C)

Erläuterung:

Nach der Bestimmung des tiefen Umkehrpunkts (B) überwacht dieser Teil des Codes die Bestimmung des hohen Umkehrpunkts (C), der der nächste entscheidende Schritt ist. Die Schleife for(int l = j; l < rates_total - LookbackBars; l++), die über die Kursdaten iteriert, beginnt mit dem Index j, bei dem der vorherige hohe Umkehrpunkt (A) gefunden wurde. Um sicherzugehen, dass C in der Reihenfolge nach B kommt, wird so lange gesucht, bis die letzten Balken gefunden sind. Um die richtige Reihenfolge des Musters aufrechtzuerhalten, prüft die Bedingung if(IsSwingHigh(high, l, LookbackBars) && time[l] > B_time), ob der aktuelle Balken ein hoher Umkehrpunkt innerhalb des angegebenen Rückblickbereichs ist, und stellt sicher, dass sein Zeitstempel nach B liegt. 

Der Preis und die Zeit eines legitimen hohen Umkehrpunkts werden in C bzw. C_time gespeichert, und die Objekte Trendlinie und Textlabel erhalten eigene Namen (C_line und C_letter). Mit ObjectCreate(chart_id, C_line, OBJ_TREND, 0, C_time, C, time[l+LookbackBars], C) wird eine Trendlinie erstellt, um das Textlabel „C“ am angegebenen hohen Umkehrpunkt hervorzuheben. Um die C-Trendlinie visuell von anderen Segmenten zu unterscheiden, wird mit ObjectSetInteger(chart_id, C_line, OBJPROP_COLOR, clrSaddleBrown); die Farbe der Linie auf SaddleBrown gesetzt.

Der letzte bedingte Block garantiert, dass sich überschneidende Muster korrekt gehandhabt werden: i = l; verhindert, dass vorherige Umkehrpunkte in einem anderen Muster verwendet werden, wenn Überschneidung auf false gesetzt ist. Mehrere Muster können sich überlappen, wenn overlap wahr ist, da i = i; den aktuellen Wert beibehält. Nach der Ermittlung des ersten legitimen hohen Umkehrpunkts (C) wird die Schleife mit break; beendet, wodurch die Effizienz durch Vermeidung unnötiger Wiederholungen gewährleistet wird.

2.1.6. Identifizierung des tiefen Umkehrpunktes (D)

Die Ermittlung des tiefen Umkehrpunktes (D) erfolgt nach der Bestimmung des hohen Umkehrpunkts (C). Dadurch wird gewährleistet, dass die Preisbewegung für die Erzeugung harmonischer Muster korrekt sequenziert wird. Um den nächsten tiefen Umkehrpunkt nach C in chronologischer Reihenfolge zu finden, beginnt die Suche nach D an der Stelle, an der C identifiziert wurde. Zwei Voraussetzungen müssen erfüllt sein, um ein rechtmäßigen tiefen Umkehrpunkt nachzuweisen. Erstens muss der aktuelle Kurs innerhalb des festgelegten Rückblickzeitraums als tiefer Umkehrpunkt gelten. Zweitens muss sein Zeitstempel später sein als der von C, um die richtige Reihenfolge der Muster zu wahren.

Der Preis und das Timing eines legitimen tiefen Umkehrpunktes werden notiert, und es werden eindeutige Bezeichner für die Trendlinie und die dazugehörige Textbeschriftung erstellt. Um den tiefen Umkehrpunkt innerhalb des Musters leichter zu erkennen, wird es durch eine Trendlinie hervorgehoben, und an seiner Position wird eine Textbeschriftung eingefügt, um es visuell zu kennzeichnen.

Beispiel:

//D
double D; // Price of the swing low (D).
datetime D_time; // Time of the swing low (D).
string D_line; // Unique name for the trend line object.
string D_letter; // Unique name for the text label object.

//Trend
string XA_line; // Unique name for XA trend line object.
string AB_line; // Unique name for AB trend line object.
string BC_line; // Unique name for BC trend line object.
string CD_line; // Unique name for CD trend line object.

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---

   if(rates_total >= bars_check)
     {

      for(int i = rates_total - bars_check; i < rates_total - LookbackBars; i++)
        {
         if(IsSwingLow(low, i, LookbackBars))
           {
            // If a swing low is found, store its price, time, and create a name for the objects to mark the X.
            X = low[i]; // Price of the swing low (X).
            X_time = time[i]; // Time of the swing low (X).
            X_line = StringFormat("XLow%d", i); // Unique name for the trend line object.
            X_letter = StringFormat("X%d", i); // Unique name for the text label object.

            ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, X_time, X); // Create text object for X
            ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".
            ObjectCreate(chart_id,X_line,OBJ_TREND,0,X_time,X,time[i+LookbackBars],X); // Create line to mark X

            for(int j = i; j < rates_total - LookbackBars; j++)
              {
               if(IsSwingHigh(high, j, LookbackBars) && time[j] > X_time)
                 {

                  A = high[j]; // Price of the swing high (A).
                  A_time = time[j]; // Time of the swing high (A).
                  A_line = StringFormat("AHigh%d", j); // Unique name for the trend line object.
                  A_letter = StringFormat("A%d", j); // Unique name for the text label object.

                  ObjectCreate(chart_id, A_letter, OBJ_TEXT, 0, A_time, A); // Create text object for A
                  ObjectSetString(chart_id, A_letter, OBJPROP_TEXT, "A"); // Set the text to "A".
                  ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                  ObjectCreate(chart_id,A_line,OBJ_TREND,0,A_time,A,time[j+LookbackBars],A); // Create line to mark A
                  ObjectSetInteger(chart_id,A_line,OBJPROP_COLOR,clrGreen); // Set line color to green

                  for(int k = j; k < rates_total - LookbackBars; k++)
                    {
                     if(IsSwingLow(low, k, LookbackBars) && time[k] > A_time)
                       {

                        // If a swing low is found, store its price, time, and create a name for the object.
                        B = low[k]; // Price of the swing low (B).
                        B_time = time[k]; // Time of the swing low (B).
                        B_line = StringFormat("BLow%d", k); // Unique name for the trend line object.
                        B_letter = StringFormat("B%d", k); // Unique name for the text label object.

                        ObjectCreate(chart_id, B_letter, OBJ_TEXT, 0, B_time, B); // Create text object for B
                        ObjectSetString(chart_id, B_letter, OBJPROP_TEXT, "B"); // Set the text to "B".
                        ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                        ObjectCreate(chart_id,B_line,OBJ_TREND,0,B_time,B,time[k+LookbackBars],B); // Create line to mark B
                        ObjectSetInteger(chart_id,B_line,OBJPROP_COLOR,clrMidnightBlue); // Set line color to MidnightBlue

                        for(int l = j ; l < rates_total - LookbackBars; l++)
                          {
                           if(IsSwingHigh(high, l, LookbackBars) && time[l] > B_time)
                             {
                              C = high[l]; // Price of the swing high (C).
                              C_time = time[l]; // Time of the swing high (C).
                              C_line = StringFormat("CHigh%d", l); // Unique name for the trend line object.
                              C_letter = StringFormat("C%d", l); // Unique name for the text label object.

                              ObjectCreate(chart_id, C_letter, OBJ_TEXT, 0, C_time, C); // Create text object for C
                              ObjectSetString(chart_id, C_letter, OBJPROP_TEXT, "C"); // Set the text to "C".
                              ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                              ObjectCreate(chart_id,C_line,OBJ_TREND,0,C_time,C,time[l+LookbackBars],C); // Create line to mark C
                              ObjectSetInteger(chart_id,C_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

                              for(int m = l; m < rates_total - (LookbackBars / 2); m++)
                                {
                                 if(IsSwingLow(low, m, LookbackBars / 2) && time[m] > C_time)
                                   {
                                    D = low[m]; // Price of the swing low (D).
                                    D_time = time[m]; // Time of the swing low (D).
                                    D_line = StringFormat("DLow%d", m); // Unique name for the trend line object.
                                    D_letter = StringFormat("D%d", m); // Unique name for the text label object.

                                    ObjectCreate(chart_id, D_letter, OBJ_TEXT, 0, D_time, D); // Create text object for D
                                    ObjectSetString(chart_id, D_letter, OBJPROP_TEXT, "D"); // Set the text to "D".
                                    ObjectSetInteger(chart_id,D_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                                    ObjectCreate(chart_id,D_line,OBJ_TREND,0,D_time,D,time[m+LookbackBars],D); // Create line to mark D
                                    ObjectSetInteger(chart_id,D_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

                                    XA_line = StringFormat("XA Line%d", m); // Unique name for the XA line.
                                    ObjectCreate(chart_id,XA_line,OBJ_TREND,0,X_time,X,A_time,A); // Create line to connect XA
                                    ObjectSetInteger(chart_id,XA_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,XA_line,OBJPROP_WIDTH,3); // Line width

                                    AB_line = StringFormat("AB Line%d", m); // Unique name for the AB line.
                                    ObjectCreate(chart_id,AB_line,OBJ_TREND,0,A_time,A,B_time,B); // Create line to connect AB
                                    ObjectSetInteger(chart_id,AB_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,AB_line,OBJPROP_WIDTH,3); // Line width

                                    BC_line = StringFormat("BC Line%d", m); // Unique name for the BC line.
                                    ObjectCreate(chart_id,BC_line,OBJ_TREND,0,B_time,B,C_time,C); // Create line to connect BC
                                    ObjectSetInteger(chart_id,BC_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,BC_line,OBJPROP_WIDTH,3); // Line width

                                    CD_line = StringFormat("CD Line%d", m); // Unique name for the CD line.
                                    ObjectCreate(chart_id,CD_line,OBJ_TREND,0,C_time,C,D_time,D); // Create line to connect CD
                                    ObjectSetInteger(chart_id,CD_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,CD_line,OBJPROP_WIDTH,3); // Line width

                                    if(overlap == false)
                                      {
                                       i = m;
                                      }
                                    if(overlap == true)
                                      {
                                       i = i;
                                      }
                                    break;

                                   }
                                }

                              break;

                             }
                          }

                        break;

                       }
                    }

                  break;
                 }
              }
           }
        }
     }

//--- return value of prev_calculated for next call
   return(rates_total);
  }

Ausgabe:

Abbildung 9. tiefer Umkehrpunkt (D)

Erläuterung:

Der Preis des tiefen Umkehrpunkts am Punkt D im erkannten Muster wird durch die Variable D dargestellt. D ist ein entscheidender Punkt im Handel mit harmonischen Mustern, an dem die Preisbewegung umkehren und das Muster beenden kann. D_time zeichnet zusätzlich zu D den Zeitstempel des Auftretens dieses Tiefs auf. Um diesen tiefen Umkehrpunkt visuell zu identifizieren, werden auch die Trendlinie und das Textelement im Chart erstellt und mit D_line und D_letter beschriftet.

Das Programm iteriert durch die Preisdaten, um den Punkt D in der Schleife zu finden, die mit for(int m = l; m < rates_total - (LookbackBars / 2); m++).... beginnt. Um festzustellen, ob der aktuelle Kurs bei Index m ein tiefer Umkehrpunkt ist, wird die Funktion IsSwingLow() verwendet, wobei sichergestellt wird, dass der tiefe Umkehrpunkt nach dem Punkt C liegt. Der Preis und die Zeit eines gültigen tiefen Umkehrpunkts werden D bzw. D_time zugewiesen.

Der Indikator erzeugt visuelle Elemente auf dem Chart, nachdem der Punkt D gefunden wurde. An der Stelle des tiefen Umkehrpunktes erstellt die Funktion ObjectCreate() ein Textlabel (D_letter) mit dem Buchstaben „D“ und färbt es der Einfachheit halber grün. Um die visuelle Darstellung konsistent zu halten, wird am Punkt D auch eine Trendlinie (D_line) gezeichnet, die sich über LookbackBars-Balken erstreckt und die Farbe Braun (clrSaddleBrown) erhält.

An dieser Stelle erstellt das Programm auch Trendlinien, die die ermittelten Umkehrpunkte miteinander verbinden. Um die entsprechenden Punkte (X mit A, A mit B, B mit C und C mit D) visuell zu verbinden, werden die Objekte XA_line, AB_line, BC_line und CD_line erstellt. Diese Linien helfen Händlern bei der Analyse möglicher Kursänderungen, indem sie das harmonische Muster umreißen. Die Breite und die Farbeinstellungen dieser Linien werden angepasst, um die Sichtbarkeit im Chart zu verbessern.

Nachdem das XABCD-Muster erfolgreich erkannt wurde, müssen einige wichtige Fragen geklärt werden. Die Logik des Programms besteht darin, dass es nach der Identifizierung des Punktes X den Punkt X erst dann aktualisiert, wenn die ABCD-Sequenz abgeschlossen ist. Dies bedeutet, dass das Programm X nicht ändert, wenn zwischen X und A ein neuer Tiefststand auftritt, der niedriger ist als das ursprünglich ermittelte X. Folglich könnte das Muster die reale Marktstruktur nicht genau widerspiegeln.

Um die Gültigkeit des Musters zu gewährleisten, müssen wir ein System einrichten, das kontinuierlich ermittelt, ob X immer noch der niedrigste Wert zwischen X und A ist. Es ist notwendig, X dynamisch zu aktualisieren, wenn innerhalb dieses Bereichs ein niedrigerer Wert auftritt. Um sicherzustellen, dass in diesem Segment keine höheren Punkte übersehen werden, sollte A ebenfalls der höchste Punkt zwischen A und B sein. Ebenso sollte C der höchste Punkt zwischen C und D sein und B der niedrigste Punkt zwischen B und C. Durch die Einhaltung dieser Anforderungen können wir die Genauigkeit der Mustererkennung verbessern und Fehlerkennungen durch eine strenge Punktauswahl vermeiden. Diese Methode bewahrt die Integrität der harmonischen Musterstruktur und ermöglicht es der Anzeige, anpassungsfähig zu bleiben und auf neue Preisaktivitäten zu reagieren.

Beispiel:

//X
int x_a_bars; // Number of bars between XA
int x_lowest_index; // Index of the lowest bar
double x_a_ll; // Price of the lowest bar
datetime x_a_ll_t; // Time of the lowest bar

//A
int a_b_bars; // Number of bars between AB
int a_highest_index; // Index of the highest bar
double a_b_hh; // Price of the highest bar
datetime a_b_hh_t; // Time of the highest bar

//B
int b_c_bars; // Number of bars between BC
int b_lowest_index; // Index of the lowest bar
double b_c_ll; // Price of the lowest bar
datetime b_c_ll_t; // Time of the lowest bar

//C
int c_d_bars; // Number of bars between CD
int c_highest_index; // Index of the highest bar
double c_d_hh; // Price of the highest bar
datetime c_d_hh_t; // Time of the highest bar

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {

//---

   if(rates_total >= bars_check)
     {

      for(int i = rates_total - bars_check; i < rates_total - LookbackBars; i++)
        {
         if(IsSwingLow(low, i, LookbackBars))
           {
            // If a swing low is found, store its price, time, and create a name for the objects to mark the X.
            X = low[i]; // Price of the swing low (X).
            X_time = time[i]; // Time of the swing low (X).
            X_line = StringFormat("XLow%d", i); // Unique name for the trend line object.
            X_letter = StringFormat("X%d", i); // Unique name for the text label object.

            for(int j = i; j < rates_total - LookbackBars; j++)
              {
               if(IsSwingHigh(high, j, LookbackBars) && time[j] > X_time)
                 {

                  A = high[j]; // Price of the swing high (A).
                  A_time = time[j]; // Time of the swing high (A).
                  A_line = StringFormat("AHigh%d", j); // Unique name for the trend line object.
                  A_letter = StringFormat("A%d", j); // Unique name for the text label object.

                  for(int k = j; k < rates_total - LookbackBars; k++)
                    {
                     if(IsSwingLow(low, k, LookbackBars) && time[k] > A_time)
                       {

                        // If a swing low is found, store its price, time, and create a name for the object.
                        B = low[k]; // Price of the swing low (B).
                        B_time = time[k]; // Time of the swing low (B).
                        B_line = StringFormat("BLow%d", k); // Unique name for the trend line object.
                        B_letter = StringFormat("B%d", k); // Unique name for the text label object.

                        for(int l = j ; l < rates_total - LookbackBars; l++)
                          {
                           if(IsSwingHigh(high, l, LookbackBars) && time[l] > B_time)
                             {
                              C = high[l]; // Price of the swing high (C).
                              C_time = time[l]; // Time of the swing high (C).
                              C_line = StringFormat("CHigh%d", l); // Unique name for the trend line object.
                              C_letter = StringFormat("C%d", l); // Unique name for the text label object.

                              for(int m = l; m < rates_total - (LookbackBars / 2); m++)
                                {
                                 if(IsSwingLow(low, m, LookbackBars / 2) && time[m] > C_time)
                                   {
                                    D = low[m]; // Price of the swing low (D).
                                    D_time = time[m]; // Time of the swing low (D).
                                    D_line = StringFormat("DLow%d", m); // Unique name for the trend line object.
                                    D_letter = StringFormat("D%d", m); // Unique name for the text label object.

                                    //D
                                    ObjectCreate(chart_id, D_letter, OBJ_TEXT, 0, D_time, D); // Create text object for D
                                    ObjectSetString(chart_id, D_letter, OBJPROP_TEXT, "D"); // Set the text to "D".
                                    ObjectSetInteger(chart_id,D_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                                    ObjectCreate(chart_id,D_line,OBJ_TREND,0,D_time,D,time[m+LookbackBars],D); // Create line to mark D
                                    ObjectSetInteger(chart_id,D_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

                                    //C
                                    c_d_bars = Bars(_Symbol,PERIOD_CURRENT,C_time, D_time);
                                    c_highest_index = ArrayMaximum(high,l, c_d_bars);

                                    c_d_hh = high[c_highest_index]; //C - D Highest High and time
                                    c_d_hh_t = time[c_highest_index];

                                    ObjectCreate(chart_id, C_letter, OBJ_TEXT, 0, c_d_hh_t, c_d_hh); // Create text object for C
                                    ObjectSetString(chart_id, C_letter, OBJPROP_TEXT, "C"); // Set the text to "C".
                                    ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                                    ObjectCreate(chart_id,C_line,OBJ_TREND,0,c_d_hh_t,C,time[c_highest_index+LookbackBars],c_d_hh); // Create line to mark C
                                    ObjectSetInteger(chart_id,C_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

                                    //B
                                    b_c_bars = Bars(_Symbol,PERIOD_CURRENT,B_time, c_d_hh_t);
                                    b_lowest_index = ArrayMinimum(low,k, b_c_bars);

                                    b_c_ll = low[b_lowest_index]; //B - C Lowest Low and time
                                    b_c_ll_t = time[b_lowest_index];

                                    ObjectCreate(chart_id, B_letter, OBJ_TEXT, 0, b_c_ll_t, b_c_ll); // Create text object for B
                                    ObjectSetString(chart_id, B_letter, OBJPROP_TEXT, "B"); // Set the text to "B".
                                    ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                                    ObjectCreate(chart_id,B_line,OBJ_TREND,0,b_c_ll_t,b_c_ll,time[b_lowest_index+LookbackBars],b_c_ll); // Create line to mark B
                                    ObjectSetInteger(chart_id,B_line,OBJPROP_COLOR,clrMidnightBlue); // Set line color to MidnightBlue

                                    //A
                                    a_b_bars = Bars(_Symbol,PERIOD_CURRENT,A_time, b_c_ll_t);
                                    a_highest_index = ArrayMaximum(high,j, a_b_bars);

                                    a_b_hh = high[a_highest_index]; //A - B Highest High and time
                                    a_b_hh_t = time[a_highest_index];

                                    ObjectCreate(chart_id, A_letter, OBJ_TEXT, 0, a_b_hh_t, a_b_hh); // Create text object for A
                                    ObjectSetString(chart_id, A_letter, OBJPROP_TEXT, "A"); // Set the text to "A".
                                    ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                                    ObjectCreate(chart_id,A_line,OBJ_TREND,0,a_b_hh_t,a_b_hh,time[a_highest_index+LookbackBars],a_b_hh); // Create line to mark A
                                    ObjectSetInteger(chart_id,A_line,OBJPROP_COLOR,clrGreen); // Set line color to green

                                    //X
                                    x_a_bars = Bars(_Symbol,PERIOD_CURRENT,X_time, a_b_hh_t);
                                    x_lowest_index = ArrayMinimum(low,i, x_a_bars);

                                    x_a_ll = low[x_lowest_index]; //X - A Lowest Low and time
                                    x_a_ll_t = time[x_lowest_index];

                                    ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, x_a_ll_t, x_a_ll); // Create text object for X
                                    ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".
                                    ObjectCreate(chart_id,X_line,OBJ_TREND,0,x_a_ll_t,x_a_ll,time[x_lowest_index+LookbackBars],x_a_ll); // Create line to mark X

                                    XA_line = StringFormat("XA Line%d", m); // Unique name for the XA line.
                                    ObjectCreate(chart_id,XA_line,OBJ_TREND,0,x_a_ll_t,x_a_ll,a_b_hh_t,a_b_hh); // Create line to connect XA
                                    ObjectSetInteger(chart_id,XA_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,XA_line,OBJPROP_WIDTH,3); // Line width

                                    AB_line = StringFormat("AB Line%d", m); // Unique name for the AB line.
                                    ObjectCreate(chart_id,AB_line,OBJ_TREND,0,a_b_hh_t,a_b_hh,b_c_ll_t,b_c_ll); // Create line to connect AB
                                    ObjectSetInteger(chart_id,AB_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,AB_line,OBJPROP_WIDTH,3); // Line width

                                    BC_line = StringFormat("BC Line%d", m); // Unique name for the BC line.
                                    ObjectCreate(chart_id,BC_line,OBJ_TREND,0,b_c_ll_t,b_c_ll,c_d_hh_t,c_d_hh); // Create line to connect BC
                                    ObjectSetInteger(chart_id,BC_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,BC_line,OBJPROP_WIDTH,3); // Line width

                                    CD_line = StringFormat("CD Line%d", m); // Unique name for the CD line.
                                    ObjectCreate(chart_id,CD_line,OBJ_TREND,0,c_d_hh_t,c_d_hh,D_time,D); // Create line to connect CD
                                    ObjectSetInteger(chart_id,CD_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,CD_line,OBJPROP_WIDTH,3); // Line width

                                    if(overlap == false)
                                      {
                                       i = m;
                                      }
                                    if(overlap == true)
                                      {
                                       i = i;
                                      }
                                    break;

                                   }
                                }

                              break;

                             }
                          }

                        break;

                       }
                    }

                  break;
                 }
              }
           }
        }
     }

//--- return value of prev_calculated for next call
   return(rates_total);
  }

Ausgabe:

Abbildung 10. Neue XABCD

Erläuterung:

Der X-Punkt dient als erster Bezugspunkt für die Erkennung möglicher Umkehrmuster beim Handel mit harmonischen Mustern. Bei einem Aufwärts-Muster bedeutet er einen großen tiefen Umkehrpunkt, bei einem Abwärts-Muster einen hohen Umkehrpunkt. Dieser Punkt ist wichtig, da er die Grundlage für die Messung von Fibonacci-Retracements und -Extensions bildet, die bei der Bestätigung harmonischer Formationen helfen. Der Zweck des Codes besteht darin, X zu erkennen, seine Zeit und seinen Preis aufzuzeichnen und ihn auf dem Chart visuell anzuzeigen. Um die gesamte Struktur des Musters zu erstellen, wird X auch mit den anderen Umkehrpunkten (A, B, C und D) verbunden.

Die Anzahl der Balken zwischen X und A wird durch die Variable x_a_bars erfasst, mit deren Hilfe die relativen Abstände zwischen den Schenkeln des Musters bestimmt werden können. Um den genauen Balken zu bestimmen, an dem X aufgetreten ist, wird in der Variablen x_lowest_index der Array-Index des niedrigsten Kurses innerhalb dieses Bereichs gespeichert. Der mit dem niedrigsten Preis verbundene Zeitstempel wird in x_a_ll_t gespeichert, während der Preis selbst x_a_ll zugeordnet wird.

Die Ermittlung der Anzahl der Balken zwischen X und A mit Hilfe der Funktion Bars() ist der erste Schritt zur Bestimmung von X. Der für die Analyse erforderliche Bereich wird durch diese Funktion bereitgestellt, die die Anzahl der Balken zwischen diesen beiden Umkehrpunkten zählt. Das Programm verwendet ArrayMinimum(), um die angegebenen Balken zu durchsuchen und den Index des niedrigsten Preises zurückzugeben, wenn der Bereich bestimmt wurde. Mit Hilfe der Felder low[x_niedrigster_index] und time[x_niedrigster_index] erhält man dann den tatsächlichen Preis und die Zeit von X.

Sobald X identifiziert wurde, verwendet das Skript das MetaTrader-Objekt, um es auf dem Chart sichtbar zu machen. Um sicherzustellen, dass Sie diesen entscheidenden Moment schnell erkennen können, wird ObjectCreate() verwendet, um ein Textlabel (X_letter) für den tiefen Umkehrpunkt X zu erzeugen. Der Klarheit halber wird der Text „X“ für die Textbeschriftung verwendet, die an der Zeit und dem Preis von X platziert wird. Um den tiefen Umkehrpunkt angemessen hervorzuheben, wird mit ObjectCreate() auch eine Trendlinie (X_line) bei X gebildet. Die Linie wird um eine bestimmte Anzahl von Balken (LookbackBars) verlängert.

Das Programm erstellt Trendlinien, um X mit anderen wichtigen Orten (A, B, C und D) zu verbinden, nachdem X bestimmt wurde. Anhand dieser Trendlinien können Sie das harmonische Muster besser erkennen. Mit der Funktion ObjectCreate() wird die erste Verbindung gezeichnet, die XA-Linie, die X und A verbindet. Diese Linie hat eine Breite von drei Pixeln und ist braun gefärbt (clrSaddleBrown), um die Sichtbarkeit zu gewährleisten. Die übrigen Schenkel des Musters - die AB-Linie, die A mit B verbindet, die BC-Linie, die B mit C verbindet, und die CD-Linie, die C mit D verbindet - werden auf ähnliche Weise mit zusätzlichen Trendlinien dargestellt. Um eine einheitliche visuelle Darstellung zu erreichen, behält jede dieser Linien die gleiche Breite und Farbcharakteristik.

2.2. Validierung von Punkt B anhand der Fibonacci-Retracements von XA

Wir werden den tiefen Umkehrpunkt B in diesem Abschnitt überprüfen, indem wir sehen, ob es über dem 78,6%-Niveau bleibt und unter das 61,8%-Retracement-Niveau von XA fällt. Diese Validierungsphase ist für den Handel mit Aufwärts-Mustern unerlässlich, da sie garantiert, dass der Punkt B die erforderlichen Fibonacci-Verhältnisse erfüllt, die zur Definition der Struktur des Musters beitragen. Wenn B in diesem Bereich liegt, besteht eine größere Chance auf eine legitime harmonische Anordnung. Andernfalls ist das Muster möglicherweise nicht echt oder bedarf weiterer Bestätigung, wenn B zu hoch oder zu niedrig ist.

Für diese Validierung bestimmen wir zunächst die Fibonacci-Retracement-Levels für den XA-Schenkel. Eine beliebte technische Analysemethode zur Erkennung möglicher Preisumkehrungen ist das Fibonacci-Retracement.

Wir werden die grafischen Werkzeuge in MQL5 verwenden, um zusätzlich zur Validierung von B ein Fibonacci-Retracement-Objekt in die Chartdarstellung einzufügen. Das Fibonacci-Tool wird mit der Funktion ObjectCreate() gezeichnet, wobei X als Startpunkt und A als Endpunkt dient. Sobald das Objekt erstellt wurde, werden wir es modifizieren, indem wir zusätzliche Fibonacci-Levels einfügen, die MetaTrader 5 standardmäßig nicht unterstützt. Dies garantiert die Anzeige aller relevanten Retracement-Zonen.

Beispiel:

//Fibo
string XA_fibo; // Unique name for XA fibo
double lvl_61_8; // Level 61.8
double lvl_78_6; // Level 78.6
string fibo_618_786; // Unique name for the object that marks 61.8 and 78.6.
string fibo_78_6_txt; // Unique name for text "78.6" cause its not available by default
for(int m = l; m < rates_total - (LookbackBars / 2); m++)
  {
   if(IsSwingLow(low, m, LookbackBars / 2) && time[m] > C_time)
     {
      D = low[m]; // Price of the swing low (D).
      D_time = time[m]; // Time of the swing low (D).
      D_line = StringFormat("DLow%d", m); // Unique name for the trend line object.
      D_letter = StringFormat("D%d", m); // Unique name for the text label object.

      //D
      ObjectCreate(chart_id, D_letter, OBJ_TEXT, 0, D_time, D); // Create text object for D
      ObjectSetString(chart_id, D_letter, OBJPROP_TEXT, "D"); // Set the text to "D".
      ObjectSetInteger(chart_id,D_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
      ObjectCreate(chart_id,D_line,OBJ_TREND,0,D_time,D,time[m+LookbackBars],D); // Create line to mark D
      ObjectSetInteger(chart_id,D_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

      //C
      c_d_bars = Bars(_Symbol,PERIOD_CURRENT,C_time, D_time);
      c_highest_index = ArrayMaximum(high,l, c_d_bars);

      c_d_hh = high[c_highest_index]; //C - D Highest High and time
      c_d_hh_t = time[c_highest_index];

      ObjectCreate(chart_id, C_letter, OBJ_TEXT, 0, c_d_hh_t, c_d_hh); // Create text object for C
      ObjectSetString(chart_id, C_letter, OBJPROP_TEXT, "C"); // Set the text to "C".
      ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
      ObjectCreate(chart_id,C_line,OBJ_TREND,0,c_d_hh_t,C,time[c_highest_index+LookbackBars],c_d_hh); // Create line to mark C
      ObjectSetInteger(chart_id,C_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

      //B
      b_c_bars = Bars(_Symbol,PERIOD_CURRENT,B_time, c_d_hh_t);
      b_lowest_index = ArrayMinimum(low,k, b_c_bars);

      b_c_ll = low[b_lowest_index]; //B - C Lowest Low and time
      b_c_ll_t = time[b_lowest_index];

      ObjectCreate(chart_id, B_letter, OBJ_TEXT, 0, b_c_ll_t, b_c_ll); // Create text object for B
      ObjectSetString(chart_id, B_letter, OBJPROP_TEXT, "B"); // Set the text to "B".
      ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
      ObjectCreate(chart_id,B_line,OBJ_TREND,0,b_c_ll_t,b_c_ll,time[b_lowest_index+LookbackBars],b_c_ll); // Create line to mark B
      ObjectSetInteger(chart_id,B_line,OBJPROP_COLOR,clrMidnightBlue); // Set line color to MidnightBlue

      //A
      a_b_bars = Bars(_Symbol,PERIOD_CURRENT,A_time, b_c_ll_t);
      a_highest_index = ArrayMaximum(high,j, a_b_bars);

      a_b_hh = high[a_highest_index]; //A - B Highest High and time
      a_b_hh_t = time[a_highest_index];

      ObjectCreate(chart_id, A_letter, OBJ_TEXT, 0, a_b_hh_t, a_b_hh); // Create text object for A
      ObjectSetString(chart_id, A_letter, OBJPROP_TEXT, "A"); // Set the text to "A".
      ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
      ObjectCreate(chart_id,A_line,OBJ_TREND,0,a_b_hh_t,a_b_hh,time[a_highest_index+LookbackBars],a_b_hh); // Create line to mark A
      ObjectSetInteger(chart_id,A_line,OBJPROP_COLOR,clrGreen); // Set line color to green

      //X
      x_a_bars = Bars(_Symbol,PERIOD_CURRENT,X_time, a_b_hh_t);
      x_lowest_index = ArrayMinimum(low,i, x_a_bars);

      x_a_ll = low[x_lowest_index]; //X - A Lowest Low and time
      x_a_ll_t = time[x_lowest_index];

      ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, x_a_ll_t, x_a_ll); // Create text object for X
      ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".
      ObjectCreate(chart_id,X_line,OBJ_TREND,0,x_a_ll_t,x_a_ll,time[x_lowest_index+LookbackBars],x_a_ll); // Create line to mark X

      XA_line = StringFormat("XA Line%d", m); // Unique name for the XA line.
      ObjectCreate(chart_id,XA_line,OBJ_TREND,0,x_a_ll_t,x_a_ll,a_b_hh_t,a_b_hh); // Create line to connect XA
      ObjectSetInteger(chart_id,XA_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
      ObjectSetInteger(chart_id,XA_line,OBJPROP_WIDTH,3); // Line width

      AB_line = StringFormat("AB Line%d", m); // Unique name for the AB line.
      ObjectCreate(chart_id,AB_line,OBJ_TREND,0,a_b_hh_t,a_b_hh,b_c_ll_t,b_c_ll); // Create line to connect AB
      ObjectSetInteger(chart_id,AB_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
      ObjectSetInteger(chart_id,AB_line,OBJPROP_WIDTH,3); // Line width

      BC_line = StringFormat("BC Line%d", m); // Unique name for the BC line.
      ObjectCreate(chart_id,BC_line,OBJ_TREND,0,b_c_ll_t,b_c_ll,c_d_hh_t,c_d_hh); // Create line to connect BC
      ObjectSetInteger(chart_id,BC_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
      ObjectSetInteger(chart_id,BC_line,OBJPROP_WIDTH,3); // Line width

      CD_line = StringFormat("CD Line%d", m); // Unique name for the CD line.
      ObjectCreate(chart_id,CD_line,OBJ_TREND,0,c_d_hh_t,c_d_hh,D_time,D); // Create line to connect CD
      ObjectSetInteger(chart_id,CD_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
      ObjectSetInteger(chart_id,CD_line,OBJPROP_WIDTH,3); // Line width

      lvl_61_8 = a_b_hh - ((61.8/100) * (a_b_hh - x_a_ll)); // Calculating level 61.8
      lvl_78_6 = a_b_hh - ((78.6/100) * (a_b_hh - x_a_ll)); // Calculating level 78.6

      //XA FIBO
      XA_fibo = StringFormat("XA FIB0 %d", i);
      ObjectCreate(chart_id,XA_fibo,OBJ_FIBO,0,x_a_ll_t,x_a_ll,a_b_hh_t,a_b_hh); // Create XA fibo
      ObjectSetInteger(chart_id,XA_fibo,OBJPROP_LEVELS,6); // Number of default levels
      for(int i = 1; i <= 6; i++)
        {

         ObjectSetInteger(chart_id,XA_fibo,OBJPROP_LEVELCOLOR,i,clrSaddleBrown); // Set each level color to SaddleBrown

        }

      fibo_618_786 = StringFormat("Fibo 78.6 - 61.8 %d", i);
      fibo_78_6_txt = StringFormat("Fibo 78.6 Text %d", i);

      ObjectCreate(chart_id,fibo_618_786,OBJ_RECTANGLE,0,x_a_ll_t, lvl_61_8,b_c_ll_t,lvl_78_6); // Create rectangle object marking 61.8 and 78.6
      ObjectSetInteger(chart_id,fibo_618_786,OBJPROP_COLOR,clrSaddleBrown); // Set color to clrSaddleBrown

      ObjectCreate(chart_id,fibo_78_6_txt,OBJ_TEXT,0,b_c_ll_t,lvl_78_6); // Create text for level 78.6
      ObjectSetString(chart_id,fibo_78_6_txt,OBJPROP_TEXT,"78.6"); // Text to be displayed
      ObjectSetInteger(chart_id,fibo_78_6_txt,OBJPROP_COLOR,clrSaddleBrown); // Set text color
      ObjectSetInteger(chart_id,fibo_78_6_txt,OBJPROP_FONTSIZE,8); // Set text size

      if(overlap == false)
        {
         i = m;
        }
      if(overlap == true)
        {
         i = i;
        }
      break;

     }
  }
Ausgabe:

Abbildung 11. Fibo

Erläuterung:

Um zu bestätigen, dass der Punkt B innerhalb einer bestimmten Spanne liegt, wenden wir in diesem Abschnitt das Fibonacci-Retracement für den XA-Schenkel an. In der technischen Analyse wird das Fibonacci-Retracement häufig verwendet, um mögliche Umkehrzonen auszumachen. Es ist wichtig zu überprüfen, ob der Punkt B mit dem erwarteten Retracement von XA übereinstimmt. Insbesondere sollte B idealerweise im Bereich der 61,8 % bis 78,6 % Retracement-Niveaus von XA liegen. Es ist einfacher festzustellen, ob der Punkt B innerhalb des akzeptablen Bereichs liegt, wenn wir ein Fibonacci-Retracement-Objekt erstellen und diese Zone auf dem Chart hervorheben. Um dies zu erreichen, müssen wir zunächst einige wichtige Variablen festlegen. Um sicherzustellen, dass jede Fibonacci-Zeichnung korrekt identifiziert wird, behält die Variable XA_fibo einen eindeutigen Namen für das Fibonacci-Retracement-Objekt.

Das Fibonacci-Retracement-Objekt auf dem XA-Leg wird mit der Funktion ObjectCreate() erstellt, nachdem die Niveaus bestimmt wurden. Anhand dieses Objekts, das sich von Punkt X (Tief) bis Punkt A (Hoch) erstreckt, können Sie verstehen, wie der Preis mit den Fibonacci-Levels interagiert. Wir haben die Anzahl der Fibonacci-Levels auf sechs festgelegt und ihre Farbe in Sattelbraun geändert, um die Klarheit der Visualisierung zu verbessern und sicherzustellen, dass jedes Level leicht zu erkennen ist und sich von anderen Chart-Elementen unterscheidet. 

Außerdem heben wir die Retracement-Zone zwischen 61,8% und 78,6% hervor, indem wir ein rechteckiges Objekt erstellen, das die Aufmerksamkeit darauf lenkt, da es sich um einen wichtigen Bereich handelt. Es ist einfach festzustellen, ob Punkt B innerhalb der erwarteten Spanne liegt, da das Rechteck die 61,8 %- und 78,6 %-Marke überspannt. Dies erleichtert eine schnelle Mustervalidierung, ohne dass mühsame Retracement-Level-Prüfungen erforderlich sind. Außerdem hat das Rechteck die Farbe SaddleBrown, wodurch das visuelle Konzept des Charts konsistent bleibt.

Wir haben auch eine Textbeschriftung für das 78,6%-Retracement-Niveau eingefügt, was eine weitere wichtige Änderung darstellt. Wir generieren manuell ein Textobjekt, um „78,6“ auf dem entsprechenden Kursniveau anzuzeigen, da das Fibonacci-Tool des MetaTrader 5 dieses Niveau standardmäßig nicht enthält. Dies erhöht die Präzision bei der Identifizierung harmonischer Muster, da die Händler die genaue Position des 78,6%-Retracements beobachten können. Durch die Umsetzung dieser Änderungen in die Praxis wird es einfacher zu überprüfen, ob der Punkt B innerhalb des harmonischen Musters legitim ist. Das Fibonacci-Retracement-Objekt, die markierte 61,8%-78,6%-Zone und die zusätzliche Textbeschriftung gewährleisten eine präzise und visuell intuitive Technik zur Validierung der harmonischen Muster. 

Wir müssen sicherstellen, dass alle Chart-Objekte nur dann gezeichnet werden, wenn die Anforderungen für ein gültiges Muster erfüllt sind, da wir nun alles haben, was wir brauchen. Insbesondere muss der Punkt D unter dem Punkt X liegen, und der Punkt B muss innerhalb des 61,8%-78,6%-Retracements von XA liegen. Wenn diese Voraussetzungen nicht erfüllt sind, sollten dem Chart keine Objekte hinzugefügt werden.

Beispiele:

for(int m = l; m < rates_total - (LookbackBars / 2); m++)
  {
   if(IsSwingLow(low, m, LookbackBars / 2) && time[m] > C_time)
     {
      D = low[m]; // Price of the swing low (D).
      D_time = time[m]; // Time of the swing low (D).
      D_line = StringFormat("DLow%d", m); // Unique name for the trend line object.
      D_letter = StringFormat("D%d", m); // Unique name for the text label object.

      //C
      c_d_bars = Bars(_Symbol,PERIOD_CURRENT,C_time, D_time);
      c_highest_index = ArrayMaximum(high,l, c_d_bars);

      c_d_hh = high[c_highest_index]; //C - D Highest High and time
      c_d_hh_t = time[c_highest_index];

      //B
      b_c_bars = Bars(_Symbol,PERIOD_CURRENT,B_time, c_d_hh_t);
      b_lowest_index = ArrayMinimum(low,k, b_c_bars);

      b_c_ll = low[b_lowest_index]; //B - C Lowest Low and time
      b_c_ll_t = time[b_lowest_index];

      //A
      a_b_bars = Bars(_Symbol,PERIOD_CURRENT,A_time, b_c_ll_t);
      a_highest_index = ArrayMaximum(high,j, a_b_bars);

      a_b_hh = high[a_highest_index]; //A - B Highest High and time
      a_b_hh_t = time[a_highest_index];

      //X
      x_a_bars = Bars(_Symbol,PERIOD_CURRENT,X_time, a_b_hh_t);
      x_lowest_index = ArrayMinimum(low,i, x_a_bars);

      x_a_ll = low[x_lowest_index]; //X - A Lowest Low and time
      x_a_ll_t = time[x_lowest_index];

      lvl_61_8 = a_b_hh - ((61.8/100) * (a_b_hh - x_a_ll)); // Calculating level 61.8
      lvl_78_6 = a_b_hh - ((78.6/100) * (a_b_hh - x_a_ll)); // Calculating level 78.6

      if((b_c_ll <= lvl_61_8 && b_c_ll >= lvl_78_6) && (D < x_a_ll))
        {

         //D
         ObjectCreate(chart_id, D_letter, OBJ_TEXT, 0, D_time, D); // Create text object for D
         ObjectSetString(chart_id, D_letter, OBJPROP_TEXT, "D"); // Set the text to "D".
         ObjectSetInteger(chart_id,D_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
         ObjectCreate(chart_id,D_line,OBJ_TREND,0,D_time,D,time[m+LookbackBars],D); // Create line to mark D
         ObjectSetInteger(chart_id,D_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

         //C
         ObjectCreate(chart_id, C_letter, OBJ_TEXT, 0, c_d_hh_t, c_d_hh); // Create text object for C
         ObjectSetString(chart_id, C_letter, OBJPROP_TEXT, "C"); // Set the text to "C".
         ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
         ObjectCreate(chart_id,C_line,OBJ_TREND,0,c_d_hh_t,C,time[c_highest_index+LookbackBars],c_d_hh); // Create line to mark C
         ObjectSetInteger(chart_id,C_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

         //B
         ObjectCreate(chart_id, B_letter, OBJ_TEXT, 0, b_c_ll_t, b_c_ll); // Create text object for B
         ObjectSetString(chart_id, B_letter, OBJPROP_TEXT, "B"); // Set the text to "B".
         ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
         ObjectCreate(chart_id,B_line,OBJ_TREND,0,b_c_ll_t,b_c_ll,time[b_lowest_index+LookbackBars],b_c_ll); // Create line to mark B
         ObjectSetInteger(chart_id,B_line,OBJPROP_COLOR,clrMidnightBlue); // Set line color to MidnightBlue

         //A
         ObjectCreate(chart_id, A_letter, OBJ_TEXT, 0, a_b_hh_t, a_b_hh); // Create text object for A
         ObjectSetString(chart_id, A_letter, OBJPROP_TEXT, "A"); // Set the text to "A".
         ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
         ObjectCreate(chart_id,A_line,OBJ_TREND,0,a_b_hh_t,a_b_hh,time[a_highest_index+LookbackBars],a_b_hh); // Create line to mark A
         ObjectSetInteger(chart_id,A_line,OBJPROP_COLOR,clrGreen); // Set line color to green

         //X
         ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, x_a_ll_t, x_a_ll); // Create text object for X
         ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".
         ObjectCreate(chart_id,X_line,OBJ_TREND,0,x_a_ll_t,x_a_ll,time[x_lowest_index+LookbackBars],x_a_ll); // Create line to mark X

         XA_line = StringFormat("XA Line%d", m); // Unique name for the XA line.
         ObjectCreate(chart_id,XA_line,OBJ_TREND,0,x_a_ll_t,x_a_ll,a_b_hh_t,a_b_hh); // Create line to connect XA
         ObjectSetInteger(chart_id,XA_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
         ObjectSetInteger(chart_id,XA_line,OBJPROP_WIDTH,3); // Line width

         AB_line = StringFormat("AB Line%d", m); // Unique name for the AB line.
         ObjectCreate(chart_id,AB_line,OBJ_TREND,0,a_b_hh_t,a_b_hh,b_c_ll_t,b_c_ll); // Create line to connect AB
         ObjectSetInteger(chart_id,AB_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
         ObjectSetInteger(chart_id,AB_line,OBJPROP_WIDTH,3); // Line width

         BC_line = StringFormat("BC Line%d", m); // Unique name for the BC line.
         ObjectCreate(chart_id,BC_line,OBJ_TREND,0,b_c_ll_t,b_c_ll,c_d_hh_t,c_d_hh); // Create line to connect BC
         ObjectSetInteger(chart_id,BC_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
         ObjectSetInteger(chart_id,BC_line,OBJPROP_WIDTH,3); // Line width

         CD_line = StringFormat("CD Line%d", m); // Unique name for the CD line.
         ObjectCreate(chart_id,CD_line,OBJ_TREND,0,c_d_hh_t,c_d_hh,D_time,D); // Create line to connect CD
         ObjectSetInteger(chart_id,CD_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
         ObjectSetInteger(chart_id,CD_line,OBJPROP_WIDTH,3); // Line width

         //XA FIBO
         XA_fibo = StringFormat("XA FIB0 %d", i);
         ObjectCreate(chart_id,XA_fibo,OBJ_FIBO,0,x_a_ll_t,x_a_ll,a_b_hh_t,a_b_hh); // Create XA fibo
         ObjectSetInteger(chart_id,XA_fibo,OBJPROP_LEVELS,6); // Number of default levels
         for(int i = 1; i <= 6; i++)
           {
            ObjectSetInteger(chart_id,XA_fibo,OBJPROP_LEVELCOLOR,i,clrSaddleBrown); // Set each level color to SaddleBrown
           }

         fibo_618_786 = StringFormat("Fibo 78.6 - 61.8 %d", i);
         fibo_78_6_txt = StringFormat("Fibo 78.6 Text %d", i);

         ObjectCreate(chart_id,fibo_618_786,OBJ_RECTANGLE,0,x_a_ll_t, lvl_61_8,b_c_ll_t,lvl_78_6); // Create rectangle object marking 61.8 and 78.6
         ObjectSetInteger(chart_id,fibo_618_786,OBJPROP_COLOR,clrSaddleBrown); // Set color to clrSaddleBrown

         ObjectCreate(chart_id,fibo_78_6_txt,OBJ_TEXT,0,b_c_ll_t,lvl_78_6); // Create text for level 78.6
         ObjectSetString(chart_id,fibo_78_6_txt,OBJPROP_TEXT,"78.6"); // Text to be displayed
         ObjectSetInteger(chart_id,fibo_78_6_txt,OBJPROP_COLOR,clrSaddleBrown); // Set text color
         ObjectSetInteger(chart_id,fibo_78_6_txt,OBJPROP_FONTSIZE,8); // Set text size

        }

      if(overlap == false)
        {
         i = m;
        }
      if(overlap == true)
        {
         i = i;
        }
      break;
     }
  }

Ausgabe:

Abbildung 12. B und X

Erläuterung:

Die Bedingung if ((b_c_ll <= lvl_61_8 && b_c_ll >= lvl_78_6) && (D < x_a_ll)) garantiert, dass alle Chart-Objekte nur dann gezeichnet werden, wenn ein geeignetes harmonisches Muster gefunden wird, indem sie zu true ausgewertet wird. Auf diese Weise wird verhindert, dass die Tabelle mit fehlerhaften Mustern überfüllt wird. Das Skript erstellt und zeigt dann alle erforderlichen Komponenten an, wie z. B. die Fibonacci-Retracement-Levels, Trendlinien, die X, A, B, C und D verbinden, und Textbeschriftungen, die jeden wichtigen Punkt identifizieren, wenn die Anforderung erfüllt ist. Da diese Methode sicherstellt, dass der Indikator nur korrekt geformte Muster anzeigt, verbessert sie die Genauigkeit und bewahrt eine klare, informative Chartanzeige.

2.3. Visualisierung der XAB- und BCD-Dreiecke

Zur besseren Veranschaulichung des harmonischen Musters werden wir in diesem Abschnitt die XAB- und BCD-Formen mit Dreiecken markieren. Als visuelle Hilfe erleichtern diese Dreiecke das Erkennen und Überprüfen der Musterstruktur auf dem Chart.

Dazu werden die Punkte X, A und B für das erste Dreieck und B, C und D für das zweite Dreieck mit OBJ_TRIANGLE-Objekten verbunden. Das BCD-Dreieck stellt den letzten Schenkel des Musters dar und verstärkt die Struktur, die zu Punkt D, der möglichen Umkehrzone, führt, während das XAB-Dreieck den ersten Schenkel betont und die Beziehung zwischen X, A und B bestätigt.

Beispiel:

string X_A_B;
string B_C_D;
if((b_c_ll <= lvl_61_8 && b_c_ll >= lvl_78_6) && (D < x_a_ll))
  {

//D
   ObjectCreate(chart_id, D_letter, OBJ_TEXT, 0, D_time, D); // Create text object for D
   ObjectSetString(chart_id, D_letter, OBJPROP_TEXT, "D"); // Set the text to "D".
   ObjectSetInteger(chart_id,D_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
   ObjectCreate(chart_id,D_line,OBJ_TREND,0,D_time,D,time[m+LookbackBars],D); // Create line to mark D
   ObjectSetInteger(chart_id,D_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

//C
   ObjectCreate(chart_id, C_letter, OBJ_TEXT, 0, c_d_hh_t, c_d_hh); // Create text object for C
   ObjectSetString(chart_id, C_letter, OBJPROP_TEXT, "C"); // Set the text to "C".
   ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
   ObjectCreate(chart_id,C_line,OBJ_TREND,0,c_d_hh_t,C,time[c_highest_index+LookbackBars],c_d_hh); // Create line to mark C
   ObjectSetInteger(chart_id,C_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

//B
   ObjectCreate(chart_id, B_letter, OBJ_TEXT, 0, b_c_ll_t, b_c_ll); // Create text object for B
   ObjectSetString(chart_id, B_letter, OBJPROP_TEXT, "B"); // Set the text to "B".
   ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
   ObjectCreate(chart_id,B_line,OBJ_TREND,0,b_c_ll_t,b_c_ll,time[b_lowest_index+LookbackBars],b_c_ll); // Create line to mark B
   ObjectSetInteger(chart_id,B_line,OBJPROP_COLOR,clrMidnightBlue); // Set line color to MidnightBlue

//A
   ObjectCreate(chart_id, A_letter, OBJ_TEXT, 0, a_b_hh_t, a_b_hh); // Create text object for A
   ObjectSetString(chart_id, A_letter, OBJPROP_TEXT, "A"); // Set the text to "A".
   ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
   ObjectCreate(chart_id,A_line,OBJ_TREND,0,a_b_hh_t,a_b_hh,time[a_highest_index+LookbackBars],a_b_hh); // Create line to mark A
   ObjectSetInteger(chart_id,A_line,OBJPROP_COLOR,clrGreen); // Set line color to green

//X
   ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, x_a_ll_t, x_a_ll); // Create text object for X
   ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".
   ObjectCreate(chart_id,X_line,OBJ_TREND,0,x_a_ll_t,x_a_ll,time[x_lowest_index+LookbackBars],x_a_ll); // Create line to mark X

   XA_line = StringFormat("XA Line%d", m); // Unique name for the XA line.
   ObjectCreate(chart_id,XA_line,OBJ_TREND,0,x_a_ll_t,x_a_ll,a_b_hh_t,a_b_hh); // Create line to connect XA
   ObjectSetInteger(chart_id,XA_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
   ObjectSetInteger(chart_id,XA_line,OBJPROP_WIDTH,3); // Line width

   AB_line = StringFormat("AB Line%d", m); // Unique name for the AB line.
   ObjectCreate(chart_id,AB_line,OBJ_TREND,0,a_b_hh_t,a_b_hh,b_c_ll_t,b_c_ll); // Create line to connect AB
   ObjectSetInteger(chart_id,AB_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
   ObjectSetInteger(chart_id,AB_line,OBJPROP_WIDTH,3); // Line width

   BC_line = StringFormat("BC Line%d", m); // Unique name for the BC line.
   ObjectCreate(chart_id,BC_line,OBJ_TREND,0,b_c_ll_t,b_c_ll,c_d_hh_t,c_d_hh); // Create line to connect BC
   ObjectSetInteger(chart_id,BC_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
   ObjectSetInteger(chart_id,BC_line,OBJPROP_WIDTH,3); // Line width

   CD_line = StringFormat("CD Line%d", m); // Unique name for the CD line.
   ObjectCreate(chart_id,CD_line,OBJ_TREND,0,c_d_hh_t,c_d_hh,D_time,D); // Create line to connect CD
   ObjectSetInteger(chart_id,CD_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
   ObjectSetInteger(chart_id,CD_line,OBJPROP_WIDTH,3); // Line width

//XA FIBO
   XA_fibo = StringFormat("XA FIB0 %d", i);
   ObjectCreate(chart_id,XA_fibo,OBJ_FIBO,0,x_a_ll_t,x_a_ll,a_b_hh_t,a_b_hh); // Create XA fibo
   ObjectSetInteger(chart_id,XA_fibo,OBJPROP_LEVELS,6); // Number of default levels
   for(int i = 1; i <= 6; i++)
     {
      ObjectSetInteger(chart_id,XA_fibo,OBJPROP_LEVELCOLOR,i,clrSaddleBrown); // Set each level color to SaddleBrown
     }

   fibo_618_786 = StringFormat("Fibo 78.6 - 61.8 %d", i);
   fibo_78_6_txt = StringFormat("Fibo 78.6 Text %d", i);

   ObjectCreate(chart_id,fibo_618_786,OBJ_RECTANGLE,0,x_a_ll_t, lvl_61_8,b_c_ll_t,lvl_78_6); // Create rectangle object marking 61.8 and 78.6
   ObjectSetInteger(chart_id,fibo_618_786,OBJPROP_COLOR,clrSaddleBrown); // Set color to clrSaddleBrown

   ObjectCreate(chart_id,fibo_78_6_txt,OBJ_TEXT,0,b_c_ll_t,lvl_78_6); // Create text for level 78.6
   ObjectSetString(chart_id,fibo_78_6_txt,OBJPROP_TEXT,"78.6"); // Text to be displayed
   ObjectSetInteger(chart_id,fibo_78_6_txt,OBJPROP_COLOR,clrSaddleBrown); // Set text color
   ObjectSetInteger(chart_id,fibo_78_6_txt,OBJPROP_FONTSIZE,8); // Set text size

   X_A_B = StringFormat("XAB %d", i);
   ObjectCreate(chart_id,X_A_B,OBJ_TRIANGLE,0,x_a_ll_t,x_a_ll, a_b_hh_t, a_b_hh, b_c_ll_t, b_c_ll);
   ObjectSetInteger(chart_id,X_A_B,OBJPROP_COLOR,clrCornflowerBlue);
   ObjectSetInteger(chart_id,X_A_B,OBJPROP_FILL,true);

   B_C_D = StringFormat("BCD %d", i);
   ObjectCreate(chart_id,B_C_D,OBJ_TRIANGLE,0,b_c_ll_t,b_c_ll, c_d_hh_t, c_d_hh, D_time, D);
   ObjectSetInteger(chart_id,B_C_D,OBJPROP_COLOR,clrCornflowerBlue);
   ObjectSetInteger(chart_id,B_C_D,OBJPROP_FILL,true);
  }

Ausgabe:

Abbildung 13. Aufwärts-Muster

Erläuterung:

Eindeutige Namen für die Dreiecke, die die XAB- und BCD-Segmente des harmonischen Musters bilden, werden in den Variablen X_A_B und B_C_D gespeichert. Drei Punkte - X, A und B - werden verwendet, um das Dreieck X_A_B zu erzeugen. Diese Punkte sind durch ihre jeweiligen Zeitstempel und Preiswerte gekennzeichnet (x_a_ll_t, x_a_ll, a_b_hh_t, a_b_hh, b_c_ll_t, b_c_ll). Das Dreieck B_C_D, das (b_c_ll_t, b_c_ll, c_d_hh_t, c_d_hh, D_time, D) verwendet, verbindet auf ähnliche Weise B, C und D. StringFormat() wird verwendet, um jedem Dreieck einen eindeutigen Namen zu geben, was das Zeichnen verschiedener Muster ohne Benennungsprobleme ermöglicht.

ObjectSetInteger() wird verwendet, um die visuellen Eigenschaften der Dreiecke festzulegen, nachdem sie mit ObjectCreate() erzeugt wurden. Das OBJPROP_FILL-Attribut ist auf true gesetzt, was garantiert, dass die Dreiecke gefüllt und nicht umrandet sind, und beide Dreiecke haben die Farbe Blau (clrCornflowerBlue). Diese visuellen Komponenten sorgen für mehr Klarheit und erleichtern die Überprüfung möglicher Handelsgelegenheiten und helfen den Händlern, die Struktur der Muster schnell zu erkennen.

2.4. Angabe von Einstiegspunkt, Stop-Loss und Take-Profit

In diesem Abschnitt werden wir den Einstiegspunkt, den Stop-Loss (SL) und den Take-Profit (TP) festlegen, um die wichtigen Handelsniveaus für das entdeckte harmonische Muster zu identifizieren. Bei Punkt D, dem niedrigsten tiefen Umkehrpunk des Musters, wird der Stop-Loss gesetzt. Da harmonische Muster Kursumkehrungen vorhersagen, minimiert das Setzen des Stop-Loss bei D mögliche Verluste, indem es garantiert, dass das Muster ungültig wird, wenn der Markt über dieses Niveau klettert.

Der Index von Punkt D plus die Hälfte der LookbackBars ist der Einstiegspunkt. Dies ermöglicht eine kleine Verzögerung nach der Identifizierung von D, sodass eine Bestätigung der Kursentwicklung möglich ist, bevor eine Transaktion durchgeführt wird. Da Punkt C der hohe Umkehrpunkt vor der erwarteten Aufwärtsbewegung ist, dient er als Take-Profit-Level. Beschriftungen und horizontale Linien für die SL-, Einstiegs- und TP-Levels werden erstellt, um diese Levels auf dem Chart darzustellen. Diese Elemente sorgen für Klarheit beim Handel auf der Grundlage des Musters, indem sie den Händlern helfen, den Handelsaufbau schnell zu erkennen.

Beispiel:

//Signal
string buy_txt;
string sell_txt;
string entry_line;
string tp_line;
string sl_line;
string tp_txt;
string sl_txt;
buy_txt = StringFormat("Buy %d", i);

ObjectCreate(chart_id,buy_txt,OBJ_TEXT,0,time[m + (LookbackBars / 2)],open[m  + (LookbackBars / 2)]);
ObjectSetString(chart_id,buy_txt,OBJPROP_TEXT,"BUY");
ObjectSetInteger(chart_id,buy_txt,OBJPROP_COLOR,clrCornflowerBlue);
ObjectSetInteger(chart_id,buy_txt,OBJPROP_FONTSIZE,10);

entry_line = StringFormat("Buy Entry Line %d", i);
ObjectCreate(chart_id,entry_line,OBJ_TREND,0,time[m  + (LookbackBars / 2)],open[m  + (LookbackBars / 2)], c_d_hh_t,open[m  + (LookbackBars / 2)]);
ObjectSetInteger(chart_id,entry_line,OBJPROP_WIDTH,3);
ObjectSetInteger(chart_id,entry_line,OBJPROP_COLOR,clrCornflowerBlue);

sl_txt = StringFormat("Buy SL %d", i);
ObjectCreate(chart_id,sl_txt,OBJ_TEXT,0,time[m + (LookbackBars / 2)],D);
ObjectSetString(chart_id,sl_txt,OBJPROP_TEXT,"SL");
ObjectSetInteger(chart_id,sl_txt,OBJPROP_COLOR,clrCornflowerBlue);
ObjectSetInteger(chart_id,sl_txt,OBJPROP_FONTSIZE,10);

sl_line = StringFormat("Buy SL Line %d", i);
ObjectCreate(chart_id,sl_line,OBJ_TREND,0,time[m + (LookbackBars / 2)],D,c_d_hh_t,D);
ObjectSetInteger(chart_id,sl_line,OBJPROP_WIDTH,3);
ObjectSetInteger(chart_id,sl_line,OBJPROP_COLOR,clrCornflowerBlue);

tp_txt = StringFormat("Buy TP %d", i);
ObjectCreate(chart_id,tp_txt,OBJ_TEXT,0,time[m +(LookbackBars / 2)],c_d_hh);
ObjectSetString(chart_id,tp_txt,OBJPROP_TEXT,"TP");
ObjectSetInteger(chart_id,tp_txt,OBJPROP_COLOR,clrCornflowerBlue);
ObjectSetInteger(chart_id,tp_txt,OBJPROP_FONTSIZE,10);

tp_line = StringFormat("Buy TP Line %d", i);
ObjectCreate(chart_id,tp_line,OBJ_TREND,0,time[m + (LookbackBars / 2)],c_d_hh,c_d_hh_t,c_d_hh);
ObjectSetInteger(chart_id,tp_line,OBJPROP_WIDTH,3);
ObjectSetInteger(chart_id,tp_line,OBJPROP_COLOR,clrCornflowerBlue);

Ausgabe:

Abbildung 14. Signale

Erläuterung:

Das Kaufsignal, der Einstiegspunkt, der Stop-Loss (SL) und der Take-Profit (TP) für das harmonische Muster werden in diesem Abschnitt definiert und als visuelle Objekte auf dem Chart erstellt. Um sicherzustellen, dass die Positionen im Chart leicht gepflegt und identifiziert werden können, speichern die Variablen buy_txt, sell_txt, entry_line, tp_line, sl_line, tp_txt und sl_txt eindeutige Namen für die entsprechenden Objekte. Am Einstiegspunkt ist das buy_txt-Objekt eine Textbeschriftung, die „BUY“ lautet und die Richtung des Handels angibt. Das Handels-Setup wird dank der entry_line, einer horizontalen Trendlinie, die den Einstiegskurs bei open[m + (LookbackBars / 2)] anzeigt, deutlich visualisiert.

Ebenso werden die Stop-Loss-Marke und die zugehörige Trendlinie mit sl_txt bzw. sl_line bezeichnet und befinden sich beide bei D, dem niedrigsten tiefen Umkehrpunk des Musters. Der Stop-Loss sorgt dafür, dass der Handel hinfällig wird, wenn der Kurs über diese Schwelle steigt. Tp_txt und tp_line, die sich auf c_d_hh, dem vorangegangenen hoher Umkehrpunkt, befinden, geben das Take-Profit-Niveau an. Diese grafischen Elemente sind in einer bestimmten Farbe (clrCornflowerBlue) gehalten, sodass Sie wichtige Handelsniveaus im Chart schnell erkennen können. Diese Komponenten unterstützen die Entwicklung einer geordneten und transparenten Handelsstrategie auf der Grundlage des harmonischen Musters.


3. Aufbau eines harmonischen Abwärts-Muster

Die gleiche Logik, die wir zur Identifizierung von harmonischen Aufwärts-Mustern verwendet haben, wird in diesem Teil für Abwärts-Muster modifiziert. Es ist nicht nötig, jedes Merkmal übermäßig zu betonen, da dies nur das Gegenteil des Aufwärts-Musters ist. Ein hoher Umkehrpunkt wird nun durch X dargestellt, ein tiefer Umkehrpunk durch A, ein hoher Umkehrpunkt durch B, ein tiefer Umkehrpunk durch C und der abschließende hohe Umkehrpunkt durch D. Dies ist der Hauptunterschied. Dies garantiert, dass das Muster ein Abwärts-Szenario abbildet und einen möglichen Verkaufszeitpunkt anzeigt.

Der B-Punkt wird weiterhin anhand der Fibonacci-Retracement-Levels überprüft, um sicherzustellen, dass er sich innerhalb des entsprechenden Bereichs im Verhältnis zum XA-Schenkel befindet. In ähnlicher Weise wird das Muster durch Trendlinien, Dreiecke und andere Chart-Elemente abgegrenzt, aber ihre Position wird geändert, um der Abwärts-Struktur zu entsprechen. Der Einstieg wird auf den Index D plus die Hälfte der LookbackBars gesetzt, der Take-Profit (TP) auf den Punkt C und der Stop-Loss (SL) auf den Punkt D. Die gleiche Logik gilt, da es sich um die Umkehrung des Aufwärts-Musters handelt; daher werden wir die Argumente nicht noch einmal in aller Ausführlichkeit erläutern.

Beispiel:

int x_highest_index;   // Stores the index of the highest price point (X) in the pattern
double x_a_hh;         // Holds the price value of the swing high at point X
datetime x_a_hh_t;     // Stores the timestamp of when the swing high at X occurred

int a_lowest_index;   // Stores the index of the lowest price point (A) in the pattern
double a_b_ll;        // Holds the price value of the swing low at point A
datetime a_b_ll_t;    // Stores the timestamp of when the swing low at A occurred

int b_highest_index;   // Stores the index of the highest price point (B) in the pattern
double b_c_hh;         // Holds the price value of the swing high at point B
datetime b_c_hh_t;     // Stores the timestamp of when the swing high at B occurred
int c_lowest_index;   // Stores the index of the lowest price point (C) in the pattern
double c_d_ll;        // Holds the price value of the swing low at point C
datetime c_d_ll_t;    // Stores the timestamp of when the swing low at C occurred
if(rates_total >= bars_check)
  {
   for(int i = rates_total - bars_check; i < rates_total - LookbackBars; i++)
     {
      if(IsSwingHigh(high, i, LookbackBars))
        {

         X = high[i];                   // Assign the highest price at index 'i' to X
         X_time = time[i];              // Assign the corresponding time value to X_time
         X_line = StringFormat("XHigh%d", i);  // Create a unique string identifier for the X-high trendline
         X_letter = StringFormat("XB%d", i);   // Create a unique string identifier for the X-high label

         for(int j = i; j < rates_total - LookbackBars; j++)
           {
            if(IsSwingLow(low, j, LookbackBars) && time[j] > X_time)
              {
               A = low[j];                    // Assign the lowest price at index 'j' to A
               A_time = time[j];               // Assign the corresponding time value to A_time
               A_line = StringFormat("ALow%d", j);  // Create a unique string identifier for the A-low trendline
               A_letter = StringFormat("AB%d", j);  // Create a unique string identifier for the A-low label

               for(int k = j; k < rates_total - LookbackBars; k++)
                 {
                  if(IsSwingHigh(high, k, LookbackBars) && time[k] > A_time)
                    {

                     B = high[k];                    // Assign the highest price at index 'k' to B
                     B_time = time[k];                // Assign the corresponding time value to B_time
                     B_line = StringFormat("BHigh%d", k);  // Create a unique string identifier for the B-high trendline
                     B_letter = StringFormat("BB%d", k);   // Create a unique string identifier for the B-high label

                     for(int l = k; l < rates_total - LookbackBars; l++)
                       {
                        if(IsSwingLow(low, l, LookbackBars) && time[l] > B_time)
                          {

                           C = low[l];                      // Assign the lowest price at index 'l' to C
                           C_time = time[l];                // Assign the corresponding time value to C_time
                           C_line = StringFormat("CLow%d", l);  // Create a unique string identifier for the C-low trendline
                           C_letter = StringFormat("CB%d", l);   // Create a unique string identifier for the C-low label

                           for(int m = l; m < rates_total - (LookbackBars / 2); m++)
                             {
                              if(IsSwingHigh(high, m, LookbackBars / 2) && time[m] > C_time)
                                {
                                 D = high[m];                      // Assign the highest price at index 'm' to D
                                 D_time = time[m];                 // Assign the corresponding time value to D_time
                                 D_line = StringFormat("DHigh%d", m);  // Create a unique string identifier for the D-high trendline
                                 D_letter = StringFormat("DB%d", m);   // Create a unique string identifier for the D-high label

                                 // C - D Segment: Find the lowest low between C and D
                                 c_d_bars = Bars(_Symbol, PERIOD_CURRENT, C_time, D_time); // Count the number of bars between C and D
                                 c_lowest_index = ArrayMinimum(low, l, c_d_bars); // Find the index of the lowest low in the range

                                 c_d_ll = low[c_lowest_index]; // Store the lowest low (C - D lowest point)
                                 c_d_ll_t = time[c_lowest_index]; // Store the corresponding time for C - D

                                 // B - C Segment: Find the highest high between B and C
                                 b_c_bars = Bars(_Symbol, PERIOD_CURRENT, B_time, c_d_ll_t); // Count the number of bars between B and C
                                 b_highest_index = ArrayMaximum(high, k, b_c_bars); // Find the index of the highest high in the range

                                 b_c_hh = high[b_highest_index]; // Store the highest high (B - C highest point)
                                 b_c_hh_t = time[b_highest_index]; // Store the corresponding time for B - C

                                 // A - B Segment: Find the lowest low between A and B
                                 a_b_bars = Bars(_Symbol, PERIOD_CURRENT, A_time, b_c_hh_t); // Count the number of bars between A and B
                                 a_lowest_index = ArrayMinimum(low, j, a_b_bars); // Find the index of the lowest low in the range

                                 a_b_ll = low[a_lowest_index]; // Store the lowest low (A - B lowest point)
                                 a_b_ll_t = time[a_lowest_index]; // Store the corresponding time for A - B

                                 // X - A Segment: Find the highest high between X and A
                                 x_a_bars = Bars(_Symbol, PERIOD_CURRENT, X_time, a_b_ll_t); // Count the number of bars between X and A
                                 x_highest_index = ArrayMaximum(high, i, x_a_bars); // Find the index of the highest high in the range

                                 x_a_hh = high[x_highest_index]; // Store the highest high (X - A highest point)
                                 x_a_hh_t = time[x_highest_index]; // Store the corresponding time for X - A

                                 // Fibonacci Retracement Levels: Calculate 61.8% and 78.6% retracement levels from X to A
                                 lvl_61_8 = a_b_ll + ((61.8 / 100) * (x_a_hh - a_b_ll)); // 61.8% retracement level
                                 lvl_78_6 = a_b_ll + ((78.6 / 100) * (x_a_hh - a_b_ll)); // 78.6% retracement level

                                 if((b_c_hh >= lvl_61_8 && b_c_hh <= lvl_78_6) && (D > x_a_hh))
                                   {
                                    //D
                                    ObjectCreate(chart_id, D_letter, OBJ_TEXT, 0, D_time, D); // Create text object for D
                                    ObjectSetString(chart_id, D_letter, OBJPROP_TEXT, "D"); // Set the text to "D".
                                    ObjectSetInteger(chart_id,D_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                                    ObjectCreate(chart_id,D_line,OBJ_TREND,0,D_time,D,time[m+LookbackBars],D); // Create line to mark D
                                    ObjectSetInteger(chart_id,D_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

                                    //C
                                    ObjectCreate(chart_id, C_letter, OBJ_TEXT, 0, c_d_ll_t, c_d_ll); // Create text object for C
                                    ObjectSetString(chart_id, C_letter, OBJPROP_TEXT, "C"); // Set the text to "C".
                                    ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                                    ObjectCreate(chart_id,C_line,OBJ_TREND,0,c_d_ll_t,C,time[c_lowest_index+LookbackBars],c_d_ll); // Create line to mark C
                                    ObjectSetInteger(chart_id,C_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

                                    //B
                                    ObjectCreate(chart_id, B_letter, OBJ_TEXT, 0, b_c_hh_t, b_c_hh); // Create text object for B
                                    ObjectSetString(chart_id, B_letter, OBJPROP_TEXT, "B"); // Set the text to "B".
                                    ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                                    ObjectCreate(chart_id,B_line,OBJ_TREND,0,b_c_hh_t,b_c_hh,time[b_highest_index+LookbackBars],b_c_hh); // Create line to mark B
                                    ObjectSetInteger(chart_id,B_line,OBJPROP_COLOR,clrMidnightBlue); // Set line color to MidnightBlue

                                    //A
                                    ObjectCreate(chart_id, A_letter, OBJ_TEXT, 0, a_b_ll_t, a_b_ll); // Create text object for A
                                    ObjectSetString(chart_id, A_letter, OBJPROP_TEXT, "A"); // Set the text to "A".
                                    ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                                    ObjectCreate(chart_id,A_line,OBJ_TREND,0,a_b_ll_t,a_b_ll,time[a_lowest_index+LookbackBars],a_b_ll); // Create line to mark A
                                    ObjectSetInteger(chart_id,A_line,OBJPROP_COLOR,clrGreen); // Set line color to green

                                    //X
                                    ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, x_a_hh_t, x_a_hh); // Create text object for X
                                    ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".
                                    ObjectCreate(chart_id,X_line,OBJ_TREND,0,x_a_hh_t,x_a_hh,time[x_highest_index+LookbackBars],x_a_hh); // Create line to mark X

                                    XA_line = StringFormat("XA LineB%d", m); // Unique name for the XA line.
                                    ObjectCreate(chart_id,XA_line,OBJ_TREND,0,x_a_hh_t,x_a_hh,a_b_ll_t,a_b_ll); // Create line to connect XA
                                    ObjectSetInteger(chart_id,XA_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,XA_line,OBJPROP_WIDTH,3); // Line width

                                    AB_line = StringFormat("AB LineB%d", m); // Unique name for the AB line.
                                    ObjectCreate(chart_id,AB_line,OBJ_TREND,0,a_b_ll_t,a_b_ll,b_c_hh_t,b_c_hh); // Create line to connect AB
                                    ObjectSetInteger(chart_id,AB_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,AB_line,OBJPROP_WIDTH,3); // Line width

                                    BC_line = StringFormat("BC LineB%d", m); // Unique name for the BC line.
                                    ObjectCreate(chart_id,BC_line,OBJ_TREND,0,b_c_hh_t,b_c_hh,c_d_ll_t,c_d_ll); // Create line to connect BC
                                    ObjectSetInteger(chart_id,BC_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,BC_line,OBJPROP_WIDTH,3); // Line width

                                    CD_line = StringFormat("CD LineB%d", m); // Unique name for the CD line.
                                    ObjectCreate(chart_id,CD_line,OBJ_TREND,0,c_d_ll_t,c_d_ll,D_time,D); // Create line to connect CD
                                    ObjectSetInteger(chart_id,CD_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,CD_line,OBJPROP_WIDTH,3); // Line width

                                    //XA FIBO
                                    XA_fibo = StringFormat("XA FIB0 B%d", i);
                                    ObjectCreate(chart_id,XA_fibo,OBJ_FIBO,0,x_a_hh_t,x_a_hh,a_b_ll_t,a_b_ll); // Create XA fibo
                                    ObjectSetInteger(chart_id,XA_fibo,OBJPROP_LEVELS,6); // Number of default levels
                                    for(int i = 1; i <= 6; i++)
                                      {
                                       ObjectSetInteger(chart_id,XA_fibo,OBJPROP_LEVELCOLOR,i,clrSaddleBrown); // Set each level color to SaddleBrown
                                      }

                                    fibo_618_786 = StringFormat("Fibo 78.6 - 61.8 B%d", i);
                                    fibo_78_6_txt = StringFormat("Fibo 78.6 Text B%d", i);

                                    ObjectCreate(chart_id,fibo_618_786,OBJ_RECTANGLE,0,x_a_hh_t, lvl_61_8,b_c_hh_t,lvl_78_6); // Create rectangle object marking 61.8 and 78.6
                                    ObjectSetInteger(chart_id,fibo_618_786,OBJPROP_COLOR,clrSaddleBrown); // Set color to clrSaddleBrown

                                    ObjectCreate(chart_id,fibo_78_6_txt,OBJ_TEXT,0,b_c_hh_t,lvl_78_6); // Create text for level 78.6
                                    ObjectSetString(chart_id,fibo_78_6_txt,OBJPROP_TEXT,"78.6"); // Text to be displayed
                                    ObjectSetInteger(chart_id,fibo_78_6_txt,OBJPROP_COLOR,clrSaddleBrown); // Set text color
                                    ObjectSetInteger(chart_id,fibo_78_6_txt,OBJPROP_FONTSIZE,8); // Set text size
                                    // Create and format the first bearish harmonic pattern (XAB)
                                    X_A_B = StringFormat("XAB B%d", i);
                                    ObjectCreate(chart_id, X_A_B, OBJ_TRIANGLE, 0, x_a_hh_t, x_a_hh, a_b_ll_t, a_b_ll, b_c_hh_t, b_c_hh);
                                    ObjectSetInteger(chart_id, X_A_B, OBJPROP_COLOR, clrMistyRose); // Set color for the pattern
                                    ObjectSetInteger(chart_id, X_A_B, OBJPROP_FILL, true); // Fill the triangle shape

                                    // Create and format the second bearish harmonic pattern (BCD)
                                    B_C_D = StringFormat("BCD B%d", i);
                                    ObjectCreate(chart_id, B_C_D, OBJ_TRIANGLE, 0, b_c_hh_t, b_c_hh, c_d_ll_t, c_d_ll, D_time, D);
                                    ObjectSetInteger(chart_id, B_C_D, OBJPROP_COLOR, clrMistyRose);
                                    ObjectSetInteger(chart_id, B_C_D, OBJPROP_FILL, true);

                                    // Create and format the SELL text at the entry position
                                    sell_txt = StringFormat("Sell %d", i);
                                    ObjectCreate(chart_id, sell_txt, OBJ_TEXT, 0, time[m + (LookbackBars / 2)], open[m + (LookbackBars / 2)]);
                                    ObjectSetString(chart_id, sell_txt, OBJPROP_TEXT, "SELL");
                                    ObjectSetInteger(chart_id, sell_txt, OBJPROP_COLOR, clrMagenta); // Set text color
                                    ObjectSetInteger(chart_id, sell_txt, OBJPROP_FONTSIZE, 10); // Set font size

                                    // Create and format the SELL entry line
                                    entry_line = StringFormat("Sell Entry Line %d", i);
                                    ObjectCreate(chart_id, entry_line, OBJ_TREND, 0, time[m + (LookbackBars / 2)], open[m + (LookbackBars / 2)], c_d_ll_t, open[m + (LookbackBars / 2)]);
                                    ObjectSetInteger(chart_id, entry_line, OBJPROP_WIDTH, 3); // Set line thickness
                                    ObjectSetInteger(chart_id, entry_line, OBJPROP_COLOR, clrMagenta); // Set line color

                                    // Create and format the Stop Loss (SL) text
                                    sl_txt = StringFormat("Sell SL %d", i);
                                    ObjectCreate(chart_id, sl_txt, OBJ_TEXT, 0, time[m + (LookbackBars / 2)], D);
                                    ObjectSetString(chart_id, sl_txt, OBJPROP_TEXT, "SL");
                                    ObjectSetInteger(chart_id, sl_txt, OBJPROP_COLOR, clrMagenta);
                                    ObjectSetInteger(chart_id, sl_txt, OBJPROP_FONTSIZE, 10);

                                    // Create and format the Stop Loss (SL) line
                                    sl_line = StringFormat("Sell SL Line %d", i);
                                    ObjectCreate(chart_id, sl_line, OBJ_TREND, 0, time[m + (LookbackBars / 2)], D, c_d_ll_t, D);
                                    ObjectSetInteger(chart_id, sl_line, OBJPROP_WIDTH, 3);
                                    ObjectSetInteger(chart_id, sl_line, OBJPROP_COLOR, clrMagenta);

                                    // Create and format the Take Profit (TP) text
                                    tp_txt = StringFormat("Sell TP %d", i);
                                    ObjectCreate(chart_id, tp_txt, OBJ_TEXT, 0, time[m + (LookbackBars / 2)], c_d_ll);
                                    ObjectSetString(chart_id, tp_txt, OBJPROP_TEXT, "TP");
                                    ObjectSetInteger(chart_id, tp_txt, OBJPROP_COLOR, clrMagenta);
                                    ObjectSetInteger(chart_id, tp_txt, OBJPROP_FONTSIZE, 10);

                                    // Create and format the Take Profit (TP) line
                                    tp_line = StringFormat("Sell TP Line %d", i);
                                    ObjectCreate(chart_id, tp_line, OBJ_TREND, 0, time[m + (LookbackBars / 2)], c_d_ll, c_d_ll_t, c_d_ll);
                                    ObjectSetInteger(chart_id, tp_line, OBJPROP_WIDTH, 3);
                                    ObjectSetInteger(chart_id, tp_line, OBJPROP_COLOR, clrMagenta);

                                    if(overlap == false)
                                      {
                                       i = m;
                                      }
                                    if(overlap == true)
                                      {
                                       i = i;
                                      }
                                    break;

                                   }

                                 break;

                                }
                             }

                           break;

                          }
                       }

                     break;

                    }
                 }

               break;

              }
           }

        }
     }
  }

Ausgabe:

Abbildung 15. Abwärts-Muster

Erläuterung:

Der erste Schritt des Erkennungsverfahrens besteht darin, einen hohen Umkehrpunkt bei X zu finden, das den Beginn des Musters kennzeichnet. Ein tiefer Umkehrpunkt (A), ein hoher Umkehrpunkt (B), ein tiefer Umkehrpunkt (C) und ein hoher Umkehrpunkt (D) sind die nächsten Punkte, nach denen es sucht. Eine rechtmäßige Struktur des Musters wird dadurch gewährleistet, dass jeder Punkt anhand seiner relativen Position zum vorhergehenden Punkt überprüft wird. Die Validierung des Musters hängt hauptsächlich von den Retracement-Niveaus ab, insbesondere von den 61,8 %- und 78,6 %-Fibonacci-Retracements von X nach A. Eine mögliche Verkaufs-Konfiguration wird gefunden, wenn diese Anforderungen erfüllt sind und D größer ist als X.

Ausführliche Erklärungen werden nicht wiederholt, da die harmonischen Aufwärts- und Abwärts-Muster ähnlich sind. Der Hauptunterschied besteht darin, dass die Aufwärts-Form dieses Musters einen Kursanstieg vorhersagt, während dieses Muster einen Kursrückgang vorhersagt. Die Ausrichtung des Musters und die damit verbundene Handelsrichtung sind die einzigen Unterschiede. Ansonsten sind die Grundgedanken dieselben.


Schlussfolgerung

In diesem Artikel haben wir untersucht, wie man einen Harmonic Patterns-ähnlichen Indikator mit Hilfe von MetaTrader 5 Chart-Objekten erstellt. Wir haben uns mit der Logik beschäftigt, die hinter der Erkennung von wichtigen Umkehrpunkten, der Strukturierung des Musters und der Validierung mithilfe von Fibonacci-Retracement-Levels steht. Anhand von Auf- und Abwärts-Mustern haben wir gezeigt, wie man potenzielle Handelsmöglichkeiten auf der Grundlage der Preisentwicklung erkennen kann. Mit diesem Ansatz können Sie harmonische Formationen direkt auf ihren Charts visualisieren, was eine bessere Entscheidungsfindung ermöglicht, ohne sich auf traditionelle Indikatorpuffer zu verlassen. Diese Methode erhöht die Flexibilität und bietet eine solide Grundlage für die weitere Anpassung und Verfeinerung von musterbasierten Handelsstrategien.

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

Letzte Kommentare | Zur Diskussion im Händlerforum (6)
Israel Pelumi Abioye
Israel Pelumi Abioye | 1 Apr. 2025 in 12:03
Simon Simson #:
Vielen Dank für Ihre gute Arbeit an dieser MQL5-Serie .
Hallo Simon.
Vielen Dank für deine netten Worte.
Oluwatosin Mary Babalola
Oluwatosin Mary Babalola | 1 Apr. 2025 in 12:15
Wow, das ist der beste, seit ich Ihre Artikel verfolge. Machen Sie weiter so
Israel Pelumi Abioye
Israel Pelumi Abioye | 1 Apr. 2025 in 13:02
Oluwatosin Mary Babalola #:
Wow, das ist der beste, seit ich Ihre Artikel verfolge. Machen Sie weiter so
Ich danke Ihnen.
Louai Habiche
Louai Habiche | 19 Apr. 2025 in 17:03

Ehrfürchtig Sie tun groß mit youre articls beste regrates

Wir können einen Alarm auslösen, wenn der Artikel erscheint!

Israel Pelumi Abioye
Israel Pelumi Abioye | 20 Apr. 2025 in 10:37
Louai Habiche #:

fantastisch Ihr macht das großartig mit Euren Artikeln beste Gratulation

Wir können einen Alarm auslösen, wenn der Artikel erscheint!

Hallo, vielen Dank für Ihre freundlichen Worte. Es ist möglich, dies mit der Funktion "PlaySound()" zu tun.

MQL5-Assistent-Techniken, die Sie kennen sollten (Teil 58): Reinforcement Learning (DDPG) mit gleitendem Durchschnitt und stochastischen Oszillatormustern MQL5-Assistent-Techniken, die Sie kennen sollten (Teil 58): Reinforcement Learning (DDPG) mit gleitendem Durchschnitt und stochastischen Oszillatormustern
Der gleitende Durchschnitt und der Stochastik-Oszillator sind sehr gebräuchliche Indikatoren, deren kollektive Muster wir im vorangegangenen Artikel mittels eines überwachten Lernnetzwerks untersucht haben, um zu sehen, welche „Muster haften bleiben“ würden. Wir gehen mit unseren Analysen aus diesem Artikel noch einen Schritt weiter, indem wir die Auswirkungen des Reinforcement Learnings auf die Leistung untersuchen, wenn es mit diesem trainierten Netz eingesetzt wird. Die Leser sollten beachten, dass sich unsere Tests auf ein sehr begrenztes Zeitfenster beziehen. Nichtsdestotrotz nutzen wir weiterhin die minimalen Programmieranforderungen, die der MQL5-Assistent bietet, um dies zu zeigen.
Erstellen von selbstoptimierenden Expert Advisor in MQL5 (Teil 6): Selbstanpassende Handelsregeln (II) Erstellen von selbstoptimierenden Expert Advisor in MQL5 (Teil 6): Selbstanpassende Handelsregeln (II)
Dieser Artikel befasst sich mit der Optimierung der RSI-Werte und -Perioden für bessere Handelssignale. Wir stellen Methoden zur Schätzung optimaler RSI-Werte vor und automatisieren die Periodenauswahl mithilfe von Rastersuche und statistischen Modellen. Schließlich implementieren wir die Lösung in MQL5 und setzen Python für die Analyse ein. Unser Ansatz ist pragmatisch und geradlinig, um Ihnen zu helfen, potenziell komplizierte Probleme auf einfache Weise zu lösen.
Statistische Arbitrage durch Mean Reversion im Paarhandel: Den Markt mit Mathematik schlagen Statistische Arbitrage durch Mean Reversion im Paarhandel: Den Markt mit Mathematik schlagen
Dieser Artikel beschreibt die Grundlagen der statistischen Arbitrage auf Portfolioebene. Sein Ziel ist es, das Verständnis der Prinzipien der statistischen Arbitrage für Leser ohne tiefgreifende mathematische Kenntnisse zu erleichtern und einen konzeptionellen Rahmen für den Ausgangspunkt vorzuschlagen. Der Artikel enthält einen funktionierenden Expert Advisor, einige Anmerkungen zu seinem einjährigen Backtest und die entsprechenden Backtest-Konfigurationseinstellungen (.ini-Datei) für die Reproduktion des Experiments.
Erforschung fortgeschrittener maschineller Lerntechniken bei der Darvas Box Breakout Strategie Erforschung fortgeschrittener maschineller Lerntechniken bei der Darvas Box Breakout Strategie
Die von Nicolas Darvas entwickelte Darvas-Box-Breakout-Strategie ist ein technischer Handelsansatz, der potenzielle Kaufsignale erkennt, wenn der Kurs einer Aktie über einen festgelegten Bereich der „Box“ ansteigt, was auf eine starke Aufwärtsdynamik hindeutet. In diesem Artikel werden wir dieses Strategiekonzept als Beispiel anwenden, um drei fortgeschrittene Techniken des maschinellen Lernens zu untersuchen. Dazu gehören die Verwendung eines maschinellen Lernmodells zur Generierung von Signalen anstelle von Handelsfiltern, die Verwendung von kontinuierlichen Signalen anstelle von diskreten Signalen und die Verwendung von Modellen, die auf verschiedenen Zeitrahmen trainiert wurden, um Handelsgeschäfte zu bestätigen.