English 日本語
preview
Automatisieren von Handelsstrategien in MQL5 (Teil 33): Erstellung des Preisaktions-Systems des harmonischen Musters Shark

Automatisieren von Handelsstrategien in MQL5 (Teil 33): Erstellung des Preisaktions-Systems des harmonischen Musters Shark

MetaTrader 5Handel |
64 0
Allan Munene Mutiiria
Allan Munene Mutiiria

Einführung

In unserem vorherigen Artikel (Teil 32) haben wir das System des 5 Drives Musters (5-0) in MetaQuotes Language 5 (MQL5) entwickelt, das steigende und fallende harmonische Muster von 5 Drives unter Verwendung von Fibonacci-Ratios erkennt und Handelsgeschäfte mit anpassbaren Stop-Loss- und Take-Profit-Levels automatisiert, die durch Chart-Objekte wie Dreiecke und Trendlinien visualisiert werden. In Teil 33 entwickeln wir das System des Shark-Musters, das dessen steigende und fallende harmonische Muster anhand von Umkehrpunkten und spezifischen Fibonacci-Retracements und Extensions identifiziert. Dieses System führt Handelsgeschäfte mit flexiblen Einstiegs-, Stop-Loss- und mehrstufigen Take-Profit-Optionen aus, die durch visuelle Dreiecke, Trendlinien und Etiketten für eine klare Musterdarstellung ergänzt werden. Wir werden die folgenden Themen behandeln:

  1. Verstehen des Systems der harmonischen Shark-Muster
  2. Implementation in MQL5
  3. Backtests
  4. Schlussfolgerung

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


Verstehen des Systems der harmonischen Shark-Muster

Das Shark-Muster ist eine harmonische Handelsformation, die durch fünf wichtige Umkehrpunkte – X, A, B, C und D – definiert ist, die sowohl in einer steigenden als auch in einer fallenden Form existieren und dazu dienen, durch spezifische Fibonacci-Retracements und -Extensions wahrscheinliche Umkehrzonen zu identifizieren. Bei einem steigenden Shark-Muster bildet die Struktur eine Tief-Hoch-Tief-Hoch-Tief-Sequenz, bei der X ein tiefer Umkehrpunkt ist, A ein hoher Umkehrpunkt, B ein tiefer Umkehrpunkt (das sich auf 0,32 bis 0,50 von XA zurückzieht), C ein hoher Umkehrpunkt (das sich auf 1,13 bis 1,618 von AB erstreckt) und D ein tiefer Umkehrpunkt (das sich auf 1,618 bis 2,24 von BC erstreckt und unter B liegt); ein fallender Shark kehrt diese Sequenz um, wobei D über B liegt:

Fallendes harmonisches Shark-Muster:

FALLENDES HARMONISCHES SHARK-MUSTER

Steigendes harmonisches Shark-Muster:

STEIGENDES HARMONISCHES SHARK-MUSTER

Unser Ansatz umfasst die Erkennung dieser Umkehrpunkt innerhalb eines bestimmten Balkenbereichs, die Validierung der Schenkel des Musters anhand nutzerdefinierter Fibonacci-Kriterien, die Visualisierung der X-A-B-C-D-Struktur mit Chart-Objekten wie Dreiecken und Trendlinien und die Ausführung von Handelsgeschäften am D-Punkt mit anpassbaren Stop-Loss- (Fibonacci-basiert oder fest) und Take-Profit-Levels (ein Drittel, zwei Drittel oder C-Pivot), um von erwarteten Umkehrungen zu profitieren. Kommen wir nun zur Umsetzung!


Implementation in MQL5

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

//+------------------------------------------------------------------+
//|                                             Shark 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 Shark 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, // One-third of the move to C
   TP2 = 2, // Two-thirds of the move to C
   TP3 = 3  // Pivot C 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 XA move)
