English
preview
Larry Williams Marktgeheimnisse (Teil 4): Automatisieren von kurzfristigen hohen und tiefen Umkehrpunkten in MQL5

Larry Williams Marktgeheimnisse (Teil 4): Automatisieren von kurzfristigen hohen und tiefen Umkehrpunkten in MQL5

MetaTrader 5Handel |
34 2
Chacha Ian Maroa
Chacha Ian Maroa

Einführung

Die Märkte erscheinen oft chaotisch, wenn man sie Kerze für Kerze betrachtet. Die Kurse bewegen sich erst nach oben, dann nach unten und dann seitwärts, sodass viele Händler nicht wissen, ob diese Bewegungen überhaupt einer Struktur folgen. Lange bevor der algorithmische Handel populär wurde, vertrat Larry Williams jedoch eine andere Auffassung. In seinem Buch „Long-Term Secrets to Short-Term Trading“ (Langfristige Geheimnisse des kurzfristigen Handels) vertrat er die Ansicht, dass die Preisbewegung nicht rein zufällig ist und dass sich bestimmte kurzfristige Umkehrmuster (swings) oft genug wiederholen, um einen messbaren Vorteil zu bieten. Diese Ideen basierten auf Beobachtungen, Statistiken und jahrzehntelanger Erfahrung auf dem Markt.

Im letzten Teil dieser Serie haben wir mehrere Ideen von Larry Williams anhand von Code und echten historischen Daten getestet. Ein Ergebnis sticht deutlich hervor. Nach der Bildung eines kurzfristigen Tiefs reagierten die Märkte stark und anhaltend aufwärts. Dieses Verhalten zeigte sich in verschiedenen Anlageklassen und Zeiträumen, was darauf hindeutet, dass das Muster nicht zufällig ist. Solche Erkenntnisse werfen natürlich eine wichtige Frage auf. Wenn dieses Verhalten gemessen und verifiziert werden kann, kann es dann auch automatisiert und als vollständiges Handelssystem getestet werden?

Dieser Artikel geht den nächsten Schritt. Wir gehen von der Analyse zur Ausführung über, indem wir einen vollautomatischen Expert Advisor in MQL5 erstellen, der mit Larry Williams' kurzfristigen tiefen und hohen Umkehrpunkten handelt. Das Ziel ist nicht Optimierung oder Kurvenanpassung, sondern Struktur und Klarheit. Indem wir ein klar definiertes Preis-Aktions-Konzept in präzise Regeln und Code umsetzen, schaffen wir ein Tool, mit dem Händler diese Ideen unabhängig testen, validieren und verfeinern können. Am Ende dieses Artikels wird der Leser über einen praktischen Rahmen verfügen, um beobachtetes Marktverhalten in einen systematischen und überprüfbaren Handelsansatz zu verwandeln.


Definition und Identifizierung der kurzfristigen Umkehrpunkte von Larry Williams

Im Mittelpunkt der Arbeit von Larry Williams steht eine einfache, aber aussagekräftige Beobachtung: Die Preise bewegen sich nicht zufällig, sondern schwanken rhythmisch zwischen kurzfristigen Extremen. Diese kurzfristigen Hochs und Tiefs bilden die kleinste, reaktionsfähigste Schicht der Marktstruktur und dienen als Bausteine, aus denen sich mittel- und langfristige Trends entwickeln.

In „Long-Term Secrets to Short-Term Trading“ (Langfristige Geheimnisse des kurzfristigen Handels) betont Larry Williams, dass das Verständnis dieser Mikrostruktur es Händlern ermöglicht, sich auf die natürliche Ebbe und Flut des Marktes einzustellen, anstatt emotional auf einzelne Kerzen zu reagieren. In diesem Abschnitt destillieren wir diese Philosophie auf ihren operativen Kern und übersetzen sie in präzise, regelbasierte Logik, die sich für die Automatisierung eignet.

Wie in Abbildung 1 dargestellt, liegt ein gültiger kurzfristiger tiefer Umkehrpunkt vor, wenn der Kurs einen klaren Pivot bildet: einen Balken, dessen Tiefpunkt von höheren Tiefpunkten auf beiden Seiten flankiert wird.

Kurzfristiges Tief

Dieser zentrale Balken markiert eine vorübergehende Erschöpfung des Verkaufsdrucks, wobei der Markt kurz innehält, bevor er seinen breiteren Rhythmus wieder aufnimmt. Umgekehrt zeigt Abbildung 2 einen kurzfristigen hohen Umkehrpunkt, mit niedrigeren Hochs, die das Hoch des zentralen Balkens umgeben, was auf eine kurzfristige Erschöpfung der Käufer hindeutet.

Kurzfristiges Hoch

Allerdings ist nicht jeder offensichtliche Umkehrpunkt auch handelbar. Einer der kritischsten Aspekte von Williams' Methodik – und einer, der oft übersehen wird – ist die Filterung. Die Qualität eines Umkehrpunktes ist viel wichtiger als seine Häufigkeit.

Sie können Ihre Aufmerksamkeit auf Abbildung 3 lenken, wo ein potentielles tiefer Umkehrpunkt aufgrund eines „Outside“-Balkens entkräftet wird.

„Outside“-Balken

„Outside“-Balken umfassen per definitionem die umliegenden Balken und führen zu einer übermäßigen Volatilität. Sie signalisieren keine kontrollierte Erschöpfung, sondern spiegeln Instabilität und Ungleichgewicht wider – Bedingungen, die den natürlichen Marktrhythmus, den Williams auszunutzen versuchte, verzerren. Deswegen wird jeder Umkehrkandidat, der von einem „Outside“-Balken gebildet wird, sofort disqualifiziert.

In ähnlicher Weise verdeutlicht Abbildung 4 die Auswirkungen von „Intside“-Balken.

„Intside“-Balken

Ein „Intside“-Balken steht für Kontraktion und Unentschlossenheit, nicht für Entschlossenheit. Wenn sich ein Umkehrkandidat auf oder neben einem Innenstab bildet, fehlt der Struktur das Engagement der Marktteilnehmer. Im Einklang mit den ursprünglichen Grundsätzen von Larry Williams werden solche Formulierungen herausgefiltert, sodass nur die eindeutigsten Ausdrücke der kurzfristigen Absicht erhalten bleiben.

Indem wir diese Ausnahmen durchsetzen, identifizieren wir nicht nur Hochs und Tiefs, sondern isolieren aussagekräftige Wendepunkte, die echte Verschiebungen im kurzfristigen Auftragsfluss widerspiegeln. Diese disziplinierte Filterung ist es, die ein visuelles Chartmuster in ein wiederholbares, testbares Marktverhalten verwandelt.

Mit diesen Definitionen verfügen wir nun über einen präzisen Rahmen, um kurzfristige Hochs und Tiefs zu erkennen, die den internen Rhythmus des Marktes genau widerspiegeln.


Allgemeiner Aufbau des Expert Advisors

Ein gut durchdachtes System ist leichter zu testen, zu erweitern und vertrauenswürdig. In diesem Abschnitt erläutern wir die wichtigsten Designprinzipien, die die Konstruktion unseres EAs für den Handel der Umkehrpunkte nach Larry Williams leiten.

Der EA ist von Grund auf so aufgebaut, dass er konfigurierbar und nicht meinungsabhängig ist. Das Marktverhalten ist nicht bei allen Instrumenten oder Zeitrahmen identisch, und keine einzige Ausführungsregel sollte jedem Händler aufgezwungen werden. Deswegen legt der EA wichtige Verhaltensentscheidungen als Nutzereingaben offen, sodass dieselbe Kernlogik unter verschiedenen Handelsannahmen bewertet werden kann.

Handelsrichtungskontrolle

Die erste Gestaltungsentscheidung betrifft die Handelsrichtung. Der EA ermöglicht es dem Nutzer, zu kaufen, verkaufen oder in beide Richtungen zu handeln. Dies ist besonders nützlich für Händler, die bereits eine Tendenz haben, die sich aus der Analyse auf höheren Zeitebenen oder aus Trendfolgemethoden ergibt.

Positionsgrößenbestimmung und Risikokontrolle

Der EA unterstützt sowohl die manuelle Positionsgröße als auch die automatische Losgrößenberechnung auf Basis eines vordefinierten Prozentsatzes des aktuellen Kontostandes. So können Händler zwischen einem festen und einem anpassungsfähigen Risiko wählen, das mit dem Kontowachstum oder -rückgang skaliert. Wichtig ist, dass dieses Design sicherstellt, dass dieselbe Strategielogik unter verschiedenen Risikomodellen bewertet werden kann, ohne den Kerncode zu ändern.

