English 日本語
preview
Automatisieren von Handelsstrategien in MQL5 (Teil 31): Erstellung eines Price Action 3 Drives Harmonic Pattern Systems

Automatisieren von Handelsstrategien in MQL5 (Teil 31): Erstellung eines Price Action 3 Drives Harmonic Pattern Systems

MetaTrader 5Handel |
109 3
Allan Munene Mutiiria
Allan Munene Mutiiria

Einführung

In unserem letzten Artikel (Teil 30) haben wir das System des Musters AB=CD in MetaQuotes Language 5 (MQL5) entwickelt, das das steigende und fallende harmonische Muster AB=CD unter Verwendung von Fibonacci-Verhältnisse erkennt und Handelsgeschäfte mit berechneten Einstiegs-, Stop-Loss- und Take-Profit-Levels automatisiert, die durch Chart-Objekte wie Dreiecke und Trendlinien visualisiert werden. In Teil 31 erstellen wir das Mustersystem 3 Drives, das das steigende und fallende harmonische Muster 3 Drives durch Umkehrpunkte und spezifische Fibonacci-Retracements und -Extensions identifiziert. Das System führt Handelsgeschäfte mit anpassbaren Take-Profit- und Stop-Loss-Optionen aus, die durch visuelle Dreiecke, Trendlinien und Kennzeichnungen für eine klare Musterdarstellung ergänzt werden. Wir werden die folgenden Themen behandeln:

  1. Das Verständnis des System der harmonische Muster 3 Drives
  2. Implementation in MQL5
  3. Backtests
  4. Schlussfolgerung

Am Ende haben Sie eine robuste MQL5-Strategie für den Handel mit harmonischen 3-Drives-Mustern, die Sie nur noch anpassen müssen – legen wir los!


Das Verständnis des System der harmonische Muster 3 Drives

Das Muster 3 Drives ist eine harmonische Handelsformation, die durch sechs wichtige Umkehrpunkte – A, B, C, D, E und F – definiert ist, die in steigender oder fallender Form existieren und dazu dienen, Umkehrzonen durch eine Reihe von drei aufeinanderfolgenden Preisbewegungen mit spezifischen Fibonacci-Retracements und Extensions zu identifizieren. In einem steigenden 3-Drives-Muster bildet die Struktur eine Hoch-Tief-Hoch-Tief-Hoch-Tief-Sequenz, in der A ein hoher, B ein tiefer (erster Drive), C ein hoher, D ein tiefer (zweiter Drive), E ein hoher und F ein tiefer (dritter Drive, unter D und B) Umkehrpunkt ist, wobei jedes Retracement (BC, DE) bei etwa 0.618 oder 0,786 des vorherigen Schwunges und jeder Schwung (CD, EF) erstreckt sich von 1,13 bis 1,618 des vorherigen Retracements; ein fallendes Muster kehrt diese Sequenz mit F über D und B um:

Fallendes harmonisches 3-Drives-Muster:

FALLENDES HARMONISCHES 3-DRIVES-MUSTER

Steigendes harmonisches 3-Drives-Muster:

STEIGENDES HARMONISCHES 3-DRIVES-MUSTER

Unser Ansatz umfasst die Erkennung dieser Umkehrpunkte innerhalb eines bestimmten Balkenbereichs, die Validierung der Kanten des Musters anhand von Fibonacci-Kriterien, die Visualisierung der Struktur A-B-C-D-E-F mit Chart-Objekten wie Dreiecken und Trendlinien und die Ausführung von Trades am F-Punkt mit anpassbaren Stop-Loss- (Fibonacci-basiert oder fest) und Take-Profit-Levels (0,382, 0,618 oder Umkehrpunkt E), um von erwarteten Umkehr zu profitieren. Kommen wir nun zur Umsetzung!


Implementation in MQL5

Um das Programm in MQL5 zu erstellen, öffnen wir den MetaEditor, gehen zum Navigator, suchen den Ordner der Indikatoren, klicken auf die Registerkarte „Neu“ und folgen den Anweisungen, um die Datei zu erstellen. Sobald das erledigt ist, müssen wir in der Programmierumgebung einige globale Variablen deklarieren, die wir im gesamten Programm verwenden werden.

//+------------------------------------------------------------------+
//|                                          3 Drives Pattern EA.mq5 |
//|                        Copyright 2025, Forex Algo-Trader, Allan. |
//|                                 "https://t.me/Forex_Algo_Trader" |
//+------------------------------------------------------------------+
#property copyright "Forex Algo-Trader, Allan"
#property link "https://t.me/Forex_Algo_Trader"
#property version "1.00"
#property description "This EA trades based on 3 Drives Strategy"
#property strict

//--- Include the trading library for order functions
#include <Trade\Trade.mqh>   //--- Include Trade library
CTrade obj_Trade;            //--- Instantiate a obj_Trade object
//--- Enumeration for TP levels
enum ENUM_TAKE_PROFIT_LEVEL {
   TP1 = 1, // 0.382 Fibonacci Retracement
   TP2 = 2, // 0.618 Fibonacci Retracement
   TP3 = 3  // Pivot E Price
};
//--- Enumeration for SL types
enum ENUM_STOP_LOSS_TYPE {
   SL_FIBO = 1, // Fibonacci Extension
   SL_FIXED = 2 // Fixed Points
};
//--- Input parameters for user configuration
input int PivotLeft = 5;                              // Number of bars to the left for pivot check
input int PivotRight = 5;                             // Number of bars to the right for pivot check
input double Tolerance = 0.10;                        // Allowed deviation (10% of move)
input double LotSize = 0.01;                          // Lot size for new orders
input bool AllowTrading = true;                       // Enable or disable trading
input ENUM_TAKE_PROFIT_LEVEL TakeProfitLevel = TP2;   // Take Profit Level
input ENUM_STOP_LOSS_TYPE StopLossType = SL_FIBO;     // Stop Loss Type
input double SL_FiboExtension = 1.618;                // Fibonacci Extension for SL
input double SL_FixedPoints = 50;                     // Fixed Points for SL (in points)
//---------------------------------------------------------------------------
//--- 3 Drives pattern definition:
//
//--- Bullish 3 Drives:
//--- Pivots (A-B-C-D-E-F): A swing high, B swing low (drive 1), C swing high, D swing low (drive 2), E swing high, F swing low (drive 3).
//--- Retracements at 0.618, drives at 1.272 extensions.
//
//--- Bearish 3 Drives:
//--- Pivots (A-B-C-D-E-F): A swing low, B swing high (drive 1), C swing low, D swing high (drive 2), E swing low, F swing high (drive 3).
//--- Retracements at 0.618, drives at 1.272 extensions.
//---------------------------------------------------------------------------
//--- Structure for a pivot point
struct Pivot {
   datetime time; //--- Bar time of the pivot
   double price;  //--- Pivot price (High for swing high, low for swing low)
   bool isHigh;   //--- True if swing high; false if swing low
};
//--- Global dynamic array for storing pivots in chronological order
Pivot pivots[]; //--- Declare a dynamic array to hold identified pivot points
//--- Global variables to lock in a pattern (avoid trading on repaint)
int g_patternFormationBar = -1; //--- Bar index where the pattern was formed (-1 means none)
datetime g_lockedPatternA = 0;  //--- The key A pivot time for the locked pattern
//--- Global array to track traded patterns (using A.time as identifier)
datetime tradedPatterns[];

