English Русский 日本語
preview
Einführung in MQL5 (Teil 17): Aufbau von Expert Advisors für eine Trendumkehr

Einführung in MQL5 (Teil 17): Aufbau von Expert Advisors für eine Trendumkehr

MetaTrader 5Handel |
177 5
Israel Pelumi Abioye
Israel Pelumi Abioye

Einführung

Willkommen zurück zu Teil 17 der Serie Einführung in MQL5! Dieser Teil baut weiter auf allem auf, was wir bisher erforscht haben, und verwendet unseren charakteristischen projektbasierten Ansatz, um Ihnen zu helfen, Ihre MQL5-Fähigkeiten anhand von Beispielen aus der Praxis zu schärfen. In Teil 16 haben wir uns auf das Kopf-Schultern-Muster konzentriert und einen Expert Advisor entwickelt, der dieses Muster automatisch erkennt, Handelsgeschäfte platziert und es sogar auf dem Chart visualisiert. Es war eine großartige Möglichkeit zu lernen, wie man mit Chart-Mustern in MQL5 arbeitet.

Ursprünglich wollte ich für diesen Artikel ein einzelnes Fortsetzungs- oder Umkehrmuster verwenden, wie z. B. die Fahne, den fallenden Keil oder den steigenden Keil. Als ich jedoch weiter nachforschte, entdeckte ich etwas Entscheidendes: Viele dieser Muster haben eine ähnliche Struktur und hängen häufig von Trendlinienbrüchen oder Umkehrungen ab. Dieser Abschnitt konzentriert sich daher auf die Entwicklung eines Expert Advisors, der Trendlinienausbrüche und Umkehrsituationen erkennen und handeln kann, anstatt sich auf ein einziges Muster zu beschränken. Mit einigen Anpassungen können Sie diese grundlegenden Ideen auf verschiedene Chart-Muster anwenden, nachdem Sie sie gemeistert haben.

In diesem Artikel erfahren Sie mehr über Folgendes:

  • Wie man mit ObjectGetValueByTime() den genauen Kurswert einer Trendlinie zum Zeitpunkt einer beliebigen Kerze abruft.
  • Identifizieren Sie potenzielle Ausbruchs- und Umkehrsignale auf der Grundlage der Kerzenstruktur um Trendlinien.
  • Der Unterschied zwischen steigenden und fallenden Trendlinien und wie man ihre Interaktion mit der Preisbewegung interpretiert.
  • Wie wichtig es ist, das Verhalten der letzten Kerzen (wie Dochte und Schlusskurse) zu überprüfen, um eine Kursablehnung oder einen Ausbruch zu bestätigen.
  • Die praktische Anwendung zeitbasierter Vergleiche, um die Ausführung von Handelsgeschäften aufgrund veralteter oder irrelevanter Signale zu vermeiden.
  • Wie man einen einfachen, aber flexiblen Expert Advisor (EA) erstellt, der automatisch auf der Grundlage von Interaktionen mit Trendlinien handelt.

1. Verstehen von Trendlinien

Eine gerade Linie, die zwei oder mehr Kurspunkte in einem Chart kreuzt, wird als Trendlinie bezeichnet. Richtig positioniert, hilft sie Ihnen, den aktuellen Trend und mögliche Handelschancen zu erkennen. Trendlinien sind schräg und folgen der natürlichen Richtung des Marktes, die seitwärts, aufwärts oder abwärts verlaufen kann, im Gegensatz zu den etablierten horizontalen Unterstützungs- und Widerstandsniveaus.

Da viele Chart-Muster von Trendlinien eingerahmt werden oder um diese herum entstehen, sind Trendlinien besonders wichtig, um bestimmte Muster zu erkennen. So wird der Kurs beispielsweise zwischen zwei konvergierenden Trendlinien eingeschlossen, bis es zu einem Durchbruch in einem fallenden oder steigenden Keil kommt. Die Konsolidierungszone vor der Fortsetzungsbewegung wird durch Trendlinien in Fahnen- und Wimpelmustern definiert. 

1.1. Arten von Trendlinien

1.1.1. Steigende Trendlinie

In einem Aufwärtstrend dient eine steigende Trendlinie als Unterstützungsniveau, indem sie höhere Tiefs verbindet. Er hilft Ihnen, wahrscheinliche Verkaufschancen zu erkennen, wenn der Kurs darunter bricht, was auf eine potenzielle Trendumkehr oder einen tieferen Abschwung hindeutet, sowie Kaufgelegenheiten bei Rücksetzern.

Abbildung 1. Steigende Trendlinie

1.1.2. Fallende Trendlinie

Eine fallende Trendlinie deutet auf eine rückläufige Dynamik hin, während eine steigende Trendlinie aufwärts gerichtet ist. In einem fallenden Markt entsteht sie durch die Verbindung von zwei oder mehr niedrigeren Hochs. Als Widerstandsmarke deutet diese abwärts gerichtete Linie darauf hin, dass sich der Markt in eine allgemein rückläufige Richtung bewegt.

Bei kurzen Kursanstiegen bieten fallende Trendlinien Verkaufsmöglichkeiten, da sie eine Kursumkehr nach unten vorhersagen, sobald der Kurs die Linie berührt. Wichtig ist jedoch ein Ausbruch, wie es bei steigenden Trendlinien der Fall ist. Der Kurs könnte eine wahrscheinliche Trendwende von einem Abwärts- zu einem Aufwärtstrend signalisieren und eine potenzielle Kaufgelegenheit darstellen, wenn er über die fallende Trendlinie bricht.

Abbildung 2 Fallende Trendlinie

Eine fallende Trendlinie deutet auf eine rückläufige Dynamik hin, während eine steigende Trendlinie aufwärts gerichtet ist. In einem fallenden Markt entsteht sie durch die Verbindung von zwei oder mehr niedrigeren Hochs. Als Widerstandsmarke deutet diese abwärts gerichtete Linie darauf hin, dass sich der Markt in eine allgemein rückläufige Richtung bewegt.

Durch die Hervorhebung signifikanter Ausbrüche, die häufig auf Veränderungen der Marktdynamik hinweisen, sorgen Trendlinien für visuelle Klarheit und taktische Handelseinstiege. Das Verständnis des Trendlinienverhaltens bietet im Gegensatz zum Auswendiglernen bestimmter Muster eine vielseitige Grundlage für die Mustererkennung und ist besonders hilfreich bei der Entwicklung automatisierter Techniken wie Expert Advisors in MQL5.


2. Das Projekt einrichten

2.1. Wie der EA funktioniert

In diesem Projekt werden wir einen Expert Advisor erstellen, der die Trendlinien des Charts nutzt, um automatisch Trades zu tätigen. Je nach Marktlage erstellt der EA legitime steigende oder fallende Trendlinien, indem er die jüngsten Hochs und Tiefs des Swing analysiert.

Der EA verfolgt, wie der Preis mit den Trendlinien interagiert, sobald diese etabliert sind. Es gibt zwei Hauptszenarien, in denen gehandelt wird. Der EA handelt zunächst in Trendrichtung und erwartet eine Umkehr, wenn der Kurs die Trendlinie erreicht und sich umkehrt. Zweitens erkennt der EA ein Breakout-Retest-Muster und platziert einen Handel in der Breakout-Richtung, wenn der Kurs eine Trendlinie kreuzt und sie dann von der anderen Seite her erneut testet. Aufgrund dieser Logik kann der EA mit verschiedenen Chart-Mustern verwendet werden, darunter Keile, Fahnen, Dreiecke und Kanäle, die alle hauptsächlich von der Dynamik der Trendlinien abhängen.

2.1.1. Steigende Trendlinie

2.1.1.1. Logik für einen Kauf

  • Der EA erkennt zwei tiefe Umkehrpunkte und zieht eine steigende Trendlinie über diese.
  • Der EA achtet kontinuierlich auf Kursbewegungen, die die Trendlinie wieder berühren oder sich ihr nähern, ohne sie zu durchbrechen.
  • Wenn der Kurs die Trendlinie berührt und sofort eine Aufwärtskerze bildet, betrachtet der EA dies als gültigen Abpraller.
  • Sobald ein Abprallen von der steigenden Trendlinie nach oben bestätigt wird, platziert der EA einen Kaufauftrag.
  • Der Nutzer kann die Anzahl der Punkte unter dem Einstiegskurs oder das Tief der Abprallkerze als SL festlegen.
  • Der Nutzer kann den TP in Punkten über dem Einstiegskurs angeben.

Abbildung 3. Steigende Trendlinie Kauflogik

2.1.1.2. Logik für einen Verkauf

  • Der EA erkennt zwei tiefe Umkehrpunkte und zieht eine steigende Trendlinie über diese.
  • Er wartet kontinuierlich auf einen Ausbruch nach unten unter diese steigende Trendlinie.
  • Sobald der Kurs unter die Trendlinie fällt, wartet der EA auf einen erneuten Test, bei dem der Kurs wieder die Trendlinie von unten berührt.
  • Wenn sich unmittelbar nach dem Retest eine Abwärtskerze bildet und das Tief unterhalb der Trendlinie liegt, betrachtet der EA dies als gültigen Ausbruch und Bestätigung.
  • Bei Bestätigung des Abwärts-Retests erteilt der EA einen Verkaufsauftrag.
  • Der Nutzer kann die Anzahl der Punkte über dem Einstiegskurs oder über dem Hoch der Retestkerze als SL festlegen.
  • Der Nutzer kann auch den TP in Punkten unterhalb des Einstiegskurses angeben.

Abbildung 4. Verkaufslogik bei Steigender Trendlinie

2.1.2. Fallende Trendlinie

2.1.2.1. Logik für einen Kauf

  • Der EA erkennt zwei hohe Umkehrpunkte und zeichnet eine fallende Trendlinie über sie.
  • Er wartet kontinuierlich auf einen Ausbruch nach oben über die fallende Trendlinie.
  • Sobald der Kurs die Trendlinie durchbricht, wartet der EA auf einen erneuten Test, bei dem der Kurs zurückkehrt und die durchbrochene Trendlinie berührt oder sich ihr von oben nähert.
  • Wenn sich unmittelbar nach dem Retest eine Aufwärtskerze bildet und das Hoch über der Trendlinie liegt, betrachtet der EA dies als gültigen Ausbruch und Bestätigung.
  • Bei Bestätigung des Aufwärts-Retests platziert der EA einen Kaufauftrag.
  • Der Nutzer kann die Anzahl der Punkte unter dem Einstiegskurs oder unter dem Tiefpunkt der Retest-Kerze als Stop Loss (SL) festlegen.
  • Der Nutzer kann auch den Take Profit (TP) in Punkten über dem Einstiegskurs festlegen.

Abbildung 5. Kauflogik bei fallender Trendlinie

2.1.2.2. Logik für einen Verkauf

  • Der EA erkennt zwei hohe Umkehrpunkte und zeichnet eine fallende Trendlinie über sie.
  • Er achtet kontinuierlich auf Kursbewegungen, die die fallende Trendlinie berühren.
  • Wenn der Kurs die Trendlinie berührt und sofort eine Abwärtskerze bildet, betrachtet der EA dies als eine gültige Umkehr.
  • Bei der Bestätigung eines Abpralls von der fallenden Trendlinie platziert der EA einen Verkaufsauftrag.
  • Der Nutzer kann die Anzahl der Punkte über dem Einstiegskurs oder dem Hoch der Abprallkerze als Stop Loss (SL) festlegen.
  • Der Nutzer kann auch den Take Profit (TP) in Punkten unterhalb des Einstiegskurses festlegen.

Abbildung 6. Verkaufslogik bei fallender Trendlinie

Anmerkung:  Das Hauptziel der Handelsstrategie, die in diesem Projekt erforscht wird, besteht darin, Ihr Wissen über die MQL5-Programmierung zu erweitern, insbesondere über die Arbeit mit Chart-Mustern und die Erstellung nützlicher Expert Advisors. Es ist nicht dafür gedacht, mit echtem Geld oder für den Live-Handel verwendet zu werden. Bevor Sie eine Technik auf einem Live-Markt anwenden, sollten Sie immer einen umfassenden Backtest durchführen und sich von einem Finanzexperten beraten lassen.


3. Identifizierung steigender und fallender Trendlinien

Nachdem wir die Funktionsweise des Expert Advisors eingehend erörtert haben, können wir nun mit der programmtechnischen Umsetzung beginnen. Der erste Schritt besteht darin, den EA in die Lage zu versetzen, Trendlinien automatisch zu erkennen und zu zeichnen. Der EA ermittelt zunächst zwei signifikante Umkehrpunkte auf dem Chart, bevor er eine Trendlinie zeichnet. Für eine steigende Trendlinie wird nach den beiden letzten höheren Tiefs (tiefe Umkehrpunkte) gesucht, die eine Aufwärtsdynamik anzeigen.