Logik des Handelsausstiegs

Basierend auf den Erkenntnissen aus unseren früheren Experimenten in Teil 3 dieser Serie, unterstützt der EA zwei verschiedene Ausstiegsmodi. Der erste schließt den Handel am Ende eines einzelnen Balkens ab, was mit der beobachteten kurzfristigen Tendenz im Anschluss an Umkehrformationen übereinstimmt. Bei der zweiten wird ein vordefiniertes Take-Profit-Niveau verwendet, das von einem konfigurierbaren Risiko-Ertragsverhältnis abgeleitet wird.

Platzierung des Schutzstopps

Ein harter Stop-Loss schützt jeden vom EA ausgeführten Handel. Dieser Stopp wird an der Spitze des Umkehrbalkens platziert, der das kurzfristige Hoch oder Tief definiert. Dies ist eine bewusste Entscheidung. Es bindet das Risiko direkt an die Marktstruktur und nicht an willkürliche Punktabstände.

Modulare Architektur

Bei der Entwicklung des EA wurde auf Modularität geachtet. Umkehrerkennung, Handelsüberprüfung, Risikoberechnung und Orderausführung sind logisch voneinander getrennt. Dieser Ansatz verbessert die Lesbarkeit und fördert bewährte Praktiken bei der MQL5-Entwicklung. Noch wichtiger ist, dass die Leser einzelne Komponenten wiederverwenden können, wenn sie ihre eigenen Systeme aufbauen oder dieses mit zusätzlichen Filtern und Ideen erweitern.

Zusätzliche Designüberlegungen

Um Forschung und Experimente zu unterstützen, stellt der EA auch sicher, dass nur eine Handelsentscheidung pro abgeschlossenem Balken getroffen wird. Dies verhindert die Duplizierung von Signalen und sorgt für ein konsistentes Verhalten zwischen Live-Handel und Strategietests. 

Mit diesen Gestaltungsprinzipien haben wir nun eine solide Grundlage. Im nächsten Abschnitt gehen wir vom Entwurf zur Implementierung über und beginnen mit der Umsetzung der kurzfristigen Umkehrkonzepte von Larry Williams in ausführbare Logik. 


Schreiben des Expert Advisors Schritt für Schritt

Nachdem die Design-Entscheidungen getroffen wurden, können wir nun zum praktischen Teil dieses Artikels übergehen und mit dem Schreiben des Expert Advisors selbst beginnen. Dieser Abschnitt ist als Leitfaden für den Einstieg gedacht. Das Ziel ist nicht nur, zu zeigen, was zu schreiben ist, sondern auch zu erklären, warum jedes Teil existiert und wie es in das Gesamtsystem passt, das wir aufbauen.

Bevor ich Ihnen folge, möchte ich ein paar Dinge erwähnen, die ich für wichtig halte. In diesem Artikel wird davon ausgegangen, dass der Leser bereits über Arbeitskenntnisse in der Programmiersprache MQL5 verfügt. Sie sollten mit dem Lesen und Schreiben von Expert Advisors vertraut sein, ohne dass Sie eine Einführung in die grundlegende Syntax benötigen. Sie sollten auch mit dem MetaTrader 5 und dem MetaEditor 5 vertraut sein und wissen, wie man neue Expert Advisor-Dateien erstellt, MQL5-Programme kompiliert, sie an Charts anhängt und Compiler-Meldungen liest. Grundlegende Erfahrungen mit dem Strategy Tester werden ebenfalls erwartet, da dieser EA so konzipiert ist, dass er unter verschiedenen Marktbedingungen getestet und bewertet werden kann.

Um den Lernprozess zu erleichtern, ist diesem Artikel eine vollständige Quelldatei namens lwShortTermStructureExpert.mq5 beigefügt. Diese Datei enthält die fertige Version des Expert Advisors, den wir gerade erstellen. Ich möchte Sie ermutigen, sie herunterzuladen und zum Nachschlagen aufzubewahren. Sie können sie mit Ihrer eigenen Umsetzung vergleichen, wenn Ihnen etwas unklar erscheint. Der beste Weg, das Programmieren zu lernen, ist, den Code selbst zu schreiben, ihn oft zu kompilieren und zu beobachten, wie die Plattform darauf reagiert.

Öffnen Sie zunächst MetaEditor 5 und erstellen Sie eine neue leere Expert Advisor-Datei. Nennen Sie sie lwShortTermStructureExpert.mq5. Sobald die Datei erstellt ist, fügen Sie den unten angegebenen Quellcode in den Editor ein und kompilieren ihn.

//+------------------------------------------------------------------+
//|                                   lwShortTermStructureExpert.mq5 |
//|          Copyright 2025, MetaQuotes Ltd. Developer is Chacha Ian |
//|                          https://www.mql5.com/en/users/chachaian |
//+------------------------------------------------------------------+

#property copyright   "Copyright 2025, MetaQuotes Ltd. Developer is Chacha Ian"
#property link        "https://www.mql5.com/en/users/chachaian"
#property version     "1.00"
#property description "This Expert Advisor automates Larry Williams’ short-term swing high and swing low trading methodology."
#property description "Trades are executed based on validated short-term swing formations derived from market structure."
#property description "The EA supports both time-based exits (single-bar holding) and risk-reward–based take-profit models."

//+------------------------------------------------------------------+
//| Standard Libraries                                               |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>

//+------------------------------------------------------------------+
//| User input variables                                             |
//+------------------------------------------------------------------+
input group "Information"
input ulong           magicNumber           = 254700680002;                 
input ENUM_TIMEFRAMES timeframe             = PERIOD_CURRENT;

//+------------------------------------------------------------------+
//| Global Variables                                                 |
//+------------------------------------------------------------------+
//--- Create a CTrade object to handle trading operations

CTrade Trade;

//--- Bid and Ask
double   askPrice;
double   bidPrice;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){

   //---  Assign a unique magic number to identify trades opened by this EA
   Trade.SetExpertMagicNumber(magicNumber);

   return(INIT_SUCCEEDED);
}

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

   //--- Notify why the program stopped running
   Print("Program terminated! Reason code: ", reason);

}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(){

   //--- Retrieve current market prices for trade execution
   askPrice      = SymbolInfoDouble (_Symbol, SYMBOL_ASK);
   bidPrice      = SymbolInfoDouble (_Symbol, SYMBOL_BID);
   
}

//+------------------------------------------------------------------+
//| TradeTransaction function                                        |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction& trans,
                        const MqlTradeRequest& request,
                        const MqlTradeResult& result)
{

   //--- To handle trade transaction events

}
  
//+------------------------------------------------------------------+

In diesem Stadium wird der Code weder handeln noch Signale erzeugen. Er dient als saubere, stabile Grundlage, die wir in den folgenden Abschnitten Schritt für Schritt ausbauen werden.

Der erste Teil der Datei enthält die Header- und Eigenschaftsdefinitionen. Dieser Abschnitt dokumentiert den Zweck des Expert Advisors, seinen Autor, seine Version und sein allgemeines Verhalten. Diese Eigenschaften werden auch angezeigt, wenn der EA an ein Chart angehängt ist, was sowohl für die Nutzer als auch für die künftige Wartung nützlich ist.
Als Nächstes wird die von MQL5 bereitgestellte Standard-Handelsbibliothek einbezogen. Dies ermöglicht uns die Verwendung der Klasse CTrade, die die Auftragsausführung und das Handelsmanagement vereinfacht. Die Verwendung von Standardbibliotheken verbessert die Zuverlässigkeit und hält den Code sauber.

Der Abschnitt für Nutzereingaben definiert Parameter, die der Händler konfigurieren kann, ohne den Quellcode zu berühren. In diesem Stadium legen wir nur allgemeine Informationen wie die magische Zahl und den Zeitrahmen fest. Weitere Eingaben werden später hinzugefügt, wenn wir Handelsrichtungsfilter, Positionsgrößenlogik und Ausstiegsmodi einführen.

Der Bereich der globalen Variablen enthält Objekte und Werte, auf die im gesamten Expert Advisor zugegriffen werden muss. Hier erstellen wir ein CTrade-Objekt, das alle Handelsoperationen abwickeln wird. Wir deklarieren auch Variablen, um die aktuellen Geld- und Briefkurse zu speichern, die für die Ausführung von Geschäften erforderlich sind.
Die Initialisierungsfunktion wird einmal beim Start des Expert Advisors aufgerufen. Seine Hauptaufgabe besteht darin, dem Handelsobjekt eine eindeutige magische Nummer zuzuweisen. Dadurch kann der EA nur seine eigenen Positionen korrekt identifizieren und verwalten.