Um die Grundlage für das Muster 3 Drives zu schaffen, binden wir zunächst die Bibliothek „<Trade\Trade.mqh>“ ein und instanziieren „obj_Trade“ als CTrade-Objekt, um Handelsoperationen wie die Ausführung von Kauf- und Verkaufsaufträgen zu verwalten. Dann definieren wir die Enumeration „ENUM_TAKE_PROFIT_LEVEL“ (TP1 für 0,382, TP2 für 0,618, TP3 für den Preis des Umkehrpunkts E) und „ENUM_STOP_LOSS_TYPE“ (SL_FIBO für die Fibonacci-Extension, SL_FIXED für Fixpunkte) für flexible Handelseinstellungen und setzen die Eingabeparameter: „PivotLeft“ und „PivotRight“ auf 5 Balken für die Umkehrpunkterkennung, „Tolerance“ bei 0.10 für die Fibonacci-Abweichung, „LotSize“ bei 0.01, „AllowTrading“ auf true, „TakeProfitLevel“ auf TP2, „StopLossType“ auf SL_FIBO, „SL_FiboExtension“ auf 1.618, und „SL_FixedPoints“ auf 50.

Als Nächstes definieren wir die Struktur „Pivot“ mit „time“, „price“ und „isHigh“, um Umkehrpunkte zu speichern, deklarieren „pivots“ als dynamisches Array und initialisieren die globalen Variablen „g_patternFormationBar“ auf -1, „g_lockedPatternA“ auf 0 für die Mustersperrung und „tradedPatterns“ als Array, um gehandelte Muster unter Verwendung der Zeit von A zu verfolgen. Dieser Aufbau bildet das Grundgerüst für die Erkennung und den Handel mit 3 Drives-Mustern. Zur Visualisierung können wir Funktionen zum Zeichnen von Linien, Beschriftungen und Dreiecken verwenden.

//+------------------------------------------------------------------+
//| Helper: Draw a filled triangle                                   |
//+------------------------------------------------------------------+
void DrawTriangle(string name, datetime t1, double p1, datetime t2, double p2, datetime t3, double p3, color cl, int width, bool fill, bool back) {
   //--- Attempt to create a triangle object with three coordinate points
   if(ObjectCreate(0, name, OBJ_TRIANGLE, 0, t1, p1, t2, p2, t3, p3)) {
      //--- Set the triangle's color
      ObjectSetInteger(0, name, OBJPROP_COLOR, cl);
      //--- Set the triangle's line style to solid
      ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_SOLID);
      //--- Set the line width of the triangle
      ObjectSetInteger(0, name, OBJPROP_WIDTH, width);
      //--- Determine if the triangle should be filled
      ObjectSetInteger(0, name, OBJPROP_FILL, fill);
      //--- Set whether the object is drawn in the background
      ObjectSetInteger(0, name, OBJPROP_BACK, back);
   }
}
//+------------------------------------------------------------------+
//| Helper: Draw a trend line                                        |
//+------------------------------------------------------------------+
void DrawTrendLine(string name, datetime t1, double p1, datetime t2, double p2, color cl, int width, int style) {
   //--- Create a trend line object connecting two points
   if(ObjectCreate(0, name, OBJ_TREND, 0, t1, p1, t2, p2)) {
      //--- Set the trend line's color
      ObjectSetInteger(0, name, OBJPROP_COLOR, cl);
      //--- Set the trend line's style (solid, dotted, etc.)
      ObjectSetInteger(0, name, OBJPROP_STYLE, style);
      //--- Set the width of the trend line
      ObjectSetInteger(0, name, OBJPROP_WIDTH, width);
   }
}
//+------------------------------------------------------------------+
//| Helper: Draw a dotted trend line                                 |
//+------------------------------------------------------------------+
void DrawDottedLine(string name, datetime t1, double p, datetime t2, color lineColor) {
   //--- Create a horizontal trend line at a fixed price level with dotted style
   if(ObjectCreate(0, name, OBJ_TREND, 0, t1, p, t2, p)) {
      //--- Set the dotted line's color
      ObjectSetInteger(0, name, OBJPROP_COLOR, lineColor);
      //--- Set the line style to dotted
      ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DOT);
      //--- Set the line width to 1
      ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);
   }
}
//+------------------------------------------------------------------+
//| Helper: Draw anchored text label (for pivots)                    |
//| If isHigh is true, anchor at the bottom (label appears above);   |
//| if false, anchor at the top (label appears below).               |
//+------------------------------------------------------------------+
void DrawTextEx(string name, string text, datetime t, double p, color cl, int fontsize, bool isHigh) {
   //--- Create a text label object at the specified time and price
   if(ObjectCreate(0, name, OBJ_TEXT, 0, t, p)) {
      //--- Set the text of the label
      ObjectSetString(0, name, OBJPROP_TEXT, text);
      //--- Set the color of the text
      ObjectSetInteger(0, name, OBJPROP_COLOR, cl);
      //--- Set the font size for the text
      ObjectSetInteger(0, name, OBJPROP_FONTSIZE, fontsize);
      //--- Set the font type and style
      ObjectSetString(0, name, OBJPROP_FONT, "Arial Bold");
      //--- Anchor the text depending on whether it's a swing high or low
      if(isHigh)
         ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_BOTTOM);
      else
         ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_TOP);
      //--- Center-align the text
      ObjectSetInteger(0, name, OBJPROP_ALIGN, ALIGN_CENTER);
   }
}

Wir fahren fort mit der Implementierung von Visualisierungsfunktionen, um klare Chartdarstellungen des harmonischen 3-Drives-Musters und seiner Handelsstufen zu erstellen. Zunächst entwickeln wir die Funktion „DrawTriangle“, die ObjectCreate verwendet, um ein gefülltes Dreieck (OBJ_TRIANGLE) zu zeichnen, das durch drei Punkte mit Zeiten („t1“, „t2“, „t3“) und Preisen („p1“, „p2“, „p3“), wobei OBJPROP_COLOR auf die angegebene Farbe, „OBJPROP_STYLE“ auf „STYLE_SOLID“, „OBJPROP_WIDTH“ auf die angegebene Breite, „OBJPROP_FILL“ zum Aktivieren oder Deaktivieren des Füllens und „OBJPROP_BACK“ zum Festlegen der Hintergrund- oder Vordergrundplatzierung mit der Funktion ObjectSetInteger gesetzt werden. Anschließend erstellen wir die Funktion „DrawTrendLine“, die eine Trendlinie („OBJ_TREND“) zwischen zwei Punkten zeichnet.