Es wird nach den beiden letzten niedrigeren Hochs (hohe Umkehrpunkte), die Abwärtsdruck bedeuten, nach einer fallenden Trendlinie suchen. Nach der Identifizierung dieser Umkehrpunkte wird der EA sie mit einer Trendlinie verbinden. Diese Linie dient dann als Benchmark für die Identifizierung möglicher Ausbruchs- oder Umkehrmöglichkeiten.

3.1. Abrufen von Kerzendaten

Die Schlüsselkomponente eines jeden Projekts, das Chart-Muster beinhaltet, sind Kerzendaten. Ohne sie ist es unmöglich, die Preisstruktur zu beurteilen oder Hochs und Tiefs zu erkennen. Aus diesem Grund ist die Extraktion historischer Kerzendaten aus dem Chart der erste Schritt bei der Erstellung unseres EA. In diesen Daten sind wichtige Kursdetails wie Eröffnungs-, Höchst-, Tiefst- und Schlusskurs der einzelnen Kerzen enthalten. Anhand dieser Daten können wir Trendlinien erkennen, Marktstrukturen ausfindig machen und Umkehr- oder Ausbruchssignale nutzen, um mögliche Handelseinstiege zu entdecken.

Beispiel:
// Timeframe to use for retrieving candlestick data (default is the current chart timeframe)
input ENUM_TIMEFRAMES time_frame = PERIOD_CURRENT;

// Number of past bars (candlesticks) to check
int bars_check = 500;

// Arrays to store candlestick data
double close_price[];   // Stores close prices
double open_price[];    // Stores open prices
double low_price[];     // Stores low prices
double high_price[];    // Stores high prices
datetime time_price[];  // Stores time data for each candle

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
// Set arrays as series so the newest bar is index 0 ( start from the latest bar)
   ArraySetAsSeries(close_price, true);
   ArraySetAsSeries(open_price, true);
   ArraySetAsSeries(low_price, true);
   ArraySetAsSeries(high_price, true);
   ArraySetAsSeries(time_price, true);

   return(INIT_SUCCEEDED);  // Signal that the EA initialized successfully
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {

  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
// Copy the latest candlestick data into the arrays
   CopyOpen(_Symbol, time_frame, 1, bars_check, open_price);     // Open prices
   CopyClose(_Symbol, time_frame, 1, bars_check, close_price);   // Close prices
   CopyLow(_Symbol, time_frame, 1, bars_check, low_price);       // Low prices
   CopyHigh(_Symbol, time_frame, 1, bars_check, high_price);     // High prices
   CopyTime(_Symbol, time_frame, 1, bars_check, time_price);     // Candle times

  }

Erläuterung:

Um einen EA zu erstellen, der auf Chart-Muster reagiert, müssen historische Kerzendaten gesammelt werden. Der Code speichert diese Informationen in fünf Arrays: open, close, high, low und time. Diese Arrays dienen als Grundlage für die Zeichnung von Trendlinien und die Erkennung von Umkehrpunkten. Mit PERIOD_CURRENT als Standardeinstellung verwendet der EA den Zeitrahmen des aktuellen Charts. Über die Eingabevariable time_frame kann der Nutzer den Zeitrahmen auswählen, in dem der EA operieren soll (z. B. M1, H1, D1). Die Variable bars_check, die in diesem Fall auf 500 gesetzt ist, bestimmt, wie viele vorherige Kerzen untersucht werden sollen. Daher wird der EA die Kerze, die sich gerade bildet, ignorieren und die letzten 500 abgeschlossenen Kerzen abrufen und untersuchen.

Jedes dieser Arrays wird mit ArraySetAsSeries(..., true); innerhalb der Funktion OnInit() eingerichtet. Dieser Schritt ist von entscheidender Bedeutung, da er die Reihenfolge des Arrays umkehrt, sodass sich Index 0 auf die jüngste abgeschlossene Kerze bezieht, Index 1 auf die Kerze, die davor lag, und so weiter. Diese Indexierungsmethode, die mit der jüngsten Kursaktivität beginnt und rückwärts arbeitet, entspricht der intuitiven Betrachtungsweise von Händlern. 

In der Methode OnTick() findet der Großteil der Datenabfrage statt. Diese Funktion wird bei jedem Tick oder bei jeder Änderung des Marktpreises aktiviert. Darin zieht der EA Kerzendaten in die entsprechenden Arrays mit CopyOpen, CopyClose, CopyHigh, CopyLow und CopyTime. Während die erste Option garantiert, dass der EA die sich gerade entwickelnde Kerze vermeidet (da sie sich schnell ändern kann und nicht zuverlässig für die Mustererkennung ist), ist das zweite Argument der gewählte Zeitrahmen. Die erhaltenen Informationen gehen zurück auf bars_check Kerzen.

3.2. Identifizierung der steigenden Trendlinie

Nach dem Abrufen der Kerzendaten folgt das Auffinden von Umkehrpunkten in der Kursbewegung. Unser erstes Ziel ist es, eine steigende Trendlinie zu finden, die in der Regel auftritt, wenn der Markt höhere Tiefs erreicht. Dies bedeutet, dass zuerst zwei legitime Tiefs gefunden werden müssen. Um dem EA zu helfen, mögliche Aufwärts-Setups wie Abpraller oder Ausbrüche entlang dieser Aufwärtsunterstützung zu identifizieren, werden diese tiefe Umkehrpunkte als Ankerpunkte für das Einzeichnen der steigenden Trendlinie dienen.

Beispiel:

// Timeframe to use for retrieving candlestick data (default is the current chart timeframe)
input ENUM_TIMEFRAMES time_frame = PERIOD_CURRENT;
// Input to enable or disable drawing of the ascending trend line (true = allow drawing)
input bool allow_uptrend = true;
// Number of candles to look back when identifying swing lows for drawing the trend line
input int LookbackBars = 5;

// Number of past bars (candlesticks) to check
int bars_check = 500;

// Arrays to store candlestick data
double close_price[];   // Stores close prices
double open_price[];    // Stores open prices
double low_price[];     // Stores low prices
double high_price[];    // Stores high prices
datetime time_price[];  // Stores time data for each candle

double first_low;           // Price value of the first identified swing low
datetime first_low_time;    // Time when the first swing low occurred

double second_low;          // Price value of the second identified swing low
datetime second_low_time;   // Time when the second swing low occurred

string up_trend = "Up Trend";  // Label used to name the ascending trend line object on the chart

long chart_id = ChartID();     // Stores the current chart ID for referencing during object creation or manipulation

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
// Set arrays as series so the newest bar is index 0 ( start from the latest bar)
   ArraySetAsSeries(close_price, true);
   ArraySetAsSeries(open_price, true);
   ArraySetAsSeries(low_price, true);
   ArraySetAsSeries(high_price, true);
   ArraySetAsSeries(time_price, true);

   return(INIT_SUCCEEDED);  // Signal that the EA initialized successfully
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {

   ObjectsDeleteAll(chart_id);

  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
// Copy the latest candlestick data into the arrays
   CopyOpen(_Symbol, time_frame, 1, bars_check, open_price);     // Open prices
   CopyClose(_Symbol, time_frame, 1, bars_check, close_price);   // Close prices
   CopyLow(_Symbol, time_frame, 1, bars_check, low_price);       // Low prices
   CopyHigh(_Symbol, time_frame, 1, bars_check, high_price);     // High prices
   CopyTime(_Symbol, time_frame, 1, bars_check, time_price);     // Candle times

// If the user allows drawing of ascending trend line
   if(allow_uptrend)
     {
      // First loop: Find the most recent swing low (first low)
      for(int i = LookbackBars; i < bars_check - LookbackBars; i++)
        {
         // Check if current point is a swing low
         if(IsSwingLow(low_price, i, LookbackBars))
           {
            // Store price and time of the first (latest) swing low
            first_low = low_price[i];
            first_low_time = time_price[i];
            break;  // Exit loop after finding the first swing low
           }
        }

      // Second loop: Find an earlier swing low that is lower than the first low
      for(int i = LookbackBars; i < bars_check - LookbackBars; i++)
        {
         // Check for earlier swing low that is lower and occurs before the first low
         if(IsSwingLow(low_price, i, LookbackBars) && low_price[i] < first_low && time_price[i] < first_low_time)
           {
            // Store price and time of the second (older) swing low
            second_low = low_price[i];
            second_low_time = time_price[i];
            break;  // Exit loop after finding the second swing low
           }
        }

      // Create an ascending trend line from the second low to the first low
      ObjectCreate(chart_id, up_trend, OBJ_TREND, 0, second_low_time, second_low, first_low_time, first_low);
      ObjectSetInteger(chart_id, up_trend, OBJPROP_TIMEFRAMES, OBJ_NO_PERIODS);  // Temporarily hide line on all timeframes

      // If the swing structure is valid (i.e., second low is lower than first)
      if(first_low > second_low && second_low > 0)
        {
         // Extend the trend line to the right
         ObjectSetInteger(chart_id, up_trend, OBJPROP_RAY_RIGHT, true);

         // Show the trend line on all timeframes
         ObjectSetInteger(chart_id, up_trend, OBJPROP_TIMEFRAMES, OBJ_ALL_PERIODS);

         // Set visual properties: color and thickness
         ObjectSetInteger(chart_id, up_trend, OBJPROP_COLOR, clrBlue);
         ObjectSetInteger(chart_id, up_trend, OBJPROP_WIDTH, 3);
        }
     }

  }

//+------------------------------------------------------------------+
//| FUNCTION FOR LOWS                                                |
//+------------------------------------------------------------------+
bool IsSwingLow(const double &low[], int index, int lookback)
  {

   for(int i = 1; i <= lookback; i++)
     {

      if(low[index] > low[index - i] || low[index] > low[index + i])
         return false;
     }
   return true;
  }

Ausgabe:

Abbildung 7. Identifizierung der steigenden Trendlinie

Erläuterung:

Der Zweck der Funktion IsSwingLow besteht darin, Tiefs in einer Kursreihe zu finden. Die drei erforderlichen Argumente sind ein Array mit Tiefstpreisen (low[]), ein bestimmter Index (index) innerhalb dieses Arrays und eine Rückblickzahl, die angibt, wie viele Balken links und rechts davon geprüft werden sollen. Die for-Schleife innerhalb der Methode iteriert von 1 bis lookback. Es wird bei jeder Iteration das Tief des aktuellen Index mit den Tiefs von Index + i (rechts) und Index - i (links) verglichen.

Die Funktion gibt den Wert false zurück und zeigt damit an, dass der Punkt kein Tiefpunkt ist, wenn der aktuelle Tiefpunkt größer ist als einer der nahegelegenen Tiefs. Die Funktion gibt true zurück und zeigt damit die Entdeckung eines tiefen Umkehrpunkts an, wenn das aktuelle Tief niedriger ist als alle nahegelegenen Lows innerhalb des Lookback-Bereichs. Sie garantiert im Wesentlichen, dass der Tief bei dem angegebenen Index ein lokales Minimum ist. Das heißt, der tiefste Punkt in der Umgebung des Ortes.

Die Logik der Trendlinie wird durch zwei wesentliche Eingänge gesteuert. Die erste, allow_uptrend, ist ein Boolescher Wert, mit dem der Nutzer wählen kann, ob die Trendlinie in steigender Reihenfolge gezeichnet werden soll. Der Code versucht, zwei tiefe Umkehrpunkte zu finden und eine Trendlinie zu erstellen, die diese verbindet, wenn er auf true gesetzt ist. LookbackBars, die zweite Eingabe, gibt an, wie viele Kerzen links und rechts von einem Punkt untersucht werden sollen, um festzustellen, ob es sich um einen tiefen Umkehrpunkt handelt. Die Funktion IsSwingLow verwendet denselben Rückblickwert. Die Anforderung eines tiefen Umkehrpunkts wird mit einem niedrigeren Wert empfindlicher und mit einem höheren Wert strenger (was einen stärkeren Einbruch erfordert).

Die Kurswerte der beiden letzten Tiefs in den Kerzendaten werden in den Variablen first_low und second_low gespeichert. Die Zeitpunkte, zu denen solche Tiefs auftraten, werden entsprechend in first_low_time und second_low_time gespeichert. Die Aufwärtstrendlinie wird dann anhand dieser Paare von Zeit und Preis eingezeichnet. Die ID des aktuellen Charts wird in chart_id gespeichert, und der Name des Trendlinien-Objekts (ein einfaches Label: „Aufwärtstrend“) wird in der Variablen up_trend gespeichert. Beim Erzeugen oder Ändern von grafischen Objekten, wie z. B. Trendlinien, wird die Chart-ID benötigt, um den entsprechenden Chartkontext zu bestimmen.