Die Deinitialisierungsfunktion wird ausgeführt, wenn der Expert Advisor entfernt oder gestoppt wird. Momentan wird lediglich der Grund für die Beendigung des Programms angegeben. Dies ist bei der Fehlersuche und beim Testen nützlich.

Die Tick-Funktion ist die Funktion, mit der der EA auf Marktaktivitäten reagiert. In diesem Stadium werden nur die aktuellen Geld- und Briefkurse abgerufen. In späteren Abschnitten wird diese Funktion die Kernlogik zur Erkennung kurzfristiger Umkehrstrukturen und zur Ausführung von Handelsgeschäften enthalten.
Schließlich wird die Funktion für Handelsgeschäfte als Platzhalter aufgenommen. Sie ermöglicht es dem EA, auf handelsbezogene Ereignisse wie Auftragsausführung oder Positionsschließung zu reagieren. Wir werden dies später nutzen, um das Handelsverhalten genauer zu überwachen und zu steuern.

Dieser Standardcode bietet einen soliden, organisierten Ausgangspunkt. Von hier aus werden wir schrittweise die Logik einführen, die die kurzfristigen Hochs und Tiefs von Larry Williams erkennt, Handelsfilter anwendet und das Risiko auf kontrollierte und überprüfbare Weise steuert.

Logik der Signaldetektion

Nachdem die EA-Grundlage geschaffen wurde, geht es nun an die kritischste Phase der Entwicklung: die Signalerkennung. Hier wird die Marktstruktur in ausführbare Logik umgesetzt.

Bei diesem Expert Advisor vermeiden wir bewusst den Aufruf eines nutzerdefinierten Indikators. Stattdessen erkennen wir Larry Williams' kurzfristige Umkehrformationen direkt aus den Kursdaten. Dadurch ist der EA leichtgewichtig, einfacher zu verteilen und vollständig in sich geschlossen – alles, was zur Identifizierung des Musters erforderlich ist, ist im EA selbst enthalten.

Signale zur richtigen Zeit erkennen

Larry Williams' kurzfristige Schwankungen sind dreistufige Strukturen. Um sie zuverlässig zu erkennen, müssen wir warten, bis sich alle erforderlichen Balken vollständig geschlossen haben. Deswegen wird die Signalerkennung nur durchgeführt, wenn ein neuer Balken geöffnet wird.

Wenn ein neuer Balken erscheint, nimmt er den Index Null in der Preisreihe ein. Die drei abgeschlossenen Balken unmittelbar davor stehen auf den Indizes 1, 2 und 3. Dies sind die Balken, die einen gültigen kurzfristigen Umkehrpunkt bilden können.

Um diese Logik zu unterstützen, definieren wir eine kleine Hilfsfunktion, die das Öffnen eines neuen Balkens erkennt.

//--- UTILITY FUNCTIONS
//+------------------------------------------------------------------+
//| Function to check if there's a new bar on a given chart timeframe|
//+------------------------------------------------------------------+
bool IsNewBar(string symbol, ENUM_TIMEFRAMES tf, datetime &lastTm)
{

   datetime currentTm = iTime(symbol, tf, 0);
   if(currentTm != lastTm){
      lastTm       = currentTm;
      return true;
   }  
   return false;
   
}

Diese Funktion vergleicht die aktuelle Balkenzeit mit der zuvor aufgezeichneten Balkenzeit. Ändert sich die Uhrzeit, hat sich ein neuer Balken gebildet, und die Funktion gibt true zurück.

Die Funktion nimmt drei Parameter entgegen. Das Symbol und der Zeitrahmen geben an, welches Chart überwacht werden soll. Eine Variable vom Typ datetime wird als Referenz übergeben und speichert den Zeitstempel des zuletzt verarbeiteten Balkens. Dadurch wird sichergestellt, dass die Logik einmal pro Balken und nicht bei jedem Tick ausgeführt wird.

Damit dies funktioniert, definieren wir auch eine globale Datetime-Variable. Diese Variable enthält den Zeitstempel des letzten verarbeiteten Balkens und ermöglicht es dem EA, den Status über Ticks hinweg beizubehalten.

//--- To help track new bar open
datetime lastBarOpenTime;

Nachdem wir die Variable deklariert haben, weisen wir ihren Anfangswert innerhalb der OnInit-Funktion zu, wie unten gezeigt.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){

   ...
   
   //--- Initialize global variables
   lastBarOpenTime       = 0;

   return(INIT_SUCCEEDED);
}

Erkennen eines kurzfristigen tiefen Umkehrpunkts

Sobald ein neuer Balken bestätigt wird, können wir die vorangegangenen drei Balken sicher auf eine kurzfristige Umkehrformation untersuchen.

//+------------------------------------------------------------------+
//| Detects a Larry Williams short-term low on the last three bars   |
//| Bar index 2 must be a swing low with higher lows on both sides   |
//| Bar 2 must NOT be an outside bar                                 |
//| Bar 1 must NOT be an inside bar                                  |
//+------------------------------------------------------------------+
bool IsLarryWilliamsShortTermLow(string symbol, ENUM_TIMEFRAMES tf){

   //--- Price data for the three bars
   double high1 = iHigh(symbol, tf, 1);
   double low1  = iLow (symbol, tf, 1);

   double high2 = iHigh(symbol, tf, 2);
   double low2  = iLow (symbol, tf, 2);

   double high3 = iHigh(symbol, tf, 3);
   double low3  = iLow (symbol, tf, 3);

   //--- Condition 1: Bar 2 must be a swing low
   bool isSwingLow =
      (low2 < low1) &&
      (low2 < low3);

   if(!isSwingLow){
      return false;
   }
      
   //--- Condition 2: Bar 2 must NOT be an outside bar relative to bar 3
   bool isOutsideBar =
      (high2 > high3) &&
      (low2  < low3);

   if(isOutsideBar){
      return false;
   }

   //--- Condition 3: Bar 1 must NOT be an inside bar relative to bar 2
   bool isInsideBar =
      (high1 < high2) &&
      (low1  > low2);

   if(isInsideBar){
      return false;
   }

   //--- All conditions satisfied
   lwShortTermSwingLevel = NormalizeDouble(low2, Digits());
   return true;
}

Die Funktion zur Erkennung eines kurzfristigen Tiefs nach Larry Williams beginnt mit der Abfrage der Höchst- und Tiefstkurse für die Balken 1, 2 und 3. Der zweite Balken ist der mittlere Balken und ist der Kandidat für einen Umkehrbalken.

Die erste Bedingung prüft, ob der zweite Balken ein echter tiefer Umkehrpunkt ist. Sein Tiefstwert muss niedriger sein als die Tiefstwerte der Balken auf beiden Seiten. Wenn diese Bedingung nicht erfüllt ist, wird das Muster sofort abgelehnt.

Die zweite Bedingung filtert Balken von außerhalb heraus. Der zweite Balken darf Balken drei nicht vollständig verschlingen. „Outside“-Balken verzerren oft die Struktur und werden ausgeschlossen, um das Muster sauber und einheitlich zu halten.

Die dritte Bedingung prüft den ersten Balken. Es darf sich nicht um einen „Inside“-Balken im Verhältnis zum zweiten Balken handeln. Die „Inside“-Balken stehen für Kontraktion und Unsicherheit, die Larry Williams bei der Definition gültiger Umkehrpunkte ausdrücklich vermeidet.

Nur wenn alle drei Bedingungen erfüllt sind, bestätigen das einen gültigen kurzfristigen tiefen Umkehrpunkt. Zu diesem Zeitpunkt speichern wir den Tiefstkurs des Umkehrbalken in einer globalen Variablen. Dieses Preisniveau markiert einen strukturell wichtigen Punkt auf dem Markt und dient später als Entscheidungsgrundlage für das Risikomanagement.

Erkennen eines kurzfristigen hohen Umkehrpunkts

Die Logik zur Erkennung eines kurzfristigen hohen Umkehrpunkts ist die Umkehrung der des tiefen Umkehrpunkts.