Als Nächstes implementieren wir die Funktion „DrawDottedLine“, die eine horizontale gepunktete Linie (OBJ_TREND) zu einem bestimmten Kurs erzeugt. Zuletzt entwickeln wir die Funktion „DrawTextEx“, die ein Textlabel (OBJ_TEXT) an den Koordinaten („t“, „p“) mit „ObjectCreate“ erstellt, wobei „OBJPROP_TEXT“ auf den angegebenen Text, „OBJPROP_COLOR“, „OBJPROP_FONTSIZE““OBJPROP_COLOR“, „OBJPROP_FONTSIZE“ und „OBJPROP_FONT“ mit ObjectSetString und „ObjectSetInteger“ auf „Arial Bold“ setzen, mit „OBJPROP_ANCHOR“ bei Hochs und bei Tiefs auf der Grundlage von „isHigh“ nach oben bzw. nach unten verankern und mit „OBJPROP_ALIGN“ zentrieren. Wir können nun mit OnTick fortfahren und versuchen, Umkehrpunkte zu identifizieren, die wir später für die Mustererkennung verwenden können. Hier ist die Logik, mit der wir das erreichen.

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick() {
   //--- Declare a static variable to store the time of the last processed bar
   static datetime lastBarTime = 0;
   //--- Get the time of the current confirmed bar
   datetime currentBarTime = iTime(_Symbol, _Period, 1);
   //--- If the current bar time is the same as the last processed, exit
   if(currentBarTime == lastBarTime)
      return;
   //--- Update the last processed bar time
   lastBarTime = currentBarTime;
 
   //--- Clear the pivot array for fresh analysis
   ArrayResize(pivots, 0);
   //--- Get the total number of bars available on the chart
   int barsCount = Bars(_Symbol, _Period);
   //--- Define the starting index for pivot detection (ensuring enough left bars)
   int start = PivotLeft;
   //--- Define the ending index for pivot detection (ensuring enough right bars)
   int end = barsCount - PivotRight;
 
   //--- Loop through bars from 'end-1' down to 'start' to find pivot points
   for(int i = end - 1; i >= start; i--) {
      //--- Assume current bar is both a potential swing high and swing low
      bool isPivotHigh = true;
      bool isPivotLow = true;
      //--- Get the high and low of the current bar
      double currentHigh = iHigh(_Symbol, _Period, i);
      double currentLow = iLow(_Symbol, _Period, i);
      //--- Loop through the window of bars around the current bar
      for(int j = i - PivotLeft; j <= i + PivotRight; j++) {
         //--- Skip if the index is out of bounds
         if(j < 0 || j >= barsCount)
            continue;
         //--- Skip comparing the bar with itself
         if(j == i)
            continue;
         //--- If any bar in the window has a higher high, it's not a swing high
         if(iHigh(_Symbol, _Period, j) > currentHigh)
            isPivotHigh = false;
         //--- If any bar in the window has a lower low, it's not a swing low
         if(iLow(_Symbol, _Period, j) < currentLow)
            isPivotLow = false;
      }
      //--- If the current bar qualifies as either a swing high or swing low
      if(isPivotHigh || isPivotLow) {
         //--- Create a new pivot structure
         Pivot p;
         //--- Set the pivot's time
         p.time = iTime(_Symbol, _Period, i);
         //--- Set the pivot's price depending on whether it is a high or low
         p.price = isPivotHigh ? currentHigh : currentLow;
         //--- Set the pivot type (true for swing high, false for swing low)
         p.isHigh = isPivotHigh;
         //--- Get the current size of the pivots array
         int size = ArraySize(pivots);
         //--- Increase the size of the pivots array by one
         ArrayResize(pivots, size + 1);
         //--- Add the new pivot to the array
         pivots[size] = p;
      }
   }
}

Hier implementieren wir die anfängliche Logik der Ereignisbehandlung durch OnTick. Zunächst deklarieren wir die statische Variable „lastBarTime“, die auf 0 initialisiert wird, um den letzten verarbeiteten Balken zu verfolgen und ihn mit der „currentBarTime“ zu vergleichen, die von iTime bei Shift 1 für das aktuelle Symbol und die aktuelle Periode erhalten wird, wobei wir den Vorgang beenden, wenn er unverändert bleibt, um redundante Verarbeitung zu vermeiden, und die „lastBarTime“ aktualisieren, wenn ein neuer Balken entdeckt wird. Dann leeren wir das Array „pivots“ mit ArrayResize, um eine neue Analyse zu gewährleisten.

Als Nächstes rufen wir die Gesamtzahl der Balken mit Bars ab, legen den Erkennungsbereich der Umkehrpunkte mit „start“ als „PivotLeft“ und „end“ als Gesamtzahl der Balken minus „PivotRight“ fest und gehen die Balken von „end – 1“ bis „start“ durch. Für jeden Balken nehmen wir an, dass es sich um einen hohen („isPivotHigh“ true) und tiefen („isPivotLow“ true) Umkehrpunkt handelt, ermitteln seine Hoch- und Tiefstpreise mit iHigh und iLow und validieren den Umkehrpunkt, indem wir die umliegenden Balken innerhalb von „PivotLeft“ und „PivotRight“ mit „iHigh“ und „iLow“ überprüfen und den Umkehrpunkt ungültig machen, wenn ein benachbarter Balken ein höheres Hoch oder ein niedrigeres Tief aufweist. Wenn sich der Balken als Umkehrpunkt qualifiziert, erstellen wir die Struktur „Pivot“, setzen „time“ mit „iTime“, „price“ auf den Höchst- oder Tiefstwert auf der Grundlage des „isPivotHigh“-Flags und des „isHigh“-Flags und fügen ihn dann mit ArrayResize an das Array „pivots“ an und speichern ihn. Wenn wir die Umkehrpunkt-Struktur ausdrucken, erhalten wir das folgende Array von Daten.

DATEN DER UMKEHRPUNKTE

Aus den Daten können wir die Umkehrpunkte extrahieren, und wenn wir genügend Umkehrpunkte haben, können wir die Muster analysieren und erkennen. Hier ist die Logik, mit der wir das erreichen.

//--- Determine the total number of pivots found
int pivotCount = ArraySize(pivots);
//--- If fewer than six pivots are found, the pattern cannot be formed
if(pivotCount < 6) {
   //--- Reset pattern lock variables
   g_patternFormationBar = -1;
   g_lockedPatternA = 0;
   //--- Exit the OnTick function
   return;
}

//--- Extract the last six pivots as A, B, C, D, E, F
Pivot A = pivots[pivotCount - 6];
Pivot B = pivots[pivotCount - 5];
Pivot C = pivots[pivotCount - 4];
Pivot D = pivots[pivotCount - 3];
Pivot E = pivots[pivotCount - 2];
Pivot F = pivots[pivotCount - 1];