Der EA beginnt mit der Suche nach zwei legitimen tiefen Umkehrpunkte, wenn allow_uptrend true ist. Um zu verhindern, dass auf Out-of-Bounds-Array-Elemente zugegriffen wird, durchläuft die erste for-Schleife die Preisdaten von LookbackBars bis zu bars_check - LookbackBars. Um festzustellen, ob es sich bei jedem Punkt um einen tiefen Umkehrpunkt handelt, wird die Funktion IsSwingLow verwendet. Nach der Ermittlung des letzten rechtmäßigen Tiefs werden dessen Preis und Uhrzeit in first_low und first_low_time gespeichert, bevor die Schleife beendet wird.

Nach der Identifizierung des ersten Tiefpunkts verwendet die zweite for-Schleife IsSwingLow, um die Suche in der gleichen Richtung fortzusetzen, fügt aber diesmal zwei Bedingungen hinzu: Der zweite Tiefpunkt muss niedriger als der erste sein, und er muss früher als der erste Tiefpunkt stattgefunden haben. Nachdem ein solcher Punkt gefunden wurde, wird die Schleife unterbrochen und der Preis und die Zeit in second_low und second_low_time gespeichert. Um eine steigende Trendlinie zu bilden, muss der EA zunächst ein früheres, niedrigeres Tief und dann ein neueres, höheres Tief entdecken, was durch diese zweistufige Suche gewährleistet wird.

Der Code verwendet dann ObjectCreate, um die steigende Trendlinie nach der Identifizierung der beiden Tiefs zu erstellen. Diese Funktion verknüpft die Werte second_low und first_low des Charts anhand ihrer jeweiligen Zeitstempel. Um zu verhindern, dass die Linie zu früh gezogen wird, wird sie zunächst mit OBJ_NO_PERIODS für alle Zeiten ausgeblendet. Nachdem bestätigt wurde, dass die Struktur korrekt ist (erster_niedriger Wert > zweiter_niedriger Wert und zweiter_niedriger Wert > 0), wird OBJPROP_RAY_RIGHT verwendet, um die Linie nach rechts zu verlängern, sodass sie in der Zeit nach vorne projiziert wird. OBJ_ALL_PERIODS wird auch verwendet, um es über alle Zeiträume hinweg sichtbar zu machen.

Die Farbe der Trendlinie wird auf blau (clrBlue) geändert, und ihre Breite wird auf drei Pixel gesetzt, um ihre visuelle Klarheit zu erhöhen. Durch diese Verbesserungen hebt sich die Trendlinie von anderen Chartelementen ab und ist im Chart leicht zu erkennen.

3.3. Identifizierung einer fallenden Trendlinie

Der nächste Schritt besteht darin, ein ähnliches Verfahren zum Auffinden und Zeichnen einer fallenden Trendlinie zu duplizieren, nachdem wir die Theorie zur Erstellung einer steigenden Trendlinie mit Hilfe von tiefen Umkehrpunkten erfolgreich angewendet haben. Dieses Mal konzentrieren wir uns jedoch auf die Hochs und nicht auf die Tiefs. Ein hoher Umkehrpunkt ist ein lokales Maximum, das auftritt, wenn ein Preispunkt größer ist als eine vorher festgelegte Anzahl von umliegenden Balken auf der linken und rechten Seite.

Wir werden eine Funktion zur Identifizierung von hohen Umkehrpunkten entwickeln, historische Kerzen durchlaufen, um zwei legitime Hochs zu identifizieren (bei denen das zweite Hoch niedriger ist als das erste), und dann eine fallende Trendlinie zeichnen, die diese beiden Punkte verbindet, genau wie wir es mit der steigenden Trendlinie getan haben. Mit ihrer abwärts gerichteten Steigung weist diese Linie auf einen Abwärtstrend hin und dient als mögliches Widerstandsniveau, an dem Händler verkaufen oder ein Abprall des Preises erwarten könnten.

Beispiel:
// Timeframe to use for retrieving candlestick data (default is the current chart timeframe)
input ENUM_TIMEFRAMES time_frame = PERIOD_CURRENT;
// Input to enable or disable drawing of the ascending trend line (true = allow drawing)
input bool allow_uptrend = true;
// Number of candles to look back when identifying swing lows for drawing the trend line
input int LookbackBars = 5;
// Input to enable or disable drawing of the descebding trend line (true = allow drawing)
input bool allow_downtrend = true;

// Number of past bars (candlesticks) to check
int bars_check = 500;

// Arrays to store candlestick data
double close_price[];   // Stores close prices
double open_price[];    // Stores open prices
double low_price[];     // Stores low prices
double high_price[];    // Stores high prices
datetime time_price[];  // Stores time data for each candle

double first_low;           // Price value of the first identified swing low
datetime first_low_time;    // Time when the first swing low occurred
double second_low;          // Price value of the second identified swing low
datetime second_low_time;   // Time when the second swing low occurred
string up_trend = "Up Trend";  // Label used to name the ascending trend line object on the chart
long chart_id = ChartID();     // Stores the current chart ID for referencing during object creation or manipulation

double first_high;          // Price value of the first identified swing high (latest high)
datetime first_high_time;   // Time when the first swing high occurred
double second_high;         // Price value of the second identified swing high (older high)
datetime second_high_time;  // Time when the second swing high occurred

string down_trend = "Down Trend";  // Label used to name the descending trend line object on the chart

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
// Set arrays as series so the newest bar is index 0 ( start from the latest bar)
   ArraySetAsSeries(close_price, true);
   ArraySetAsSeries(open_price, true);
   ArraySetAsSeries(low_price, true);
   ArraySetAsSeries(high_price, true);
   ArraySetAsSeries(time_price, true);

   return(INIT_SUCCEEDED);  // Signal that the EA initialized successfully
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {

   ObjectsDeleteAll(chart_id);

  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
// Copy the latest candlestick data into the arrays
   CopyOpen(_Symbol, time_frame, 1, bars_check, open_price);     // Open prices
   CopyClose(_Symbol, time_frame, 1, bars_check, close_price);   // Close prices
   CopyLow(_Symbol, time_frame, 1, bars_check, low_price);       // Low prices
   CopyHigh(_Symbol, time_frame, 1, bars_check, high_price);     // High prices
   CopyTime(_Symbol, time_frame, 1, bars_check, time_price);     // Candle times

// If the user allows drawing of ascending trend line
   if(allow_uptrend)
     {
      // First loop: Find the most recent swing low (first low)
      for(int i = LookbackBars; i < bars_check - LookbackBars; i++)
        {
         // Check if current point is a swing low
         if(IsSwingLow(low_price, i, LookbackBars))
           {
            // Store price and time of the first (latest) swing low
            first_low = low_price[i];
            first_low_time = time_price[i];
            break;  // Exit loop after finding the first swing low
           }
        }

      // Second loop: Find an earlier swing low that is lower than the first low
      for(int i = LookbackBars; i < bars_check - LookbackBars; i++)
        {
         // Check for earlier swing low that is lower and occurs before the first low
         if(IsSwingLow(low_price, i, LookbackBars) && low_price[i] < first_low && time_price[i] < first_low_time)
           {
            // Store price and time of the second (older) swing low
            second_low = low_price[i];
            second_low_time = time_price[i];
            break;  // Exit loop after finding the second swing low
           }
        }

      // Create an ascending trend line from the second low to the first low
      ObjectCreate(chart_id, up_trend, OBJ_TREND, 0, second_low_time, second_low, first_low_time, first_low);
      ObjectSetInteger(chart_id, up_trend, OBJPROP_TIMEFRAMES, OBJ_NO_PERIODS);  // Temporarily hide line on all timeframes

      // If the swing structure is valid (i.e., second low is lower than first)
      if(first_low > second_low && second_low > 0)
        {
         // Extend the trend line to the right
         ObjectSetInteger(chart_id, up_trend, OBJPROP_RAY_RIGHT, true);

         // Show the trend line on all timeframes
         ObjectSetInteger(chart_id, up_trend, OBJPROP_TIMEFRAMES, OBJ_ALL_PERIODS);

         // Set visual properties: color and thickness
         ObjectSetInteger(chart_id, up_trend, OBJPROP_COLOR, clrBlue);
         ObjectSetInteger(chart_id, up_trend, OBJPROP_WIDTH, 3);
        }
     }

//
// Only proceed if drawing descending trend lines is enabled
   if(allow_downtrend)
     {
      // First loop: Find the most recent swing high (first high)
      for(int i = LookbackBars; i < bars_check - LookbackBars; i++)
        {
         // Check if the current bar is a swing high
         if(IsSwingHigh(high_price, i, LookbackBars))
           {
            // Store the price and time of this latest swing high
            first_high = high_price[i];
            first_high_time = time_price[i];

            break;  // Exit loop once the first swing high is found
           }
        }

      // Second loop: Find an earlier swing high that is higher than the first high and occurred before it
      for(int i = LookbackBars; i < bars_check - LookbackBars; i++)
        {
         // Check for earlier swing high that is higher and happened before the first one
         if(IsSwingHigh(high_price, i, LookbackBars) && high_price[i] > first_high && time_price[i] < first_high_time)
           {
            // Store the price and time of this older swing high
            second_high = high_price[i];
            second_high_time = time_price[i];

            break;  // Exit loop once the second swing high is found
           }
        }

      // Create a trend line object from the second swing high to the first swing high
      ObjectCreate(chart_id, down_trend, OBJ_TREND, 0, second_high_time, second_high, first_high_time, first_high);

      // Initially hide the trend line across all timeframes to avoid partial drawing
      ObjectSetInteger(chart_id, down_trend, OBJPROP_TIMEFRAMES, OBJ_NO_PERIODS);

      // Validate the swing structure:
      // The older swing high should be higher than the later swing high to confirm a descending trend line
      if(first_high < second_high && second_high > 0)
        {
         // Extend the trend line indefinitely to the right for better visual guidance
         ObjectSetInteger(chart_id, down_trend, OBJPROP_RAY_RIGHT, true);

         // Make the trend line visible on all chart timeframes
         ObjectSetInteger(chart_id, down_trend, OBJPROP_TIMEFRAMES, OBJ_ALL_PERIODS);

         // Set the trend line color to dark green for clear distinction
         ObjectSetInteger(chart_id, down_trend, OBJPROP_COLOR, clrDarkGreen);

         // Set the thickness of the trend line to 3 pixels for better visibility
         ObjectSetInteger(chart_id, down_trend, OBJPROP_WIDTH, 3);
        }
     }
  }

//+------------------------------------------------------------------+
//| FUNCTION FOR LOWS                                                |
//+------------------------------------------------------------------+
bool IsSwingLow(const double &low[], int index, int lookback)
  {

   for(int i = 1; i <= lookback; i++)
     {

      if(low[index] > low[index - i] || low[index] > low[index + i])
         return false;
     }
   return true;
  }

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

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

Ausgabe:

Abbildung 8. Identifizierung der fallenden Trendlinie

Erläuterung:

Die Funktion IsSwingHigh vergleicht das Hoch eines Balkens mit den Hochs der benachbarten Balken während eines vorgegebenen Rückblickzeitraums und ermittelt so, ob ein bestimmter Balken ein hoher Umkehrpunkt ist. Der Balken gibt „true“ zurück und bestätigt einen lokalen Höchststand, wenn sein Höchststand größer ist als der eines dieser Nachbarn; andernfalls gibt er „false“ zurück. Die fallende Trendlinie im Chart kann mit der Eingabevariablen allow_downtrend gezeichnet oder deaktiviert werden.

Der Code sucht zunächst nach dem letzten hohen Umkehrpunkt, oder first_high, und zeichnet dessen Preis und Zeit auf, um die fallende Trendlinie zu bestimmen. Anschließend wird ein früherer hoher Umkehrpunkt (second_high) gesucht, das dem ersten vorausging und höher war. Die Trendlinie, die diese beiden Orte miteinander verbindet, wird daher „Abwärtstrend“ genannt. Eine fallende Trendlinie wird deutlich, wenn das jüngste Hoch unter dem vorherigen liegt, was einen Abwärtstrend bestätigt. Er verbindet die unteren Hochs, ist gut sichtbar gestaltet und erstreckt sich auf der Karte nach vorne. Diese Logik ist im Wesentlichen das Gegenteil einer steigenden Trendlinie, die höhere Tiefs verbindet, um einen Aufwärtstrend anzuzeigen.


4. Ausführen von Handelsgeschäften auf der Grundlage von Trendlinienausbrüchen und -umkehrungen