//+------------------------------------------------------------------+
//| Detects a Larry Williams short-term high on the last three bars  |
//| Bar index 2 must be a swing high with lower highs on both sides  |
//| Bar 2 must NOT be an outside bar                                 |
//| Bar 1 must NOT be an inside bar                                  |
//+------------------------------------------------------------------+
bool IsLarryWilliamsShortTermHigh(string symbol, ENUM_TIMEFRAMES tf){

   //--- Price data for the three bars
   double high1 = iHigh(symbol, tf, 1);
   double low1  = iLow (symbol, tf, 1);

   double high2 = iHigh(symbol, tf, 2);
   double low2  = iLow (symbol, tf, 2);

   double high3 = iHigh(symbol, tf, 3);
   double low3  = iLow (symbol, tf, 3);

   //--- Condition 1: Bar 2 must be a swing high
   bool isSwingHigh =
      (high2 > high1) &&
      (high2 > high3);

   if(!isSwingHigh){
      return false;
   }
      
   //--- Condition 2: Bar 2 must NOT be an outside bar relative to bar 3
   bool isOutsideBar =
      (high2 > high3) &&
      (low2  < low3);

   if(isOutsideBar){
      return false;
   }

   //--- Condition 3: Bar 1 must NOT be an inside bar relative to bar 2
   bool isInsideBar =
      (high1 < high2) &&
      (low1  > low2);

   if(isInsideBar){
      return false;
   }

   //--- All conditions satisfied
   lwShortTermSwingLevel = NormalizeDouble(high2, Digits());
   return true;
}

Anstatt nach tieferen Tiefs zu suchen, suchen wir nach höheren Hochs. Anstatt fallende „Outside“-Balken abzulehnen, lehnen wir Aufwärtsbalken ab. Es gelten die gleichen strukturellen Filter, nur gespiegelt.

Da die Logik der gleichen Struktur und dem gleichen Fluss folgt, ist es nicht nötig, sie noch einmal im Detail aufzuschlüsseln. Wenn die Funktion für den tiefen Umkehrpunkt verstanden worden ist, wird die Funktion für den hohen Umkehrpunkt intuitiv.

Wenn ein gültiger hoher Umkehrpunkt erkannt wird, wird der Höchstkurs des mittleren Balkens in derselben globalen Variablen gespeichert. Dadurch kann der EA den letzten Umkehrpunkt unabhängig von der Richtung verfolgen.

Verfolgung des letzten Umkehrniveaus

Wenn Sie in diesem Stadium versuchen, den EA zu kompilieren, werden Sie auf Fehler von nicht deklarierten Bezeichnern stoßen. Dies geschieht, weil wir einer Variablen einen Wert zuweisen, der noch nicht definiert wurde.

Um dieses Problem zu lösen, deklarieren wir eine globale Variable, die das Preisniveau des zuletzt festgestellten kurzfristigen Ausschlags speichert, unabhängig davon, ob es sich um einen Höchst- oder Tiefststand handelt.

//--- Stores the price level of the most recently detected Larry Williams' short-term swing high or low
double lwShortTermSwingLevel;

Diese Variable dient einem einzigen Zweck. Sie verfolgt das letzte bestätigte strukturelle Extrem. Später im EA wird dieser Wert verwendet, um schützende Stopp-Levels an logischen Marktpunkten und nicht in willkürlichen Abständen zu platzieren.

Nachdem wir die Variable deklariert haben, weisen wir ihren Anfangswert innerhalb der OnInit-Funktion zu, wie unten gezeigt.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){

   ...
   
   //--- Initialize global variables
   
   ...
   
   lwShortTermSwingLevel = DBL_MAX;

   return(INIT_SUCCEEDED);
}

Durch die Trennung von Signalerkennung und Handelsausführung bleibt die Logik modular und leicht erweiterbar. In der nächsten Phase wird diese ermittelte Struktur mit den Regeln für den Einstieg in den Handel, den Ausstieg aus dem Handel und das Risikomanagement verknüpft.

An diesem Punkt kann der EA den Markt beobachten, gültige kurzfristige Umkehrformationen nach Larry Williams erkennen und deren Preisniveaus genau und konsistent aufzeichnen. Dies bildet die Kernintelligenz des Systems, und alles, was folgt, baut auf dieser Grundlage auf.

Handelslogik und Auftragsdurchführung

In diesem Abschnitt geht es darum, wie Signale in reale Positionen umgesetzt werden, wobei die zuvor vereinbarten Gestaltungsregeln eingehalten werden.

Die Handelslogik ist auf Klarheit und Kontrolle ausgerichtet. Jede Entscheidung, die der EA trifft, wird von expliziten Regeln geleitet, die der Nutzer konfigurieren kann. Um dies zu erreichen, führen wir mehrere nutzerdefinierte Enumerationen, Nutzereingaben und Hilfsfunktionen ein, die als ein einziges System zusammenarbeiten.

Kontrolle der Handelsrichtung

Die erste Designentscheidung, die wir umsetzen, ist die Flexibilität der Handelsrichtung. Nicht jeder Händler möchte immer nach beide Seiten des Marktes handeln. Einige ziehen es vor, sich an einem vorherrschenden Trend zu orientieren und den Einstieg auf eine einzige Richtung zu beschränken.

Um dies zu unterstützen, definieren wir eine nutzerdefinierte Enumeration, die es dem EA ermöglicht, in drei Modi zu arbeiten. Nur kaufen, nur verkaufen oder in beide Richtungen handeln. Der gewählte Modus bestimmt, welche Signale einen Handel auslösen.

//--- CUSTOM ENUMERATIONS
enum ENUM_TRADE_DIRECTION  
{ 
   ONLY_LONG, 
   ONLY_SHORT, 
   TRADE_BOTH 
};

Diese Auswahl wird dem Nutzer dann als Eingabemöglichkeit präsentiert.

input group "Trade And Risk Management"
input ENUM_TRADE_DIRECTION direction        = TRADE_BOTH;

Wenn der EA läuft, überprüft er diese Einstellung, bevor er einen Auftrag ausführt. Signale, die nicht mit der gewählten Richtung übereinstimmen, werden vollständig ignoriert. 

Modi zur Bestimmung der Losgröße

Als Nächstes befassen wir uns mit der Positionsgröße. Risikomanagement ist keine Option, und verschiedene Händler bevorzugen unterschiedliche Ansätze. Der EA unterstützt zwei Losgrößenmodi. Im manuellen Modus gibt der Nutzer eine feste Losgröße vor. Für jeden Handel wird das gleiche Volumen verwendet, unabhängig von der Stopp-Distanz oder der Kontogröße.

enum ENUM_LOT_SIZE_INPUT_MODE 
{ 
   MODE_MANUAL, 
   MODE_AUTO 
};

Im automatischen Modus berechnet der EA die Losgröße dynamisch. Die Berechnung basiert auf einem Prozentsatz des aktuellen Kontostands und dem Abstand zwischen dem Einstiegskurs und dem schützenden Stopp. Dadurch wird sichergestellt, dass das Risiko bei allen Handelsgeschäften gleich bleibt, auch wenn sich die Marktvolatilität ändert.

Beide Modi werden als Eingänge angezeigt.

input ENUM_LOT_SIZE_INPUT_MODE lotSizeMode  = MODE_AUTO;
input double riskPerTradePercent            = 1.0;
input double positionSize                   = 0.01;

Wenn der automatische Modus ausgewählt ist, ignoriert der EA die Eingabe der festen Losgröße und verwendet stattdessen den Risikoprozentsatz. Wenn der manuelle Modus gewählt wird, wird der Risikoprozentsatz ignoriert.

Strategien zur Gewinnmitnahme und Steuerung des Risiko-Ertrags-Verhältnisses

Die nächste Flexibilitätsebene ist die Logik für den Ausstieg aus dem Handel. Aus früheren Experimenten wissen wir, dass kurzfristige Umkehrmuster häufig innerhalb des nächsten Balkens eine Richtungsänderung bewirken. Einige Händler bevorzugen jedoch strukturierte Renditeziele.

Um beide Ansätze zu unterstützen, definieren wir eine Enumeration von Gewinnmitnahme-Modi.

enum ENUM_TAKE_PROFIT_MODE
{
   TP_HOLD_ONE_BAR,
   TP_FIXED_RRR_1_ONE,
   TP_FIXED_RRR_1_ONEptFIVE,
   TP_FIXED_RRR_1_TWO,
   TP_FIXED_RRR_1_THREE
};

Bei der ersten Option wird der Handel nach genau einem Balken geschlossen. In diesem Modus wird kein Take Profit festgelegt. Der Ausstieg aus dem Handel erfolgt nach Zeit und nicht nach Preis.