input double MinRetrace = 0.32;                      // Minimum retracement for AB (strictness control)
input double MaxRetrace = 0.50;                      // Maximum retracement for AB (strictness control)
input double MinExt1 = 1.13;                         // Minimum extension for BC (strictness control)
input double MaxExt1 = 1.618;                        // Maximum extension for BC (strictness control)
input double MinExt2 = 1.618;                        // Minimum extension for CD (strictness control)
input double MaxExt2 = 2.24;                         // Maximum extension for CD (strictness control)
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)
//---------------------------------------------------------------------------

//--- 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_lockedPatternX = 0; //--- The key X pivot time for the locked pattern
//--- Global array to track traded patterns (using X.time as identifier)
datetime tradedPatterns[];

Um die Grundlage für das Shark-Muster 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 Enumerationen „ENUM_TAKE_PROFIT_LEVEL“ (TP1 für ein Drittel, TP2 für zwei Drittel, TP3 für den Umkehrpunkt C-Preis) und „ENUM_STOP_LOSS_TYPE“ (SL_FIBO für die Fibonacci-Erweiterung, SL_FIXED für Fixpunkte) für flexible Handelseinstellungen und setzen Eingabeparameter: „PivotLeft“ und „PivotRight“ bei 5 Bars für die Umkehrpunkt-Erkennung, „Tolerance“ bei 0,10 für die Fibonacci-Abweichung, „MinRetrace“ bei 0,32 und „MaxRetrace“ bei 0,50 für das AB-Leg, „MinExt1“ bei 1,13 und „MaxExt1“ bei 1.618 für das BC-Leg, „MinExt2“ bei 1,618 und „MaxExt2“ bei 2,24 für das CD-Leg, „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“ zum Speichern von Umkehrpunkten, deklarieren „pivots“ als dynamisches Array und initialisieren die globalen Variablen „g_patternFormationBar“ auf -1 zum Verfolgen der Musterbildung, „g_lockedPatternX“ auf 0 zum Sperren der X-Pivot-Zeit und „tradedPatterns“ als Array zum Verfolgen der gehandelten Muster unter Verwendung der X-Zeit. Dieses System bildet den zentralen Rahmen für die Erkennung von und den Handel mit Shark-Mustern. Zur Visualisierung können wir Funktionen zum Zeichnen von Linien, Kennzeichnungen 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 Shark-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 Preis von „t1“ bis „t2“ 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“ für Hochs und Tiefs auf der Grundlage von „isHigh“ oberhalb bzw. unterhalb 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 ursprüngliche Logik der Funktion OnTick, um Umkehrpunkte zu erkennen, die für die Identifizierung des harmonischen Shark-Musters unerlässlich sind. Zunächst deklarieren wir ein 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 Pivot-Erkennungsbereich mit „start“ als „PivotLeft“ und „end“ als Gesamtzahl der Balken minus „PivotRight“ fest und durchlaufen die ausgewählten Balken.

Für jeden Balken nehmen wir an, dass es sich um einen hohen („isPivotHigh“ = true) und einen tiefen Umkehrpunkt („isPivotLow“ = true) handelt, wir ermitteln sein Hoch und Tief 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“, den „price“ auf das Hoch oder Tief auf der Grundlage von „isPivotHigh“ und dem „isHigh“-Flag 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.

ANALYSIERTE UMKEHRPUNKT-DATEN

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 five pivots are found, the pattern cannot be formed
if(pivotCount < 5) {
   //--- Reset pattern lock variables
   g_patternFormationBar = -1;
   g_lockedPatternX = 0;
   //--- Exit the OnTick function
   return;
}

//--- Extract the last five pivots as X, A, B, C, and D
Pivot X = pivots[pivotCount - 5];
Pivot A = pivots[pivotCount - 4];
Pivot B = pivots[pivotCount - 3];
Pivot C = pivots[pivotCount - 2];
Pivot D = pivots[pivotCount - 1];