Im letzten Kapitel haben wir besprochen, wie man die wichtigen Umkehrpunkte des Preischarts verwendet, um sowohl steigende als auch fallende Trendlinien programmatisch zu erstellen. Auf dieser Grundlage werden wir in diesem Kapitel erörtern, wie man auf der Grundlage von Trendlinienausbrüchen und -umkehrungen handelt. Wir werden uns insbesondere damit befassen, wie man erkennt, wann der Kurs bestimmte Trendlinien kreuzt oder eine Kursumkehr vollzieht, und wie man diese Indikatoren zum effizienten Einstieg in oder Ausstieg aus Trades nutzt.

4.1. Steigende Trendlinien

Wir haben uns bisher nur darauf konzentriert, den ersten und zweiten Tiefststand zu ermitteln, um die steigende Trendlinie zu bilden. Wie können wir jedoch feststellen, wann der Markt ausbricht und die Trendlinie erneut testen könnte, oder wann er sie berührt und sich umkehrt? Um Handelsentscheidungen auf der Grundlage der Interaktion zwischen dem Kurs und der Trendlinie zu treffen, ist diese Phase unerlässlich. Dank der eingebauten Funktionen, die es uns ermöglichen, das Preisniveau einer Trendlinie zu einem beliebigen Zeitpunkt oder Balkenindex zu erhalten, hat MQL5 diesen Prozess zum Glück vereinfacht.

Um fundiertere Handelsentscheidungen treffen zu können, gehen wir in diesem Abschnitt darauf ein, wie man erkennt, wann sich der Kurs einer steigenden Trendlinie nähert oder diese kreuzt. Wir werden uns die Werkzeuge ansehen, die MQL5 bietet, egal ob Sie versuchen, einen Abprall von der Unterstützung oder einen Breakout-and-Retest-Einstieg zu erwischen. Wir werden uns auf die Untersuchung der letzten vier Balken im Chart konzentrieren, da Ausbrüche und Umkehrungen in der Regel innerhalb der letzten Kerzen stattfinden. In den meisten Fällen zeigen diese jüngsten Balken an, dass eine Trendlinie durchbrochen oder eingehalten wurde.

Daher werden wir sorgfältig prüfen, ob alle vier jüngsten Balken die Voraussetzungen für einen Ausbruch oder eine Umkehr erfüllen, anstatt den gesamten Chartverlauf zu betrachten. Mit dieser Strategie können wir auf neue Marktbewegungen reagieren und fundierte Handelsentscheidungen treffen. In den folgenden Abschnitten werden wir MQL5 verwenden, um diese Überlegungen programmatisch umzusetzen.

Beispiel:
double t_line_value;   // Ascending trend line price level at the time of the most recent bar (not the ticking bar)
double t1_line_value;  // Ascending trend line price level at the time of the second most recent bar
double t2_line_value;  // Ascending trend line price level at the time of the third most recent bar
double t3_line_value;  // Ascending trend line price level at the time of the fourth most recent bar
if(allow_uptrend)
  {
// First loop: Find the most recent swing low (first low)
   for(int i = LookbackBars; i < bars_check - LookbackBars; i++)
     {
      // Check if current point is a swing low
      if(IsSwingLow(low_price, i, LookbackBars))
        {
         // Store price and time of the first (latest) swing low
         first_low = low_price[i];
         first_low_time = time_price[i];
         break;  // Exit loop after finding the first swing low
        }
     }

// Second loop: Find an earlier swing low that is lower than the first low
   for(int i = LookbackBars; i < bars_check - LookbackBars; i++)
     {
      // Check for earlier swing low that is lower and occurs before the first low
      if(IsSwingLow(low_price, i, LookbackBars) && low_price[i] < first_low && time_price[i] < first_low_time)
        {
         // Store price and time of the second (older) swing low
         second_low = low_price[i];
         second_low_time = time_price[i];
         break;  // Exit loop after finding the second swing low
        }
     }

// Create an ascending trend line from the second low to the first low
   ObjectCreate(chart_id, up_trend, OBJ_TREND, 0, second_low_time, second_low, first_low_time, first_low);
   ObjectSetInteger(chart_id, up_trend, OBJPROP_TIMEFRAMES, OBJ_NO_PERIODS);  // Temporarily hide line on all timeframes

// If the swing structure is valid (i.e., second low is lower than first)
   if(first_low > second_low && second_low > 0)
     {
      // Extend the trend line to the right
      ObjectSetInteger(chart_id, up_trend, OBJPROP_RAY_RIGHT, true);

      // Show the trend line on all timeframes
      ObjectSetInteger(chart_id, up_trend, OBJPROP_TIMEFRAMES, OBJ_ALL_PERIODS);

      // Set visual properties: color and thickness
      ObjectSetInteger(chart_id, up_trend, OBJPROP_COLOR, clrBlue);
      ObjectSetInteger(chart_id, up_trend, OBJPROP_WIDTH, 3);


      // Get the price values of the trend line at the corresponding times of the four most recent bars
      t_line_value = ObjectGetValueByTime(chart_id, up_trend, time_price[0], 0);   // Current bar
      t1_line_value = ObjectGetValueByTime(chart_id, up_trend, time_price[1], 0);  // One bar ago
      t2_line_value = ObjectGetValueByTime(chart_id, up_trend, time_price[2], 0);  // Two bars ago
      t3_line_value = ObjectGetValueByTime(chart_id, up_trend, time_price[3], 0);  // Three bars ago

      Comment("Ascending trend tine value for the last 4 Bars",
              "\nBar 0: ",  DoubleToString(t_line_value, _Digits),
              "\nBar 1: ", DoubleToString(t1_line_value, _Digits),
              "\nBar 2: ",  DoubleToString(t2_line_value, _Digits),
              "\nBar 3: ",  DoubleToString(t3_line_value, _Digits));

     }
  }

Ausgabe:

Abbildung 9. Trendlinienwerte

Erläuterung:

Um den Wert der Trendlinie zu erhalten, wird die Funktion ObjectGetValueByTime() verwendet, die das Preisniveau des bezeichneten Chartobjekts (in diesem Fall die Trendlinie) zu einem bestimmten Zeitpunkt liefert. Auf diese Weise lässt sich die Position der Trendlinie zum Schluss jedes der letzten Balken bestimmen.

Hierfür verwenden wir vier verschiedene Variablen. Der Wert der Trendlinie bei Takt 0, d. h. der jüngste abgeschlossene Takt und nicht derjenige, der sich aktiv aufbaut (gemeinhin als „tickender Takt“ bezeichnet), wird in der Variablen t_line_value gespeichert. Das Niveau der Trendlinie bei Takt 1 oder dem unmittelbar vorangegangenen Takt wird in der Variablen t1_line_value gespeichert. Die Trendlinienwerte für die Balken 2 und 3, die die Balken widerspiegeln, die vor zwei bzw. drei Perioden geschlossen wurden, werden in ähnlicher Weise in t2_line_value und t3_line_value gespeichert.

Auch wenn wir time_price[0] als „bar 0“ bezeichnen, wird er im Chart als der zweite Balken von rechts angezeigt. Das liegt daran, dass wir den letzten Balken, der am weitesten rechts liegt, nicht in unsere Analyse einbeziehen, weil er noch im Wachstum begriffen ist und noch nicht geschlossen wurde. Die Art und Weise, wie wir die Funktion CopyTime() früher im Code verwendet haben, bei der der Kopiervorgang bei Index 1 begann und der aktuelle (nicht geschlossene) Balken für vertrauenswürdigere Daten übersprungen wurde, entspricht ebenfalls diesem Muster. Zur Überprüfung oder Fehlersuche druckt der Code diese Trendlinienwerte mit der Funktion Comment() direkt in das Chart. Anhand dieser Ausgabe können Sie beobachten, wie sich die Trendlinie im Verhältnis zu den letzten Balken verhält. Sie wird im oberen linken Bereich des Chartfensters angezeigt. Sie ist besonders hilfreich, um herauszufinden, ob die Trendlinie einen Ausbruch oder eine Umkehrung darstellt.

4.1.1. Handelsausführung bei steigender Trendlinie

Der nächste Schritt ist die Bereitstellung der Logik, die entscheidet, wann ein Handel ausgeführt wird, sei es ein Ausbruch oder eine Umkehrung, da wir nun wissen, wie wir die Trendlinienwerte zum Zeitpunkt der letzten geschlossenen Balken genau extrahieren können. Wir können nun feststellen, was an der Trendlinie geschieht, indem wir die Werte der Trendlinie für die letzten Balken mit der tatsächlichen Kursbewegung vergleichen, z. B. mit den Kerzenschlüssen oder den Tiefs/Hochs.

4.1.1.1. Umkehrung

Es ist nun an uns, die Logik für die Durchführung von Handelsgeschäften auf der Grundlage von Umkehrsignalen zu spezifizieren, da wir nun wissen, wie wir die Kurswerte der Trendlinie zu verschiedenen Taktzeiten erhalten können. Um festzustellen, ob der Markt die Trendlinie respektiert hat und von ihr abweicht, werden die aktuellen Balkenpreise mit den entsprechenden Trendlinienwerten verglichen. Halten Sie Ausschau nach einem Abprall von der Trendlinie, auch wenn dieses Konzept einfach erscheinen mag. Die exakte Umsetzung kann etwas schwieriger sein. Umkehrungen können viele Strukturen haben und sind häufig subtil. Manchmal liegt der gesamte Kerzenkörper auf der Trendlinie, während die Kerze zu anderen Zeiten einfach in die Linie hineinläuft und oberhalb der Linie schließt. Manchmal bricht der Kurs sogar unter ein bestimmtes Niveau und kehrt dann heftig zurück, ein Phänomen, das als falscher Ausbruch bezeichnet wird.

Die Parameter, die erforderlich sind, um eine echte Umkehrung genau zu erkennen, können durch diese Abweichungen kompliziert werden. Neben der Position der aktuellen Kerze sollte auch die Art und Weise berücksichtigt werden, wie mehrere Kerzen mit der Trendlinie interagieren. Dies könnte bedeuten, dass man mit unterstützenden Indikatoren wie z. B. Aufwärtskerzenmustern überprüft, ob es einen signifikanten Schlusskurs unterhalb der Trendlinie gibt und ob die Tiefs der letzten Kerzen die Linie berühren oder von ihr abprallen. Um Fehlsignale zu minimieren, erfordern diese mehrschichtigen Bedingungen eine sorgfältige Programmierlogik und machen die Umkehrerkennung mit Trendlinien komplexer.

Im Folgenden sind einige gültige Umkehrbedingungen aufgeführt:

Abprall des Dochts und Aufwärtsumkehr bei steigender Trendlinie:

Abbildung 10. Abprall des Dochts und Aufwärtsumkehr

Wie Sie sehen können, kehrte die Kerze sofort nach oben um, nachdem nur der Docht die steigende Trendlinie berührt hatte. Dies beweist, dass der Kurs schnell zurückgewiesen wurde, als er die Trendlinie als Unterstützung angriff. Die Umkehr wird auch durch die Tatsache unterstützt, dass derselbe Balken später als Aufwärtskerze schließt. Diese Art von Kursbewegung, bei der der Docht mit der Trendlinie interagiert, der Körper aber stark in die andere Richtung schließt, ist eine legitime Voraussetzung für einen Kaufabschluss, da sie eine starke Reaktion der Käufer auf einem entscheidenden Unterstützungsniveau zeigt.

Berührung des Dochtes einer Abwärtskerze, gefolgt von einer Aufwärts-Bestätigung:

Abbildung 11. Berührung des Dochts einer Abwärts-Kerze, gefolgt von einer Aufwärts-Bestätigung

Der Docht einer Abwärtskerze berührte die steigende Trendlinie in der obigen Grafik, und die Kerze schloss oberhalb dieser Linie. Die Kerze erfüllt jedoch nicht sofort das Erfordernis eines Umkehr-Einstiegs, da sie fällt. Die unmittelbar folgende Aufwärtskerze bestätigt dies. Diese Aufwärtskerze ist eine legitime Bedingung für die Durchführung eines Kaufgeschäfts, da sie anzeigt, dass die Käufer nach dem Kontakt mit der Trendlinie eingegriffen haben. Um die Umkehrung zu bestätigen, muss ein Aufwärtsbalken vorhanden sein.

Mehrere Abwärts-Schlusskurse vor Bestätigung der Aufwärts-Trendwende:

Abbildung 12. Mehrere Abwärts-Schlusskurse vor der Bestätigung der Aufwärts-Trendwende

Eine Abwärtskerze schloss oberhalb der steigenden Trendlinie, als ihr Docht diese berührte. Obwohl die nächste Kerze ebenfalls rückläufig war, schloss sie oberhalb der Trendlinie. Eine Aufwärtskerze, die die Voraussetzungen für einen Einstieg in den Umkehrkurs erfüllte, bildete sich erst bei der dritten Kerze. Der Markt folgte der Trendlinie, aber es dauerte ein paar Kerzen, bis die Bullen die Kontrolle übernahmen, wie dieses Setup zeigt. Eine mögliche Kauftransaktion wird durch die letzte Aufwärtskerze bestätigt.