Für die übrigen Optionen gelten feste Risiko-Ertrags-Verhältnisse. Diese Modi berechnen einen Take-Profit-Niveau auf der Grundlage der Stopp-Distanz und des gewählten Ertragsmultiplikators. Der EA setzt dann bei der Ausführung sowohl einen Stop-Loss als auch einen Take-Profit.

Mit einem einzigen Eingabeparameter kann der Nutzer den gewünschten Ausstiegsstil auswählen. Der EA passt sein Verhalten auf der Grundlage dieser Wahl automatisch an.

input ENUM_TAKE_PROFIT_MODE takeProfitMode  = TP_HOLD_ONE_BAR;

Ein Handel nach dem anderen durchsetzen

Eine der wichtigsten Designregeln ist, dass der EA immer nur eine Position einnehmen kann. Dadurch werden Überschneidungen vermieden und die Ergebnisse bleiben sauber und interpretierbar.

Um diese Regel durchzusetzen, definieren wir Hilfsfunktionen, die prüfen, ob bereits eine aktive Kauf- oder Verkaufsposition besteht.

//+------------------------------------------------------------------+
//| To verify whether this EA currently has an active buy position.  |                                 |
//+------------------------------------------------------------------+
bool IsThereAnActiveBuyPosition(ulong magic){
   
   for(int i = PositionsTotal() - 1; i >= 0; i--){
      ulong ticket = PositionGetTicket(i);
      if(ticket == 0){
         Print("Error while fetching position ticket ", _LastError);
         continue;
      }else{
         if(PositionGetInteger(POSITION_MAGIC) == magic && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY){
            return true;
         }
      }
   }
   
   return false;
}

//+------------------------------------------------------------------+
//| To verify whether this EA currently has an active sell position. |                                 |
//+------------------------------------------------------------------+
bool IsThereAnActiveSellPosition(ulong magic){
   
   for(int i = PositionsTotal() - 1; i >= 0; i--){
      ulong ticket = PositionGetTicket(i);
      if(ticket == 0){
         Print("Error while fetching position ticket ", _LastError);
         continue;
      }else{
         if(PositionGetInteger(POSITION_MAGIC) == magic && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL){
            return true;
         }
      }
   }
   
   return false;
}

Diese Funktionen durchsuchen alle offenen Positionen und finden eine, die mit der magischen Zahl des EA und dem gewünschten Handelstyp übereinstimmt.

Wenn eine passende Position gefunden wird, weiß der EA, dass er bereits ein Handelsgeschäft eröffnet hat und ignoriert alle neuen Signale. Diese Logik sorgt für Disziplin und verhindert eine Überbelichtung.

Die Funktionen, die prüfen, ob eine Kauf- oder Verkaufsposition vorliegt, folgen der gleichen Struktur. Wenn der Leser das eine verstanden hat, wird das andere sofort klar.

Schließen eines Handelsgeschäft gehalten für einen Balken

Bei Handelsgeschäften, die nur für einen einzigen Balken gehalten werden, benötigen wir eine zuverlässige Möglichkeit, sie zu schließen. Zu diesem Zweck definieren wir eine Funktion, die alle mit der magischen Zahl EA verbundenen Positionen schließt.

//+------------------------------------------------------------------+
//| To close all positions with a specified magic number             |   
//+------------------------------------------------------------------+
void ClosePositionsByMagic(ulong magic) {
    
    for (int i = PositionsTotal() - 1; i >= 0; i--) {
        ulong ticket = PositionGetTicket(i);
        if (PositionSelectByTicket(ticket)) {
            if (PositionGetInteger(POSITION_MAGIC) == magic) {
                ulong positionType = PositionGetInteger(POSITION_TYPE);
                double volume = PositionGetDouble(POSITION_VOLUME);
                if (positionType == POSITION_TYPE_BUY) {
                    Trade.PositionClose(ticket);
                } else if (positionType == POSITION_TYPE_SELL) {
                    Trade.PositionClose(ticket);
                }
            }
        }
    }    
}

Diese Funktion durchläuft alle offenen Positionen, identifiziert diejenigen, die zum EA gehören, und schließt sie mithilfe des Handelsobjekts. Dabei spielt es keine Rolle, ob es Kauf- oder Verkaufspositionen sind. Wenn die magische Zahl übereinstimmt, wird die Position geschlossen.

Diese Funktion wird später aufgerufen, wenn ein neuer Balken geöffnet wird, um sicherzustellen, dass sich zeitbasierte Ausgänge genau wie vorgesehen verhalten.

Eröffnung einer Kaufposition

Da alle unterstützenden Komponenten vorhanden sind, können wir nun den Handel eröffnen.

Die Kaufabwicklungsfunktion erledigt alles, was erforderlich ist, um eine erweiterte Position sicher und konsistent zu platzieren.

//+------------------------------------------------------------------+
//| Function to open a market long position                          |
//+------------------------------------------------------------------+
bool OpenBuy(double entryPrice, double lotSize){
   
   double stopLevel      = lwShortTermSwingLevel;
   double stopDistance   = entryPrice - stopLevel;
   double contractSize   = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_CONTRACT_SIZE);
   double accountBalance = AccountInfoDouble(ACCOUNT_BALANCE);
   
   if(takeProfitMode == TP_HOLD_ONE_BAR){
   
      if(lotSizeMode == MODE_AUTO){
         double amountAtRisk = (riskPerTradePercent / 100.0) *  accountBalance;
         lotSize             = amountAtRisk / (contractSize * stopDistance);
         lotSize             = NormalizeDouble(lotSize, 2);
      }
      
      if(!Trade.Buy(NormalizeDouble(lotSize, 2), _Symbol, entryPrice, stopLevel)){
         Print("Error while executing a market buy order: ", GetLastError());
         Print(Trade.ResultRetcode());
         Print(Trade.ResultComment());
         return false;
      }   
   
   }
   
   else{
   
      double rewardValue              = 1.0;
      
      switch(takeProfitMode){
         case TP_FIXED_RRR_1_ONE: 
            rewardValue = 1.0;
            break;
         case TP_FIXED_RRR_1_ONEptFIVE:
            rewardValue = 1.5;
            break;
         case TP_FIXED_RRR_1_TWO: 
            rewardValue = 2.0;
            break;
         case TP_FIXED_RRR_1_THREE: 
            rewardValue = 3.0;
            break;
         default:
            rewardValue = 1.0;
            break;
      }
      
      double targetLevel = NormalizeDouble(entryPrice + stopDistance * rewardValue ,Digits());
      if(!Trade.Buy(NormalizeDouble(lotSize, 2), _Symbol, entryPrice, stopLevel, targetLevel)){
         Print("Error while executing a market buy order: ", GetLastError());
         Print(Trade.ResultRetcode());
         Print(Trade.ResultComment());
         return false;
      }   
   }

   return true;
}

Er verwendet das zuletzt festgestellte Umkehrniveau als schützenden Stopp. Der Abstand zwischen dem Einstiegskurs und diesem Stop definiert das Handelsrisiko.

Wenn die automatische Losgrößenbestimmung aktiviert ist, berechnet die Funktion die Losgröße, um den vordefinierten Prozentsatz des Kontosaldos im Risiko zu halten. Wird die manuelle Größenbestimmung gewählt, wird die angegebene Losgröße direkt verwendet.

Die Funktion prüft dann den gewählten Take-Profit-Modus. Wenn das Handelsgeschäft nur während eines Balkens offengehalten werden soll, wird nur ein Stop-Loss gesetzt. Wenn ein fester Ertragsmodus ausgewählt ist, wird ein Take-Profit-Niveau auf der Grundlage des gewählten Risiko-Ertrags-Verhältnisses berechnet.

Schließlich sendet die Funktion den Kaufauftrag über das Handelsobjekt und gibt einen Erfolgs- oder Misserfolgsstatus zurück. Alle Ausführungsfehler werden zur Fehlersuche protokolliert.

Eröffnung einer Verkaufsposition

Die Ausführungsfunktion zum Verkaufen folgt der gleichen Logik wie die Funktion zum Kaufen, jedoch in umgekehrter Richtung.

