English 日本語
preview
Automatisieren von Handelsstrategien in MQL5 (Teil 30): Erstellen eines harmonischen AB-CD-Preisaktionsmusters mit visuellem Feedback

Automatisieren von Handelsstrategien in MQL5 (Teil 30): Erstellen eines harmonischen AB-CD-Preisaktionsmusters mit visuellem Feedback

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

Einführung

In unserem letzten Artikel (Teil 29) haben wir das System der Gartley-Muster in MetaQuotes Language 5 (MQL5) entwickelt, das harmonische Auf- und Abwärtsmuster von Gartley unter Verwendung präziser Fibonacci-Verhältnisse erkennt, den Handel mit berechneten Einstiegs-, Stop-Loss- und Take-Profit-Levels automatisiert und die Muster mit Chart-Objekten wie Dreiecken und Trendlinien visualisiert. In Teil 30 stellen wir ein AB=CD-Mustersystem vor. Während das Gartley-System auf der Erkennung spezifischer harmonischer Strukturen mit mehreren Kanten beruht, die durch mehrere Fibonacci-Niveaus definiert sind, identifiziert das AB=CD-System speziell Muster, die sich bilden, wenn zwei gleichwertige Preissegmente (AB und CD) durch Umkehrpunkte und unterschiedliche Retracement- und Extensions-Verhältnisse gefunden werden, was zu einer einfacheren, aber dynamischen Mustererkennung führt. Das AB=CD-System führt Trades mit dynamischen Eingängen und mehrstufigen Take-Profit-Zielen aus und verbessert die Visualisierung mit Dreiecken, Trendlinien und Labels für eine klare Musterdarstellung. Wir werden die folgenden Themen behandeln:

  1. Verstehen des harmonischen Musters AB=CD
  2. Implementation in MQL5
  3. Backtests
  4. Schlussfolgerung

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


Verstehen des harmonischen Musters AB=CD

Das Muster AB=CD ist eine harmonische Handelsformation, die potenzielle Umkehrzonen durch vier wichtige Umkehrpunkte – A, B, C und D – identifiziert, die steigender oder fallender Form existieren, und die Fibonacci Verhältnisse nutzt, um hochwahrscheinliche Handels-Setups zu identifizieren. Bei einem steigenden AB=CD bildet die Struktur eine Hoch-Tief-Hoch-Tief-Sequenz, bei der A ein hoher, B ein tiefer, C ein hoher und D ein tiefer (unter B) Umkehrpunkt ist, wobei die AB- und CD-Kanten gleich lang sind oder durch Fibonacci-Retracement- und Extensions-Verhältnisse miteinander verbunden sind; ein bearisches AB=CD folgt einer Tief-Hoch-Tief-Hoch-Sequenz, wobei D über B liegt:

Harmonisches Abwärtsmuster AB=CD:

HARMONISCHES ABWÄRTSMUSTER AB=CD

Harmonisches Aufwärtsmuster AB=CD

HARMONISCHES AUFWÄRTSMUSTER AB=CD

Unser Ansatz umfasst das Erkennen dieser Umkehrpunkte innerhalb eines bestimmten Bereichs der Balken, die Validierung des Musters, indem sichergestellt wird, dass die BC-Kante 0,382 bis 0,886 von AB und die CD-Kante 1,13 bis 2,618 von BC zurückgeht, die Visualisierung des Musters mit Chart-Objekten wie Dreiecken und Trendlinien für mehr Klarheit und die Ausführung von Trades am D-Punkt mit berechneten Stop-Loss- und mehreren Take-Profit-Levels auf der Grundlage von Fibonacci-Retracements, um von erwarteten Umkehrungen 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.

//+------------------------------------------------------------------+
//|                                              ABCD 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 AB=CD 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

//--- 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 AB move)
input double LotSize = 0.01;      // Lot size for new orders
input bool AllowTrading = true;   // Enable or disable trading
//---------------------------------------------------------------------------

//--- 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

Um den Grundstein für das Muster AB=CD zu legen, 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. Anschließend definieren wir die Eingabeparameter für die Nutzeranpassung: „PivotLeft“ und „PivotRight“ auf jeweils 5 Takte, um den Rückblickbereich für die Umkehrpunkt-Erkennung festzulegen, „Tolerance“ auf 0,10, um eine 10%ige Abweichung bei den Fibonacci Ratios zuzulassen, „LotSize“ auf 0,01 für das Handelsvolumen und „AllowTrading“ auf true, um den automatischen Handel zu ermöglichen.