//--- Initialize a flag to indicate if a valid Shark pattern is found
bool patternFound = false;
//--- Initialize pattern type
string patternType = "";
//--- Check for the low-high-low-high-low (Bullish reversal) structure
if((!X.isHigh) && A.isHigh && (!B.isHigh) && C.isHigh && (!D.isHigh)) {
   //--- Calculate the difference between pivot A and X
   double diff = A.price - X.price;
   //--- Ensure the difference is positive
   if(diff > 0) {
      //--- Calculate the retracement from A to B
      double retrace = A.price - B.price;
      //--- Verify retracement is within user-defined range
      if((retrace >= MinRetrace * diff) && (retrace <= MaxRetrace * diff)) {
         //--- Calculate the extension from B to C
         double extension1 = C.price - B.price;
         //--- Verify extension is within user-defined range of retrace
         if((extension1 >= MinExt1 * retrace) && (extension1 <= MaxExt1 * retrace)) {
            //--- Calculate the extension from C to D
            double extension2 = C.price - D.price;
            //--- Verify extension is within user-defined range of previous extension
            if((extension2 >= MinExt2 * extension1) && (extension2 <= MaxExt2 * extension1) && (D.price < B.price)) {
               patternFound = true;
               patternType = "Bullish";
            }
         }
      }
   }
}
//--- Check for the high-low-high-low-high (Bearish reversal) structure
if(X.isHigh && (!A.isHigh) && B.isHigh && (!C.isHigh) && D.isHigh) {
   //--- Calculate the difference between pivot X and A
   double diff = X.price - A.price;
   //--- Ensure the difference is positive
   if(diff > 0) {
      //--- Calculate the retracement from A to B
      double retrace = B.price - A.price;
      //--- Verify retracement is within user-defined range
      if((retrace >= MinRetrace * diff) && (retrace <= MaxRetrace * diff)) {
         //--- Calculate the extension from B to C
         double extension1 = B.price - C.price;
         //--- Verify extension is within user-defined range of retrace
         if((extension1 >= MinExt1 * retrace) && (extension1 <= MaxExt1 * retrace)) {
            //--- Calculate the extension from C to D
            double extension2 = D.price - C.price;
            //--- Verify extension is within user-defined range of previous extension
            if((extension2 >= MinExt2 * extension1) && (extension2 <= MaxExt2 * extension1) && (D.price > B.price)) {
               patternFound = true;
               patternType = "Bearish";
            }
         }
      }
   }
}

Zunächst wird die Gesamtzahl der Umkehrpunkte mit „ArraySize(pivots)“ ermittelt, die in „pivotCount“ gespeichert ist, und beendet, wenn weniger als 5 Umkehrpunkte gefunden werden, wobei „g_patternFormationBar“ und „g_lockedPatternX“ auf -1 und 0 zurückgesetzt werden, da das Shark-Muster X-, A-, B-, C- und D-Punkte erfordert. Dann extrahieren wir die letzten fünf Umkehrpunkte aus dem Array „pivots“ und ordnen „X“ (früheste), „A“, „B“, „C“ und „D“ (späteste) zu.