//+------------------------------------------------------------------+
//| Function to open a market short position                         |
//+------------------------------------------------------------------+
bool OpenSel(double entryPrice, double lotSize){

   double stopLevel      = lwShortTermSwingLevel;
   double stopDistance   = stopLevel - entryPrice;
   double contractSize   = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_CONTRACT_SIZE);
   double accountBalance = AccountInfoDouble(ACCOUNT_BALANCE);
   
   if(takeProfitMode == TP_HOLD_ONE_BAR){
      if(lotSizeMode == MODE_AUTO){
         double amountAtRisk = (riskPerTradePercent / 100.0) *  accountBalance;
         lotSize             = amountAtRisk / (contractSize * stopDistance);
         lotSize             = NormalizeDouble(lotSize, 2);
      }
      
      if(!Trade.Sell(NormalizeDouble(lotSize, 2), _Symbol, entryPrice, stopLevel)){
         Print("Error while executing a market buy order: ", GetLastError());
         Print(Trade.ResultRetcode());
         Print(Trade.ResultComment());
         return false;
      }      
   }
   
   else{
   
      double rewardValue              = 1.0;
      
      switch(takeProfitMode){
         case TP_FIXED_RRR_1_ONE: 
            rewardValue = 1.0;
            break;
         case TP_FIXED_RRR_1_ONEptFIVE:
            rewardValue = 1.5;
            break;
         case TP_FIXED_RRR_1_TWO: 
            rewardValue = 2.0;
            break;
         case TP_FIXED_RRR_1_THREE: 
            rewardValue = 3.0;
            break;
         default:
            rewardValue = 1.0;
            break;
      }
      
      double targetLevel = NormalizeDouble(entryPrice - stopDistance * rewardValue ,Digits());
      if(!Trade.Sell(NormalizeDouble(lotSize, 2), _Symbol, entryPrice, stopLevel, targetLevel)){
         Print("Error while executing a market buy order: ", GetLastError());
         Print(Trade.ResultRetcode());
         Print(Trade.ResultComment());
         return false;
      } 
   
   }   

   return true;
}

Der schützende Stopp wird beim letzten hohen Umkehrpunkt gesetzt. Der Abstand des Stop-Loss wird entsprechend berechnet. Die Bestimmung der Losgröße folgt denselben Regeln, und die Platzierung der Gewinnmitnahme entspricht der Kauflogik.

Da die Struktur und der Ablauf identisch sind, lässt sich die Verkaufsfunktion leicht nachvollziehen, wenn man die Kauffunktion versteht. Zusammen bilden sie eine ausgewogene und konsistente Ausführungsebene.

Alles in OnTick vereinen

In diesem Stadium haben wir bereits alle wesentlichen Teile des Expert Advisors erstellt. Wir können gültige kurzfristige Umkehrsignale erkennen, das Risiko kalkulieren und Handelsgeschäfte eröffnen und verwalten. Was bleibt, ist die Verbindung dieser Teile, damit sich der EA in Echtzeit genauso verhält, wie er soll.

Diese endgültige Integration erfolgt innerhalb der Funktion OnTick.

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(){

   ...
   
   //--- Run this block only when a new bar is detected on the selected timeframe
   if(IsNewBar(_Symbol, timeframe, lastBarOpenTime)){
      
      if(takeProfitMode == TP_HOLD_ONE_BAR){
      
         //--- Close any existing buy positions for this EA before opening a new one
         if(IsThereAnActiveBuyPosition(magicNumber)){
            ClosePositionsByMagic(magicNumber);
            Sleep(100);
         }
         
         if(IsThereAnActiveSellPosition(magicNumber)){
            ClosePositionsByMagic(magicNumber);
            Sleep(100);
         }      
      
      }
      
      //---  Enter a buy position when a Larry Williams-defined short-term low swing pattern is detected
      if(direction == ONLY_LONG || direction == TRADE_BOTH){

         if(IsLarryWilliamsShortTermLow(_Symbol, timeframe) && !IsThereAnActiveBuyPosition(magicNumber) && !IsThereAnActiveSellPosition(magicNumber)){
            OpenBuy(askPrice, positionSize);
         }

      }

      //---  Enter a short position when a Larry Williams-defined short-term high swing pattern is detected
      if(direction == ONLY_SHORT || direction == TRADE_BOTH){

         if(IsLarryWilliamsShortTermHigh(_Symbol, timeframe) && !IsThereAnActiveSellPosition(magicNumber) && !IsThereAnActiveBuyPosition(magicNumber)){
            OpenSel(bidPrice, positionSize);
         }
      }           
   }
}

Diese Funktion wird immer dann aufgerufen, wenn der Marktpreis aktualisiert wird, und dient als Kontrollzentrum des EAs. Hier entscheiden wir, wann wir Signale auswerten, Geschäfte eröffnen und schließen.

Warum wir nur einem neuen Balken handeln

Die erste und wichtigste Entscheidung innerhalb von OnTick ist, dass die gesamte Logik nur dann ausgeführt wird, wenn ein neuer Balken im ausgewählten Zeitrahmen erkannt wird.

Auf diese Weise vermeiden wir es, auf das Rauschen der Preise innerhalb einer Kerze zu reagieren. Die kurzfristige Umkehrlogik von Larry Williams basiert auf geschlossenen Balken, nicht auf sich bildenden Balken. Indem die Logik nur bei der Eröffnung eines neuen Balkens ausgeführt wird, wird sichergestellt, dass alle von uns analysierten Kursdaten endgültig und stabil sind.

Dadurch bleibt der EA auch effizient. Anstatt die Bedingungen bei jedem Tick auszuwerten, trifft der EA seine Entscheidungen einmal pro Balken, was genau das ist, was wir für diese Art von Strategie wollen.

Verwaltung von Ein-Balken-Handelsgeschäfte

Wenn der Take-Profit-Modus so eingestellt ist, dass er für 1 Balken gehalten wird, wird das Handelsmanagement zu einem zeit- und nicht preisbasierten.

Sobald ein neuer Balken erkannt wird, prüft der EA, ob aktive Positionen für diesen Expert Advisor geöffnet sind. Wenn es solche Positionen gibt, werden sie sofort geschlossen. Dadurch wird sichergestellt, dass die im vorherigen Balken eröffneten Geschäfte nicht in den nächsten Balken übergehen.

Diese Logik sorgt für Disziplin. Jeder Handel lebt genau einen Balken lang und nicht länger. Nachdem bestehende Positionen geschlossen wurden, kann der EA neue Signale an der gerade eröffneten Kerze auswerten.

Auswertung von Kaufsignalen

Sobald die Bereinigung des Handels abgeschlossen ist, geht der EA zur Signalauswertung über.

Wenn der Nutzer Kaufen zugelassen hat, prüft der EA, ob sich ein gültiges kurzfristigen Tief nach Larry Williams gebildet hat. Gleichzeitig bestätigt sie, dass es keine aktive Kauf- oder Verkaufsposition gibt. Dadurch wird sichergestellt, dass es zu einem bestimmten Zeitpunkt nur einen Handel geben kann.

Wenn alle Bedingungen erfüllt sind, eröffnet der EA eine Kaufposition unter Verwendung der zuvor definierten Ausführungslogik. Der Einstiegskurs, das Stop-Level, die Losgröße und das Take-Profit-Verhalten werden automatisch auf der Grundlage der Einstellungen des Nutzers festgelegt.

Auswertung von Verkaufssignalen

Die Logik für Verkaufstransaktionen folgt der gleichen Struktur.

Wenn Verkaufen erlaubt sind, sucht der EA nach einem gültigen kurzfristigen Tief nach Larry Williams. Sie bestätigt erneut, dass keine aktive Position vorhanden ist, bevor sie fortfährt.

Wenn die Bedingungen erfüllt sind, wird eine Verkaufsposition eröffnet, wobei dieselben Risikomanagement- und Ausführungsregeln gelten, jedoch in umgekehrter Richtung. Da die Kauf- und Verkaufslogik spiegelbildlich konzipiert wurde, bleibt das Verhalten konsistent und vorhersehbar.

Die Essenz der Entwicklung

Das Besondere an dieser Struktur ist ihre Einfachheit.

Jeder neue Balken löst einen neuen Entscheidungszyklus aus. Bestehende Handelsgeschäfte werden zuerst verwaltet, dann werden die Signale ausgewertet, und nur wenn alle Regeln übereinstimmen, werden die Einträge ausgeführt. Es gibt keine Überschneidungen, keine Zweideutigkeit und kein verstecktes Verhalten.

Der EA verhält sich nun wie ein disziplinierter Händler. Er wartet geduldig ab, handelt nur bei bestätigter Struktur, beachtet die Risikoregeln und übertreibt nie mit dem Handel.

Bevor Sie mit dem Testen beginnen, vergewissern Sie sich bitte, dass der Chart sauber und gut lesbar bleibt, wenn der EA angehängt ist. Eine saubere visuelle Umgebung macht es viel einfacher, zu überprüfen, ob die Handelsgeschäfte genau dort ausgeführt werden, wo sich die beabsichtigten Umkehrstrukturen bilden. Dies ist vorwiegend beim Testen und Debuggen von Strategien hilfreich.