Falscher Ausbruchsversuch mit sofortiger Aufwärts-Bestätigung:

Abbildung 13. Falscher Ausbruch

Ein möglicher Durchbruch könnte dadurch angezeigt werden, dass die erste Kerze, die die steigende Trendlinie berührt hat, unterhalb dieser geschlossen hat. Die darauf folgende Kerze war jedoch eine kräftige Aufwärtskerze, die oberhalb der Trendlinie schloss. Diese prompte Reaktion ist von entscheidender Bedeutung, da die Aufwärtskerze, die sich unmittelbar nach der Berührung entwickelt hat, die Umkehr unterstützt. Der Markt betrachtet die Trendlinie nach wie vor als Unterstützung, wie die sofortige Aufwärtsreaktion trotz eines kurzen Schlusskurses unterhalb der Linie beweist. Es handelt sich also um ein legitimes Setup für einen Kauf.

Es gibt bestimmte Bedingungen, die eine Umkehrung an der Trendlinie ungültig machen, ebenso wie es viele Bedingungen gibt, die sie rechtfertigen. Dank dieser falschen Umstände können wir uns von schlechten Handelsgeschäften und falschen Warnungen fernhalten. Sie sind auch wichtig, um zu verhindern, dass innerhalb eines kurzen Zeitraums mehrere Handelsgeschäfte getätigt werden, die durch ähnliche oder sich wiederholende Signale ausgelöst werden. Dadurch bleibt unser Ansatz diszipliniert und verhindert ein Überhandeln.

Ungültige Umkehr nach bestätigtem Ausbruch:

Abbildung 14. Ungültige Umkehr nach bestätigtem Ausbruch

Die steigende Trendlinie wurde bereits von zwei Abwärtskerzen überschritten. Eine Aufwärtskerze gilt nicht mehr als legitimer Umkehrindikator, selbst wenn sie oberhalb der Trendlinie endet. Der Ausbruch gilt als bestätigt, da die Struktur bereits durchbrochen wurde. Jede weitere Aufwärts-Aktivität wird als Rauschen oder als möglicher erneuter Test angesehen und gilt nicht als legitimer Einstieg.

Verhinderung von wiederholten Handelssignalen bei mehreren Umkehrungen:

Abbildung 15. Sich wiederholende Handelssignale

Jede der drei Aufwärtskerzen im vorangegangenen Bild hat einen Docht, der die steigende Trendlinie berührt, bevor er nach oben umschlägt. Der Algorithmus könnte bei jeder Berührung mehrere Trades ausführen, wenn nicht die richtigen Bedingungen gegeben sind, um solche Muster herauszufiltern, selbst wenn sie alle Teil der gleichen breiten Umkehrbewegung sind. In solchen Situationen ist es wichtig, eine Logik zu entwickeln, die die Ausführung des Handels auf das erste gültige Signal beschränkt.

Ihre Logik muss für diese und eine Reihe anderer vergleichbarer Situationen gründlich geprüft und überdacht werden. Bei unsachgemäßer Handhabung können sie zu verzögerten Einträgen, wiederholten Abschlüssen oder falschen Signalen führen. Es müssen strenge Validierungsanforderungen aufgestellt werden, um unnötige oder doppelte Handelsausführungen bei dicht gedrängten Signalen zu vermeiden und um legitime Umkehrsituationen zu überprüfen.

Beispiel:

#include <Trade/Trade.mqh>
CTrade trade;
int MagicNumber = 532127;


// Timeframe to use for retrieving candlestick data (default is the current chart timeframe)
input ENUM_TIMEFRAMES time_frame = PERIOD_CURRENT;
// Input to enable or disable drawing of the ascending trend line (true = allow drawing)
input bool allow_uptrend = true;
// Number of candles to look back when identifying swing lows for drawing the trend line
input int LookbackBars = 5;

// Input to enable or disable drawing of the descebding trend line (true = allow drawing)
input bool allow_downtrend = true;
input bool allow_break_out = true;    // Enable or disable trade execution on trend line breakout (true = allow)
input bool allow_reversal = true;     // Enable or disable trade execution on trend line reversal (true = allow)
input double lot_size = 0.6;          // Lot size for each trade
input double sl_points = 10;          // Stop Loss in points from entry price
input double tp_points = 50;          // Take Profit in points from entry price

// Number of past bars (candlesticks) to check
int bars_check = 500;

// Arrays to store candlestick data
double close_price[];   // Stores close prices
double open_price[];    // Stores open prices
double low_price[];     // Stores low prices
double high_price[];    // Stores high prices
datetime time_price[];  // Stores time data for each candle

double first_low;           // Price value of the first identified swing low
datetime first_low_time;    // Time when the first swing low occurred

double second_low;          // Price value of the second identified swing low
datetime second_low_time;   // Time when the second swing low occurred
string up_trend = "Up Trend";  // Label used to name the ascending trend line object on the chart
long chart_id = ChartID();     // Stores the current chart ID for referencing during object creation or manipulation
double first_high;          // Price value of the first identified swing high (latest high)
datetime first_high_time;   // Time when the first swing high occurred
double second_high;         // Price value of the second identified swing high (older high)
datetime second_high_time;  // Time when the second swing high occurred
string down_trend = "Down Trend";  // Label used to name the descending trend line object on the chart
double t_line_value;   // Ascending trend line price level at the time of the most recent bar (not the ticking bar)
double t1_line_value;  // Ascending trend line price level at the time of the second most recent bar
double t2_line_value;  // Ascending trend line price level at the time of the third most recent bar
double t3_line_value;  // Ascending trend line price level at the time of the fourth most recent bar

// Time boundary used to limit lookback for valid reversal setups
datetime lookbackf_time;

datetime lastTradeBarTime = 0;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
// Set arrays as series so the newest bar is index 0 ( start from the latest bar)
   ArraySetAsSeries(close_price, true);
   ArraySetAsSeries(open_price, true);
   ArraySetAsSeries(low_price, true);
   ArraySetAsSeries(high_price, true);
   ArraySetAsSeries(time_price, true);

   trade.SetExpertMagicNumber(MagicNumber);

   return(INIT_SUCCEEDED);  // Signal that the EA initialized successfully
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {

   ObjectsDeleteAll(chart_id);

  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
// Copy the latest candlestick data into the arrays
   CopyOpen(_Symbol, time_frame, 1, bars_check, open_price);     // Open prices
   CopyClose(_Symbol, time_frame, 1, bars_check, close_price);   // Close prices
   CopyLow(_Symbol, time_frame, 1, bars_check, low_price);       // Low prices
   CopyHigh(_Symbol, time_frame, 1, bars_check, high_price);     // High prices
   CopyTime(_Symbol, time_frame, 1, bars_check, time_price);     // Candle times

   double ask_price = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
   datetime currentBarTime = iTime(_Symbol, time_frame, 0);

// If the user allows drawing of ascending trend line
   if(allow_uptrend)
     {
      // First loop: Find the most recent swing low (first low)
      for(int i = LookbackBars; i < bars_check - LookbackBars; i++)
        {
         // Check if current point is a swing low
         if(IsSwingLow(low_price, i, LookbackBars))
           {
            // Store price and time of the first (latest) swing low
            first_low = low_price[i];
            first_low_time = time_price[i];
            lookbackf_time = time_price[i - 3];

            break;  // Exit loop after finding the first swing low
           }
        }

      // Second loop: Find an earlier swing low that is lower than the first low
      for(int i = LookbackBars; i < bars_check - LookbackBars; i++)
        {
         // Check for earlier swing low that is lower and occurs before the first low
         if(IsSwingLow(low_price, i, LookbackBars) && low_price[i] < first_low && time_price[i] < first_low_time)
           {
            // Store price and time of the second (older) swing low
            second_low = low_price[i];
            second_low_time = time_price[i];
            break;  // Exit loop after finding the second swing low
           }
        }

      // Create an ascending trend line from the second low to the first low
      ObjectCreate(chart_id, up_trend, OBJ_TREND, 0, second_low_time, second_low, first_low_time, first_low);
      ObjectSetInteger(chart_id, up_trend, OBJPROP_TIMEFRAMES, OBJ_NO_PERIODS);  // Temporarily hide line on all timeframes

      // If the swing structure is valid (i.e., second low is lower than first)
      if(first_low > second_low && second_low > 0)
        {
         // Extend the trend line to the right
         ObjectSetInteger(chart_id, up_trend, OBJPROP_RAY_RIGHT, true);

         // Show the trend line on all timeframes
         ObjectSetInteger(chart_id, up_trend, OBJPROP_TIMEFRAMES, OBJ_ALL_PERIODS);

         // Set visual properties: color and thickness
         ObjectSetInteger(chart_id, up_trend, OBJPROP_COLOR, clrBlue);
         ObjectSetInteger(chart_id, up_trend, OBJPROP_WIDTH, 3);

         // Get the price values of the trend line at the corresponding times of the four most recent bars
         t_line_value = ObjectGetValueByTime(chart_id, up_trend, time_price[0], 0);   // Current bar
         t1_line_value = ObjectGetValueByTime(chart_id, up_trend, time_price[1], 0);  // One bar ago
         t2_line_value = ObjectGetValueByTime(chart_id, up_trend, time_price[2], 0);  // Two bars ago
         t3_line_value = ObjectGetValueByTime(chart_id, up_trend, time_price[3], 0);  // Three bars ago

         // Number of bars between the valid bullish confirmation candle and current time
         int no_bars = 0;

         // Loop through the last 4 bars to check for reversal wick touch on the trend line
         for(int i = 0; i <= 3; i++)
           {
            // Condition: Wick of the candle touches below the trend line but opens above it (indicating a potential reversal zone)
            if(low_price[i] < ObjectGetValueByTime(chart_id, up_trend, time_price[i], 0) &&
               open_price[i] > ObjectGetValueByTime(chart_id, up_trend, time_price[i], 0))
              {
               // Check if there's a bullish confirmation candle after the wick touch (within or immediately after)
               for(int j = i; j >= 0; j--)
                 {
                  // Bullish candle that closed above the trend line
                  if(close_price[j] > open_price[j] &&
                     close_price[j] > ObjectGetValueByTime(chart_id, up_trend, time_price[j], 0))
                    {
                     // Count how many bars ago this confirmation occurred
                     no_bars = Bars(_Symbol, time_frame, time_price[j], TimeCurrent());
                     break;
                    }
                 }
               break; // Exit after first valid reversal zone is found
              }
           }

         // Check whether a similar wick touch (reversal) happened recently to avoid repeated signals
         bool prev_touch = false;

         if((low_price[1] < t1_line_value && close_price[1] > open_price[1]) ||  // Bar 1 had reversal wick and bullish body
            (low_price[2] < t2_line_value && close_price[2] > open_price[2]))    // Bar 2 had reversal wick and bullish body
           {
            prev_touch = true;  // Flag that a recent touch already occurred
           }

         // Final condition for executing a BUY trade on a reversal setup
         if(
            // One of the recent 4 bars touched and rejected the trend line (wick below, open above), AND
            ((low_price[0] < t_line_value && open_price[0] > t_line_value) ||
             (low_price[1] < t1_line_value && open_price[1] > t1_line_value) ||
             (low_price[2] < t2_line_value && open_price[2] > t2_line_value) ||
             (low_price[3] < t3_line_value && open_price[3] > t3_line_value))
            &&
            // Current candle must be bullish and close above the trend line
            (close_price[0] > open_price[0]) && close_price[0] > t_line_value
            &&
            // The bullish confirmation must occur within 3 bars
            (no_bars < 3)
            &&
            // No recent wick reversal signal already processed
            prev_touch == false
            &&
            // The signal must be more recent than the lookback time threshold
            (time_price[3] > lookbackf_time)
            &&
            // Reversal signals are allowed and this signal is not duplicated from the same bar
            (allow_reversal == true && currentBarTime != lastTradeBarTime)
         )
           {
            // Execute BUY trade with defined lot size, SL and TP
            trade.Buy(lot_size, _Symbol, ask_price, ask_price - sl_points, ask_price + tp_points);
            lastTradeBarTime = currentBarTime; // Update last trade bar time to avoid duplicate signals
           }
        }
     }

//
// Only proceed if drawing descending trend lines is enabled
   if(allow_downtrend)
     {
      // First loop: Find the most recent swing high (first high)
      for(int i = LookbackBars; i < bars_check - LookbackBars; i++)
        {
         // Check if the current bar is a swing high
         if(IsSwingHigh(high_price, i, LookbackBars))
           {
            // Store the price and time of this latest swing high
            first_high = high_price[i];
            first_high_time = time_price[i];

            break;  // Exit loop once the first swing high is found
           }
        }

      // Second loop: Find an earlier swing high that is higher than the first high and occurred before it
      for(int i = LookbackBars; i < bars_check - LookbackBars; i++)
        {
         // Check for earlier swing high that is higher and happened before the first one
         if(IsSwingHigh(high_price, i, LookbackBars) && high_price[i] > first_high && time_price[i] < first_high_time)
           {
            // Store the price and time of this older swing high
            second_high = high_price[i];
            second_high_time = time_price[i];

            break;  // Exit loop once the second swing high is found
           }
        }

      // Create a trend line object from the second swing high to the first swing high
      ObjectCreate(chart_id, down_trend, OBJ_TREND, 0, second_high_time, second_high, first_high_time, first_high);

      // Initially hide the trend line across all timeframes to avoid partial drawing
      ObjectSetInteger(chart_id, down_trend, OBJPROP_TIMEFRAMES, OBJ_NO_PERIODS);

      // Validate the swing structure:
      // The older swing high should be higher than the later swing high to confirm a descending trend line
      if(first_high < second_high && second_high > 0)
        {
         // Extend the trend line indefinitely to the right for better visual guidance
         ObjectSetInteger(chart_id, down_trend, OBJPROP_RAY_RIGHT, true);

         // Make the trend line visible on all chart timeframes
         ObjectSetInteger(chart_id, down_trend, OBJPROP_TIMEFRAMES, OBJ_ALL_PERIODS);

         // Set the trend line color to dark green for clear distinction
         ObjectSetInteger(chart_id, down_trend, OBJPROP_COLOR, clrDarkGreen);

         // Set the thickness of the trend line to 3 pixels for better visibility
         ObjectSetInteger(chart_id, down_trend, OBJPROP_WIDTH, 3);

        }
     }
  }