Als Nächstes berechnen wir für ein steigendes Muster (X Tief, A Hoch, B Tief, C Hoch, D Tief) die XA-Differenz („A.Preis – X.Preis“), stellen sicher, dass sie positiv ist, überprüfen das AB-Retracement („A.Preis – B.Preis“) innerhalb von „MinRetrace“ (0,32) bis „MaxRetrace“ (0,50) von XA liegt, prüfen wir, ob die BC-Erweiterung („C.Preis – B.Preis“) innerhalb von „MinExt1“ (1.13) bis „MaxExt1“ (1.618) von AB liegt, und bestätigen Sie, dass die CD-Erweiterung („C.Preis – D.Preis“) innerhalb von „MinExt2“ (1.618) bis „MaxExt2“ (2.24) von BC mit „D.price < B.price“, wobei „patternFound“ auf true und „patternType“ auf „Bullish“ gesetzt wird, falls gültig. Zuletzt wenden wir für ein fallendes Muster (X Hoch, A Tief, B Hoch, C Tief, D Hoch) ähnliche Validierungen für XA („X.price – A.price“), AB Retracement („B.price – A.price“), BC Extension („B.price – C.price“) und CD Erweiterung („D.price – C.price“) mit „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 Shark pattern is detected
if(patternFound) {
   //--- Print a message indicating the pattern type and detection time
   Print(patternType, " Shark pattern detected at ", TimeToString(D.time, TIME_DATE|TIME_MINUTES|TIME_SECONDS));
  
   //--- Create a unique prefix for all graphical objects related to this pattern
   string signalPrefix = "SH_" + IntegerToString(X.time);
  
   //--- Choose triangle color based on the pattern type
   color triangleColor = (patternType=="Bullish") ? clrBlue : clrRed;
  
   //--- Draw the first triangle connecting pivots X, A, and B
   DrawTriangle(signalPrefix+"_Triangle1", X.time, X.price, A.time, A.price, B.time, B.price,
                triangleColor, 2, true, true);
   //--- Draw the second triangle connecting pivots B, C, and D
   DrawTriangle(signalPrefix+"_Triangle2", B.time, B.price, C.time, C.price, D.time, D.price,
                triangleColor, 2, true, true);
}

Hier starten wir die Visualisierung der erkannten Muster im Chart. Wenn ein gültiges Muster erkannt wird („patternFound“ ist true), protokollieren wir zunächst die Erkennung mit Print und geben den „patternType“ („Bullish“ oder „Bearish“) und die mit TimeToString formatierte Zeit des D-Pivots aus, einschließlich Datum, Minuten und Sekunden. Anschließend erstellen wir einen eindeutigen Bezeichner „signalPrefix“ durch Verkettung von „SH_“ mit „X.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ärtsmuster oder rot für Abwärtsmuster, um sie visuell zu unterscheiden. Zuletzt rufen wir „DrawTriangle“ zweimal auf, um das Muster zu visualisieren: zuerst, um das XAB-Dreieck zu zeichnen, das die Umkehrpunkte X, A und B verbindet, und dann, um das BCD-Dreieck zu zeichnen, das die Umkehrpunkte B, C und D verbindet. Dabei verwenden wir „signalPrefix“ mit den Suffixen „_Triangle1“ und „_Triangle2“, die jeweiligen Zeiten und Preise der Umkehrpunkte, „triangleColor“, eine Breite von 2 und aktivieren die Füllung und die Hintergrundanzeige mit true-Flags. 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 abbilden, um sie innerhalb der Grenzen vollständig sichtbar zu machen und eine Beschriftung zur leichteren Identifizierung der Ebenen hinzuzufügen.

//--- Draw boundary trend lines connecting the pivots for clarity
DrawTrendLine(signalPrefix+"_TL_XA", X.time, X.price, A.time, A.price, clrBlack, 2, STYLE_SOLID);
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_XB", X.time, X.price, B.time, B.price, clrBlack, 2, STYLE_SOLID);
DrawTrendLine(signalPrefix+"_TL_BD", B.time, B.price, D.time, D.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_X = (X.isHigh ? X.price + offset : X.price - offset);
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);

//--- Draw text labels for each pivot with appropriate anchoring
DrawTextEx(signalPrefix+"_Text_X", "X", X.time, textY_X, clrBlack, 11, X.isHigh);
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);