Die Funktion ConfigureChartAppearance übernimmt diese Aufgabe.

//+------------------------------------------------------------------+
//| This function configures the chart's appearance.                 |
//+------------------------------------------------------------------+
bool ConfigureChartAppearance()
{
   if(!ChartSetInteger(0, CHART_COLOR_BACKGROUND, clrWhite)){
      Print("Error while setting chart background, ", GetLastError());
      return false;
   }
   
   if(!ChartSetInteger(0, CHART_SHOW_GRID, false)){
      Print("Error while setting chart grid, ", GetLastError());
      return false;
   }
   
   if(!ChartSetInteger(0, CHART_MODE, CHART_CANDLES)){
      Print("Error while setting chart mode, ", GetLastError());
      return false;
   }

   if(!ChartSetInteger(0, CHART_COLOR_FOREGROUND, clrBlack)){
      Print("Error while setting chart foreground, ", GetLastError());
      return false;
   }

   if(!ChartSetInteger(0, CHART_COLOR_CANDLE_BULL, clrSeaGreen)){
      Print("Error while setting bullish candles color, ", GetLastError());
      return false;
   }
      
   if(!ChartSetInteger(0, CHART_COLOR_CANDLE_BEAR, clrBlack)){
      Print("Error while setting bearish candles color, ", GetLastError());
      return false;
   }
   
   if(!ChartSetInteger(0, CHART_COLOR_CHART_UP, clrSeaGreen)){
      Print("Error while setting bearish candles color, ", GetLastError());
      return false;
   }
   
   if(!ChartSetInteger(0, CHART_COLOR_CHART_DOWN, clrBlack)){
      Print("Error while setting bearish candles color, ", GetLastError());
      return false;
   }
   
   return true;
}

Sie stellt den Chart programmatisch auf ein neutrales und einfaches Layout ein, indem es einen weißen Hintergrund anlegt, das Raster ausschaltet, in den Kerzen-Modus umschaltet und klare Auf- und Abwärtsfarben der Kerzen definiert. Diese Einstellungen entfernen visuelles Rauschen, sodass die Umkehrniveaus und die Preisstruktur deutlich hervortreten. Jede Charteigenschaft wird sicher angewendet, und wenn eine Einstellung fehlschlägt, meldet die Funktion den Fehler und bricht die weitere Ausführung ab. Dadurch wird sichergestellt, dass der EA nur dann ausgeführt wird, wenn die Chartumgebung angemessen vorbereitet ist.

Sobald die Funktion definiert ist, wird sie in der Funktion OnInit aufgerufen.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){

   ...
   
   //--- To configure the chart's appearance
   if(!ConfigureChartAppearance()){
      Print("Error while configuring chart appearance", GetLastError());
      return INIT_FAILED;
   }

   return(INIT_SUCCEEDED);
}

Dadurch wird gewährleistet, dass das Chart sofort konfiguriert wird, wenn der EA geladen wird, bevor die Handelslogik ausgeführt wird. Wenn die Konfiguration fehlschlägt, wird die EA-Initialisierung abgebrochen, um den Handel unter unklaren oder unbeabsichtigten Chartbedingungen zu verhindern. Dieser Ansatz folgt guten defensiven Programmierpraktiken und trägt dazu bei, Verwirrung beim Live-Handel oder den Backtests zu vermeiden.

Mit diesem letzten Schritt ist die Entwicklungsphase des Expert Advisors abgeschlossen. Wir haben jetzt einen voll funktionsfähigen EA, der Signale erkennt, Handelsgeschäfte verwaltet und einen sauberen visuellen Kontext für die Analyse darstellt. Die nächste Phase ist die Testphase, in der wir Backtests mit verschiedenen Finanzinstrumenten durchführen, um die Leistung der Strategie anhand historischer Daten zu bewerten und zu überprüfen, ob sich die Logik unter verschiedenen Marktbedingungen wie erwartet verhält.


Test des EAs

Bevor eine Strategie als vollständig betrachtet wird, muss sie anhand historischer Daten getestet werden. In dieser Phase können wir beobachten, wie sich der EA unter verschiedenen Marktbedingungen und Anlageklassen verhält, während wir stets dieselben Regeln und Beschränkungen anwenden.

Für diese Studie haben wir Rückvergleiche vom 1. Januar 2024 bis zum 30. November 2025 durchgeführt. Zum Zeitpunkt der Erstellung dieses Berichts umfasst dies etwa dreiundzwanzig Monate an Marktdaten. Alle Tests wurden nur täglich durchgeführt.

Der EA wurde an vier Instrumenten getestet, die verschiedene Markttypen repräsentieren: ein Rohstoff, ein Index, eine Kryptowährung und ein wichtiges Devisenpaar. Um Fairness und Wiederholbarkeit zu gewährleisten, wurden für alle Tests dieselbe Konfiguration und dieselben Eingabeparameter verwendet. Diese wurden als configurations.ini und parameters.set an diesen Artikel angehängt, sodass Sie die gleichen Ergebnisse auf Ihrer eigenen Plattform reproduzieren können.

Jeder Test begann mit einem Anfangsguthaben von 10.000 Dollar.

Gold

Von allen getesteten Instrumenten schnitt Gold am besten ab. Während des Testzeitraums erwirtschaftete der EA einen Gesamtnettogewinn von 9.123,25 $, bei einer Gewinnrate von 55%.

Gold-Kapitalkurve

Goldtest-Bericht

Wie aus dem nebenstehenden Screenshot der Kapitalkurve hervorgeht, stimmen die Goldpreisbewegungen gut mit der von Larry Williams definierten kurzfristigen Umkehrstruktur überein. Die Tendenz des Marktes, auf höheren Zeitskalen einen sauberen Trend zu verfolgen, ermöglicht es dem EA, nachhaltige Richtungsbewegungen zu erfassen und gleichzeitig das Risiko zu kontrollieren.

Dieses Ergebnis verdeutlicht, warum Gold oft ein günstiges Instrument für umkehrbasierte Strategien auf dem täglichen Zeitrahmen ist. 

S&P 500

Der S&P 500 lieferte bescheidene, aber stabile Ergebnisse. Der Gesamtnettogewinn für den Zeitraum betrug 158 $, bei einer Gewinnquote von 42,11 %.

Kapitalkurve S&P 500

Testbericht S&P 500

Während der Gesamtgewinn gering ist, zeigt die Kapitalkurve ein relativ glattes Verhalten mit begrenzten Drawdowns. Dies deutet darauf hin, dass die Strategie in den Indexmärkten strukturell solide bleibt, obwohl sie von einer weiteren Optimierung der Ausstiege oder der Positionsgröße profitieren könnte, um längere Richtungsbewegungen besser zu erfassen.

Ein Screenshot der Kapitalkurve und ein detaillierter Testbericht werden bereitgestellt, um dieses Verhalten visuell zu bestätigen. 

Bitcoin

Bei Bitcoin lieferte der EA im Testzeitraum eine solide Performance. Ausgehend von einem Anfangsguthaben von 10.000 Dollar erzielte das System einen Gesamtnettogewinn von 4.572,63 Dollar, bei einer Gewinnquote von 42,42 Prozent.

Bitcoin-Kapitalkurve

Bitcoin-Testbericht

Die Kapitalkurve zeigt ein nachhaltiges Wachstum während der Perioden, in denen Bitcoin auf dem täglichen Zeitrahmen eine präzise Richtungsbewegung zeigte. Dieses Verhalten steht im Einklang mit der kurzfristigen Umkehrstruktur der Strategie und ermöglicht gewinnbringende Handelsgeschäfte, wenn ein Momentum vorhanden ist.

Obwohl Bitcoin für seine Volatilität bekannt ist, trägt der Handel auf einem höheren Zeitrahmen dazu bei, kurzfristige Störungen auszugleichen. Diese Ergebnisse deuten darauf hin, dass die Strategie auf den Kryptowährungsmärkten erfolgreich sein kann, sofern die Risikomanagementregeln eingehalten werden und die Erwartungen realistisch bleiben.

Britisches Pfund

Das britische Pfund verzeichnete bei einem Startguthaben von 10.000 Dollar einen Nettoverlust von 279 Dollar, bei einer Gewinnrate von 19,05 Prozent.

GBPUSD-Kapitalkurve

GBPUSD Testbericht