//+------------------------------------------------------------------+
//| FUNCTION FOR LOWS                                                |
//+------------------------------------------------------------------+
bool IsSwingLow(const double &low[], int index, int lookback)
  {

   for(int i = 1; i <= lookback; i++)
     {

      if(low[index] > low[index - i] || low[index] > low[index + i])
         return false;
     }
   return true;
  }

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

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

Ausgabe:

Abbildung 16. Abprall des Dochts

Abbildung 17. Falscher Ausbruch

Abbildung 18. Abprall des Dochts und Aufwärtsumkehr

Erläuterung:

Um auf die Klasse CTrade zuzugreifen, die zum Platzieren und Verwalten von Handelsgeschäften in MQL5 verwendet wird, muss der Code zunächst die Handelsbibliothek Trade.mqh enthalten. So wie Buy() und Sell() Handelsoperationen durchführen, wird ein CTrade-Objekt namens trade erstellt. Um die von diesem speziellen Expert Advisor ausgeführten Transaktionen von anderen zu unterscheiden, weist der Computer dem EA eine eindeutige MagicNumber zu. SetExpertMagicNumber() wird verwendet, um diesen Wert zu setzen.

Anschließend wird eine Reihe von Eingabeparametern festgelegt. Damit kann der Nutzer das Verhalten des EA ändern, ohne den Hauptcode zu ändern. Um zu regeln, ob z.B. in Abwärtstrendsituationen, bei Ausbruchsmustern oder bei Umkehr-Setups gehandelt werden darf, werden die Ein/Aus-Schalter allow_downtrend, allow_break_out und allow_reversal verwendet. Während sl_points und tp_points den Abstand in Punkten zwischen dem Stop-Loss und dem Take-Profit vom Einstiegskurs angeben, legt der Parameter lot_size die Größe der einzelnen Positionen fest.

Für die Zeitsteuerung werden zwei Variablen verwendet: lookbackf_time und lastTradeBarTime. Wie weit in der Vergangenheit die Software nach legitimen Umkehrkonfigurationen suchen soll, wird durch die lookbackf_time bestimmt. Alle vorherigen Konfigurationen werden zu diesem Zeitpunkt ignoriert. Um redundante oder doppelte Signale zu vermeiden, wird die lastTradeBarTime-Variable verwendet, um zu verhindern, dass mehrere Trades für dieselbe Kerze durchgeführt werden.

int no_bars = 0;
for(int i = 0; i <= 3; i++)
  {
   if(low_price[i] < ObjectGetValueByTime(chart_id, up_trend, time_price[i], 0) &&
      open_price[i] > ObjectGetValueByTime(chart_id, up_trend, time_price[i], 0))
     {
      for(int j = i; j >= 0; j--)
        {
         if(close_price[j] > open_price[j] &&
            close_price[j] > ObjectGetValueByTime(chart_id, up_trend, time_price[j], 0))
           {
            no_bars = Bars(_Symbol, time_frame, time_price[j], TimeCurrent());
            break;
           }
        }
      break;
     }
  }

In diesem Teil werden die letzten vier Kerzen (Balken 0 bis 3) überprüft, um festzustellen, ob eine von ihnen ein Dochtverhalten aufweist, das auf ein Umkehrsignal hinweist: Das Tief ist unter die Trendlinie gefallen, aber die Eröffnung blieb darüber. Dies bedeutet, dass die Trendlinie abgelehnt wurde. Sobald eine solche Kerze identifiziert wurde, sucht die innere Schleife nach einer Aufwärts-Bestätigungskerze, d. h. einer Kerze, die sowohl über der Eröffnung als auch über der Trendlinie geschlossen hat. Wenn sie gefunden wird, wird mit Bars() ermittelt, vor wie vielen Takten die Bestätigung erfolgt ist, und das Ergebnis wird in no_bars gespeichert.

bool prev_touch = false;
if((low_price[1] < t1_line_value && close_price[1] > open_price[1]) ||
   (low_price[2] < t2_line_value && close_price[2] > open_price[2])) {
    prev_touch = true;
}

Dieser Block bestimmt, ob die Kerzen 1 oder 2 bereits die Trendlinie berührt und aufwärts geschlossen haben, um eine Wiederholung oder verfrühte Warnungen zu vermeiden. Prev_touch wird auf true gesetzt, wenn eine der beiden Bedingungen zutrifft, was darauf hindeutet, dass vor kurzem eine Umkehrung stattgefunden haben könnte und dass ein anderes Signal auf dem aktuellen Balken außer Acht gelassen werden sollte.

if(
   ((low_price[0] < t_line_value && open_price[0] > t_line_value) ||
    (low_price[1] < t1_line_value && open_price[1] > t1_line_value) ||
    (low_price[2] < t2_line_value && open_price[2] > t2_line_value) ||
    (low_price[3] < t3_line_value && open_price[3] > t3_line_value))
   &&
   (close_price[0] > open_price[0]) && close_price[0] > t_line_value
   &&
   (no_bars < 3)
   &&
   prev_touch == false
   &&
   (time_price[3] > lookbackf_time)
   &&
   (allow_reversal == true && currentBarTime != lastTradeBarTime)
)
  {
   trade.Buy(lot_size, _Symbol, ask_price, ask_price - sl_points, ask_price + tp_points);
   lastTradeBarTime = currentBarTime;
  }

Zunächst wird überprüft, ob mindestens eine der letzten vier Kerzen einen Docht aufwies, d. h., ob der Kurs die Trendlinie berührte, aber oberhalb der Trendlinie eröffnete, was auf eine mögliche Abprallzone hindeutet; dann muss die aktuelle eine Aufwärtskerze sein und oberhalb der Trendlinie geschlossen haben, um das Signal zu verstärken; und schließlich muss die zuvor identifizierte Aufwärtsbestätigungskerze innerhalb der letzten drei Balken aufgetreten sein, um sicherzustellen, dass das Setup noch gültig ist. Dieser bedingte Block prüft anhand einer Reihe wichtiger Kriterien, ob ein Kauf wegen einer Umkehr ausgeführt werden sollte.

Der Algorithmus prüft, dass in letzter Zeit kein vergleichbares Docht-basiertes Berührungssignal erkannt wurde, daher muss prev_touch falsch sein, um wiederholte Einträge zu verhindern. Außerdem stellt es sicher, dass das Setup aktueller ist als die angegebene lookbackf_time, was den Bereich der Signale einschränkt, die das Programm als legitim akzeptiert.

Schließlich wird überprüft, ob currentBarTime ungleich lastTradeBarTime ist, um Doppeltransaktionen zu verhindern und um sicherzustellen, dass Umkehrgeschäfte erlaubt sind (allow_reversal ist true) und dass kein Handel bereits an derselben Kerze durchgeführt wurde. Ein Kaufauftrag mit der angegebenen Losgröße, dem Stop-Loss und dem Take-Profit wird ausgeführt, wenn alle diese Bedingungen erfüllt sind. Um zu verhindern, dass weitere Abschlüsse für dieselbe Kerze getätigt werden, wird die lastTradeBarTime dann auf den Zeitpunkt des aktuellen Balkens aktualisiert.

4.1.1.2. Ausbruch und Retest

Die Setups von Ausbruchs und Retest um eine steigende Trendlinie herum folgen ähnlichen Kriterien für die Auftragsplatzierung wie Umkehrungen. Der Kurs könnte sich zurückziehen und die gebrochene Unterstützung, die jetzt als Widerstand dient, erneut testen, nachdem er die Trendlinie unterschritten hat. Eine vollmundige Kerze oder auch nur ein Docht, der die Trendlinie berührt, kann diesen Retest auslösen. Der Ausbruch kann durch die Erteilung eines Verkaufsauftrags bestätigt werden, wenn der erneute Test erfolgreich ist und der Preis abgelehnt wird.

Abbildung 19. Ausbruch und Retest

Beispiel:

// If the user allows drawing of ascending trend line
if(allow_uptrend)
  {
// First loop: Find the most recent swing low (first low)
   for(int i = LookbackBars; i < bars_check - LookbackBars; i++)
     {
      // Check if current point is a swing low
      if(IsSwingLow(low_price, i, LookbackBars))
        {
         // Store price and time of the first (latest) swing low
         first_low = low_price[i];
         first_low_time = time_price[i];
         lookbackf_time = time_price[i - 3];

         break;  // Exit loop after finding the first swing low
        }
     }

// Second loop: Find an earlier swing low that is lower than the first low
   for(int i = LookbackBars; i < bars_check - LookbackBars; i++)
     {
      // Check for earlier swing low that is lower and occurs before the first low
      if(IsSwingLow(low_price, i, LookbackBars) && low_price[i] < first_low && time_price[i] < first_low_time)
        {
         // Store price and time of the second (older) swing low
         second_low = low_price[i];
         second_low_time = time_price[i];
         break;  // Exit loop after finding the second swing low
        }
     }

// Create an ascending trend line from the second low to the first low
   ObjectCreate(chart_id, up_trend, OBJ_TREND, 0, second_low_time, second_low, first_low_time, first_low);
   ObjectSetInteger(chart_id, up_trend, OBJPROP_TIMEFRAMES, OBJ_NO_PERIODS);  // Temporarily hide line on all timeframes

// If the swing structure is valid (i.e., second low is lower than first)
   if(first_low > second_low && second_low > 0)
     {
      // Extend the trend line to the right
      ObjectSetInteger(chart_id, up_trend, OBJPROP_RAY_RIGHT, true);

      // Show the trend line on all timeframes
      ObjectSetInteger(chart_id, up_trend, OBJPROP_TIMEFRAMES, OBJ_ALL_PERIODS);

      // Set visual properties: color and thickness
      ObjectSetInteger(chart_id, up_trend, OBJPROP_COLOR, clrBlue);
      ObjectSetInteger(chart_id, up_trend, OBJPROP_WIDTH, 3);


      // Get the price values of the trend line at the corresponding times of the four most recent bars
      t_line_value = ObjectGetValueByTime(chart_id, up_trend, time_price[0], 0);   // Current bar
      t1_line_value = ObjectGetValueByTime(chart_id, up_trend, time_price[1], 0);  // One bar ago
      t2_line_value = ObjectGetValueByTime(chart_id, up_trend, time_price[2], 0);  // Two bars ago
      t3_line_value = ObjectGetValueByTime(chart_id, up_trend, time_price[3], 0);  // Three bars ago

      // Number of bars between the valid bullish confirmation candle and current time
      int no_bars = 0;

      // Loop through the last 4 bars to check for reversal wick touch on the trend line
      for(int i = 0; i <= 3; i++)
        {
         // Condition: Wick of the candle touches below the trend line but opens above it (indicating a potential reversal zone)
         if(low_price[i] < ObjectGetValueByTime(chart_id, up_trend, time_price[i], 0) &&
            open_price[i] > ObjectGetValueByTime(chart_id, up_trend, time_price[i], 0))
           {
            // Check if there's a bullish confirmation candle after the wick touch (within or immediately after)
            for(int j = i; j >= 0; j--)
              {
               // Bullish candle that closed above the trend line
               if(close_price[j] > open_price[j] &&
                  close_price[j] > ObjectGetValueByTime(chart_id, up_trend, time_price[j], 0))
                 {
                  // Count how many bars ago this confirmation occurred
                  no_bars = Bars(_Symbol, time_frame, time_price[j], TimeCurrent());
                  break;
                 }
              }
            break; // Exit after first valid reversal zone is found
           }
        }

      // Check whether a similar wick touch (reversal) happened recently to avoid repeated signals
      bool prev_touch = false;

      if((low_price[1] < t1_line_value && close_price[1] > open_price[1]) ||  // Bar 1 had reversal wick and bullish body
         (low_price[2] < t2_line_value && close_price[2] > open_price[2]))    // Bar 2 had reversal wick and bullish body
        {
         prev_touch = true;  // Flag that a recent touch already occurred
        }

      // Final condition for executing a BUY trade on a reversal setup
      if(
         // One of the recent 4 bars touched and rejected the trend line (wick below, open above), AND
         ((low_price[0] < t_line_value && open_price[0] > t_line_value) ||
          (low_price[1] < t1_line_value && open_price[1] > t1_line_value) ||
          (low_price[2] < t2_line_value && open_price[2] > t2_line_value) ||
          (low_price[3] < t3_line_value && open_price[3] > t3_line_value))
         &&
         // Current candle must be bullish and close above the trend line
         (close_price[0] > open_price[0]) && close_price[0] > t_line_value
         &&
         // The bullish confirmation must occur within 3 bars
         (no_bars < 3)
         &&
         // No recent wick reversal signal already processed
         prev_touch == false
         &&
         // The signal must be more recent than the lookback time threshold
         (time_price[3] > lookbackf_time)
         &&
         // Reversal signals are allowed and this signal is not duplicated from the same bar
         (allow_reversal == true && currentBarTime != lastTradeBarTime)
      )
        {
         // Execute BUY trade with defined lot size, SL and TP
         trade.Buy(lot_size, _Symbol, ask_price, ask_price - sl_points, ask_price + tp_points);
         lastTradeBarTime = currentBarTime; // Update last trade bar time to avoid duplicate signals
        }

      //BREAKOUT AND RETEST

      // Flag to track whether a recent bearish wick rejection (touch) already occurred
      bool prev_touch2 = false;

      // Check the last 2 bars to see if a candle had its high wick above the trend line,
      // but closed bearishly below the open - indicating a possible rejection
      if((high_price[1] > t1_line_value && close_price[1] < open_price[1]) ||
         (high_price[2] > t2_line_value && close_price[2] < open_price[2] && open_price[2] < t2_line_value))
        {
         prev_touch2 = true; // Set flag to avoid duplicate signals
        }

      // Variable to store how many bars ago the bearish confirmation candle appeared
      int no_bars2 = 0;

      // Loop through the last 4 candles to detect a wick rejection of the trend line (retest)
      for(int i = 0; i <= 3; i++)
        {
         // Condition: Candle wick (high) goes above the trend line, but the open is below it
         if(high_price[i] > ObjectGetValueByTime(chart_id, up_trend, time_price[i], 0) &&
            open_price[i] < ObjectGetValueByTime(chart_id, up_trend, time_price[i], 0))
           {
            // Search backward from that bar for a bearish confirmation candle
            for(int j = i; j >= 0; j--)
              {
               // Bearish candle that also closed below the trend line
               if(close_price[j] < open_price[j] &&
                  close_price[j] < ObjectGetValueByTime(chart_id, up_trend, time_price[j], 0))
                 {
                  // Count bars between that confirmation and now
                  no_bars2 = Bars(_Symbol, time_frame, time_price[j], TimeCurrent());
                  break; // Exit inner loop
                 }
              }
            break; // Exit outer loop after first valid retest
           }
        }

      // Final conditions to confirm a breakout and retest sell setup:
      // 1. One of the last 4 candles had a wick above the trend line but opened below it
      // 2. Current candle is bearish and closed below the trend line
      // 3. There was no recent similar signal (prev_touch2 == false)
      // 4. The bearish confirmation occurred within the last 3 bars
      // 5. Breakout trades are allowed and this signal is not from the same bar as the last trade
      if(((high_price[1] >= t1_line_value && open_price[1] < t1_line_value) ||
          (high_price[2] >= t2_line_value && open_price[2] < t2_line_value) ||
          (high_price[3] >= t3_line_value && open_price[3] < t3_line_value) ||
          (high_price[0] >= t_line_value)) &&
         (close_price[0] < t_line_value && close_price[0] < open_price[0] && open_price[1] < t1_line_value) &&
         prev_touch2 == false &&
         (no_bars2 < 3) &&
         (allow_break_out == true && currentBarTime != lastTradeBarTime))
        {
         // All conditions met - place SELL trade with defined SL and TP
         trade.Sell(lot_size, _Symbol, ask_price, ask_price + sl_points, ask_price - tp_points);

         // Update timestamp to prevent duplicate signals from the same bar
         lastTradeBarTime = currentBarTime;
        }
     }
  }

Ausgaben:

Abbildung 20. Unmittelbarer Retest

Abbildung 21. Ausbruch und Retest

Erläuterung:

Der Code beginnt mit der Deklaration einer booleschen Variable namens prev_touch2, die als Flag dient, um zu erkennen, ob vor kurzem bereits ein Abwärts-Docht abgestoßen worden ist (ein falscher Ausbruch). Mit diesem Flag soll verhindert werden, dass der Algorithmus mehrere Handelssignale aus einem ähnlichen, bereits abgewickelten Setup auslöst. Dies trägt dazu bei, falsche Signale zu reduzieren und stellt sicher, dass der Expert Advisor nur auf neue, gültige Setups reagiert.

Der Algorithmus sucht dann nach Anzeichen für einen Abwärts-Abprall an der Trendlinie, indem er die beiden vorangegangenen Kerzen (high_price[1] und high_price[2]) analysiert. Dabei wird insbesondere untersucht, ob der Höchststand der Kerze schließlich unter dem Eröffnungskurs schloss, was auf einen rückläufigen Druck und die Unfähigkeit, den Ausbruch aufrechtzuerhalten, hindeutet, oder ob sie kurzzeitig über die Trendlinie ausbrach, was auf einen potenziellen Ausbruchsversuch hindeutet. Um den Abprall zu bestätigen, fügt es eine Bedingung für den zweiten Balken ([2]) hinzu, um sicherzustellen, dass der Eröffnungskurs ebenfalls unter der Trendlinie liegt. Prev_touch2 wird auf true gesetzt, wenn eines dieser Kriterien erfüllt ist.

Nachdem ein Docht die Trendlinie berührt hat, wird die Variable no_bars2 initialisiert, um anzugeben, vor wie vielen Balken eine Bestätigung durch eine Abwärtskerze erschienen ist. Diese Daten sind entscheidend für die Bestätigung, dass das Signal immer noch echt ist und dass der erneute Test in letzter Zeit durchgeführt wurde.

Danach tritt der Code in eine Schleife ein, in der die vorherigen vier Kerzen wiederholt werden. Ziel ist es, eine Kerze zu finden, deren Docht (das Hoch) die Trendlinie überquert hat, die aber unterhalb der Trendlinie eröffnet wurde; dies zeigt an, dass der Kurs die Trendlinie ausprobiert hat, aber nicht sauber ausgebrochen ist. Nachdem eine solche Kerze gefunden wurde, sucht eine verschachtelte Schleife rückwärts nach einer Abwärts-Bestätigung, d. h. einer Kerze, die zu diesem Zeitpunkt sowohl unter der Eröffnung als auch unter der Trendlinie geschlossen hat. Wenn diese Bestätigung entdeckt wird, wird die Methode Bars() verwendet, um festzustellen, vor wie vielen Balken diese Kerze aufgetreten ist, und das Ergebnis wird in no_bars2 gespeichert. Um Berechnungen zu sparen, werden die Schleifen frühzeitig beendet, sobald gültige Signale erkannt werden.

Schließlich wertet der Code eine Reihe von kombinierten Bedingungen aus, um zu entscheiden, ob ein Verkauf getätigt werden soll. Diese Bedingungen prüfen, ob:

  • Eine der letzten vier Kerzen hatte einen Docht, der oberhalb der Trendlinie lag, aber unterhalb der Trendlinie eröffnete.
  • Die aktuelle Kerze ist rückläufig und hat sowohl unter der Trendlinie als auch unter ihrer eigenen Eröffnung geschlossen.
  • Es wurde kein früheres ähnliches Signal markiert (prev_touch2 == false).
  • Die rückläufige Bestätigungskerze ist vor kurzem (innerhalb der letzten 3 Balken) entstanden.
  • Das Handelsgeschäft ist erlaubt (allow_break_out == true) und wird nicht während desselben Balkens dupliziert (currentBarTime != lastTradeBarTime).

Ein Verkauf mit der angegebenen Losgröße, dem Stop-Loss- und dem Take-Profit-Wert wird ausgeführt, wenn alle diese Anforderungen erfüllt sind. Um zu verhindern, dass ein weiteres Handelsgeschäft aufgrund desselben Signals getätigt wird, wird der Zeitpunkt des aktuellen Balkens in lastTradeBarTime gespeichert.

4.1.2. Handelsausführung bei fallender Trendlinie

In diesem Abschnitt werden wir nach Ausbruchs- und Umkehrmöglichkeiten bei einer fallenden Trendlinie suchen. Die Argumentation ist genau das Gegenteil von dem, was wir für die steigende Trendlinie getan haben. Um unnötige Wiederholungen zu vermeiden, werden wir hier nicht zu sehr in die Tiefe gehen, da die Methodik und die Struktur ziemlich identisch sind. Unser Augenmerk wird auf Abwärts-Setups bei Umkehrungen und Aufwärts-Setups bei Ausbrüchen und erneuten Tests gerichtet sein, da die fallende Trendlinie als Widerstand dient. Dies ist der wichtigste Unterschied.

Beispiel:

// Only proceed if drawing descending trend lines is enabled
if(allow_downtrend)
  {
// First loop: Find the most recent swing high (first high)
   for(int i = LookbackBars; i < bars_check - LookbackBars; i++)
     {
      // Check if the current bar is a swing high
      if(IsSwingHigh(high_price, i, LookbackBars))
        {
         // Store the price and time of this latest swing high
         first_high = high_price[i];
         first_high_time = time_price[i];

         break;  // Exit loop once the first swing high is found
        }
     }

// Second loop: Find an earlier swing high that is higher than the first high and occurred before it
   for(int i = LookbackBars; i < bars_check - LookbackBars; i++)
     {
      // Check for earlier swing high that is higher and happened before the first one
      if(IsSwingHigh(high_price, i, LookbackBars) && high_price[i] > first_high && time_price[i] < first_high_time)
        {
         // Store the price and time of this older swing high
         second_high = high_price[i];
         second_high_time = time_price[i];

         break;  // Exit loop once the second swing high is found
        }
     }

// Create a trend line object from the second swing high to the first swing high
   ObjectCreate(chart_id, down_trend, OBJ_TREND, 0, second_high_time, second_high, first_high_time, first_high);

// Initially hide the trend line across all timeframes to avoid partial drawing
   ObjectSetInteger(chart_id, down_trend, OBJPROP_TIMEFRAMES, OBJ_NO_PERIODS);

// Validate the swing structure:
// The older swing high should be higher than the later swing high to confirm a descending trend line
   if(first_high < second_high && second_high > 0)
     {
      // Extend the trend line indefinitely to the right for better visual guidance
      ObjectSetInteger(chart_id, down_trend, OBJPROP_RAY_RIGHT, true);

      // Make the trend line visible on all chart timeframes
      ObjectSetInteger(chart_id, down_trend, OBJPROP_TIMEFRAMES, OBJ_ALL_PERIODS);

      // Set the trend line color to dark green for clear distinction
      ObjectSetInteger(chart_id, down_trend, OBJPROP_COLOR, clrDarkGreen);

      // Set the thickness of the trend line to 3 pixels for better visibility
      ObjectSetInteger(chart_id, down_trend, OBJPROP_WIDTH, 3);

      //REVERSAL

      td_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[0],0);
      td1_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[1],0);
      td2_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[2],0);
      td3_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[3],0);

      int no_bars = 0;

      for(int i = 0; i <= 3; i++)
        {

         if(high_price[i] > ObjectGetValueByTime(chart_id,down_trend,time_price[i],0) && open_price[i] < ObjectGetValueByTime(chart_id,down_trend,time_price[i],0)
           )
           {

            for(int j = i; j >= 0; j--)
              {

               if(close_price[j] < open_price[j] && close_price[j] < ObjectGetValueByTime(chart_id,down_trend,time_price[j],0))
                 {

                  no_bars = Bars(_Symbol,time_frame,time_price[j],TimeCurrent());

                  break;

                 }

              }
            break;

           }

        }

      bool prev_touch = false;

      if((high_price[1] > td1_line_value && close_price[1] < open_price[1])
         ||
         (high_price[2] > td2_line_value && close_price[2] < open_price[2])
        )
        {

         prev_touch = true;

        }

      if(((high_price[1] >= td1_line_value && open_price[1] < td1_line_value) || (high_price[2] >= td2_line_value && open_price[2] < td2_line_value)
          || (high_price[3] >= td3_line_value && open_price[3] < td3_line_value) || (high_price[0] >= td_line_value))
         && (close_price[0] < td_line_value && close_price[0] < open_price[0] && open_price[1] < td1_line_value)
         && (no_bars < 3)
         && prev_touch == false
         && (allow_reversal == true  && currentBarTime != lastTradeBarTime)
        )
        {

         trade.Sell(lot_size,_Symbol,ask_price,ask_price + sl_points, ask_price - tp_points);
         lastTradeBarTime = currentBarTime;

        }

      //BREAKOUT AMD RETEST

      // Flag to track whether a recent bullish wick rejection (touch) already occurred
      bool prev_touch2 = false;

      // Check the last 2 candles for bullish rejection from below the descending trend line
      // A bullish rejection occurs when the low goes below the trend line but closes above the open (bullish candle)
      if((low_price[1] < td1_line_value && close_price[1] > open_price[1]) ||
         (low_price[2] < td2_line_value && close_price[2] > open_price[2] && open_price[2] > td2_line_value))
        {
         prev_touch2 = true; // Set flag to prevent duplicate signals from the same type of setup
        }

      // Variable to hold how many bars ago a bullish confirmation candle occurred after wick rejection
      int no_bars2 = 0;

      // Loop through the last 4 candles to detect a wick rejection of the descending trend line
      for(int i = 0; i <= 3; i++)
        {
         // Condition: Candle wick (low) goes below the trend line, but the open is above it
         if(low_price[i] < ObjectGetValueByTime(chart_id, down_trend, time_price[i], 0) &&
            open_price[i] > ObjectGetValueByTime(chart_id, down_trend, time_price[i], 0))
           {
            // Look backward for a bullish confirmation candle that closes above the trend line
            for(int j = i; j >= 0; j--)
              {
               if(close_price[j] > open_price[j] &&
                  close_price[j] > ObjectGetValueByTime(chart_id, down_trend, time_price[j], 0))
                 {
                  // Count how many bars ago that bullish confirmation happened
                  no_bars2 = Bars(_Symbol, time_frame, time_price[j], TimeCurrent());
                  break; // Exit inner loop once confirmation is found
                 }
              }
            break; // Exit outer loop after the first valid retest is processed
           }
        }

      // Final conditions to confirm a breakout or retest for a BUY setup on descending trend line:
      // 1. One of the last 4 candles had a wick below the trend line but opened above it
      // 2. Current candle is bullish and closed above the trend line
      // 3. A valid bullish confirmation occurred within the last 3 bars
      // 4. No recent similar touch detected (prev_touch2 == false)
      // 5. Candle timestamps are valid (not too far back)
      // 6. Breakout trading is allowed, and this bar is not the same as the last trade bar
      if(
         ((low_price[0] < td_line_value && open_price[0] > td_line_value) ||
          (low_price[1] < td1_line_value && open_price[1] > td1_line_value) ||
          (low_price[2] < td2_line_value && open_price[2] > td2_line_value) ||
          (low_price[3] < td3_line_value && open_price[3] > td3_line_value)) &&
         (close_price[0] > open_price[0]) && close_price[0] > td_line_value &&
         (no_bars2 < 3) &&
         prev_touch2 == false &&
         (time_price[3] > lookbackfd_time) &&
         (allow_break_out == true && currentBarTime != lastTradeBarTime)
      )
        {
         // All conditions met - place a BUY trade with defined SL and TP
         trade.Buy(lot_size, _Symbol, ask_price, ask_price - sl_points, ask_price + tp_points);

         // Update the last trade time to avoid repeated trades from the same bar
         lastTradeBarTime = currentBarTime;
        }
     }
  }

Ausgaben:

Abbildung 22. Ausbruch aus der fallenden Trendlinie

Abbildung 23. Umkehrung der fallenden Trendlinie

Erläuterung:

Die Logik für die Ausführung Käufen auf der Grundlage des Durchbruchs oder Abpralls einer fallenden Trendlinie wird in diesem Abschnitt implementiert. Um festzustellen, ob bereits ein Abprall des Dochts nach oben stattgefunden hat, konstruieren wir zunächst eine boolesche Variable namens prev_touch2. Auf diese Weise können wir verhindern, dass wir mit demselben Signal doppelt handeln. Als Nächstes sehen wir uns die letzten beiden Kerzen an, um festzustellen, ob eine von ihnen einen Docht hatte, der trotz Unterschreitung der rückläufigen Trendlinie nach oben schloss (d. h. höher als der Eröffnungswert). Wir setzen prev_touch2 auf true, wenn ein solches Szenario entdeckt wird.

Die Anzahl der Kerzen seit dem Auftreten einer legitimen Bestätigung eine Aufwärtskerze wird dann in einer Variablen namens no_bars2 gespeichert. Um festzustellen, ob ein erneuter Test wahrscheinlich ist, gehen wir die letzten vier Kerzen durch und prüfen, ob eine von ihnen einen Docht hatte, der unter die fallende Trendlinie fiel, während er oberhalb davon eröffnete. Als Nächstes wird von dieser Kerze aus eine Rückblickschleife gezogen, um eine Aufwärtsbestätigungskerze zu finden, die oberhalb der fallenden Trendlinie und ihres Eröffnungskurses geschlossen hat, falls ein solcher Abprall des Dochts entdeckt wird. Sobald wir sie gefunden haben, speichern wir die Bestätigungskerze in no_bars2 und ermitteln, vor wie vielen Balken sie erschienen ist.

Um eine rechtmäßige Kauf-Konfiguration zu überprüfen, integrieren wir schließlich mehrere Bedingungen. Wir prüfen, ob eine der vier vorangegangenen Kerzen oberhalb der Trendlinie eröffnete, aber einen Docht unterhalb der Trendlinie hatte. Wir überprüfen zusätzlich, ob die aktuelle Kerze oberhalb der Trendlinie geschlossen hat, ob sie aufwärts ist (der Schlusskurs liegt über dem Eröffnungskurs) und ob die Aufwärtsbestätigung innerhalb der vorangegangenen drei Balken erfolgte.

Ebenso stellen wir sicher, dass der Zeitrahmen legitim ist, dass Ausbrüche erlaubt sind, dass das Signal nicht von der gleichen Kerze wie der vorherige Handel stammt und dass keine kürzlichen Abpralls (prev_touch2) vorher aufgezeichnet wurden. Der EA verwendet die angegebenen Werte für Losgröße, Stop Loss und Take Profit, um einen Kauf auszuführen, wenn alle diese Kriterien erfüllt sind. Außerdem wird die lastTradeBarTime geändert, um doppelte Abschlüsse für dieselbe Kerze zu vermeiden.


Schlussfolgerung

Mit allem, was wir in diesem Artikel behandelt haben, verfügen Sie nun über das grundlegende Wissen, um mit jedem Chart-Muster zu arbeiten, das Trendlinien beinhaltet. Von Kanälen bis hin zu auf- und fallenden Trendlinien haben Sie gelernt, wie man Trendlinienwerte abruft und sie mit der Preisentwicklung vergleicht, und wie man auf der Grundlage eindeutiger Ausbruchs- oder Umkehrbedingungen handelt. Wir haben dieses Wissen praktisch angewandt, indem wir einen Expert Advisor (EA) entwickelt haben, der automatisch Trendlinien-Interaktionen in Echtzeit erkennen und darauf reagieren kann. Diese Logik ist in hohem Maße anpassungsfähig, d. h. Sie können sie auf andere Chart-Muster wie Dreiecke, Keile und sogar doppelte Spitzen oder Böden anwenden.

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

Beigefügte Dateien |
Letzte Kommentare | Zur Diskussion im Händlerforum (5)
Dominic Michael Frehner
Dominic Michael Frehner | 5 Juni 2025 in 08:17
Vielen Dank für diesen Artikel! Ich möchte Sie nur darüber informieren, dass es einen kleinen Fehler bei der Berechnung von Stoploss und Takeprofit gibt :-) Sie basiert nicht auf Punkten. Probieren Sie es mit einem beliebigen Devisenpaar aus (EURUSD, GBPUSD, etc.)
Israel Pelumi Abioye
Israel Pelumi Abioye | 5 Juni 2025 in 13:16
Dominic Michael Frehner GBPUSD, etc.)
Hallo, Dominic.
Vielen Dank für Ihre freundlichen Worte, es ist kein Fehler. Sie können sich zum Beispiel entscheiden, 0,0010 für 10 Pips zu verwenden, es hängt vom Instrument ab.
Yaovi Inoussa Atchou
Yaovi Inoussa Atchou | 11 Juli 2025 in 13:30

Hallo Bro

Kann Ihr Ea wird auf Deriv auf Volatilität arbeiten??

Celestine Nwakaeze
Celestine Nwakaeze | 28 Okt. 2025 in 15:48
Danke für diesen Artikel, er ist sehr lehrreich. Gott segne Sie.
Israel Pelumi Abioye
Israel Pelumi Abioye | 28 Okt. 2025 in 17:42
Celestine Nwakaeze #:
Danke für diesen Artikel, er ist sehr lehrreich. Gott segne Sie.

Gern geschehen, vielen Dank für Ihre freundlichen Worte.


Datenwissenschaft und ML (Teil 42): Forex-Zeitreihenvorhersage mit ARIMA in Python, alles was Sie wissen müssen Datenwissenschaft und ML (Teil 42): Forex-Zeitreihenvorhersage mit ARIMA in Python, alles was Sie wissen müssen
ARIMA, kurz für Auto Regressive Integrated Moving Average, ist ein leistungsfähiges traditionelles Zeitreihenprognosemodell. Mit der Fähigkeit, Spitzen und Schwankungen in Zeitreihendaten zu erkennen, kann dieses Modell genaue Vorhersagen über die nächsten Werte machen. In diesem Artikel werden wir verstehen, was es ist, wie es funktioniert, was Sie damit tun können, wenn es um die Vorhersage der nächsten Preise auf dem Markt mit hoher Genauigkeit und vieles mehr.
Erstellen von selbstoptimierenden Expertenberatern in MQL5 (Teil 7): Handel mit mehreren Periodenlängen gleichzeitig Erstellen von selbstoptimierenden Expertenberatern in MQL5 (Teil 7): Handel mit mehreren Periodenlängen gleichzeitig
In dieser Artikelserie haben wir mehrere verschiedene Möglichkeiten zur Ermittlung der besten Periodenlänge für die Verwendung unserer technischen Indikatoren untersucht. Heute werden wir dem Leser zeigen, wie er stattdessen die umgekehrte Logik anwenden kann, d. h., anstatt die beste Periodenlänge auszuwählen, werden wir dem Leser zeigen, wie er alle verfügbaren Periodenlängen effektiv nutzen kann. Dieser Ansatz reduziert die Menge der verworfenen Daten und bietet alternative Anwendungsmöglichkeiten für Algorithmen des maschinellen Lernens, die über die normale Preisvorhersage hinausgehen.
Meistern der Log-Einträge (Teil 7): Protokolle auf dem Chart anzeigen Meistern der Log-Einträge (Teil 7): Protokolle auf dem Chart anzeigen
Lernen Sie, wie man Logs direkt auf einem MetaTrader-Chart anzeigt, mit Rahmen, Titeln und automatischem Scrollen. In diesem Artikel zeigen wir Ihnen, wie Sie mit MQL5 ein visuelles Protokollsystem erstellen, das sich ideal für die Überwachung der Aktivitäten Ihres Roboters in Echtzeit eignet.
Umstellung auf MQL5 Algo Forge (Teil 2): Arbeiten mit mehreren Repositorys Umstellung auf MQL5 Algo Forge (Teil 2): Arbeiten mit mehreren Repositorys
In diesem Artikel betrachten wir einen der möglichen Ansätze zur Organisation der Speicherung des Quellcodes eines Projekts in einem öffentlichen Repository. Wir werden den Code auf verschiedene Zweige verteilen, um klare und bequeme Regeln für die Projektentwicklung festzulegen.