//--- Calculate the central label's time as the midpoint between pivots X and B
datetime centralTime = (X.time + B.time) / 2;
//--- Set the central label's price at pivot D's price
double centralPrice = D.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 Shark" : "Bearish Shark");
   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 weiter, indem wir detaillierte Chart-Objekte hinzufügen, um die Struktur der Muster klar darzustellen. Zunächst zeichnen wir mit „DrawTrendLine“ sechs durchgezogene Trendlinien mit dem eindeutigen „signalPrefix“, um wichtige Umkehrpunkte zu verbinden: XA, AB, BC, CD, XB und BD, unter Verwendung von Umkehrpunkt-Zeiten und -Preisen (z. B., „X.time“, „X.price“), wobei OBJPROP_COLOR auf „clrBlack“, „OBJPROP_WIDTH“ auf 2 und „OBJPROP_STYLE“ auf „STYLE_SOLID“ mit ObjectSetInteger gesetzt wird, um die Strecken des Musters zu zeichnen. Dann wird die Punktgröße des Symbols mit „SymbolInfoDouble(_Symbol, SYMBOL_POINT)“ abgerufen und ein 15-Punkte-Offset für die Positionierung der Etiketten berechnet, wobei die Y-Koordinaten („textY_X“, „textY_A“, „textY_B“, „textY_C“, „textY_D“) durch Addieren oder Subtrahieren des Offsets, je nachdem, ob es sich bei dem jeweiligen Umkehrpunkt um einen hohen („isHigh“ true) oder tiefen Umkehrpunkt handelt, um die Kennzeichnungen über den Hochs oder unter den Tiefs zu platzieren.

Als Nächstes verwenden wir „DrawTextEx“, um Textkennzeichnungen für die Umkehrpunkte X, A, B, C und D mit „signalPrefix“ und Suffixen wie „_Text_X“ zu erstellen, die den jeweiligen Buchstaben anzeigen, an der Zeit des Umkehrpunkte und der eingestellten Y-Koordinate positioniert sind und „clrBlack“, Schriftgröße 11 und den „isHigh“-Status des Umkehrpunkte zur Verankerung verwenden. Zuletzt berechnen wir die Position des zentralen Labels bei „centralTime“ als Mittelpunkt von „X.time“ und „B.time“ und „centralPrice“ bei „D.Preis“, erstellen ein Textobjekt mit „ObjectCreate“ mit dem Namen „signalPrefix + '_Text_Center'“, setzen OBJPROP_TEXT auf „Bullish Shark“ oder „Bearish Shark“ 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 den Funktionen ObjectSetString und „ObjectSetInteger“. Wenn wir das Programm ausführen, sehen Sie hier eine Visualisierung der Ausgabe, die wir erhalten.

MUSTER MIT ETIKETTEN UND RÄNDERN

Auf dem Bild können wir sehen, dass wir die Ränder und die Kennzeichnungen zum Muster hinzugefügt haben, um es aufschlussreicher und anschaulicher zu machen. Als Nächstes müssen wir die Handelsniveaus für das Muster festlegen.

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

//--- Declare variables for entry price and take profit levels
double entryPriceLevel, TP1Level, TP2Level, TP3Level, tradeDiff;
//--- Calculate trade levels based on whether the pattern is Bullish or Bearish
if(patternType=="Bullish") { //--- Bullish → BUY signal
   //--- Use the current ASK price as the entry
   entryPriceLevel = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   //--- Set TP3 at pivot C's price
   TP3Level = C.price;
   //--- Calculate the total distance to be covered by the trade
   tradeDiff = TP3Level - entryPriceLevel;
   //--- Set TP1 at one-third of the total move
   TP1Level = entryPriceLevel + tradeDiff/3;
   //--- Set TP2 at two-thirds of the total move
   TP2Level = entryPriceLevel + 2*tradeDiff/3;
} else { //--- Bearish → SELL signal
   //--- Use the current BID price as the entry
   entryPriceLevel = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   //--- Set TP3 at pivot C's price
   TP3Level = C.price;
   //--- Calculate the total distance to be covered by the trade
   tradeDiff = entryPriceLevel - TP3Level;
   //--- Set TP1 at one-third of the total move
   TP1Level = entryPriceLevel - tradeDiff/3;
   //--- Set TP2 at two-thirds of the total move
   TP2Level = entryPriceLevel - 2*tradeDiff/3;
}