//--- Initialize a flag to indicate if a valid 3 Drives pattern is found
bool patternFound = false;
//--- Initialize pattern type
string patternType = "";
double used_ext = 0.0;
//--- Define fib ratios
double retr_levels[] = {0.618, 0.786};
double ext_levels[] = {1.13, 1.272, 1.618};
//--- Check for the high-low-high-low-high-low (Bullish reversal) structure
if(A.isHigh && (!B.isHigh) && C.isHigh && (!D.isHigh) && E.isHigh && (!F.isHigh)) {
   //--- Calculate drive 1
   double drive1 = A.price - B.price;
   if(drive1 > 0) {
      //--- Retrace A
      double retraceA = C.price - B.price;
      bool valid_retrA = false;
      double used_retrA = 0.0;
      for(int k=0; k<ArraySize(retr_levels); k++) {
         double ideal_retraceA = retr_levels[k] * drive1;
         if(MathAbs(retraceA - ideal_retraceA) <= Tolerance * drive1) {
            valid_retrA = true;
            used_retrA = retr_levels[k];
            break;
         }
      }
      if(valid_retrA) {
         //--- Drive 2
         double drive2 = C.price - D.price;
         bool valid_drive2 = false;
         double used_ext2 = 0.0;
         for(int k=0; k<ArraySize(ext_levels); k++) {
            double ideal_drive2 = ext_levels[k] * retraceA;
            if(MathAbs(drive2 - ideal_drive2) <= Tolerance * retraceA) {
               valid_drive2 = true;
               used_ext2 = ext_levels[k];
               break;
            }
         }
         if(valid_drive2) {
            //--- Retrace B
            double retraceB = E.price - D.price;
            bool valid_retrB = false;
            double used_retrB = 0.0;
            for(int k=0; k<ArraySize(retr_levels); k++) {
               double ideal_retraceB = retr_levels[k] * drive2;
               if(MathAbs(retraceB - ideal_retraceB) <= Tolerance * drive2) {
                  valid_retrB = true;
                  used_retrB = retr_levels[k];
                  break;
               }
            }
            if(valid_retrB) {
               //--- Drive 3
               double drive3 = E.price - F.price;
               bool valid_drive3 = false;
               for(int k=0; k<ArraySize(ext_levels); k++) {
                  double ideal_drive3 = ext_levels[k] * retraceB;
                  if(MathAbs(drive3 - ideal_drive3) <= Tolerance * retraceB) {
                     valid_drive3 = true;
                     used_ext = ext_levels[k];
                     break;
                  }
               }
               if(valid_drive3 && F.price < D.price && D.price < B.price) {
                  patternFound = true;
                  patternType = "Bullish";
               }
            }
         }
      }
   }
}
//--- Check for the low-high-low-high-low-high (Bearish reversal) structure
if((!A.isHigh) && B.isHigh && (!C.isHigh) && D.isHigh && (!E.isHigh) && F.isHigh) {
   //--- Calculate drive 1
   double drive1 = B.price - A.price;
   if(drive1 > 0) {
      //--- Retrace A
      double retraceA = B.price - C.price;
      bool valid_retrA = false;
      double used_retrA = 0.0;
      for(int k=0; k<ArraySize(retr_levels); k++) {
         double ideal_retraceA = retr_levels[k] * drive1;
         if(MathAbs(retraceA - ideal_retraceA) <= Tolerance * drive1) {
            valid_retrA = true;
            used_retrA = retr_levels[k];
            break;
         }
      }
      if(valid_retrA) {
         //--- Drive 2
         double drive2 = D.price - C.price;
         bool valid_drive2 = false;
         double used_ext2 = 0.0;
         for(int k=0; k<ArraySize(ext_levels); k++) {
            double ideal_drive2 = ext_levels[k] * retraceA;
            if(MathAbs(drive2 - ideal_drive2) <= Tolerance * retraceA) {
               valid_drive2 = true;
               used_ext2 = ext_levels[k];
               break;
            }
         }
         if(valid_drive2) {
            //--- Retrace B
            double retraceB = D.price - E.price;
            bool valid_retrB = false;
            double used_retrB = 0.0;
            for(int k=0; k<ArraySize(retr_levels); k++) {
               double ideal_retraceB = retr_levels[k] * drive2;
               if(MathAbs(retraceB - ideal_retraceB) <= Tolerance * drive2) {
                  valid_retrB = true;
                  used_retrB = retr_levels[k];
                  break;
               }
            }
            if(valid_retrB) {
               //--- Drive 3
               double drive3 = F.price - E.price;
               bool valid_drive3 = false;
               for(int k=0; k<ArraySize(ext_levels); k++) {
                  double ideal_drive3 = ext_levels[k] * retraceB;
                  if(MathAbs(drive3 - ideal_drive3) <= Tolerance * retraceB) {
                     valid_drive3 = true;
                     used_ext = ext_levels[k];
                     break;
                  }
               }
               if(valid_drive3 && F.price > D.price && D.price > B.price) {
                  patternFound = true;
                  patternType = "Bearish";
               }
            }
         }
      }
   }
}

Zunächst wird die Gesamtzahl der Umkehrpunkte mit „ArraySize(pivots)“ ermittelt, die in „pivotCount“ gespeichert ist. Werden weniger als 6 Umkehrpunkte gefunden, werden „g_patternFormationBar“ und „g_lockedPatternA“ auf -1 und 0 zurückgesetzt, da das 3-Drives-Muster die Punkte A, B, C, D, E und F erfordert.

Dann extrahieren wir die letzten sechs Umkehrpunkte aus dem Array „pivots“ und ordnen „A“ (frühester), „B“, „C“, „D“, „E“ und „F“ (spätester) zu. Als Nächstes berechnen wir für ein steigendes Muster (A Hoch, B Tief, C Hoch, D Tief, E Hoch, F Tief) Drive 1 („A.price – B.price“), validieren Retracement A („C.price – B.price“ bei 0,618 oder 0,786 von Drive 1 innerhalb der „Toleranz“), Drive 2 („C.price – D.price“ bei 1,13, 1,272 oder 1,618 von Retrace A), Retracement B („E.price – D.price“ bei 0,618 oder 0,786 von Drive 2) und Drive 3 („E.price – F.price“ bei 1,13, 1,272 oder 1,618 von Retrace B), wobei „F.price < D.price < B.price“, wobei „patternFound“ auf true und „patternType“ auf „Bullish“ gesetzt wird, falls gültig, und die verwendete Erweiterung („used_ext“) gespeichert wird. Bei einem fallenden Muster (A Tief, B Hoch, C Tief, D Hoch, E Tief, F Hoch) werden ähnliche Validierungen für Drive 1 („B.price – A.price“), Retrace A, Drive 2, Retrace B und Drive 3 durchgeführt, wobei sichergestellt wird, dass „F.price > D.price > B.price“, wobei „patternFound“ auf true und „patternType“ auf „Bearish“ gesetzt wird, falls gültig. Wenn das Muster gefunden wurde, können wir es im Chart visualisieren.

//--- If a valid 3 Drives pattern is detected
if(patternFound) {
   //--- Print a message indicating the pattern type and detection time
   Print(patternType, " 3 Drives pattern detected at ", TimeToString(F.time, TIME_DATE|TIME_MINUTES|TIME_SECONDS));
 
   //--- Create a unique prefix for all graphical objects related to this pattern
   string signalPrefix = "3D_" + IntegerToString(A.time);
 
   //--- Choose triangle color based on the pattern type
   color triangleColor = (patternType=="Bullish") ? clrBlue : clrRed;
 
   //--- Draw the first triangle connecting pivots B, C, D
   DrawTriangle(signalPrefix+"_Triangle1", B.time, B.price, C.time, C.price, D.time, D.price,
                triangleColor, 2, true, true);
   //--- Draw the second triangle connecting pivots D, E, F
   DrawTriangle(signalPrefix+"_Triangle2", D.time, D.price, E.time, E.price, F.time, F.price,
                triangleColor, 2, true, true);
}

Hier wird die Visualisierung der erkannten Muster im Chart eingeleitet. Wenn ein gültiges Muster erkannt wird („patternFound“ ist true), protokollieren wir zunächst die Erkennung mit Print und geben den „patternType“ („Bullish“ (aufwärts) oder „Bearish“ (abwärts)) und die mit TimeToString formatierte Zeit des Umkehrpunkts F aus, einschließlich Datum, Minuten und Sekunden. Anschließend erstellen wir einen eindeutigen Bezeichner „signalPrefix“ durch Verkettung von „3D_“ mit „A.time“, der mit IntegerToString in eine Zeichenkette umgewandelt wird, um eine eindeutige Benennung der Chart-Objekte zu gewährleisten.

