Automatisieren von Handelsstrategien in MQL5 (Teil 27): Erstellen eines Price Action Harmonic Pattern der Krabbe mit visuellem Feedback
Einführung
In unserem letzten Artikel (Teil 26) haben wir ein Pin Bar Averaging System in MetaQuotes Language 5 (MQL5) entwickelt, das das Kerzenmuster der Pin Bar verwendet, um Handelsgeschäfte zu initiieren und mehrere Positionen durch eine Mittelungsstrategie zu verwalten, komplett mit einem dynamischen Dashboard für eine Echtzeit-Überwachung. In Teil 27 erstellen wir ein System für das Krabben-Muster, das harmonische Auf- oder Abwärtsmuster mit Hilfe von Umkehrpunkten und Fibonacci-Verhältnissen identifiziert und den Handel mit präzisen Einstiegs-, Stop-Loss- und Take-Profit-Levels automatisiert, die durch visuelle Chart-Objekte wie Dreiecke und Trendlinien für eine klare Darstellung der Muster ergänzt werden. Wir werden die folgenden Themen behandeln:
- Verstehen des harmonischen Systems eines Krabbenmusters
- Implementation in MQL5
- Backtests
- Schlussfolgerung
Am Ende haben Sie eine ausgefeilte MQL5-Strategie für den Handel mit harmonischen Mustern, die Sie nur noch anpassen müssen – legen wir los!
Verstehen des harmonischen Systems eines Krabbenmusters
Das Muster der Krabbe ist eine harmonische Handelsformation, die durch fünf wichtige Umkehrpunkte – X, A, B, C und D – definiert ist und in zwei Formen existiert: ein Aufwärts- und ein Abwärts-Muster. Bei einer Aufwärts-Krabbe bildet die Struktur eine Tief-Hoch-Tief-Hoch-Tief-Sequenz, bei der Punkt X ein tiefer Umkehrpunkt ist, Punkt A ein hoher Umkehrpunkt, Punkt B ein tiefer Umkehrpunkt (das 0,618 von XA zurückgeht), Punkt C ein hoher Umkehrpunkt (das sich von 0,382 bis 0,886 von AB erstreckt) und Punkt D ein tiefer Umkehrpunkt (das sich von 1,618 von XA erstreckt und unter X liegt). Umgekehrt bildet eine Abwärts-Krabbe eine Hoch-Tief-Hoch-Tief-Hoch-Sequenz, mit Punkt X als hoher Umkehrpunkt, Punkt A als tiefer Umkehrpunkt, Punkt B als hoher Umkehrpunkt, Punkt C als tiefer Umkehrpunkt und Punkt D als hoher Umkehrpunkt (das sich über 1,618 von XA erstreckt und über X liegt). Nachfolgend sind die visualisierten Mustertypen aufgeführt.
Das harmonische Muster der Aufwärts-Krabbe:

Das harmonische Muster der Abwärts-Krabbe:

Um die Muster zu erkennen, gehen wir wie folgt strukturiert vor:
- Die Definition der XA-Strecke: Die anfängliche impulsive Bewegung von Punkt X zu Punkt A bildet die Grundlage des Musters, bestimmt die Richtung (abwärts für steigend, aufwärts für fallend) und dient als Referenz für die Fibonacci-Berechnungen.
- Die Einrichtung der AB-Strecke: Punkt B sollte etwa 0,618 der XA-Strecke zurückgehen, was eine Korrektur bestätigt, ohne die anfängliche Bewegung zu aggressiv umzukehren.
- Analyse der BC-Strecke: Diese Strecke sollte sich zwischen 0,382 und 0,886 der AB-Strecke erstrecken, wodurch eine scharfe Gegenbewegung entsteht, die die endgültige Verlängerung einleitet.
- Einstellung der CD-Strecke: Die letzte Strecke sollte sich über 1,618 der XA-Strecke erstrecken und die potenzielle Umkehrzone am Punkt D markieren, wo sich das Muster vervollständigt und ein Handelssignal erzeugt wird.
Durch die Anwendung dieser geometrischen und Fibonacci-basierten Kriterien wird unser Handelssystem systematisch gültige Krabben-Muster in Kursdaten erkennen. Sobald die Formation identifiziert ist, visualisiert das System sie auf dem Chart mit Dreiecken, Trendlinien, Beschriftungen für die Punkte X, A, B, C und D sowie gestrichelten Linien für Einstiegs- und Gewinnmitnahmen. Dieses Setup ermöglicht die automatische Ausführung von Handelsgeschäften am D-Punkt mit kalkuliertem Stop-Loss und mehrstufigen Take-Profits, wobei die hohe Umkehrwahrscheinlichkeit des Musters für effektive Markteinstiege genutzt wird. 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.
//+------------------------------------------------------------------+ //| Crab 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 Crab Strategy" #property strict #include <Trade\Trade.mqh> //--- Include Trade library for order management CTrade obj_Trade; //--- Instantiate trade object for executing orders //--- Input parameters for user configuration input int PivotLeft = 5; // Number of bars to the left for pivot identification input int PivotRight = 5; // Number of bars to the right for pivot identification input double Tolerance = 0.10; // Allowed deviation for Fibonacci levels (10% of XA move) input double LotSize = 0.01; // Lot size for opening new trade positions input bool AllowTrading = true; // Enable or disable automated trading functionality //--------------------------------------------------------------------------- //--- Crab pattern definition: //--- Bullish Crab: //--- Pivots (X-A-B-C-D): X swing low, A swing high, B swing low, C swing high, D swing low. //--- Normally XA > 0; Ideal B = A - 0.5*(A-X); Legs within specified ranges. //--- Bearish Crab: //--- Pivots (X-A-B-C-D): X swing high, A swing low, B swing high, C swing low, D swing high. //--- Normally XA > 0; Ideal B = A + 0.5*(X-A); Legs within specified ranges. //--------------------------------------------------------------------------- struct Pivot { //--- Define structure for pivot points datetime time; //--- Store time of pivot bar double price; //--- Store price (high for swing high, low for swing low) bool isHigh; //--- Indicate true for swing high, false for swing low }; Pivot pivots[]; //--- Declare array to store pivot points int g_patternFormationBar = -1; //--- Store bar index of pattern formation (-1 if none) datetime g_lockedPatternX = 0; //--- Store X pivot time for locked pattern
Wir beginnen mit der Implementierung des Krabben-Musters, indem wir die Bibliothek „<Trade\Trade.mqh>“ einbinden und „obj_Trade“ als CTrade-Objekt instanziieren, um die Auftragsverwaltung zu erleichtern, z. B. durch das Senden von Kauf- und Verkaufsanfragen. Anschließend definieren wir die Eingabeparameter für die Nutzeranpassung: „PivotLeft“ und „PivotRight“ mit jeweils 5 Bars, um den Lookback für die Identifizierung von Umkehrpunkte festzulegen, „Tolerance“ mit 0,10 für die Fibonacci-Abweichung, „LotSize“ mit 0,01 für das Handelsvolumen und „AllowTrading“ als true, um die automatische Ausführung zu aktivieren.
Als Nächstes definieren wir die Struktur des „Pivot“ mit „time“ (datetime), „price“ (double) und „isHigh“ (bool), um Umkehrpunkte zu speichern, deklarieren „pivots“ als ein Array von „Pivot“ und initialisieren sie die Globalen „g_patternformationbar“ mit -1, um die Balken der Muster zu verfolgen, und „g_lockedpatternx“ mit 0, um den Zeitpunkt X-pivot für die Bestätigung zu sperren und so die Grundlage für die Mustererkennung zu schaffen. Zur Visualisierung können wir Funktionen zum Zeichnen von Linien, Beschriftungen und Dreiecken verwenden.
//+------------------------------------------------------------------+ //| Draw filled triangle on chart | //+------------------------------------------------------------------+ void DrawTriangle(string name, datetime t1, double p1, datetime t2, double p2, datetime t3, double p3, color cl, int width, bool fill, bool back) { if (ObjectCreate(0, name, OBJ_TRIANGLE, 0, t1, p1, t2, p2, t3, p3)) { //--- Create triangle with three points ObjectSetInteger(0, name, OBJPROP_COLOR, cl); //--- Set triangle color ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_SOLID); //--- Set solid line style ObjectSetInteger(0, name, OBJPROP_WIDTH, width); //--- Set line width ObjectSetInteger(0, name, OBJPROP_FILL, fill); //--- Enable or disable fill ObjectSetInteger(0, name, OBJPROP_BACK, back); //--- Set background or foreground } } //+------------------------------------------------------------------+ //| Draw trend line on chart | //+------------------------------------------------------------------+ void DrawTrendLine(string name, datetime t1, double p1, datetime t2, double p2, color cl, int width, int style) { if (ObjectCreate(0, name, OBJ_TREND, 0, t1, p1, t2, p2)) { //--- Create trend line between two points ObjectSetInteger(0, name, OBJPROP_COLOR, cl); //--- Set line color ObjectSetInteger(0, name, OBJPROP_STYLE, style); //--- Set line style (solid, dotted, etc.) ObjectSetInteger(0, name, OBJPROP_WIDTH, width); //--- Set line width } } //+------------------------------------------------------------------+ //| Draw dotted horizontal line on chart | //+------------------------------------------------------------------+ void DrawDottedLine(string name, datetime t1, double p, datetime t2, color lineColor) { if (ObjectCreate(0, name, OBJ_TREND, 0, t1, p, t2, p)) { //--- Create horizontal dotted line ObjectSetInteger(0, name, OBJPROP_COLOR, lineColor); //--- Set line color ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DOT); //--- Set dotted style ObjectSetInteger(0, name, OBJPROP_WIDTH, 1); //--- Set line width to 1 } } //+------------------------------------------------------------------+ //| Draw anchored text label for pivots | //+------------------------------------------------------------------+ void DrawTextEx(string name, string text, datetime t, double p, color cl, int fontsize, bool isHigh) { if (ObjectCreate(0, name, OBJ_TEXT, 0, t, p)) { //--- Create text label at specified coordinates ObjectSetString(0, name, OBJPROP_TEXT, text); //--- Set label text content ObjectSetInteger(0, name, OBJPROP_COLOR, cl); //--- Set text color ObjectSetInteger(0, name, OBJPROP_FONTSIZE, fontsize); //--- Set font size ObjectSetString(0, name, OBJPROP_FONT, "Arial Bold"); //--- Set font to Arial Bold if (isHigh) { //--- Check if pivot is swing high ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_BOTTOM); //--- Anchor label above pivot } else { //--- Handle swing low ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_TOP); //--- Anchor label below pivot } ObjectSetInteger(0, name, OBJPROP_ALIGN, ALIGN_CENTER); //--- Center-align text } }
Hier implementieren wir Visualisierungsfunktionen für das Programm, um Chart-Objekte zu zeichnen, die das harmonische Krabben-Muster und seine Handelsstufen darstellen. Zunächst erstellen wir die Funktion „DrawTriangle“, die ObjectCreate verwendet, um ein gefülltes Dreieck (OBJ_TRIANGLE) mit drei Punkten zu zeichnen, die durch Zeiten („t1“, „t2“, „t3“) und Preise („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 implementieren wir die Funktion „DrawTrendLine“, die mit „ObjectCreate“ eine Trendlinie („OBJ_TREND“) zwischen zwei Punkten erstellt, mit „OBJPROP_COLOR“, „OBJPROP_STYLE“ (durchgezogen, gepunktet usw.) konfiguriert und OBJPROP_WIDTH mit „ObjectSetInteger“ für ein anpassbares Linienbild. Als Nächstes entwickeln wir die Funktion „DrawDottedLine“, die eine horizontale gepunktete Linie (obj_trend) zu einem bestimmten Preis von „t1“ nach „t2“ zeichnet und dieselbe Logik verwendet. Zuletzt implementieren wir die Funktion „DrawTextEx“, die ein Textlabel (OBJ_TEXT) an den Koordinaten („t“, „p“) mit der Objekterstellungsfunktion erstellt und das gleiche Format wie die vorherigen Funktionen verwendet, um eine klare visuelle Darstellung des Krabben-Musters und der Handelsstufen auf dem Chart zu gewährleisten. Wir können nun mit OnTick fortfahren und versuchen, die Umkehrpunkte zu finden, die wir später zur Identifizierung von Mustern verwenden können. Hier ist die Logik, mit der wir das erreichen.
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { static datetime lastBarTime = 0; //--- Store time of last processed bar datetime currentBarTime = iTime(_Symbol, _Period, 1); //--- Get time of current confirmed bar if (currentBarTime == lastBarTime) return; //--- Exit if no new bar lastBarTime = currentBarTime; //--- Update last processed bar time ArrayResize(pivots, 0); //--- Clear pivot array for fresh analysis int barsCount = Bars(_Symbol, _Period); //--- Retrieve total number of bars int start = PivotLeft; //--- Set starting index for pivot detection int end = barsCount - PivotRight; //--- Set ending index for pivot detection for (int i = end - 1; i >= start; i--) { //--- Iterate through bars to identify pivots bool isPivotHigh = true; //--- Assume bar is a swing high bool isPivotLow = true; //--- Assume bar is a swing low double currentHigh = iHigh(_Symbol, _Period, i); //--- Get current bar high price double currentLow = iLow(_Symbol, _Period, i); //--- Get current bar low price for (int j = i - PivotLeft; j <= i + PivotRight; j++) { //--- Check surrounding bars if (j < 0 || j >= barsCount) continue; //--- Skip out-of-bounds indices if (j == i) continue; //--- Skip current bar if (iHigh(_Symbol, _Period, j) > currentHigh) isPivotHigh = false; //--- Invalidate swing high if (iLow(_Symbol, _Period, j) < currentLow) isPivotLow = false; //--- Invalidate swing low } if (isPivotHigh || isPivotLow) { //--- Check if bar is a pivot Pivot p; //--- Create new pivot structure p.time = iTime(_Symbol, _Period, i); //--- Set pivot bar time p.price = isPivotHigh ? currentHigh : currentLow; //--- Set pivot price p.isHigh = isPivotHigh; //--- Set pivot type int size = ArraySize(pivots); //--- Get current pivot array size ArrayResize(pivots, size + 1); //--- Resize pivot array pivots[size] = p; //--- Add pivot to array } } }
Wir fahren fort, die anfängliche Logik von OnTick für unser Programm zu implementieren, um Umkehrpunkten zu erkennen, die die Grundlage für die Identifizierung von harmonischen Krabben-Mustern bilden. Zunächst wird geprüft, ob ein neuer Balken vorliegt, indem „lastBarTime“ (statisch, initialisiert mit 0) mit „currentBarTime“ von iTime bei Shift 1 verglichen wird, um zu vermeiden, dass der aktuelle unvollständige Balken für das aktuelle Symbol und die aktuelle Periode verwendet wird, und „lastBarTime“ aktualisiert wird, wenn ein neuer Balken erkannt wird. Dann leeren wir das Array „Pivots“ mit ArrayResize, um eine neue Analyse zu gewährleisten. Als Nächstes rufen wir die Gesamtanzahl der Balken mit Bars ab, setzen den Erkennungsbereich der Umkehrpunkte von „start“ (gleich „PivotLeft“) bis „end“ (Gesamtanzahl der Balken minus „PivotRight“) und iterieren durch die Balken von „end – 1“ bis „start“.
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 überprüfen die umliegenden Balken innerhalb von „PivotLeft“ und „PivotRight“ mit „iHigh“ und iLow, um den Pivot ungültig zu machen, wenn ein benachbarter Balken ein höheres Hoch oder ein niedrigeres Tief hat. Wenn zum Schluss der Balken einen gültigen Umkehrpunkt (hoher oder tiefer) erkannt wird, erstellen wir die Struktur „Pivot“, setzen „time“ mit „iTime“, den „price“ auf das Hoch oder Tief, basierend auf „isPivotHigh“ und dem „isHigh“ Flag, und fügen es dann mit „ArrayResize“ an das Array „pivots“ an und speichern es. Wenn wir das Array ausdrucken, erhalten wir das folgende Ergebnis.

Aus den Daten können wir die Umkehrpunkte extrahieren, und wenn wir genügend Pivots haben, können wir die Muster analysieren und erkennen. Hier ist die Logik, mit der wir das erreichen.
int pivotCount = ArraySize(pivots); //--- Get total number of pivots if (pivotCount < 5) { //--- Check if insufficient pivots g_patternFormationBar = -1; //--- Reset pattern formation bar g_lockedPatternX = 0; //--- Reset locked X pivot return; //--- Exit function } Pivot X = pivots[pivotCount - 5]; //--- Extract X pivot (earliest) Pivot A = pivots[pivotCount - 4]; //--- Extract A pivot Pivot B = pivots[pivotCount - 3]; //--- Extract B pivot Pivot C = pivots[pivotCount - 2]; //--- Extract C pivot Pivot D = pivots[pivotCount - 1]; //--- Extract D pivot (latest) bool patternFound = false; //--- Initialize pattern detection flag if (X.isHigh && !A.isHigh && B.isHigh && !C.isHigh && D.isHigh) { //--- Check bearish Crab pattern double diff = X.price - A.price; //--- Calculate XA leg difference if (diff > 0) { //--- Ensure positive XA move double idealB = A.price + 0.618 * diff; //--- Compute ideal B (0.618 retracement) if (MathAbs(B.price - idealB) <= Tolerance * diff) { //--- Verify B within tolerance double AB = B.price - A.price; //--- Calculate AB leg length double BC = B.price - C.price; //--- Calculate BC leg length if (BC >= 0.382 * AB && BC <= 0.886 * AB) { //--- Check BC within Fibonacci range double extension = D.price - A.price; //--- Calculate AD extension if (MathAbs(extension - 1.618 * diff) <= Tolerance * diff && D.price > X.price) { //--- Verify 1.618 extension and D > X patternFound = true; //--- Confirm bearish pattern } } } } } if (!X.isHigh && A.isHigh && !B.isHigh && C.isHigh && !D.isHigh) { //--- Check bullish Crab pattern double diff = A.price - X.price; //--- Calculate XA leg difference if (diff > 0) { //--- Ensure positive XA move double idealB = A.price - 0.618 * diff; //--- Compute ideal B (0.618 retracement) if (MathAbs(B.price - idealB) <= Tolerance * diff) { //--- Verify B within tolerance double AB = A.price - B.price; //--- Calculate AB leg length double BC = C.price - B.price; //--- Calculate BC leg length if (BC >= 0.382 * AB && BC <= 0.886 * AB) { //--- Check BC within Fibonacci range double extension = A.price - D.price; //--- Calculate AD extension if (MathAbs(extension - 1.618 * diff) <= Tolerance * diff && D.price < X.price) { //--- Verify 1.618 extension and D < X patternFound = true; //--- Confirm bullish pattern } } } } }
Um die Muster zu erkennen, verwenden wir Fibonacci-basierte Kriterien. Zunächst wird die Gesamtzahl der Pivots mit „ArraySize(pivots)“ ermittelt und in „pivotCount“ gespeichert, wobei „g_patternFormationBar“ und „g_lockedPatternX“ auf -1 bzw. 0 zurückgesetzt werden, wenn weniger als 5 Pivots gefunden werden, da das Krabben-Muster X-, A-, B-, C- und D-Punkte erfordert. Dann extrahieren wir die letzten fünf Pivots aus dem Array „pivots“ und ordnen „X“ (früheste), „A“, „B“, „C“ und „D“ (späteste) zu, um die Struktur des Musters darzustellen.
Als Nächstes prüfen wir, ob es sich um ein Abwärts-Muster der Krabbe handelt, indem wir die Sequenz (X hoch, A tief, B hoch, C tief, D hoch) überprüfen, die Differenz der XA-Strecke („X.price - A.price“) berechnen und sicherstellen, dass sie positiv ist, den idealen Punkt B als „A.price + 0.618 * diff“, und bestätigen, dass B innerhalb der „Tolerance * diff“ liegt, indem wir MathAbs verwenden; wir validieren dann die Strecke BC (0,382 bis 0,886 von AB) und die AD-Erweiterung (1,618 von XA mit D über X) und setzen „patternFound“ auf true, wenn alle Bedingungen erfüllt sind. Zuletzt prüfen wir, ob ein Aufwärts-Muster der Krabbe vorliegt (X Tief, A Hoch, B Tief, C Hoch, D Tief), indem wir XA als „A.price – X.price“ berechnen und sicherstellen, dass es positiv ist, B bei 0,618 Rücksetzer, BC innerhalb von 0,382 bis 0,886 von AB und AD bei 1,618 von XA mit D unterhalb von X überprüfen und „patternFound“ auf true setzen, wenn es gültig ist. Wenn das Muster gefunden wurde, können wir es im Chart visualisieren.
string patternType = ""; //--- Initialize pattern type if (patternFound) { //--- Check if pattern detected if (D.price > X.price) patternType = "Bearish"; //--- Set bearish pattern (sell signal) else if (D.price < X.price) patternType = "Bullish"; //--- Set bullish pattern (buy signal) } if (patternFound) { //--- Process valid Crab pattern Print(patternType, " Crab pattern detected at ", TimeToString(D.time, TIME_DATE|TIME_MINUTES|TIME_SECONDS)); //--- Log pattern detection string signalPrefix = "CR_" + IntegerToString(X.time); //--- Generate unique prefix for objects color triangleColor = (patternType == "Bullish") ? clrBlue : clrRed; //--- Set triangle color based on pattern DrawTriangle(signalPrefix + "_Triangle1", X.time, X.price, A.time, A.price, B.time, B.price, triangleColor, 2, true, true); //--- Draw XAB triangle DrawTriangle(signalPrefix + "_Triangle2", B.time, B.price, C.time, C.price, D.time, D.price, triangleColor, 2, true, true); //--- Draw BCD triangle }
Um die erkannten Muster zu klassifizieren und auf dem Chart zu visualisieren, initialisieren wir „patternType“ als leeren String, um zu speichern, ob es ein Auf- oder Abwärts-Muster ist. Wenn „patternFound“ wahr ist, wird der Mustertyp durch den Vergleich von „D.price“ mit „X.price“ bestimmt: „patternType“ wird auf „Bearish“ gesetzt, wenn D über X liegt (was ein Verkaufssignal bedeutet), oder auf „Bullish“, wenn D unter X liegt (was ein Kaufsignal bedeutet). Wenn dann ein gültiges Krabben-Muster bestätigt wird, protokollieren wir die Erkennung mit Print und geben den „patternType“ und die Zeit des D-Pivots mit „TimeToString“ formatiert mit Datum, Minuten und Sekunden aus.
Zuletzt erstellen wir einen eindeutigen Bezeichner „signalPrefix“ als „CR_“ verkettet mit „X.time“ in einen String konvertiert, setzen „triangleColor“ auf blau für ein Aufwärts- oder rot für ein Abwärts-Muster und rufen „DrawTriangle“ zweimal auf, um das Muster zu visualisieren: zuerst für das XAB-Dreieck (Verbindung von X, A, B) und dann für das BCD-Dreieck (Verbindung von B, C, D), unter Verwendung von „signalPrefix“ mit den Suffixen „_Triangle1“ und „_Triangle2“, den jeweiligen Pivot-Zeiten und -Kursen, „triangleColor“, einer Breite von 2 und der Aktivierung der Füll- und Hintergrundanzeige, wodurch eine klare Identifizierung und visuelle Darstellung der erkannten Krabben-Muster für Handelsentscheidungen gewährleistet wird. Hier ist der Meilenstein, den wir haben.

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.
DrawTrendLine(signalPrefix + "_TL_XA", X.time, X.price, A.time, A.price, clrBlack, 2, STYLE_SOLID); //--- Draw XA trend line DrawTrendLine(signalPrefix + "_TL_AB", A.time, A.price, B.time, B.price, clrBlack, 2, STYLE_SOLID); //--- Draw AB trend line DrawTrendLine(signalPrefix + "_TL_BC", B.time, B.price, C.time, C.price, clrBlack, 2, STYLE_SOLID); //--- Draw BC trend line DrawTrendLine(signalPrefix + "_TL_CD", C.time, C.price, D.time, D.price, clrBlack, 2, STYLE_SOLID); //--- Draw CD trend line DrawTrendLine(signalPrefix + "_TL_XB", X.time, X.price, B.time, B.price, clrBlack, 2, STYLE_SOLID); //--- Draw XB trend line DrawTrendLine(signalPrefix + "_TL_BD", B.time, B.price, D.time, D.price, clrBlack, 2, STYLE_SOLID); //--- Draw BD trend line double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); //--- Retrieve symbol point size double offset = 15 * point; //--- Calculate label offset (15 points) double textY_X = X.isHigh ? X.price + offset : X.price - offset; //--- Set X label Y coordinate double textY_A = A.isHigh ? A.price + offset : A.price - offset; //--- Set A label Y coordinate double textY_B = B.isHigh ? B.price + offset : B.price - offset; //--- Set B label Y coordinate double textY_C = C.isHigh ? C.price + offset : C.price - offset; //--- Set C label Y coordinate double textY_D = D.isHigh ? D.price + offset : D.price - offset; //--- Set D label Y coordinate DrawTextEx(signalPrefix + "_Text_X", "X", X.time, textY_X, clrBlack, 11, X.isHigh); //--- Draw X pivot label DrawTextEx(signalPrefix + "_Text_A", "A", A.time, textY_A, clrBlack, 11, A.isHigh); //--- Draw A pivot label DrawTextEx(signalPrefix + "_Text_B", "B", B.time, textY_B, clrBlack, 11, B.isHigh); //--- Draw B pivot label DrawTextEx(signalPrefix + "_Text_C", "C", C.time, textY_C, clrBlack, 11, C.isHigh); //--- Draw C pivot label DrawTextEx(signalPrefix + "_Text_D", "D", D.time, textY_D, clrBlack, 11, D.isHigh); //--- Draw D pivot label datetime centralTime = (X.time + B.time) / 2; //--- Calculate central label time double centralPrice = D.price; //--- Set central label price if (ObjectCreate(0, signalPrefix + "_Text_Center", OBJ_TEXT, 0, centralTime, centralPrice)) { //--- Create central pattern label ObjectSetString(0, signalPrefix + "_Text_Center", OBJPROP_TEXT, patternType == "Bullish" ? "Bullish Crab" : "Bearish Crab"); //--- Set pattern name ObjectSetInteger(0, signalPrefix + "_Text_Center", OBJPROP_COLOR, clrBlack); //--- Set text color ObjectSetInteger(0, signalPrefix + "_Text_Center", OBJPROP_FONTSIZE, 11); //--- Set font size ObjectSetString(0, signalPrefix + "_Text_Center", OBJPROP_FONT, "Arial Bold"); //--- Set font type ObjectSetInteger(0, signalPrefix + "_Text_Center", OBJPROP_ALIGN, ALIGN_CENTER); //--- Center-align text }
Um die Struktur des Musters darzustellen, fügen wir weiterhin Linien und Beschriftungen hinzu. Zunächst zeichnen wir mit „DrawTrendLine“ sechs Trendlinien mit dem eindeutigen „signalPrefix“, um wichtige Umkehrpunkte zu verbinden: XA, AB, BC, CD, XB und BD, jeweils mit Endpunkten, die durch ihre jeweiligen Pivot-Zeiten und -Preise (z. B. „X.time“, „X.price“) definiert sind, mit „clrBlack“ als Farbe, einer Breite von 2 und STYLE_SOLID für eine durchgezogene Linie, die die XABCD-Struktur und die Stützpfeiler umreißt. Dann wird ein Offset für die Kennzeichnungen berechnet, indem die Punktgröße des Symbols mit „SymbolInfoDouble(_Symbol, SYMBOL_POINT)“ abgerufen und mit 15 multipliziert wird, und die Y-Koordinaten für die Pivot-Labels („textY_X“, „textY_A“, „textY_B“, „textY_C“, „textY_D“) durch Addieren oder Subtrahieren des Offsets, je nachdem, ob es sich bei dem jeweiligen Pivot um einen hohen („isHigh“ true) oder tiefen Umkehrpunkt handelt, um sicherzustellen, dass die Beschriftungen über den Hochs und unter den Tiefs erscheinen.
Als Nächstes erstellen wir mit „DrawTextEx“ Textbeschriftungen für die Pivots X, A, B, C und D, jeweils mit „signalPrefix“ und Suffixen wie „_Text_X“, die den jeweiligen Buchstaben anzeigen, an der Pivot-Zeit und der eingestellten Y-Koordinate positioniert sind, unter Verwendung von „clrBlack“, Schriftgröße 11 und dem „isHigh“-Status des Pivots zur Verankerung. Zuletzt berechnen wir eine zentrale Etikettenposition bei „centralTime“ als Mittelpunkt von „X.time“ und „B.time“ und „centralPrice“ bei „D.price“, erstellen ein Textobjekt mit ObjectCreate mit dem Namen „signalPrefix + '_Text_Center'“, setzen OBJPROP_TEXT auf „Bullish Crab“ oder „Bearish Crab“, basierend auf „patternType“, und konfigurieren „OBJPROP_COLOR“ auf „clrBlack“, „OBJPROP_FONTSIZE“ auf 11, „OBJPROP_FONT“ auf „Arial Bold“ und „OBJPROP_ALIGN“ auf „ALIGN_CENTER“ mit ObjectSetString und „ObjectSetInteger“. Dies gewährleistet eine umfassende visuelle Darstellung der Struktur und des Typs des Krabben-Musters auf dem Chart. Wenn wir das Programm ausführen, erhalten wir die folgende Darstellung.

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.
datetime lineStart = D.time; //--- Set start time for trade level lines datetime lineEnd = D.time + PeriodSeconds(_Period) * 2; //--- Set end time for trade level lines double entryPriceLevel, TP1Level, TP2Level, TP3Level, tradeDiff; //--- Declare trade level variables if (patternType == "Bullish") { //--- Handle bullish trade levels entryPriceLevel = SymbolInfoDouble(_Symbol, SYMBOL_ASK); //--- Set entry at ask price TP3Level = C.price; //--- Set TP3 at C pivot price tradeDiff = TP3Level - entryPriceLevel; //--- Calculate total trade distance TP1Level = entryPriceLevel + tradeDiff / 3; //--- Set TP1 at 1/3 of distance TP2Level = entryPriceLevel + 2 * tradeDiff / 3; //--- Set TP2 at 2/3 of distance } else { //--- Handle bearish trade levels entryPriceLevel = SymbolInfoDouble(_Symbol, SYMBOL_BID); //--- Set entry at bid price TP3Level = C.price; //--- Set TP3 at C pivot price tradeDiff = entryPriceLevel - TP3Level; //--- Calculate total trade distance TP1Level = entryPriceLevel - tradeDiff / 3; //--- Set TP1 at 1/3 of distance TP2Level = entryPriceLevel - 2 * tradeDiff / 3; //--- Set TP2 at 2/3 of distance } DrawDottedLine(signalPrefix + "_EntryLine", lineStart, entryPriceLevel, lineEnd, clrMagenta); //--- Draw entry level line DrawDottedLine(signalPrefix + "_TP1Line", lineStart, TP1Level, lineEnd, clrForestGreen); //--- Draw TP1 level line DrawDottedLine(signalPrefix + "_TP2Line", lineStart, TP2Level, lineEnd, clrGreen); //--- Draw TP2 level line DrawDottedLine(signalPrefix + "_TP3Line", lineStart, TP3Level, lineEnd, clrDarkGreen); //--- Draw TP3 level line datetime labelTime = lineEnd + PeriodSeconds(_Period) / 2; //--- Set time for trade level labels string entryLabel = patternType == "Bullish" ? "BUY (" : "SELL ("; //--- Start entry label text entryLabel += DoubleToString(entryPriceLevel, _Digits) + ")"; //--- Append entry price DrawTextEx(signalPrefix + "_EntryLabel", entryLabel, labelTime, entryPriceLevel, clrMagenta, 11, true); //--- Draw entry label string tp1Label = "TP1 (" + DoubleToString(TP1Level, _Digits) + ")"; //--- Create TP1 label text DrawTextEx(signalPrefix + "_TP1Label", tp1Label, labelTime, TP1Level, clrForestGreen, 11, true); //--- Draw TP1 label string tp2Label = "TP2 (" + DoubleToString(TP2Level, _Digits) + ")"; //--- Create TP2 label text DrawTextEx(signalPrefix + "_TP2Label", tp2Label, labelTime, TP2Level, clrGreen, 11, true); //--- Draw TP2 label string tp3Label = "TP3 (" + DoubleToString(TP3Level, _Digits) + ")"; //--- Create TP3 label text DrawTextEx(signalPrefix + "_TP3Label", tp3Label, labelTime, TP3Level, clrDarkGreen, 11, true); //--- Draw TP3 label
Hier setzen wir die Definition und Visualisierung der Handelsstufen für das erkannte Muster fort. Zunächst setzen wir „lineStart“ auf die Zeit des D-Pivots („D.time“) und „lineEnd“ auf zwei Perioden im Voraus mit „PeriodSeconds(_Period) * 2“ und deklarieren die Variablen „entryPriceLevel“, „TP1Level“, „TP2Level“, „TP3Level“ und „tradeDiff“ für die Handelsberechnungen. Dann setzen wir für ein Aufwärts-Muster („patternType == 'Bullish'“) „entryPriceLevel“ auf den aktuellen Briefkurs mit SymbolInfoDouble, „TP3Level“ auf den preis des Umkehrpunktes C, berechnen „tradeDiff“ als „TP3Level – entryPriceLevel“ und berechnen „TP1Level“ und „TP2Level“ als ein Drittel und zwei Drittel von „tradediff“, addiert zu „entryPriceLevel“; für ein Abwärts-Muster verwenden wir den Geldkurs, setzen „TP3Level“ auf den Preis von C, berechnen „tradediff“ als „entryPriceLevel – TP3Level“ und berechnen „TP1Level“ und „TP2Level“ durch Subtraktion von einem Drittel und zwei Dritteln der Handelsdifferenz.
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 die Kennzeichnungen mit über DoubleToString formatierten Preisen (z.B., „BUY (price)“ oder „SELL (price)“ für die Eröffnung, „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ärts-Muster:

Aufwärts-Muster:

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.
int currentBarIndex = Bars(_Symbol, _Period) - 1; //--- Retrieve current bar index if (g_patternFormationBar == -1) { //--- Check if no pattern is locked g_patternFormationBar = currentBarIndex; //--- Lock current bar as formation bar g_lockedPatternX = X.time; //--- Lock X pivot time Print("Pattern detected on bar ", currentBarIndex, ". Waiting for confirmation on next bar."); //--- Log detection return; //--- Exit function } if (currentBarIndex == g_patternFormationBar) { //--- Check if still on formation bar Print("Pattern is repainting; still on locked formation bar ", currentBarIndex, ". No trade yet."); //--- Log repainting return; //--- Exit function } if (currentBarIndex > g_patternFormationBar) { //--- Check if new bar after formation if (g_lockedPatternX == X.time) { //--- Verify same X pivot for confirmation Print("Confirmed pattern (locked on bar ", g_patternFormationBar, "). Opening trade on bar ", currentBarIndex, "."); //--- Log confirmed pattern g_patternFormationBar = currentBarIndex; //--- Update formation bar to current if (AllowTrading && !PositionSelect(_Symbol)) { //--- Check trading allowed and no open position double entryPriceTrade = 0, stopLoss = 0, takeProfit = 0; //--- Declare trade parameters point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); //--- Update point value bool tradeResult = false; //--- Initialize trade result flag if (patternType == "Bullish") { //--- Process bullish trade entryPriceTrade = SymbolInfoDouble(_Symbol, SYMBOL_ASK); //--- Set entry at ask price double diffTrade = TP2Level - entryPriceTrade; //--- Calculate trade distance stopLoss = entryPriceTrade - diffTrade * 3; //--- Set stop loss (3x distance) takeProfit = TP2Level; //--- Set take profit at TP2 tradeResult = obj_Trade.Buy(LotSize, _Symbol, entryPriceTrade, stopLoss, takeProfit, "Crab Signal"); //--- Execute buy trade if (tradeResult) { //--- Check trade success Print("Buy order opened successfully."); //--- Log successful buy } else { //--- Handle trade failure Print("Buy order failed: ", obj_Trade.ResultRetcodeDescription()); //--- Log failure reason } } else if (patternType == "Bearish") { //--- Process bearish trade entryPriceTrade = SymbolInfoDouble(_Symbol, SYMBOL_BID); //--- Set entry at bid price double diffTrade = entryPriceTrade - TP2Level; //--- Calculate trade distance stopLoss = entryPriceTrade + diffTrade * 3; //--- Set stop loss (3x distance) takeProfit = TP2Level; //--- Set take profit at TP2 tradeResult = obj_Trade.Sell(LotSize, _Symbol, entryPriceTrade, stopLoss, takeProfit, "Crab Signal"); //--- Execute sell trade if (tradeResult) { //--- Check trade success Print("Sell order opened successfully."); //--- Log successful sell } else { //--- Handle trade failure Print("Sell order failed: ", obj_Trade.ResultRetcodeDescription()); //--- Log failure reason } } } else { //--- Trading not allowed or position exists Print("A position is already open for ", _Symbol, ". No new trade executed."); //--- Log no trade } } else { //--- Pattern has changed g_patternFormationBar = currentBarIndex; //--- Update formation bar g_lockedPatternX = X.time; //--- Update locked X pivot Print("Pattern has changed; updating lock on bar ", currentBarIndex, ". Waiting for confirmation."); //--- Log pattern change return; //--- Exit function } } } else { //--- No valid pattern detected g_patternFormationBar = -1; //--- Reset formation bar g_lockedPatternX = 0; //--- Reset locked X pivot }
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 die X-Pivot-Zeit in „g_lockedPatternX“ mit „X.time“, protokollieren die Erkennung mit dem Hinweis, dass auf eine Bestätigung gewartet wird, und beenden das Programm. Wenn wir uns dann immer noch auf dem Formationsbalken befinden („currentBarIndex == g_patternFormationBar“), protokollieren wir, dass das Muster neu gemalt wird, und steigen aus, um einen vorzeitigen Handel zu vermeiden.
Zuletzt, wenn sich ein neuer Balken gebildet hat („currentBarIndex > g_patternFormationBar“) und der X-Pivot mit „g_lockedPatternX“ übereinstimmt, bestätigen wir das Muster, protokollieren es, aktualisieren „g_patternFormationBar“ und prüfen, ob der Handel mit „AllowTrading“ erlaubt ist und mit PositionSelect überprüfen wir, ob Positionen existieren. Für ein Aufwärts-Muster setzen wir „entryPriceTrade“ auf den Briefkurs, berechnen „diffTrade“ als „TP2Level – entryPriceTrade“, setzen „stopLoss“ auf das Dreifache dieses Abstands darunter, setzen „takeProfit“ auf „TP2Level“ und führen einen Kauf mit „obj_Trade. Buy” unter Verwendung von „LotSize” und dem Kommentar „Crab Signal” aus, wobei Erfolg oder Misserfolg protokolliert werden. Bei einem Abwärts-Muster verwenden wir den Geldkurs, setzen „stopLoss” auf das Dreifache darüber und führen einen Verkauf mit „obj_Trade.Sell“ aus; wenn der Handel nicht zulässig ist oder eine Position besteht, protokollieren wir keinen Handel; wenn sich das Muster ändert, aktualisieren wir die Sperre und warten; wenn kein Muster gefunden wird, setzen wir „g_patternFormationBar“ und „g_lockedPatternX“ zurück, um sicherzustellen, dass bestätigte Krabben-Muster Handelsgeschäfte mit präzisem Risikomanagement auslösen. Zum Schluss müssen wir nur noch die Muster aus dem Chart löschen, wenn wir das Programm entfernen.
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { ObjectsDeleteAll(0, "CR_"); //--- Remove all chart objects with "CR_" prefix ArrayResize(pivots, 0); //--- Clear pivots array g_patternFormationBar = -1; //--- Reset pattern formation bar index g_lockedPatternX = 0; //--- Reset locked pattern X pivot time ChartRedraw(0); //--- Redraw chart to reflect changes }
Hier implementieren wir OnDeinit, um eine ordnungsgemäße Bereinigung sicherzustellen, wenn der EA aus dem Chart entfernt wird. Zunächst werden alle Chart-Objekte mit dem Präfix „CR_“ mit ObjectsDeleteAll entfernt, um visuelle Elemente wie Dreiecke, Trendlinien und Beschriftungen im Zusammenhang mit Krabben-Mustern zu löschen. Dann wird die Größe des Arrays „pivots“ mit ArrayResize auf 0 gesetzt, um die gespeicherten Pivot-Daten zu löschen. Als Nächstes setzen wir „g_patternFormationBar“ auf -1 und „g_lockedPatternX“ auf 0 zurück, um die Musterverfolgungsvariablen zu löschen. Zuletzt rufen wir ChartRedraw auf, um das Chart zu aktualisieren und sicherzustellen, dass es die Entfernung aller Objekte und Daten widerspiegelt. Dies gewährleistet einen sauberen Ausstieg, setzt Ressourcen frei und verhindert Rückstände. Nach der Kompilierung erhalten wir folgendes Ergebnis.
Abwä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:

Bericht des Backtest:

Schlussfolgerung
Zusammenfassend haben wir ein System des Krabben-Musters in MQL5 entwickelt, das Preisaktionen nutzt, um harmonische Auf- oder Abwärts-Muster der Krabbe mit präzisen Fibonacci-Verhältnissen zu identifizieren und den Handel mit berechneten Einstiegs-, Stop-Loss- und mehrstufigen Take-Profit-Punkten zu automatisieren, die durch dynamische Chart-Objekte wie Dreiecke und Trendlinien visualisiert werden.
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 Implementierungen nutzen, können Sie dieses Krabben-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/19099
Warnung: Alle Rechte sind von MetaQuotes Ltd. vorbehalten. Kopieren oder Vervielfältigen untersagt.
Dieser Artikel wurde von einem Nutzer der Website verfasst und gibt dessen persönliche Meinung wieder. MetaQuotes Ltd übernimmt keine Verantwortung für die Richtigkeit der dargestellten Informationen oder für Folgen, die sich aus der Anwendung der beschriebenen Lösungen, Strategien oder Empfehlungen ergeben.
Vom Neuling zum Experten: Animierte Nachrichtenüberschrift mit MQL5 (VIII) – Schnellhandelsschaltflächen für den Nachrichtenhandel
Aufbau eines Handelssystems (Teil 2): Die Wissenschaft der Positionsbestimmung
Parafrac-Oszillator: Kombination von Parabel- und Fraktalindikator
Entwicklung des Price Action Analysis Toolkit (Teil 37): Sentiment Tilt Meter
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.