//--- 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 Handelsstufen für das erkannte Muster zu definieren und zu visualisieren, 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 steigendes Muster („patternType == 'Bullish'“) „entryPriceLevel“ mit der Funktion SymbolInfoDouble auf den aktuellen Briefkurs (Ask), „TP3Level“ auf den Preis des C-Pivots, berechnen „tradeDiff“ als „TP3Level – entryPriceLevel“ und berechnen „TP1Level“ und „TP2Level“ als ein Drittel und zwei Drittel von „tradeDiff“, addiert zu „entryPriceLevel“; für ein fallendes Muster verwenden wir den Geldkurs (Bid), 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 Periodenlänge, erstellen Etikettentexte mit Preisen, die mit der Funktion DoubleToString formatiert werden (z.B., „BUY (price)“ oder „SELL (price)“ für den Einstieg, „TP1 (price)“ usw.), und verwenden „DrawTextEx“, um diese Kennzeichnungen zum „labelTime“ mit entsprechenden Farben, Schriftgröße 11 und verankert über den Kursniveaus zu zeichnen. Nach dem Kompilieren 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_lockedPatternX = X.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 X pivot
   if(g_lockedPatternX == X.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] == X.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 second_drive = C.price - D.price;
               stopLoss = D.price - (SL_FiboExtension - 1.0) * second_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, "Shark 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 second_drive = D.price - C.price;
               stopLoss = D.price + (SL_FiboExtension - 1.0) * second_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, "Shark 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] = X.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 X pivot
      g_patternFormationBar = currentBarIndex;
      g_lockedPatternX = X.time;
      Print("Pattern has changed; updating lock on bar ", currentBarIndex, ". Waiting for confirmation.");
      return;
   }

}
else {
   //--- If no valid Shark pattern is detected, reset the pattern lock variables
   g_patternFormationBar = -1;
   g_lockedPatternX = 0;
}

Hier schließen wir die Implementierung des OnTick-Ereignishandlers 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 X in „g_lockedPatternX“ mit „X.time“, protokollieren die Erkennung mit Print, warten auf die Bestätigung und beenden die Funktion.

Wenn wir uns dann immer noch auf dem Formationsbalken befinden („currentBarIndex == g_patternFormationBar“), protokollieren wir das Repainting und beenden die Funktion, um ein zu frühes Handelsgeschäft zu verhindern. Zuletzt, wenn sich ein neuer Balken gebildet hat („currentBarIndex > g_patternFormationBar“) und der Umkehrpunkt X mit „g_lockedPatternX“ übereinstimmt, bestätigen wir das Muster, aktualisieren „g_patternFormationBar“ und überprüfen über die Funktion PositionSelect, ob der Handel zulässig ist und keine offenen Positionen bestehen. 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 Ihrer Auswahl, berechnen den Stop-Loss erneut basierend auf der Nutzerauswahl, stellen sicher, dass der Stop-Loss gültig ist (unterhalb des Einstiegs für Kauf, oberhalb für Verkauf, bei Bedarf um 10 Punkte angepasst), führen einen Kauf oder Verkauf mit „obj_Trade. Buy” oder „obj_Trade.Sell” unter Verwendung von „LotSize” und „Shark Signal”, protokollieren Erfolg oder Misserfolg und markieren das Muster in „tradedPatterns” als gehandelt; 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 dem Kompilieren erhalten wir folgendes Ergebnis.

Abwärtssignal:

BESTÄTIGTES ABWÄRTSSIGNAL

Aufwärtssignal:

BESTÄTIGTES AUFWÄRTSSIGNAL

Aus dem Bild können wir ersehen, dass wir das harmonische Muster zeichnen können 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. Bleibt nur noch das Backtesting 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 System für die Shark-Muster in MQL5 entwickelt, das die Preisaktion nutzt, um steigende und fallende harmonische Shark-Muster mit Fibonacci-Ratios 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 Implementierungen nutzen, können Sie dieses Shark-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/19479