Als Nächstes setzen wir „triangleColor“ auf blau für Aufwärts-Muster oder rot für Abwärts-Muster, um sie visuell zu unterscheiden. Zuletzt rufen wir „DrawTriangle“ zweimal auf, um das Muster zu visualisieren: zuerst, um das BCD-Dreieck zu zeichnen, das die Umkehrpunkte B, C und D verbindet, und dann, um das DEF-Dreieck zu zeichnen, das die Umkehrpunkte D, E und F verbindet, wobei „signalPrefix“ mit den Suffixen „_Triangle1“ und „_Triangle2“, den jeweiligen Zeiten und Preisen der Umkehrpunkte, „triangleColor“, einer Breite von 2 und der Aktivierung der Füll- und Hintergrundanzeige mit true-Flags verwendet wird. Wir kommen zu folgendem Ergebnis:

DREIECK-SET

Anhand des Bildes können wir sehen, dass wir das erkannte Muster korrekt abbilden und visualisieren können. Jetzt müssen wir die Trendlinien weiter kartieren, um sie innerhalb der Grenzen vollständig sichtbar zu machen und eine Beschriftung hinzuzufügen, damit die Ebenen leichter zu identifizieren sind.

//--- Draw boundary trend lines connecting the pivots for clarity
DrawTrendLine(signalPrefix+"_TL_AB", A.time, A.price, B.time, B.price, clrBlack, 2, STYLE_SOLID);
DrawTrendLine(signalPrefix+"_TL_BC", B.time, B.price, C.time, C.price, clrBlack, 2, STYLE_SOLID);
DrawTrendLine(signalPrefix+"_TL_CD", C.time, C.price, D.time, D.price, clrBlack, 2, STYLE_SOLID);
DrawTrendLine(signalPrefix+"_TL_DE", D.time, D.price, E.time, E.price, clrBlack, 2, STYLE_SOLID);
DrawTrendLine(signalPrefix+"_TL_EF", E.time, E.price, F.time, F.price, clrBlack, 2, STYLE_SOLID);

//--- Retrieve the symbol's point size to calculate offsets for text positioning
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
//--- Calculate an offset (15 points) for positioning text above or below pivots
double offset = 15 * point;

//--- Determine the Y coordinate for each pivot label based on its type
double textY_A = (A.isHigh ? A.price + offset : A.price - offset);
double textY_B = (B.isHigh ? B.price + offset : B.price - offset);
double textY_C = (C.isHigh ? C.price + offset : C.price - offset);
double textY_D = (D.isHigh ? D.price + offset : D.price - offset);
double textY_E = (E.isHigh ? E.price + offset : E.price - offset);
double textY_F = (F.isHigh ? F.price + offset : F.price - offset);

//--- Draw text labels for each pivot with appropriate anchoring
DrawTextEx(signalPrefix+"_Text_A", "A", A.time, textY_A, clrBlack, 11, A.isHigh);
DrawTextEx(signalPrefix+"_Text_B", "B", B.time, textY_B, clrBlack, 11, B.isHigh);
DrawTextEx(signalPrefix+"_Text_C", "C", C.time, textY_C, clrBlack, 11, C.isHigh);
DrawTextEx(signalPrefix+"_Text_D", "D", D.time, textY_D, clrBlack, 11, D.isHigh);
DrawTextEx(signalPrefix+"_Text_E", "E", E.time, textY_E, clrBlack, 11, E.isHigh);
DrawTextEx(signalPrefix+"_Text_F", "F", F.time, textY_F, clrBlack, 11, F.isHigh);

//--- Calculate the central label's time as the midpoint between pivots A and D
datetime centralTime = (A.time + D.time) / 2;
//--- Set the central label's price at pivot F's price
double centralPrice = F.price;
//--- Create the central text label indicating the pattern type
if(ObjectCreate(0, signalPrefix+"_Text_Center", OBJ_TEXT, 0, centralTime, centralPrice)) {
   ObjectSetString(0, signalPrefix+"_Text_Center", OBJPROP_TEXT,
      (patternType=="Bullish") ? "Bullish 3 Drives" : "Bearish 3 Drives");
   ObjectSetInteger(0, signalPrefix+"_Text_Center", OBJPROP_COLOR, clrBlack);
   ObjectSetInteger(0, signalPrefix+"_Text_Center", OBJPROP_FONTSIZE, 11);
   ObjectSetString(0, signalPrefix+"_Text_Center", OBJPROP_FONT, "Arial Bold");
   ObjectSetInteger(0, signalPrefix+"_Text_Center", OBJPROP_ALIGN, ALIGN_CENTER);
}

Wir verbessern die Visualisierung der erkannten Muster, indem wir detaillierte Chart-Objekte hinzufügen, um die Struktur der Muster klar darzustellen. Zunächst zeichnen wir mit „DrawTrendLine“ fünf durchgezogene Trendlinien mit dem eindeutigen „signalPrefix“, um wichtige Umkehrpunkte zu verbinden: AB, BC, CD, DE und EF, unter Verwendung der Zeiten und Preisen der Umkehrpunkte (z. B., „A.time“, „A.price“), wobei OBJPROP_COLOR auf „clrBlack“, „OBJPROP_WIDTH“ auf 2 und „OBJPROP_STYLE“ auf „STYLE_SOLID“ mit ObjectSetInteger gesetzt wird, um die Kanten des Musters zu umreißen. Dann wird die Punktgröße des Symbols mit SymbolInfoDouble(_Symbol, SYMBOL_POINT) abgerufen und ein 15-Punkte-Offset für die Positionierung der Kennzeichnung berechnet, wobei die Y-Koordinaten („textY_A“, „textY_B“, „textY_C“, „textY_D“, „textY_E“, „textY_F“) durch Addieren oder Subtrahieren des Offsets, je nachdem, ob es sich bei dem jeweiligen Umkehrpunkt um ein hoher („isHigh“ true) oder -Tief handelt, um die Beschriftungen über den Hochs oder unter den Tiefs zu platzieren.

Als Nächstes erstellen wir mit „DrawTextEx“ Textbeschriftungen für die Umkehrpunkte A, B, C, D, E und F mit „signalPrefix“ und Suffixen wie „_Text_A“, die den jeweiligen Buchstaben anzeigen, an der Zeit des Umkehrpunkts und der eingestellten Y-Koordinate positioniert sind und „clrBlack“, Schriftgröße 11 und den „isHigh“-Status zdes Umkehrpunkts zur Verankerung verwenden. Zuletzt berechnen wir die Position des zentralen Etiketts bei „centralTime“ als Mittelwert von „A.time“ und „D.time“ und „centralPrice“ bei „F.price“, erstellen mit „ObjectCreate“ ein Textobjekt mit dem Namen „signalPrefix + '_Text_Center'“, setzen OBJPROP_TEXT auf „Bullish 3 Drives“ oder „Bearish 3 Drives“ basierend auf „patternType“und die Konfiguration von „OBJPROP_COLOR“ auf „clrBlack“, „OBJPROP_FONTSIZE“ auf 11, OBJPROP_FONT auf „Arial Bold“ und „OBJPROP_ALIGN“ auf „ALIGN_CENTER“ mit ObjectSetString und „ObjectSetInteger“. Diese Logik gewährleistet eine umfassende visuelle Darstellung der Struktur und des Typs des 3-Drives-Musters im Chart. Wenn wir das Programm ausführen, sehen Sie hier eine Visualisierung der Ausgabe, die wir erhalten.