Als Nächstes definieren wir die Struktur „Pivot“ mit „time“ (datetime), „price“ (double) und „isHigh“ (bool), um Umkehrpunkte zu speichern, deklarieren „pivots“ als dynamisches Array, um diese Punkte zu halten, und initialisieren die Globals „g_patternFormationBar“ auf -1, um den Balken zu verfolgen, an dem sich ein Muster bildet, und „g_lockedPatternA“ auf 0, um die A-Pivot-Zeit für die Bestätigung des Musters zu sperren, wobei zu beachten ist, dass A anstelle von X verwendet wird, um den Fokus des AB=CD-Musters auf die AB- und CD-Kanten zu richten. Dieser Aufbau bildet den zentralen Rahmen für die Erkennung und den Handel mit AB=CD-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 Musters AB=CD 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.

Dann erstellen wir die Funktion „DrawTrendLine“, die eine Trendlinie (OBJ_TREND) zwischen zwei Punkten zeichnet, und schließlich entwickeln wir die Funktion „DrawTextEx“, die einen Text (OBJ_TEXT) an den Koordinaten („t“, „p“) mit „ObjectCreate“ erstellt, wobei „OBJPROP_TEXT“ auf den angegebenen Text, „OBJPROP_COLOR“, „OBJPROP_FONTSIZE“ und „OBJPROP_FONT“ auf „Arial Bold“ mit ObjectSetString und „ObjectSetInteger“ auf „Arial Bold“ gesetzt, mit OBJPROP_ANCHOR oberhalb der Hochs bzw. unterhalb der Tiefs verankert und mit OBJPROP_ALIGN zentriert. Wir können nun mit der Ereignishandlung durch OnTick fortfahren und versuchen, Umkehrpunkte zu identifizieren, die wir später zur 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 Anfangslogik der Funktion 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 erkannt wird. Anschließend wird das Array „pivots“ mit ArrayResize gelöscht, um eine neue Analyse zu gewährleisten. Als Nächstes rufen wir die Gesamtzahl der Balken mit Bars ab, legen den Umkehrpunkt-Erkennungsbereich mit „start“ als „PivotLeft“ und „end“ als Gesamtbalkenzahl minus „PivotRight“ fest und durchlaufen die Balken von „end – 1“ bis „start“.

Für jeden Balken nehmen wir an, dass es sich um einen hohen Umkehrpunkt („isPivotHigh“ true) und einen tiefen Umkehrpunkt („isPivotLow“ true) handelt, ermitteln die Hoch- und Tiefstpreise mit „iHigh“ und „iLow“und validieren den Pivot, indem sie 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 das 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.

DATEN DER UMKEHRPUNTE

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