Beigefügte Dateien |
Entwicklung des Price Action Analysis Toolkit (Teil 42): Interaktive Chart-Prüfung mit Schaltflächenlogik und statistischen Ebenen Entwicklung des Price Action Analysis Toolkit (Teil 42): Interaktive Chart-Prüfung mit Schaltflächenlogik und statistischen Ebenen
In einer Welt, in der es auf Geschwindigkeit und Präzision ankommt, müssen die Analysetools so intelligent sein wie die Märkte, auf denen wir handeln. In diesem Artikel wird ein EA vorgestellt, der auf der Logik von Schaltflächen basiert – ein interaktives System, das rohe Kursdaten sofort in aussagekräftige statistische Werte umwandelt. Mit einem einzigen Klick werden Mittelwert, Abweichung, Perzentile und vieles mehr berechnet und angezeigt, sodass fortschrittliche Analysen zu klaren Signalen auf dem Chart werden. Es hebt die Zonen hervor, in denen der Preis am wahrscheinlichsten abprallen, zurückgehen oder durchbrechen wird, was die Analyse sowohl schneller als auch praktischer macht.
Wie man ein zyklusbasiertes Handelssystem aufbaut und optimiert (Detrended Price Oscillator – DPO) Wie man ein zyklusbasiertes Handelssystem aufbaut und optimiert (Detrended Price Oscillator – DPO)
Dieser Artikel erklärt, wie man ein Handelssystem mit dem Detrended Price Oscillator (DPO) in MQL5 entwickelt und optimiert. Er umreißt die Kernlogik des Indikators und zeigt, wie er kurzfristige Zyklen erkennt, indem er langfristige Trends herausfiltert. Anhand einer Reihe von Schritt-für-Schritt-Beispielen und einfachen Strategien lernen die Leser, wie man den Code erstellt, Ein- und Ausstiegssignale definiert und Backtests durchführt. Schließlich werden praktische Optimierungsmethoden vorgestellt, um die Leistung zu verbessern und das System an die sich ändernden Marktbedingungen anzupassen.
Aufbau eines Handelssystems (Teil 4): Wie zufällige Ausstiege die Handelserwartung beeinflussen Aufbau eines Handelssystems (Teil 4): Wie zufällige Ausstiege die Handelserwartung beeinflussen
Viele Händler haben diese Erfahrung gemacht, sie halten sich oft an ihre Einstiegskriterien, aber sie haben Probleme mit dem Handelsmanagement. Selbst bei den richtigen Setups können emotionale Entscheidungen – wie z. B. panische Ausstiege vor Erreichen des Take-Profit- oder Stop-Loss-Niveaus – zu einer fallenden Kapitalkurve führen. Wie können Händler dieses Problem lösen und ihre Ergebnisse verbessern? Dieser Artikel geht auf diese Fragen ein, indem er zufällige Gewinnraten untersucht und anhand von Monte-Carlo-Simulationen aufzeigt, wie Händler ihre Strategien verfeinern können, indem sie bei angemessenen Niveaus Gewinne mitnehmen, bevor das ursprüngliche Ziel erreicht ist.
Vereinfachen von Datenbanken in MQL5 (Teil 2): Verwendung von Metaprogrammierung zur Erstellung von Entitäten Vereinfachen von Datenbanken in MQL5 (Teil 2): Verwendung von Metaprogrammierung zur Erstellung von Entitäten
Wir haben die fortgeschrittene Verwendung von #define für die Metaprogrammierung in MQL5 erforscht, indem wir Entitäten erstellt haben, die Tabellen und Spaltenmetadaten (Typ, Primärschlüssel, Autoinkrement, Nullbarkeit usw.) darstellen. Wir haben diese Definitionen in TickORM.mqh zentralisiert, wodurch die Generierung von Metadatenklassen automatisiert und der Weg für eine effiziente Datenmanipulation durch den ORM geebnet wird, ohne dass SQL manuell geschrieben werden muss.