GEKENNZEICHNETES MUSTER MIT KANTEN

Auf dem Bild können wir sehen, dass wir die Kanten und die Kennzeichnung zum Muster hinzugefügt haben, um es aufschlussreicher und anschaulicher zu machen. Als Nächstes müssen wir die Handelsniveaus für dieses Muster bestimmen.

//--- Define start and end times for drawing horizontal dotted lines for trade levels
datetime lineStart = F.time;
datetime lineEnd = F.time + PeriodSeconds(_Period)*2;

//--- Declare variables for entry price and take profit levels
double entryPriceLevel, TP1Level, TP2Level, TP3Level;
//--- Calculate pattern range (drive 3 length)
double patternRange = (patternType=="Bullish") ? (E.price - F.price) : (F.price - E.price);
//--- Calculate trade levels based on whether the pattern is Bullish or Bearish
if(patternType=="Bullish") { //--- Bullish → BUY signal
   //--- Set entry at the pattern tip (F price)
   entryPriceLevel = F.price;
   //--- Set TP3 at pivot E's price
   TP3Level = E.price;
   //--- Set TP1 at 0.382 fib retrace from F to E
   TP1Level = F.price + 0.382 * patternRange;
   //--- Set TP2 at 0.618 fib retrace from F to E
   TP2Level = F.price + 0.618 * patternRange;
} else { //--- Bearish → SELL signal
   //--- Set entry at the pattern tip (F price)
   entryPriceLevel = F.price;
   //--- Set TP3 at pivot E's price
   TP3Level = E.price;
   //--- Set TP1 at 0.382 fib retrace from F to E
   TP1Level = F.price - 0.382 * patternRange;
   //--- Set TP2 at 0.618 fib retrace from F to E
   TP2Level = F.price - 0.618 * patternRange;
}

//--- Draw dotted horizontal lines to represent the entry and TP levels
DrawDottedLine(signalPrefix+"_EntryLine", lineStart, entryPriceLevel, lineEnd, clrMagenta);
DrawDottedLine(signalPrefix+"_TP1Line", lineStart, TP1Level, lineEnd, clrForestGreen);
DrawDottedLine(signalPrefix+"_TP2Line", lineStart, TP2Level, lineEnd, clrGreen);
DrawDottedLine(signalPrefix+"_TP3Line", lineStart, TP3Level, lineEnd, clrDarkGreen);

//--- Define a label time coordinate positioned just to the right of the dotted lines
datetime labelTime = lineEnd + PeriodSeconds(_Period)/2;

//--- Construct the entry label text with the price
string entryLabel = (patternType=="Bullish") ? "BUY (" : "SELL (";
entryLabel += DoubleToString(entryPriceLevel, _Digits) + ")";
//--- Draw the entry label on the chart
DrawTextEx(signalPrefix+"_EntryLabel", entryLabel, labelTime, entryPriceLevel, clrMagenta, 11, true);

//--- Construct and draw the TP1 label
string tp1Label = "TP1 (" + DoubleToString(TP1Level, _Digits) + ")";
DrawTextEx(signalPrefix+"_TP1Label", tp1Label, labelTime, TP1Level, clrForestGreen, 11, true);

//--- Construct and draw the TP2 label
string tp2Label = "TP2 (" + DoubleToString(TP2Level, _Digits) + ")";
DrawTextEx(signalPrefix+"_TP2Label", tp2Label, labelTime, TP2Level, clrGreen, 11, true);

//--- Construct and draw the TP3 label
string tp3Label = "TP3 (" + DoubleToString(TP3Level, _Digits) + ")";
DrawTextEx(signalPrefix+"_TP3Label", tp3Label, labelTime, TP3Level, clrDarkGreen, 11, true);

Um die Handelsniveaus für das erkannte Muster zu definieren und zu visualisieren, setzen wir „lineStart“ auf den Zeitpunkt des Umkehrpunktes F („F.time“) und „lineEnd“ auf zwei Perioden im Voraus mit „PeriodSeconds(_Period) * 2“ und deklarieren die Variablen „entryPriceLevel“, „TP1Level“, „TP2Level“ und „TP3Level“ für die Handelsberechnungen. Dann berechnen wir die „patternRange“ als die dritte Drive-Länge („E.price – F.price“ für steigend, „F.price – E.price“ für fallend); für ein steigendes Muster setzen wir „entryPriceLevel“ auf „F.price“, „TP3Level“ auf „E.price“, „TP1Level“ auf „F.price + 0.382 * patternRange“, und „TP2Level“ auf „F.price + 0.618 * patternRange“; für ein fallendes Muster setzen wir „entryPriceLevel“ auf „F.price“, „TP3Level“ auf „E.price“, „TP1Level“ auf „F.price – 0.382 * patternRange“, und „TP2Level“ auf „F.price – 0.618 * patternRange“.

Als Nächstes zeichnen wir mit „DrawDottedLine“ vier gepunktete horizontale Linien: eine Einstiegslinie bei „entryPriceLevel“ in Magenta und Take-Profit-Linien bei „TP1Level“ (forest green), „TP2Level“ (green) und „TP3Level“ (dark green), die sich von „lineStart“ bis „lineEnd“ erstrecken. Zuletzt setzen wir „labelTime“ auf „lineEnd“ plus eine halbe Periode, erstellen Texte mit über DoubleToString formatierten Preisen (z.B., „BUY (Preis)“ oder „SELL (price)“ für den Einstieg, „TP1 (price)“ usw.), und verwenden „DrawTextEx“, um diese Beschriftungen zum „labelTime“ mit entsprechenden Farben, Schriftgröße 11 und verankert über den Preisniveaus zu zeichnen. Nach der Kompilierung erhalten wir folgendes Ergebnis.

Abwärtsmuster:

ABWÄRTSMUSTER

Aufwärtsmuster:

AUFWÄRTSMUSTER

Anhand der Bilder können wir sehen, dass wir die Handelsstufen richtig zugeordnet haben. Was wir jetzt tun müssen, ist, die eigentlichen Handelspositionen zu initiieren, und das ist alles.