Die Kapitalkurve zeigt eher viele kleine Verlustgeschäfte als einen einzigen großen Fehlschlag. Dies ist typisch, wenn sich ein Markt in einer Seitwärtsbewegung befindet und keine anhaltenden Richtungsbewegungen aufweist. Beim GBPUSD führten die auf Umkehrpunkte basierenden Einstiegspunkte nur zu begrenzten Kursbewegungen und einer niedrigen Gewinnquote.

Dieses Ergebnis legt zwei Optionen nahe. Eine besteht darin, die Exposition gegenüber diesem Instrument zu verringern. Die andere Möglichkeit besteht darin, die Ausstiegs- und Belohnungseinstellungen anzupassen und Filter hinzuzufügen, sodass nur unter stärkeren Trendbedingungen gehandelt wird. 

Zusammenfassung der Tests

Diese Ergebnisse zeigen eine wesentliche Wahrheit in der Systementwicklung: Keine einzige Konfiguration ist auf allen Märkten gleich gut. Die gleiche Logik, die sich bei Trendinstrumenten wie Gold auszeichnet, kann in schwankenden oder stark volatilen Umgebungen Probleme bereiten.

Genau an dieser Stelle wird Ihr eigenes Experimentieren wertvoll. Wenn Sie die mitgelieferten Dateien configurations.ini und parameters.set laden, können Sie diese Tests wiederholen, einzelne Eingaben anpassen und beobachten, wie sich die Leistung in verschiedenen Märkten und Zeiträumen verändert.

Bitte betrachten Sie diesen EA als einen Forschungsrahmen und nicht als ein fertiges Produkt. Führen Sie Ihre eigenen Backtests durch, testen Sie alternative Ertragsverhältnisse, untersuchen Sie verschiedene Ausstiegsmodi und studieren Sie die Kapitalkurven genau. In diesem Prozess werden echtes Verständnis und Vorsprung aufgebaut.


Schlussfolgerung

In diesem Artikel geht es nicht nur darum, einen fertigen Expert Advisor vorzustellen. Er führte durch einen vollständigen und praktischen Entwicklungsprozess, von der Signalerkennung und den Designentscheidungen bis hin zur Ausführungslogik, dem Risikomanagement und den Tests. Am Ende dieser Reise verfügt der Leser nicht nur über einen funktionierenden EA, sondern auch über ein klares Verständnis dafür, warum er sich so verhält, wie er es tut.

Die Strategie selbst ist absichtlich einfach strukturiert, aber diszipliniert in der Ausführung. Es handelt mit genau definierten Umkehrformationen, begrenzt das Risiko durch einen harten, schützenden Stop und erzwingt eine strenge Positionskontrolle, indem es nur einen aktiven Handel zur gleichen Zeit zulässt. Diese Entscheidungen sind nicht zufällig getroffen worden. Sie spiegeln einen maßvollen Umgang mit Risiken und eine Denkweise wider, die neben dem Wachstum auch den Kapitalerhalt in den Vordergrund stellt. Damit eignet sich der EA nicht nur zum Experimentieren, sondern auch als Grundlage, die verfeinert und verantwortungsvoll eingesetzt werden kann.

Die Backtest-Ergebnisse unterstreichen eine weitere wichtige Erkenntnis. Keine Strategie schneidet auf allen Märkten gleich gut ab. Durch das Testen des EA mit verschiedenen Instrumenten und die Beobachtung, wo er sich auszeichnet und wo er Schwierigkeiten hat, wird der Leser daran erinnert, dass Testen, Bewertung und Anpassung für den systematischen Handel unerlässlich sind. Die mitgelieferten Konfigurations- und Parameterdateien machen es einfach, die Ergebnisse zu reproduzieren und, was noch wichtiger ist, neue Experimente durchzuführen und Verbesserungen zu erforschen.

Letztlich gibt dieser Artikel dem Leser etwas Greifbares. Ein vollständiger Expert Advisor, den Sie studieren, testen, ändern und erweitern können. Gleichzeitig bietet es einen klaren Rahmen für den Aufbau robuster Handelssysteme in MQL5. Unabhängig davon, ob das Ziel darin besteht, etwas zu lernen, zu experimentieren oder zu implementieren, bietet das hier erworbene Wissen eine solide, praktische Ausgangsbasis.

Die folgende Tabelle gibt einen Überblick über die in diesem Artikel enthaltenen Dateien, ihre spezifischen Funktionen und ihre Verwendung auf der Plattform MetaTrader 5.


Dateiname Beschreibung
1. lwShortTermStructureExpert.mq5 Der Hauptquellcode für den Expert Advisor wird in diesem Artikel detailliert beschrieben und enthält die Implementierung der Logik der Kurzzeitstruktur
2. configurations.ini Eine Konfigurationsdatei mit globalen Umgebungseinstellungen, die für das Testen des EA erforderlich sind
3. parameters.set Eine standardisierte Eingabeparameterdatei, mit der Sie die für Backtests verwendeten Nutzereingabeparameter schnell laden können

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

Beigefügte Dateien |
configurations.ini (1.18 KB)
parameters.set (1.06 KB)
Letzte Kommentare | Zur Diskussion im Händlerforum (2)
Arun Kumar
Arun Kumar | 30 Jan. 2026 in 08:44
Hallo ,

Kaufauftrag wird nicht angenommen wir stehen vor 2026.01.30 14:06:59.971 lwShortTermStructureExpert(XAUUSDm,M1) Fehler bei der Ausführung eines Marktkaufauftrags : 0

Chacha Ian Maroa
Chacha Ian Maroa | 30 Jan. 2026 in 08:50
Arun Kumar (XAUUSDm,M1) Fehler bei der Ausführung eines Marktkaufauftrags : 0

Danke, ich werde das überprüfen.
Aufbau von Volatilitätsmodellen in MQL5 (Teil I): Die erste Implementierung Aufbau von Volatilitätsmodellen in MQL5 (Teil I): Die erste Implementierung
In diesem Artikel stellen wir eine MQL5-Bibliothek für die Modellierung von Volatilität vor, die ähnlich wie das Arch-Paket von Python funktioniert. Die Bibliothek unterstützt derzeit die Spezifikation gängiger bedingter Mittelwert- (HAR, AR, Constant Mean, Zero Mean) und bedingter Volatilitätsmodelle (Constant Variance, ARCH, GARCH).
Aufbau von KI-gestützten Handelssystemen in MQL5 (Teil 8): UI-Polnisch mit Animationen, zeitlichen Metriken und Tools für das Reaktionsmanagement Aufbau von KI-gestützten Handelssystemen in MQL5 (Teil 8): UI-Polnisch mit Animationen, zeitlichen Metriken und Tools für das Reaktionsmanagement
In diesem Artikel erweitern wir das KI-gestützte Handelssystem in MQL5 um Verbesserungen der Nutzeroberfläche, einschließlich Ladeanimationen für die Vorbereitungs- und Denkphasen von Anfragen sowie Zeitmesswerte, die in den Antworten für ein besseres Feedback angezeigt werden. Wir fügen Tools zur Verwaltung von Antworten hinzu, wie z. B. Schaltflächen zum erneuten Abfragen der KI und Exportoptionen zum Speichern der letzten Antwort in einer Datei, um die Interaktion zu optimieren.
Eine alternative Log-datei mit der Verwendung der HTML und CSS Eine alternative Log-datei mit der Verwendung der HTML und CSS
In diesem Artikel werden wir eine sehr einfache, aber leistungsfähige Bibliothek zur Erstellung der HTML-Dateien schreiben, dabei lernen wir auch, wie man eine ihre Darstellung einstellen kann (nach seinem Geschmack) und sehen wir, wie man es leicht in seinem Expert Advisor oder Skript hinzufügen oder verwenden kann.
Sigma-Score Indikator für MetaTrader 5: Ein einfacher statistischer Anomalie-Detektor Sigma-Score Indikator für MetaTrader 5: Ein einfacher statistischer Anomalie-Detektor
Erstellen Sie einen praktischen MetaTrader 5 „Sigma-Score“ Indikator von Grund auf und lernen Sie, was er wirklich misst: den z-Score der logarithmischen Renditen (wie viele Standardabweichungen die letzte Bewegung vom letzten Durchschnitt abweicht). Der Artikel geht jeden Codeblock in OnInit(), OnCalculate() und OnDeinit() durch und zeigt dann, wie man Schwellenwerte (z. B. ±2) interpretiert und den Sigma-Score als einfaches „Marktstress-Messgerät“ für Mean-Reversion und Momentum-Trading einsetzt.