//--- Extract the last four pivots as A, B, C, and D
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 AB=CD pattern is found
bool patternFound = false;
//--- Initialize pattern type
string patternType = "";
double used_retr = 0.0;
double used_ext = 0.0;
//--- Check for the high-low-high-low (Bullish reversal) structure
if(A.isHigh && (!B.isHigh) && C.isHigh && (!D.isHigh)) {
   //--- Calculate the difference between pivot A and B
   double diff = A.price - B.price;
   //--- Ensure the difference is positive
   if(diff > 0) {
      //--- Calculate the BC leg length
      double BC = C.price - B.price;
      double retrace = BC / diff;
      //--- Calculate the CD leg length
      double CD = C.price - D.price;
      double extension = CD / BC;
      //--- Define fib ratios
      double fib_retr[] = {0.382, 0.5, 0.618, 0.786, 0.886};
      double fib_ext[] = {2.618, 2.0, 1.618, 1.272, 1.13};
      bool valid = false;
      for(int k = 0; k < ArraySize(fib_retr); k++) {
         if(MathAbs(retrace - fib_retr[k]) <= Tolerance && MathAbs(extension - fib_ext[k]) <= Tolerance) {
            valid = true;
            used_retr = fib_retr[k];
            used_ext = fib_ext[k];
            break;
         }
      }
      if(valid && (D.price < B.price)) {
         patternFound = true;
         patternType = "Bullish";
      }
   }
}
//--- Check for the low-high-low-high (Bearish reversal) structure
if((!A.isHigh) && B.isHigh && (!C.isHigh) && D.isHigh) {
   //--- Calculate the difference between pivot B and A
   double diff = B.price - A.price;
   //--- Ensure the difference is positive
   if(diff > 0) {
      //--- Calculate the BC leg length
      double BC = B.price - C.price;
      double retrace = BC / diff;
      //--- Calculate the CD leg length
      double CD = D.price - C.price;
      double extension = CD / BC;
      //--- Define fib ratios
      double fib_retr[] = {0.382, 0.5, 0.618, 0.786, 0.886};
      double fib_ext[] = {2.618, 2.0, 1.618, 1.272, 1.13};
      bool valid = false;
      for(int k = 0; k < ArraySize(fib_retr); k++) {
         if(MathAbs(retrace - fib_retr[k]) <= Tolerance && MathAbs(extension - fib_ext[k]) <= Tolerance) {
            valid = true;
            used_retr = fib_retr[k];
            used_ext = fib_ext[k];
            break;
         }
      }
      if(valid && (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 4 Umkehrpunkte gefunden werden, wobei „g_patternFormationBar“ und „g_lockedPatternA“ auf -1 und 0 zurückgesetzt werden, da das Muster AB=CD die Punkte A, B, C und D erfordert. Dann extrahieren wir die letzten vier Umkehrpunkte aus dem Array „pivots“ und ordnen „A“ (früheste), „B“, „C“ und „D“ (späteste) zu, um die Musterstruktur zu bilden.

Als Nächstes prüfen wir, ob ein steigendes AB=CD-Muster (A Hoch, B Tief, C Hoch, D Tief) vorliegt, indem wir die AB-Kantendifferenz („A.price – B.price“) berechnen und sicherstellen, dass sie positiv ist, die BC-Kantenlänge („C.price – B.price“) und ihr Retracement-Verhältnis im Verhältnis zu AB, Berechnung der CD-Kantenlänge („C.price – D.price“) und ihres Ausdehnungsverhältnisses im Verhältnis zu BC, Festlegung von Fibonacci-Retracement-Verhältnissen (0.382, 0,5, 0,618, 0,786, 0,886) und Verlängerungsverhältnisse (2,618, 2,0, 1,618, 1,272, 1,13), und Überprüfung, ob beide Verhältnisse innerhalb der „Toleranz“ liegen, wobei sichergestellt wird, dass „D.price < B.price“, setzt „patternFound“ auf true, „patternType“ auf „Bullish“ (aufwärts) und speichert die übereinstimmenden „used_retr“ und „used_ext“. Zuletzt prüfen wir, ob ein fallendes AB=CD-Muster (A Tief, B Hoch, C Tief, D Hoch) vorliegt, indem wir ähnliche Berechnungen für AB („B.price – A.price“), BC („B.price – C.price“) und CD („D.price – C.price“), die anhand derselben Fibonacci-Verhältnisse validiert werden und sicherstellen, dass „D.price > B.price“ ist, wobei „patternFound“ auf „true“ und „patternType“ auf „Bearish“ (abwärts) gesetzt wird, falls gültig. Wenn das Muster gefunden wurde, können wir es im Chart visualisieren.

//--- If a valid AB=CD pattern is detected
if(patternFound) {
   //--- Print a message indicating the pattern type and detection time
   Print(patternType, " AB=CD 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 = "AB_" + IntegerToString(A.time);
  
   //--- Choose triangle color based on the pattern type
   color triangleColor = (patternType=="Bullish") ? clrBlue : clrRed;
  
   //--- Draw the first triangle connecting pivots A, B, and C
   DrawTriangle(signalPrefix+"_Triangle1", A.time, A.price, B.time, B.price, C.time, C.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);
}

Um das Muster zu visualisieren, protokollieren wir zunächst, wenn ein gültiges Muster erkannt wird („patternFound“ ist true), 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 „AB_“ 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ä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 ABC-Dreieck zu zeichnen, das die Umkehrpunkte A, B und C 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 Zeitpunkte der Umkehrpunkte und -preise, „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 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);

//--- 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);

//--- 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);

//--- Calculate the central label's time as the midpoint between pivots A and C
datetime centralTime = (A.time + C.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 AB=CD" : "Bearish AB=CD");
   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“ drei durchgezogene Trendlinien mit dem eindeutigen „signalPrefix“, um wichtige Umkehrpunkte zu verbinden: AB, BC und CD, unter Verwendung von Umkehrpunkt-Zeiten und -Preisen (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 Etiketten berechnet, wobei die Y-Koordinaten („textY_A“, „textY_B“, „textY_C“, „textY_D“), indem der Versatz addiert oder subtrahiert wird, je nachdem, ob es sich bei einem Umkehrpunkt um ein hohen („isHigh“ true) oder ein tiefen handelt, um die Kennzeichnung über den Hochs oder unter den Tiefs zu platzieren.

Als Nächstes erstellen wir mit „DrawTextEx“ Textbeschriftungen für die Umkehrpunkte A, B, C und D mit „signalPrefix“ und Suffixen wie „_Text_A“, die den jeweiligen Buchstaben anzeigen, an dem Zeitpunkt des Umkehrpunkts und der eingestellten Y-Koordinate positioniert sind und „clrBlack“, Schriftgröße 11 und den „isHigh“-Status desUmkehrpunkte zur Verankerung verwenden. Zuletzt berechnen wir die Position des zentralen Etiketts bei „centralTime“ als Mittelwert von „A.time“ und „C.time“ und „centralPrice“ bei „D.price“, erstellen mit ObjectCreate ein Textobjekt mit dem Namen „signalPrefix + '_Text_Center'“, setzen OBJPROP_TEXT auf „Bullish AB=CD“ oder „Bearish AB=CD“, 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“, um eine umfassende visuelle Darstellung der Struktur und des Typs des Musters im Chart zu gewährleisten. Wenn wir das Programm ausführen, sehen Sie hier eine Visualisierung der Ausgabe, die wir erhalten.

MUSTER MIT KENNZEICHNUNGEN UND 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 = D.time;
datetime lineEnd = D.time + PeriodSeconds(_Period)*2;

//--- Declare variables for entry price and take profit levels
double entryPriceLevel, TP1Level, TP2Level, TP3Level;
//--- Calculate pattern range (CD length)
double patternRange = (patternType=="Bullish") ? (C.price - D.price) : (D.price - C.price);
//--- 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;
   //--- Set TP1 at 0.382 fib retrace from D to C
   TP1Level = D.price + 0.382 * patternRange;
   //--- Set TP2 at 0.618 fib retrace from D to C
   TP2Level = D.price + 0.618 * patternRange;
} 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;
   //--- Set TP1 at 0.382 fib retrace from D to C
   TP1Level = D.price - 0.382 * patternRange;
   //--- Set TP2 at 0.618 fib retrace from D to C
   TP2Level = D.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 Handelsstufen 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“ und „TP3Level“ für Handelsberechnungen. Dann berechnen wir die „patternRange“ als CD-Länge („C.price – D.price“ für steigend, „D.price – C.price“ für fallend); für ein Aufwärts-Muster setzen wir „entryPriceLevel“ auf den Briefkurs (Ask) mit SymbolInfoDouble, „TP3Level“ auf den Preis von C, „TP1Level“ auf „D.price + 0.382 * patternRange“, und „TP2Level“ auf „D.price + 0.618 * patternRange“; für ein Abwärts-Muster verwenden wir den Geldkurs (Bid), setzen „TP3Level“ auf den Kurs von C, „TP1Level“ auf „D.price – 0,382 * patternRange“, und „TP2Level“ auf „D.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 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 Kennzeichnung 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:

ABWÄRTS-MUSTER

Aufwä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.

//--- 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)) {
         double entryPriceTrade = 0, stopLoss = 0, takeProfit = 0;
         point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
         bool tradeResult = false;
         //--- Determine next extension for SL
         double next_ext = 0.0;
         if(MathAbs(used_ext - 1.13) < 0.05) next_ext = 1.272;
         else if(MathAbs(used_ext - 1.272) < 0.05) next_ext = 1.618;
         else if(MathAbs(used_ext - 1.618) < 0.05) next_ext = 2.0;
         else if(MathAbs(used_ext - 2.0) < 0.05) next_ext = 2.618;
         else if(MathAbs(used_ext - 2.618) < 0.05) next_ext = 3.618;
         else next_ext = used_ext * 1.618; // fallback
         //--- For a Bullish pattern, execute a BUY trade
         if(patternType=="Bullish") { //--- BUY signal
            entryPriceTrade = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
            double BC_leg = C.price - B.price;
            stopLoss = C.price - next_ext * BC_leg;
            if(stopLoss > D.price) stopLoss = D.price - 10 * point;
            takeProfit = TP2Level;
            tradeResult = obj_Trade.Buy(LotSize, _Symbol, entryPriceTrade, stopLoss, takeProfit, "AB=CD 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);
            double BC_leg = B.price - C.price;
            stopLoss = C.price + next_ext * BC_leg;
            if(stopLoss < D.price) stopLoss = D.price + 10 * point;
            takeProfit = TP2Level;
            tradeResult = obj_Trade.Sell(LotSize, _Symbol, entryPriceTrade, stopLoss, takeProfit, "AB=CD Signal");
            if(tradeResult)
               Print("Sell order opened successfully.");
            else
               Print("Sell order failed: ", obj_Trade.ResultRetcodeDescription());
         }
      }
      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 AB=CD pattern is detected, reset the pattern lock variables
   g_patternFormationBar = -1;
   g_lockedPatternA = 0;
}

Hier schließen wir die Tick-Implementierung für das Muster ab, indem wir die Handelsausführung und die Musterbestätigung für das erkannte harmonische Muster AB=CD 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 dem Hinweis, dass auf eine Bestätigung gewartet wird, und beenden den Vorgang. Wenn wir uns dann immer noch auf dem Formationsbalken befinden („currentBarIndex == g_patternFormationBar“), steigen wir aus, um einen vorzeitigen Handel zu verhindern.

Zuletzt, wenn sich ein neuer Balken gebildet hat („currentBarIndex > g_patternFormationBar“) und der A-Pivot mit „g_lockedPatternA“ übereinstimmt, bestätigen wir das Muster, protokollieren es, aktualisieren „g_patternFormationBar“und prüfen, ob der Handel mit „AllowTrading“ erlaubt ist und keine offenen Positionen über PositionSelect existieren; wir bestimmen die nächste Fibonacci-Extension („next_ext“) für den Stop-Loss basierend auf „used_ext“ (z.g., 1,13 bis 1,272, bis 3,618, oder eine Ausweichlösung von „used_ext * 1,618“); für ein Aufwärts-Muster setzen wir „entryPriceTrade“ auf den Briefkurs (Ask), berechnen „BC_leg“ als „C.price – B.price“, setzen „stopLoss“ auf „C.price – next_ext * BC_leg“ (angepasst auf „D.price – 10 * point“, wenn über D), setzen „takeProfit“ auf „TP2Level“ und führen einen Kauf mit „obj_Trade.Buy“ unter Verwendung von „LotSize“ und „AB=CD Signal“ aus, wobei Erfolg oder Misserfolg protokolliert werden; für ein Abwärts-Muster verwenden wir den Geldkurs (Bid), berechnen „BC_leg“ als „B.price – C.price“, setzen „stopLoss“ auf „C.price + next_ext * BC_leg“ (angepasst auf „D.price + 10 * point“, wenn unter D), und führen einen Verkauf mit „obj_Trade.Sell“ aus; wenn der Handel nicht erlaubt 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 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 AB=CD-Mustersystem in MQL5 entwickelt, das die Preisaktion nutzt, um die harmonischen Auf- und Abwärts-Muster AB=CD mit präzisen Fibonacci-Retracement- und Verlängerungsverhältnissen zu erkennen, den Handel mit berechneten 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 AB=CD-Mustersystem 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/19442

Beigefügte Dateien |
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.
Vom Neuling zum Experten: Detaillierte Handelsberichte mit Reporting EA beherrschen Vom Neuling zum Experten: Detaillierte Handelsberichte mit Reporting EA beherrschen
In diesem Artikel befassen wir uns mit der Verbesserung der Details von Handelsberichten und der Übermittlung des endgültigen Dokuments per E-Mail im PDF-Format. Dies stellt eine Weiterentwicklung unserer bisherigen Arbeit dar, da wir weiterhin erforschen, wie wir die Leistungsfähigkeit von MQL5 und Python nutzen können, um Handelsberichte in den bequemsten und professionellsten Formaten zu erstellen und zu planen. Nehmen Sie an dieser Diskussion teil und erfahren Sie mehr über die Optimierung der Erstellung von Handelsberichten innerhalb des MQL5-Ökosystems.
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 eines individuellen Indikators für die Marktstimmung Entwicklung eines individuellen Indikators für die Marktstimmung
In diesem Artikel entwickeln wir einen nutzerdefinierten Indikator für die Marktstimmung, um die Bedingungen in aufwärts, abwärts, mehr und weniger Risiko oder neutral zu klassifizieren. Durch die Verwendung von mehreren Zeitrahmen kann der Indikator Händlern eine klarere Perspektive der allgemeinen Markttendenz und der kurzfristigen Bestätigungen bieten.