//--- Retrieve the index of the current bar
int currentBarIndex = Bars(_Symbol, _Period) - 1;
//--- If no pattern has been previously locked, lock the current pattern formation
if(g_patternFormationBar == -1) {
   g_patternFormationBar = currentBarIndex;
   g_lockedPatternA = A.time;
   //--- Print a message that the pattern is detected and waiting for confirmation
   Print("Pattern detected on bar ", currentBarIndex, ". Waiting for confirmation on next bar.");
   return;
}
//--- If still on the same formation bar, the pattern is considered to be repainting
if(currentBarIndex == g_patternFormationBar) {
   Print("Pattern is repainting; still on locked formation bar ", currentBarIndex, ". No trade yet.");
   return;
}
//--- If we are on a new bar compared to the locked formation
if(currentBarIndex > g_patternFormationBar) {
   //--- Check if the locked pattern still corresponds to the same A pivot
   if(g_lockedPatternA == A.time) {
      Print("Confirmed pattern (locked on bar ", g_patternFormationBar, "). Opening trade on bar ", currentBarIndex, ".");
      //--- Update the pattern formation bar to the current bar
      g_patternFormationBar = currentBarIndex;
      //--- Only proceed with trading if allowed and if there is no existing position
      if(AllowTrading && !PositionSelect(_Symbol)) {
         //--- Check if this pattern has already been traded
         bool alreadyTraded = false;
         for(int k = 0; k < ArraySize(tradedPatterns); k++) {
            if(tradedPatterns[k] == A.time) {
               alreadyTraded = true;
               break;
            }
         }
         if(alreadyTraded) {
            Print("This pattern has already been traded. No new trade executed.");
            return;
         }
         double entryPriceTrade = 0, stopLoss = 0, takeProfit = 0;
         point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
         bool tradeResult = false;
         //--- Select TP level based on user input
         switch(TakeProfitLevel) {
            case TP1:
               takeProfit = TP1Level;
               break;
            case TP2:
               takeProfit = TP2Level;
               break;
            case TP3:
               takeProfit = TP3Level;
               break;
            default:
               takeProfit = TP2Level; // Fallback to TP2
         }
         //--- Calculate SL based on user-selected method
         if(patternType=="Bullish") { //--- BUY signal
            entryPriceTrade = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
            if(StopLossType == SL_FIBO) {
               double third_drive = E.price - F.price;
               stopLoss = F.price - (SL_FiboExtension - 1.0) * third_drive;
            } else { // SL_FIXED
               stopLoss = entryPriceTrade - SL_FixedPoints * point;
            }
            // Ensure SL is below entry for BUY
            if(stopLoss >= entryPriceTrade) {
               stopLoss = entryPriceTrade - 10 * point;
            }
            tradeResult = obj_Trade.Buy(LotSize, _Symbol, entryPriceTrade, stopLoss, takeProfit, "3 Drives Signal");
            if(tradeResult)
               Print("Buy order opened successfully.");
            else
               Print("Buy order failed: ", obj_Trade.ResultRetcodeDescription());
         }
         //--- For a Bearish pattern, execute a SELL trade
         else if(patternType=="Bearish") { //--- SELL signal
            entryPriceTrade = SymbolInfoDouble(_Symbol, SYMBOL_BID);
            if(StopLossType == SL_FIBO) {
               double third_drive = F.price - E.price;
               stopLoss = F.price + (SL_FiboExtension - 1.0) * third_drive;
            } else { // SL_FIXED
               stopLoss = entryPriceTrade + SL_FixedPoints * point;
            }
            // Ensure SL is above entry for SELL
            if(stopLoss <= entryPriceTrade) {
               stopLoss = entryPriceTrade + 10 * point;
            }
            tradeResult = obj_Trade.Sell(LotSize, _Symbol, entryPriceTrade, stopLoss, takeProfit, "3 Drives Signal");
            if(tradeResult)
               Print("Sell order opened successfully.");
            else
               Print("Sell order failed: ", obj_Trade.ResultRetcodeDescription());
         }
         //--- If trade was successful, mark the pattern as traded
         if(tradeResult) {
            int size = ArraySize(tradedPatterns);
            ArrayResize(tradedPatterns, size + 1);
            tradedPatterns[size] = A.time;
         }
      }
      else {
         //--- If a position is already open, do not execute a new trade
         Print("A position is already open for ", _Symbol, ". No new trade executed.");
      }
   }
   else {
      //--- If the pattern has changed, update the lock with the new formation bar and A pivot
      g_patternFormationBar = currentBarIndex;
      g_lockedPatternA = A.time;
      Print("Pattern has changed; updating lock on bar ", currentBarIndex, ". Waiting for confirmation.");
      return;
   }
}
else {
   //--- If no valid 3 Drives pattern is detected, reset the pattern lock variables
   g_patternFormationBar = -1;
   g_lockedPatternA = 0;
}

Wir schließen die Implementierung ab, indem wir die Handelsausführung und die Musterbestätigung für das erkannte Muster verwalten. Zunächst wird der aktuelle Balken-Index mit „Bars(_Symbol, _Period) – 1“ ermittelt und in „currentBarIndex“ gespeichert. Wenn dann kein Muster gesperrt ist („g_patternFormationBar == -1“), setzen wir „g_patternFormationBar“ auf „currentBarIndex“, sperren den Zeitpunkt des Umkehrpunkts A in „g_lockedPatternA“ mit „A.time“, protokollieren die Erkennung mit „Print“ und warten auf die Bestätigung und beenden.

Wenn wir uns dann immer noch auf dem Formationsbalken befinden („currentBarIndex == g_patternFormationBar“), protokollieren wir das Repainting und beenden den Handel, um ein verfrühtes Handeln zu verhindern. Zuletzt, wenn sich ein neuer Balken gebildet hat („currentBarIndex > g_patternFormationBar“) und der Umkehrpunkt A mit „g_lockedPatternA“ übereinstimmt, bestätigen wir das Muster, protokollieren es, aktualisieren „g_patternFormationBar“ und prüfen, ob der Handel mit „AllowTrading“ zulässig ist und keine offenen Positionen über die Funktion PositionSelect vorhanden sind. Wir überprüfen, ob das Muster noch nicht gehandelt wurde, indem wir „tradedPatterns“ überprüfen, wählen das Take-Profit-Niveau („TP1Level“, „TP2Level“ oder „TP3Level“) basierend auf „TakeProfitLevel“ aus, berechnen den Stop-Loss mit „SL_FIBO“ („F.price ± (SL_FiboExtension - 1.0) * third_drive”) oder „SL_FIXED” („entryPriceTrade ± SL_FixedPoints * point”) berechnet, stellt sicher, dass der Stop-Loss gültig ist, führt einen Kauf oder Verkauf mit „obj_Trade. Buy„ oder “obj_Trade.Sell„ unter Verwendung von ‚LotSize‘ und “3 Drives Signal„, protokollieren wir Erfolg oder Misserfolg und markieren das Muster als gehandelt in „tradedPatterns"; wenn der Handel nicht zulässig ist, eine Position besteht oder das Muster gehandelt wurde, protokollieren wir keinen Handel; wenn sich das Muster ändert, aktualisieren wir die Sperre und warten; wenn kein Muster gefunden wird, setzen wir die globalen Variablen zurück. Nach der Kompilierung erhalten wir folgendes Ergebnis.

Abwärtssignal:

ABWÄRTSSIGNAL

Aufwärtssignal:

AUFWÄRTSSIGNAL

Aus dem Bild können wir ersehen, dass wir das harmonische Muster aufzeichnen und in der Lage sind, es entsprechend zu handeln, sobald es bestätigt ist. Damit haben wir unser Ziel erreicht, das Muster zu identifizieren, aufzuzeichnen und zu handeln. Bleiben nur noch die Backtests des Programms, und das wird im nächsten Abschnitt behandelt.


Backtests

Nach einem gründlichen Backtest erhalten wir folgende Ergebnisse.

Backtest-Grafik:

GRAPH

Bericht des Backtest:

BERICHT


Schlussfolgerung

Zusammenfassend haben wir ein 3 Drives-Mustersystem in MQL5 entwickelt, das die Preisbewegung nutzt, um harmonische Muster der steigenden und fallenden 3 Drives mit präzisen Fibonacci Retracements und Extensions zu erkennen, den Handel mit anpassbaren Einstiegs-, Stop-Loss- und mehrstufigen Take-Profit-Punkten zu automatisieren und die Muster mit Chart-Objekten wie Dreiecken und Trendlinien zu visualisieren.

Haftungsausschluss: Dieser Artikel ist nur für Bildungszwecke gedacht. Der Handel ist mit erheblichen finanziellen Risiken verbunden, und die Volatilität der Märkte kann zu Verlusten führen. Gründliche Backtests und sorgfältiges Risikomanagement sind entscheidend, bevor Sie dieses Programm auf den Live-Märkten einsetzen.

Indem Sie die vorgestellten Konzepte und die Umsetzung nutzen, können Sie dieses 3-Treiber-Muster-System an Ihren Handelsstil anpassen und Ihre algorithmischen Strategien verbessern. Viel Spaß beim Handeln! 

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

Beigefügte Dateien |
Letzte Kommentare | Zur Diskussion im Händlerforum (3)
Pawlos6
Pawlos6 | 12 Sept. 2025 in 20:07
Warum wird das Ea nicht auf dem Diagramm angezeigt und wie hoch sollte die Optimierungszahl sein, um das Ea und den Mindesthandelsbetrag zu verwenden?
Allan Munene Mutiiria
Allan Munene Mutiiria | 12 Sept. 2025 in 23:58
Pawlos6 #:
Warum die ea nicht auf dem Graphen angezeigt und was sollte die Optimierung Zahl sein, um die ea und Mindesthandelsbetrag zu verwenden?

Hallo. Sie können auf der Registerkarte "Optimierung" optimieren.

Cyberdude
Cyberdude | 16 Sept. 2025 in 18:43
Dieser Autor hat eine Tonne von Artikeln, und das ist das erste Zeichen, dass etwas falsch ist. Dennoch, ich gab den Vorteil des Zweifels und folgte mehrere Artikel sehr genau, neu erstellt sie, und verglich sie mit seinem EA. Ausnahmslos jeder Artikel enthielt einen halbgaren EA, der nicht das tat, was er sagte. Die Screenshots sind auch sehr verdächtig, da der EA nur ein Muster erkennt, nachdem es schon weiter in der Zukunft ist, und dann zeichnet er das Muster in der Vergangenheit mit allen Arten von TP Ebenen. Ich habe ein paar seiner Artikel gelesen, und sie waren alle eine komplette Zeitverschwendung.
Aufbau eines professionellen Handelssystems mit Heikin Ashi (Teil 1): Entwickeln eines nutzerdefinierten Indikators Aufbau eines professionellen Handelssystems mit Heikin Ashi (Teil 1): Entwickeln eines nutzerdefinierten Indikators
Dieser Artikel ist der erste Teil einer zweiteiligen Serie, die praktische Fähigkeiten und Best Practices für das Schreiben von nutzerdefinierten Indikatoren in MQL5 vermitteln soll. Anhand des Heikin Ashi als Arbeitsbeispiel untersucht der Artikel die Theorie hinter den Heikin Ashi-Charts, erklärt, wie Heikin Ashi-Kerzen berechnet werden, und demonstriert ihre Anwendung in der technischen Analyse. Das Herzstück ist eine schrittweise Anleitung zur Entwicklung eines voll funktionsfähigen Heikin Ashi-Indikators von Grund auf, mit klaren Erklärungen, die dem Leser helfen zu verstehen, was zu programmieren ist und warum. Dieses Grundwissen bildet die Grundlage für den zweiten Teil, in dem wir einen Expert Advisor erstellen werden, der auf der Grundlage der Heikin Ashi-Logik handelt.
Vom Neuling zum Experten: Animierte Schlagzeilen mit MQL5 (X) – Multiple Symbol Chart View für den Nachrichtenhandel Vom Neuling zum Experten: Animierte Schlagzeilen mit MQL5 (X) – Multiple Symbol Chart View für den Nachrichtenhandel
Heute werden wir ein System zur Darstellung mehrerer Charts mit Hilfe von Chartobjekten entwickeln. Ziel ist es, den Nachrichtenhandel durch die Anwendung von MQL5-Algorithmen zu verbessern, die dazu beitragen, die Reaktionszeit des Händlers in Zeiten hoher Volatilität, wie z. B. bei wichtigen Nachrichten, zu verkürzen. In diesem Fall bieten wir Händlern eine integrierte Möglichkeit, mehrere wichtige Symbole mit einem einzigen All-in-One-Tool für den Nachrichtenhandel zu überwachen. Unsere Arbeit entwickelt sich mit dem News Headline EA kontinuierlich weiter. Er verfügt nun über eine wachsende Anzahl von Funktionen, die sowohl für Händler, die vollautomatische Systeme verwenden, als auch für diejenigen, die den manuellen Handel mit Hilfe von Algorithmen bevorzugen, einen echten Mehrwert darstellen. Klicken Sie sich durch und beteiligen Sie sich an dieser Diskussion, um mehr Wissen, Einblicke und praktische Ideen zu erhalten.
Entwicklung des Price Action Analysis Toolkit (Teil 39): Automatisierung der BOS- und ChoCH-Erkennung in MQL5 Entwicklung des Price Action Analysis Toolkit (Teil 39): Automatisierung der BOS- und ChoCH-Erkennung in MQL5
Dieser Artikel stellt das Fractal Reaction System vor, ein kompaktes MQL5-System, das fraktale Pivots in umsetzbare Marktstruktursignale umwandelt. Der EA verwendet eine geschlossene Balkenlogik, um ein erneutes Zeichnen zu vermeiden, erkennt Change-of-Character-Warnungen (ChoCH) und bestätigt Breaks-of-Structure (BOS), zeichnet persistente Chartobjekte und protokolliert/meldet jedes bestätigte Ereignis (Desktop, Mobile und Sound). Lesen Sie weiter, um den Algorithmusentwurf, Implementierungshinweise, Testergebnisse und den vollständigen EA-Code zu erfahren, damit Sie den Detektor selbst kompilieren, testen und einsetzen können.
Selbstoptimierende Expert Advisors in MQL5 (Teil 13): Eine sanfte Einführung in die Kontrolltheorie mit Hilfe der Matrixfaktorisierung Selbstoptimierende Expert Advisors in MQL5 (Teil 13): Eine sanfte Einführung in die Kontrolltheorie mit Hilfe der Matrixfaktorisierung
Die Finanzmärkte sind unberechenbar, und Handelsstrategien, die in der Vergangenheit profitabel erschienen, brechen unter realen Marktbedingungen oft zusammen. Das liegt daran, dass die meisten Strategien, wenn sie einmal eingeführt sind, nicht mehr angepasst werden oder aus ihren Fehlern lernen können. Mit Hilfe von Ideen aus der Kontrolltheorie können wir mit Hilfe von Rückkopplungsreglern beobachten, wie unsere Strategien mit den Märkten interagieren und ihr Verhalten auf Rentabilität ausrichten. Unsere Ergebnisse zeigen, dass das Hinzufügen eines Feedback-Controllers zu einer einfachen gleitenden Durchschnittsstrategie die Gewinne verbessert, das Risiko reduziert und die Effizienz erhöht, was beweist, dass dieser Ansatz ein großes Potenzial für Handelsanwendungen hat.