Larry Williams Marktgeheimnisse (Teil 5): Automatisieren der Strategie des Volatilitätsausbruchs in MQL5
Einführung
Die Märkte entwickeln sich nicht zufällig. Laut Larry Williams entstehen nachhaltige Kursbewegungen in der Regel aus Momenten extremer Volatilität, wenn sich der Preis über das hinaus ausdehnt, was in letzter Zeit normal war. Diese Volatilitätsausbrüche wirken wie ein Funke, der den Markt in Bewegung bringt und ihn in der gleichen Richtung hält, bis eine gegnerische Kraft auftritt. Diese Idee stellt die weitverbreitete Gewohnheit infrage, kleinen Intraday-Schwankungen nachzujagen, und lenkt die Aufmerksamkeit stattdessen auf die Momente, in denen die Preisaktivität wirklich wichtig ist.
In seinem Buch „Long-Term Secrets to Short-Term Trading“ (Langfristige Geheimnisse des kurzfristigen Handels) erklärt Larry Williams, dass sich der Preis bei einer plötzlichen Ausweitung der Volatilität ähnlich wie ein einmal in Bewegung gesetztes Objekt verhält. Er tendiert dazu, sich in diese Richtung zu bewegen. Die Schwierigkeit für viele Händler besteht nicht darin, das Konzept zu verstehen, sondern es konsequent und ohne Emotionen, Zögern oder verpasste Chancen anzuwenden. Die Volatilität richtig zu messen, im richtigen Moment zu reagieren und das Risiko diszipliniert zu managen, ist keine einfache Aufgabe, die man Tag für Tag manuell erledigen muss.
In diesem Artikel untersuchen wir eine praktische Möglichkeit, das Konzept von Larry Williams Volatilitätsausbruch mit MQL5 zu automatisieren. Das Ziel ist einfach: eine überzeugende Handelsidee in einen wiederholbaren und objektiven Prozess umzuwandeln, der getestet, verfeinert und als zuverlässig angesehen werden kann. Auf diese Weise beseitigen wir das Rätselraten, reduzieren die emotionale Beeinflussung und ermöglichen es der Strategie, ihren Vorteil im Laufe der Zeit und nicht Trade für Trade zum Ausdruck zu bringen.
Das Konzept des Volatilitätsausbruchs verstehen
In der Welt des kurzfristigen Handels betont Larry Williams die Macht der Volatilitätsausbrüche. Im Mittelpunkt dieses Konzepts steht die Idee, dass ein Markt, der an einem einzigen Tag eine große Schwankungsbreite aufweist, oft den Beginn eines neuen Trends signalisiert. Dieser Abschnitt befasst sich mit den Grundlagen der Messung dieser Volatilität und damit, wie sie unsere Handelsstrategie beeinflusst.
Messung der Spannweite von gestern
Zunächst betrachten wir die Spannweite (range) des Vortages, die einfach die Differenz zwischen dem Höchst- und dem Tiefstkurs des vorangegangenen Handelstages ist.

Diese Spannweite dient als Richtwert für die Identifizierung potenzieller Ausbrüche.
Warum die Spannweite des Vortages wichtig ist
Die Spannweite des Vortages gibt uns einen Anhaltspunkt. Wenn der heutige Kurs einen bestimmten Prozentsatz der gestrigen Spannweite übersteigt, deutet dies darauf hin, dass sich der Markt wahrscheinlich weiter in diese Richtung bewegen wird.
Wie Ausbruchsniveaus von der heutigen Eröffnung abgeleitet werden
Sobald wir die Spannweite des Vortages haben, addieren oder subtrahieren wir einen Prozentsatz dieser Spannweite vom Eröffnungskurs des aktuellen Tages. Daraus ergeben sich unsere Einstiegsniveaus für Kauf und Verkauf. Genau genommen sagen wir den Markt nicht voraus, sondern wir reagieren auf die steigende Volatilität.
Das grundlegende Konzept besteht darin, dass wir nach signifikanten Preisausweitungen Ausschau halten und nicht versuchen, genaue Höchst- oder Tiefststände zu erraten. Dieser Ansatz hilft Händlern, sich an der Marktdynamik zu orientieren und profitable Bewegungen zu nutzen.
In den folgenden Abschnitten werden wir die Einstiegs- und Ausstiegsmodelle, einschließlich der Stop-Loss- und Take-Profit-Niveaus, näher beleuchten, um Ihnen ein umfassendes Verständnis für die effektive Anwendung dieser Strategie zu vermitteln.
Handelsregeln
In dieser Phase kommen wir von der Theorie zu etwas Umsetzbarem. Alles, was bisher besprochen wurde, lässt sich nun in eine kleine Reihe präziser und wiederholbarer Handelsregeln umsetzen. Diese Regeln beruhen nicht auf Vorhersagen. Sie beruhen auf der Reaktion auf die Ausweitung der Volatilität, genau wie von Larry Williams beabsichtigt. Der erste Schritt ist immer derselbe. Zu Beginn eines neuen Handelstages messen wir die Spannweite des gestrigen Tages. Diese Spannweite spiegelt die jüngsten Marktaktivitäten und die Volatilität wider. Sie zeigt uns, wie weit der Preis in der vorangegangenen Sitzung bereit war zu steigen.
Sobald die Spannweite bekannt ist, wird der heutige Eröffnungskurs zu unserem Referenzpunkt. Ausgehend von diesem Eröffnungskurs prognostizieren wir zwei Niveaus. Eine oberhalb der Eröffnung für einen potenziellen Kauf, und eine unterhalb der Eröffnung für einen potenziellen Verkauf. Jede Stufe wird durch Anwendung eines nutzerdefinierten Prozentsatzes des gestrigen Bereichs berechnet. Diese voraussichtlichen Niveaus dienen als Volatilitätsgrenzen. Der Preis muss so weit steigen, dass er diese Werte erreicht, bevor ein Handel zulässig ist. 
Ein Handelsgeschäft wird nur dann getätigt, wenn der Kurs eines dieser Niveaus erreicht. Es gibt keine Vorwegnahme und keine frühe Eröffnung. Wenn der Kurs dieses Niveau im Laufe des Tages nicht erreicht, wird kein Handel getätigt und die Konstellation wird verworfen. Der nächste Handelstag beginnt mit einer neuen Berechnung und neuen Werten.
Sobald ein Eintrag ausgelöst wird, wird das Risiko sofort definiert. Der Stop-Loss wird in einem festen Abstand zum Einstiegskurs platziert, der als Prozentsatz der gestrigen Spannweite berechnet wird. Dadurch wird das Risiko an das aktuelle Marktverhalten angepasst und nicht an willkürliche Punktwerte. In volatileren Märkten werden die Stopps natürlich ausgeweitet. Auf ruhigeren Märkten schrumpfen sie.
Die Höhe der Gewinnmitnahme wird dann anhand eines Risiko-Ertrags-Modells ermittelt. Der Abstand zwischen dem Einstiegskurs und dem Stop-Loss definiert das Risiko. Ein nutzerdefinierter Ertragswert legt fest, um wie viel größer das Gewinnziel im Verhältnis zu diesem Risiko sein sollte. Dadurch wird sichergestellt, dass jeder Handel eine angemessene und bewusste Realisationsstruktur hat.
Es kann jeweils nur eine Position existieren. Diese Entscheidung spiegelt die Idee wider, dass Volatilitätsausbrüche richtungsweisende Ereignisse sind. Wenn sich der Markt für eine Seite entscheidet, wird es auch das System tun. Es gibt keine Stapelung von Positionen und kein Hedging.
Das Wesentliche dieser Regeln ist einfach – das Messen der Volatilität. Wir warten auf die Erweiterung. Das Risiko definieren wir anhand der gleichen Volatilitätsquelle. Wir lassen den Preis entscheiden, ob ein Handel gültig ist. Diese Einfachheit macht die Strategie für die Automatisierung geeignet und robust gegenüber verschiedenen Märkten.
Kodierung der Volatilitätsausbruchsstrategie
Bevor wir mit dem Schreiben der Logik beginnen, ist es wichtig, sicherzustellen, dass Sie gut vorbereitet sind, um dem Entwicklungsprozess folgen zu können. In diesem Abschnitt geht es um die Umsetzung, nicht um die Theorie, daher sind einige Voraussetzungen erforderlich.
Um diesen Teil des Artikels bequem durcharbeiten zu können, sollten Sie über Grundkenntnisse von MQL5 wie Variablen, Steueranweisungen, Datenstrukturen und allgemeine Programmierkonzepte verfügen. Sie sollten auch mit MetaTrader 5 vertraut sein und wissen, wie Sie einen Expert Advisor an ein Chart anhängen und den Strategy Tester verwenden. Schließlich sollten Sie wissen, wie Sie den MetaEditor 5 verwenden, einschließlich der Erstellung von Quelldateien, dem Schreiben von Code, dem Kompilieren, der Fehlerprüfung und der Durchführung von grundlegenden Fehlersuchen.
Sollten Sie mit einem dieser Bereiche nicht vertraut sein, wird die offizielle MQL5-Referenz dringend empfohlen. Es handelt sich um eine umfassende und gut gepflegte Dokumentation, die die Sprache, die Handelsumgebung und die APIs der Plattform im Detail behandelt.
In diesem Artikel werden wir den Expert Advisor Schritt für Schritt entwickeln. Der Einfachheit halber wird der gesamte Quellcode, auf den wir aufbauen, in einer einzigen MQL5-Datei namens lwVolatilityBreakoutExpert.mq5 bereitgestellt. Wir empfehlen Ihnen, mitzukodieren, damit Sie die Logik später leichter verstehen und ändern können.
An dieser Stelle sollten wir uns die Hände schmutzig machen. Öffnen Sie MetaEditor 5, erstellen Sie einen neuen Expert Advisor, wählen Sie eine leere Vorlage, geben Sie ihr einen Namen Ihrer Wahl und fügen Sie den mitgelieferten Quellcode ein.
//+------------------------------------------------------------------+ //| lwVolatilityBreakoutExpert.mq5 | //| Copyright 2026, MetaQuotes Ltd. Developer is Chacha Ian | //| https://www.mql5.com/de/users/chachaian | //+------------------------------------------------------------------+ #property copyright "Copyright 2026, MetaQuotes Ltd. Developer is Chacha Ian" #property link "https://www.mql5.com/de/users/chachaian" #property version "1.00" //+------------------------------------------------------------------+ //| Standard Libraries | //+------------------------------------------------------------------+ #include <Trade\Trade.mqh> //--- CUSTOM ENUMERATIONS enum ENUM_TRADE_DIRECTION { ONLY_LONG, ONLY_SHORT, TRADE_BOTH }; enum ENUM_LOT_SIZE_INPUT_MODE { MODE_MANUAL, MODE_AUTO }; //+------------------------------------------------------------------+ //| User input variables | //+------------------------------------------------------------------+ input group "Information" input ulong magicNumber = 254700680002; input ENUM_TIMEFRAMES timeframe = PERIOD_CURRENT; input group "Volatility Breakout Parameters" input double inpBuyRangeMultiplier = 0.50; input double inpSellRangeMultiplier = 0.50; input double inpStopRangeMultiplier = 0.50; input double inpRewardValue = 4.0; input group "Trade and Risk Management" input ENUM_TRADE_DIRECTION direction = TRADE_BOTH; input ENUM_LOT_SIZE_INPUT_MODE lotSizeMode = MODE_AUTO; input double riskPerTradePercent = 1.0; input double positionSize = 0.1; //+------------------------------------------------------------------+ //| 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) { } //--- UTILITY FUNCTIONS //+------------------------------------------------------------------+
Diese Datei dient als Grundgerüst, auf dem die gesamte Strategie aufgebaut wird.
Verstehen der Struktur der Vorlage
Die Quelldatei ist bereits in logische Abschnitte unterteilt, die jeweils einem bestimmten Zweck im Lebenszyklus eines Expert Advisors dienen.
Der Kopfbereich enthält Metadaten wie den Dateinamen, Informationen zum Autor, die Versionsnummer und Links.
//+------------------------------------------------------------------+ //| lwVolatilityBreakoutExpert.mq5 | //| Copyright 2026, MetaQuotes Ltd. Developer is Chacha Ian | //| https://www.mql5.com/de/users/chachaian | //+------------------------------------------------------------------+ #property copyright "Copyright 2026, MetaQuotes Ltd. Developer is Chacha Ian" #property link "https://www.mql5.com/de/users/chachaian" #property version "1.00"
Dies hat zwar keinen Einfluss auf das Handelsverhalten, ist aber eine gute Praxis, insbesondere bei der gemeinsamen Nutzung oder Veröffentlichung von Code.
Der Abschnitt Standardbibliotheken enthält die Bibliothek Trade.mqh.
//+------------------------------------------------------------------+ //| Standard Libraries | //+------------------------------------------------------------------+ #include <Trade\Trade.mqh>
Dadurch erhalten wir Zugang zur CTrade-Klasse, die die Auftragsausführung und das Handelsmanagement erheblich vereinfacht. Die Verwendung von Standardbibliotheksklassen wird empfohlen, da diese von MetaQuotes optimiert und gepflegt werden.
Der Abschnitt für nutzerdefinierte Enumerationen definiert kontrollierte Eingabemöglichkeiten.
//--- CUSTOM ENUMERATIONS enum ENUM_TRADE_DIRECTION { ONLY_LONG, ONLY_SHORT, TRADE_BOTH }; enum ENUM_LOT_SIZE_INPUT_MODE { MODE_MANUAL, MODE_AUTO };
Zum Beispiel ist die Handelsrichtung auf Kaufen, Verkaufen oder beides beschränkt. In ähnlicher Weise ermöglicht der Losgrößenmodus das Umschalten zwischen manueller Positionsgrößenbestimmung und automatischer risikobasierter Größenbestimmung. Enumerationen machen Nutzereingaben sicherer und präziser.
Nutzereingabeparameter und ihre Rolle
Die Eingabevariablen sind aus Gründen der Übersichtlichkeit und Nutzerfreundlichkeit im Einstellungsfenster des Expert Advisors gruppiert.
Die Gruppe Informationen enthält die magische Zahl und den Zeitrahmen.
//+------------------------------------------------------------------+ //| User input variables | //+------------------------------------------------------------------+ input group "Information" input ulong magicNumber = 254700680002; input ENUM_TIMEFRAMES timeframe = PERIOD_CURRENT;
Die magische Zahl identifiziert die von diesem EA eröffneten Handelsgeschäfte eindeutig, was für die programmatische Verwaltung von Positionen unerlässlich ist. Der eingegebene Zeitrahmen bestimmt, welche Chartdaten zur Messung der Volatilität verwendet werden. Dies knüpft direkt an die Arbeit von Larry Williams an, bei der die Spannweite des Vortages im Mittelpunkt der Strategie steht.
Die Parametergruppe des Volatilitätsausbruchs enthält die wichtigsten Strategieeinstellungen.
input group "Volatility Breakout Parameters" input double inpBuyRangeMultiplier = 0.50; input double inpSellRangeMultiplier = 0.50; input double inpStopRangeMultiplier = 0.50; input double inpRewardValue = 4.0;
Die Multiplikatoren für die Kauf- und Verkaufsspanne legen fest, wie weit sich der Kurs von der heutigen Eröffnung im Verhältnis zur gestrigen Spannweite entfernen muss, bevor ein Handel ausgelöst wird. Diese Werte werden als Bruchteile der Spannweite des Vortages ausgedrückt. Dies spiegelt das Konzept von Larry Williams wider, nur dann einzusteigen, wenn es zu einer bedeutenden Erweiterung kommt und nicht zu einer zufälligen Preisbewegung.
Der Stop-Range-Multiplikator steuert, wie der Stop-Loss-Abstand von der gleichen Volatilitätsmessung abgeleitet wird. Da sich die Stopps an der Volatilität und nicht an festen Punkten orientieren, passt sich die Strategie auf natürliche Weise an sich ändernde Marktbedingungen an.
RewardValue definiert das Verhältnis zwischen Risiko und Ertrag. Nach dem Ansatz von Larry Williams sind die Ausgänge nicht willkürlich. Sie sind so konzipiert, dass erfolgreiche Volatilitätsausweitungen die Kosten für mehrere fehlgeschlagene Versuche decken.
Die Gruppe des Handels- und Risikomanagements legt fest, wie der Handel kontrolliert und bemessen wird.
input group "Trade and Risk Management" input ENUM_TRADE_DIRECTION direction = TRADE_BOTH; input ENUM_LOT_SIZE_INPUT_MODE lotSizeMode = MODE_AUTO; input double riskPerTradePercent = 1.0; input double positionSize = 0.1;
Mit der Eingabe der Handelsrichtung können Sie die Strategie auf steigende, fallende oder beide Marktbedingungen beschränken. Dies ist nützlich, wenn der EA auf eine breitere Marktausrichtung oder einen höheren Zeitrahmen ausgerichtet werden soll.
Der Losgrößenmodus bestimmt, ob die Positionsgröße manuell festgelegt oder automatisch auf der Grundlage eines vordefinierten Risikos berechnet wird. Bei einer automatischen Losgröße bestimmt der Prozentsatz des Risikos pro Handel den Prozentsatz des Kontosaldos, der bei jedem Handel riskiert wird. Dies unterstreicht einen der wichtigsten Grundsätze in Larry Williams' Arbeit: Überleben durch disziplinierte Risikokontrolle. Die manuelle Eingabe der Positionsgröße wird nur verwendet, wenn die automatische Größenanpassung deaktiviert ist.
Jeder dieser Inputs wird später bei der Berechnung von Volatilitätsniveaus, Einstiegskursen, Stop-Losses und Take-Profit-Zielen verwendet.
Globale Variablen und Kernfunktionen
Der Abschnitt „Globale Variablen“ initialisiert Objekte und gemeinsame Daten, die im gesamten EA verwendet werden. Das CTrade-Objekt wickelt alle Handelsoperationen ab. Geld- und Briefkurse werden global gespeichert, um einen effizienten Zugriff während der Ausführung zu ermöglichen.
//+------------------------------------------------------------------+ //| Global Variables | //+------------------------------------------------------------------+ //--- Create a CTrade object to handle trading operations CTrade Trade; //--- Bid and Ask double askPrice; double bidPrice;
Die Funktion OnInit wird einmal ausgeführt, wenn der EA geladen wird. Hier vergeben wir die magische Zahl, damit alle Handelsgeschäfte korrekt gekennzeichnet werden.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(){ //--- Assign a unique magic number to identify trades opened by this EA Trade.SetExpertMagicNumber(magicNumber); return(INIT_SUCCEEDED); }
Die Funktion OnDeinit wird ausgeführt, wenn der EA entfernt oder die Plattform heruntergefahren wird. Die Protokollierung des Beendigungsgrundes ist beim Testen und Debuggen hilfreich.
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason){ //--- Notify why the program stopped running Print("Program terminated! Reason code: ", reason); }
Mit der Funktion OnTick reagiert der EA auf eingehende Kursdaten. In diesem Stadium werden lediglich die aktuellen Geld- und Briefkurse abgefragt. Später wird diese Funktion das Herzstück der Strategie sein, wo die Volatilitätsniveaus berechnet und die Handelsbedingungen bewertet werden.
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick(){ //--- Retrieve current market prices for trade execution askPrice = SymbolInfoDouble (_Symbol, SYMBOL_ASK); bidPrice = SymbolInfoDouble (_Symbol, SYMBOL_BID); }
Die Funktion OnTradeTransaction ist für die Bearbeitung von handelsbezogenen Ereignissen reserviert.
//+------------------------------------------------------------------+ //| TradeTransaction function | //+------------------------------------------------------------------+ void OnTradeTransaction(const MqlTradeTransaction& trans, const MqlTradeRequest& request, const MqlTradeResult& result) { }
Sie ist zwar im Moment noch leer, wird aber später für die Überwachung von Ausführungen, Abschlüssen und potenzieller Handelsverwaltungslogik hilfreich sein.
Im Abschnitt Utility Functions schließlich werden wir schrittweise nutzerdefinierte Hilfsfunktionen hinzufügen.
//--- UTILITY FUNCTIONS //+------------------------------------------------------------------+
Hier werden die Volatilitätsberechnungen, die Logik für die Positionsgrößenbestimmung und die wiederverwendbaren Komponenten untergebracht. Die Trennung dieser Funktionen verbessert die Lesbarkeit, das Testen und die langfristige Wartung.
Neuberechnung der täglichen Volatilitätsniveaus bei einem neuen Balken
Wie bereits erwähnt, beruht die Volatilitäts-Breakout-Methode auf den zu Beginn eines jeden Handelstages neu berechneten Kursen. Diese Niveaus bleiben den ganzen Tag über bestehen und dienen als Richtschnur für jede Entscheidung bezüglich des Handelseinstiegs, der Platzierung des Stop-Loss und der Gewinnziele. Sobald ein neuer Tag beginnt, werden die alten Werte verworfen und ein neuer Satz wird anhand des letzten abgeschlossenen Balkens berechnet.
Für diese Strategie berechnen wir sieben wichtige Preise. Der erste ist die gestrige Spannweite, die die Differenz zwischen dem Höchst- und dem Tiefstwert des vorherigen Balkens darstellt. Aus dieser Spannweite leiten wir die Eröffnungskurse für Kauf und Verkauf ab. Anschließend berechnen wir die entsprechenden Stop-Loss-Niveaus für beide Richtungen. Schließlich berechnen wir die Take-Profit-Niveaus anhand eines vordefinierten Ertrags-Faktors. Da diese Werte nur einmal pro Tag neu berechnet werden müssen, benötigen wir eine zuverlässige Methode, um zu erkennen, wann sich ein neuer Balken innerhalb des ausgewählten Zeitrahmens gebildet hat.
Erkennen einer neuen Balkenbildung
In MQL5 bietet das Terminal kein direktes Ereignis, das die Eröffnung eines neuen Balkens signalisiert. Stattdessen erkennen wir diese Bedingung manuell, indem wir die Eröffnungszeit des aktuellen Balkens mit der des zuvor verarbeiteten Balkens vergleichen. Um dies zu erreichen, definieren wir eine kleine Hilfsfunktion namens IsNewBar. Diese Funktion ist so konzipiert, dass sie bei jedem Tick ausgeführt wird, aber nur einmal pro Balken true zurückgibt.
//--- 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; }
Die Funktion ermittelt die Öffnungszeit des letzten Balkens mithilfe der Funktion iTime. Anschließend wird dieser Wert mit einem gespeicherten Zeitstempel verglichen, der den letzten verarbeiteten Balken darstellt. Wenn sich die Uhrzeit geändert hat, hat sich ein neuer Balken gebildet. Die Funktion aktualisiert den gespeicherten Zeitstempel und signalisiert diese Änderung, indem sie true zurückgibt.
Der dritte Parameter dieser Funktion wird als Referenz übergeben. Dies ist wichtig, da es der Funktion ermöglicht, die gespeicherte Balkenzeit direkt zu aktualisieren und sicherzustellen, dass die Änderung über Ticks hinweg bestehen bleibt. Um diese Logik zu unterstützen, definieren wir eine globale Datumsvariable namens lastBarOpenTime.
//--- To help track new bar open datetime lastBarOpenTime;
Diese Variable erfasst die Eröffnungszeit des zuletzt verarbeiteten Balkens und dient als Speicher, um Neuberechnungen am selben Tag zu verhindern.
Bei der Initialisierung des Experten wird diese Variable ausdrücklich auf Null gesetzt.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(){ ... //--- Initialize global variables lastBarOpenTime = 0; return(INIT_SUCCEEDED); }
Die Initialisierung sorgt für ein vorhersehbares Verhalten beim Start des Expertenberaters und verhindert die versehentliche Wiederverwendung alter Werte.
Tägliche Volatilitätsniveaus im Speicher ablegen
Da die berechneten Werte während des gesamten Handelstages wiederverwendet werden müssen, speichern wir sie in einem strukturierten Container, anstatt sie immer wieder neu zu berechnen. Zu diesem Zweck definieren wir eine nutzerdefinierte Struktur namens MqlLwVolatilityLevels. Diese Struktur fasst alle volatilitätsbezogenen Preisniveaus zu einer einzigen logischen Einheit zusammen. Sie enthält Felder für die gestrige Spannweite, beide Einstiegskurse, beide Stop-Loss-Niveaus und beide Take-Profit-Niveaus.
//--- Holds all price levels derived from Larry Williams' volatility breakout calculations struct MqlLwVolatilityLevels { double yesterdayRange; double buyEntryPrice; double sellEntryPrice; double bullishStopLoss; double bearishStopLoss; double bullishTakeProfit; double bearishTakeProfit; }; MqlLwVolatilityLevels lwVolatilityLevels;
Nach der Definition der Struktur erstellen wir eine einzige globale Instanz namens lwVolatilityLevels. Diese Instanz speichert die aktiven Tageswerte und macht sie im gesamten Expert Advisor leicht zugänglich.
Während der Initialisierung setzen wir alle Felder dieser Struktur mit der Funktion ZeroMemory auf Null.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(){ ... //--- Reset Larry Williams' volatility levels ZeroMemory(lwVolatilityLevels); return(INIT_SUCCEEDED); }
Dieser Schritt löscht alle Restdaten und stellt sicher, dass jedes Feld mit einem bekannten Wert beginnt. Diese Praxis hilft, subtile Fehler zu vermeiden, die durch nicht initialisierten Speicher verursacht werden.
Berechnen der gestrigen Spannweite
Die Grundlage der Strategie ist die Spannweite (range) der Preise von gestern. Um sie zu berechnen, definieren wir eine Hilfsfunktion namens GetBarRange.
//+------------------------------------------------------------------+ //| Returns the price range (high - low) of a bar at the given index | //+------------------------------------------------------------------+ double GetBarRange(const string symbol, ENUM_TIMEFRAMES tf, int index){ double high = iHigh(symbol, tf, index); double low = iLow (symbol, tf, index); if(high == 0.0 || low == 0.0){ return 0.0; } return NormalizeDouble(high - low, Digits()); }
Diese Funktion ermittelt die Höchst- und Tiefstpreise eines Balkens bei einem bestimmten Index unter Verwendung von iHigh und iLow. Für den gestrigen Bereich wird ein Index von 1 übergeben, der sich auf den letzten abgeschlossenen Balken bezieht. Wenn entweder der Höchst- oder der Tiefstpreis nicht verfügbar ist, gibt die Funktion sicher Null zurück. Andernfalls wird die Spannweite durch Subtraktion des Tiefstwerts vom Höchstwert berechnet und das Ergebnis auf die Preisgenauigkeit des Symbols normiert. Dieser Wert stellt die Marktexpansion vom Vortag dar und dient als Messlatte für alle Ausbruchsniveaus.
Berechnung von Ausbruchskursen
Anhand der verfügbaren Spannweite berechnen wir die Einstiegskurse für den Ausbruch. Der Einstiegskurs für die Käufe wird ermittelt, indem ein Bruchteil der gestrigen Kurssspannweite zum heutigen Eröffnungskurs addiert wird. Diese Logik ist in der Funktion CalculateBuyEntryPrice implementiert.
//+------------------------------------------------------------------+ //| Calculates the bullish breakout entry price using today's open and yesterday's range | //+------------------------------------------------------------------+ double CalculateBuyEntryPrice(double todayOpen, double yesterdayRange, double buyMultiplier){ return todayOpen + (yesterdayRange * buyMultiplier); }
Mit dem Multiplikator kann der Händler steuern, wie aggressiv oder konservativ das Ausbruchsniveau sein soll.
In ähnlicher Weise wird der Einstiegskurs eines Verlaufs berechnet, indem ein Bruchteil der gestrigen Spannweite vom heutigen Eröffnungskurs abgezogen wird. Diese Logik wird von der Funktion CalculateSellEntryPrice übernommen.
//+------------------------------------------------------------------+ //| Calculates the bearish breakout entry price using today's open and yesterday's range | //+------------------------------------------------------------------+ double CalculateSellEntryPrice(double todayOpen, double yesterdayRange, double sellMultiplier){ return todayOpen - (yesterdayRange * sellMultiplier); }
Zusammen definieren diese beiden Preise die Punkte, an denen der Markt seine Stärke oder Schwäche beweisen muss, bevor ein Handel in Betracht gezogen wird.
Berechnung von Stop-Loss-Niveaus
Die Risikokontrolle steht im Mittelpunkt der Methodik von Larry Williams. Die Stop-Loss-Niveaus werden relativ zum Einstiegskurs unter Verwendung des gleichen Volatilitätsmaßes festgelegt.
Bei Käufen wird der Stop-Loss um einen bestimmten Bruchteil der gestrigen Kursspannweite unter den Einstiegskurs gesetzt. Diese Berechnung wird von der Funktion CalculateBullishStopLoss durchgeführt.
//+------------------------------------------------------------------+ //| Calculates the stop-loss price for a bullish position based on entry price and yesterday's range | //+------------------------------------------------------------------+ double CalculateBullishStopLoss(double entryPrice, double yesterdayRange, double stopMultiplier){ return entryPrice - (yesterdayRange * stopMultiplier); }
Bei Verkäufen wird der Stop-Loss nach der gleichen Logik, die in der Funktion CalculateBearishStopLoss implementiert ist, über dem Einstiegskurs platziert.
//+------------------------------------------------------------------+ //| Calculates the stop-loss price for a bearish position based on entry price and yesterday's range | //+------------------------------------------------------------------+ double CalculateBearishStopLoss(double entryPrice, double yesterdayRange, double stopMultiplier){ return entryPrice + (yesterdayRange * stopMultiplier); }
Die Verwendung von volatilitätsbasierten Stopps stellt sicher, dass sich das Risiko an die sich ändernden Marktbedingungen anpasst und nicht starr bleibt.
Berechnung von Gewinnmitnahme-Niveaus
Take-Profit-Niveaus werden auf der Grundlage eines Risiko-Ertrags-Verhältnisses und nicht eines willkürlichen Kursziels berechnet. Bei Käufen bestimmt der Abstand zwischen dem Einstiegskurs und dem Stop-Loss das Risiko. Dieser Abstand wird mit einem Ertragsfaktor multipliziert, um das Gewinnziel zu bestimmen. Die Funktion CalculateBullishTakeProfit wendet diese Logik an und platziert den Take-Profit oberhalb des Einstiegskurses.
//+------------------------------------------------------------------+ //| Calculates take-profit level for a bullish trade using risk-reward logic | //+------------------------------------------------------------------+ double CalculateBullishTakeProfit(double entryPrice, double stopLossPrice, double rewardValue){ double stopDistance = entryPrice - stopLossPrice; double rewardDistance = stopDistance * rewardValue; return NormalizeDouble(entryPrice + rewardDistance, Digits()); }
Für Verkäufe gilt die gleiche Logik in umgekehrter Form. Die Funktion CalculateBearishTakeProfit berechnet die Ertrags-Distanz und subtrahiert sie vom Einstiegskurs.
//+------------------------------------------------------------------+ //| Calculates take-profit level for a bearish trade using risk-reward logic | //+------------------------------------------------------------------+ double CalculateBearishTakeProfit(double entryPrice, double stopLossPrice, double rewardValue){ double stopDistance = stopLossPrice - entryPrice; double rewardDistance = stopDistance * rewardValue; return NormalizeDouble(entryPrice - rewardDistance, Digits()); }
Dieser Ansatz sorgt dafür, dass die Erträge proportional zum Risiko sind, und das entspricht den Grundsätzen eines disziplinierten Handelsmanagements.
Alles in einem neuen Balken vereinen
Sobald alle unterstützenden Funktionen vorhanden sind, vereinen wir sie in der Funktion OnTick. Sobald neue Kursdaten auf dem Terminal eintreffen, aktualisiert der Expert Advisor zunächst die aktuellen Geld- und Briefkurse. Anschließend wird mit der Funktion IsNewBar geprüft, ob sich ein neuer Balken gebildet hat.
Wenn ein neuer Balken erkannt wird, berechnet der Experte alle Volatilitätswerte in einer klaren und logischen Reihenfolge neu.
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick(){ ... //--- Run this block only when a new bar is detected on the selected timeframe if(IsNewBar(_Symbol, timeframe, lastBarOpenTime)){ lwVolatilityLevels.yesterdayRange = GetBarRange(_Symbol, timeframe, 1); lwVolatilityLevels.buyEntryPrice = CalculateBuyEntryPrice (askPrice, lwVolatilityLevels.yesterdayRange, inpBuyRangeMultiplier ); lwVolatilityLevels.sellEntryPrice = CalculateSellEntryPrice(bidPrice, lwVolatilityLevels.yesterdayRange, inpSellRangeMultiplier); lwVolatilityLevels.bullishStopLoss = CalculateBullishStopLoss(lwVolatilityLevels.buyEntryPrice, lwVolatilityLevels.yesterdayRange, inpStopRangeMultiplier); lwVolatilityLevels.bearishStopLoss = CalculateBearishStopLoss(lwVolatilityLevels.sellEntryPrice, lwVolatilityLevels.yesterdayRange, inpStopRangeMultiplier); lwVolatilityLevels.bullishTakeProfit = CalculateBullishTakeProfit(lwVolatilityLevels.buyEntryPrice, lwVolatilityLevels.bullishStopLoss, inpRewardValue); lwVolatilityLevels.bearishTakeProfit = CalculateBearishTakeProfit(lwVolatilityLevels.sellEntryPrice, lwVolatilityLevels.bearishStopLoss, inpRewardValue); } }
Zuerst wird der Bereich von gestern berechnet. Diese Spannweite wird dann zur Berechnung von Einstiegskursen verwendet, gefolgt von Stop-Loss-Niveaus und schließlich Take-Profit-Niveaus. Jeder berechnete Wert wird in der Struktur lwVolatilityLevels gespeichert. Von diesem Zeitpunkt an bleiben diese Werte den ganzen Tag über konstant und können von der Handelsausführungslogik effizient referenziert werden.
Dadurch wird sichergestellt, dass die Volatilitätswerte einmal pro Tag berechnet werden, über alle Ticks hinweg konsistent bleiben und die Kernprinzipien des Volatilitäts-Breakout-Ansatzes von Larry Williams widerspiegeln.
Im nächsten Abschnitt werden wir damit beginnen, diese gespeicherten Ebenen zu verwenden, um die Handelsausführung und das Positionsmanagement auf strukturierte und disziplinierte Weise zu steuern.
Vervollständigen der Handelslogik und Ausführen von Handelsgeschäften
In diesem Stadium der Entwicklung weiß der Expert Advisor bereits, was und wo er handeln soll. Die von der gestrigen Spannweite abgeleiteten Volatilitätsniveaus werden einmal pro Tag berechnet und gespeichert und bleiben gültig, bis sich ein neuer Balken bildet. Was bleibt, ist zu definieren, wie der EA reagiert, wenn der Preis mit diesen Niveaus interagiert.
Die Volatilitätsausbruchslogik von Larry Williams ist einfach in der Ausführung. Sobald der Preis über ein vordefiniertes Niveau hinausgeht, signalisiert der Markt seine Absicht. Wir sagen nicht die Richtung voraus. Wir reagieren auf die Expansion. Das bedeutet, dass unser EA erst dann aktiv wird, wenn der Kurs entweder das Eröffnungsniveau für Kauf oder Verkauf deutlich durchbrochen hat. Um dies zuverlässig durchführen zu können, müssen wir dem EA zunächst beibringen, eine Preisüberschreitung zu erkennen.
Erkennen eines Kreuzens
Die erste Nutzenfunktion, die wir einführen, erkennt, wenn der Preis ein bestimmtes Niveau von unten nach oben überschreitet. Dies ist der Auslöser für einen potenziellen Kauf.
//+------------------------------------------------------------------+ //| To detect a crossover at a given price level | //+------------------------------------------------------------------+ bool IsCrossOver(const double price, const double &closePriceMinsData[]){ if(closePriceMinsData[1] <= price && closePriceMinsData[0] > price){ return true; } return false; }
Die Logik vergleicht zwei aufeinanderfolgende Schlusskurse aus einem niedrigeren Zeitrahmen. Der vorherige Schlusskurs muss unter oder gleich dem Niveau liegen, während der letzte Schlusskurs darüber liegen muss. Wenn diese Bedingung erfüllt ist, hat der Preis aufwärts gekreuzt. Mit dieser Methode wird vermieden, dass der Preis einfach nur durch das Erreichen eines bestimmten Niveaus beeinflusst wird. Stattdessen wird bestätigt, dass der Kurs diese Grenze entscheidend überschritten hat. In praktischer Hinsicht entspricht dies der Idee von Larry Williams, dass Expansion wichtig ist. Ein echter Ausbruch ist keine Berührung. Das ist Bewegung.
Erkennen einer Abwärtskreuzens
Die zweite Nutzenfunktion erfüllt die entgegengesetzte Aufgabe. Er erkennt, wenn der Preis unter ein vordefiniertes Niveau fällt.
//+------------------------------------------------------------------+ //| To detect a crossunder at a given price level | //+------------------------------------------------------------------+ bool IsCrossUnder(const double price, const double &closePriceMinsData[]){ if(closePriceMinsData[1] >= price && closePriceMinsData[0] < price){ return true; } return false; }
In diesem Fall muss der vorherige Schlusskurs über oder gleich dem Niveau liegen, während der letzte Schlusskurs unter dem Niveau liegen muss. Dies bestätigt die Abwärtsbewegung und ist der Auslöser für einen Verkauf.
Zusammen bilden diese beiden Funktionen das Rückgrat unserer Logik zur Erkennung von Eröffnungen. Beide Funktionen für das Kreuzen basieren auf einer Reihe von einminütigen Schlusskursen. In diesem Array muss Index Null immer der des aktuellsten Balkens sein.
Um dies zu ermöglichen, wird das Array im globalen Bereich deklariert, damit im gesamten EA darauf zugegriffen werden kann.
//--- To store minutes data double closePriceMinutesData [];
Bei der Initialisierung des Experten wird es dediziert als Zeitreihe festgelegt.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(){ ... //--- Treat the following arrays as timeseries (index 0 becomes the most recent bar) ArraySetAsSeries(closePriceMinutesData, true); return(INIT_SUCCEEDED); }
Dadurch wird sichergestellt, dass Index Null immer der der neuesten Daten ist, Index Eins der des vorherigen Balkens usw. Diese Designentscheidung ermöglicht es dem EA, schnell und präzise auf Intraday-Kursbewegungen zu reagieren, auch wenn die Haupthandelslogik auf höheren Zeitrahmen basiert.
Innerhalb der Tick-Funktion wird das Array kontinuierlich anhand einer kleinen Menge historischer Daten aktualisiert. Wir brauchen nur die letzten Balken, um ein Kreuzen zu erkennen, aber das Kopieren einiger zusätzlicher Balken sorgt für Stabilität und verhindert Fehler in Grenzfällen.
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick(){ ... //--- Get some minutes data if(CopyClose(_Symbol, PERIOD_M1, 0, 7, closePriceMinutesData) == -1){ Print("Error while copying minutes datas ", GetLastError()); return; } }
Wenn keine Preisdaten abgerufen werden können, stoppt der EA die weitere Verarbeitung für diesen Tick. Dadurch wird verhindert, dass die Handelslogik auf unvollständige oder ungültige Daten reagiert.
Verhindern von mehreren gleichzeitigen Handelsgeschäften
Das Volatilitätsausbruchsmodell von Larry Williams geht von einer einseitigen Tendenz aus. Sobald ein Ausbruch erfolgt, hat der Händler entweder gekauft oder verkauft, aber nicht beides. Um diese Regel programmatisch durchzusetzen, muss der EA immer wissen, ob er bereits eine offene Position hat.
Zwei Hilfsfunktionen übernehmen diese Aufgabe. Die erste scannt alle offenen Positionen und prüft, ob es eine aktive Kaufposition gibt, die von diesem EA eröffnet wurde.
//+------------------------------------------------------------------+ //| 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; }
Dies geschieht durch den Vergleich der magischen Zahl der Position und der Positionsart. Wenn eine passende Kaufposition gefunden wird, gibt die Funktion den Wert true zurück. Die zweite Funktion macht dasselbe für Verkaufspositionen.
//+------------------------------------------------------------------+ //| 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; }
Durch die Trennung von Kauf- und Verkaufsprüfungen lässt sich die Logik später problemlos erweitern, wenn zusätzliche Filter oder Regeln eingeführt werden.
Bevor ein neuer Handel eröffnet wird, stellt der EA sicher, dass aktuell keine Position aktiv ist. Damit ist gewährleistet, dass es zu jedem Zeitpunkt nur ein Handelsgeschäft gibt.
Automatische Berechnung der Positionsgröße
Das Risikomanagement ist ein zentraler Bestandteil der Arbeit von Larry Williams. Anstatt mit willkürlichen Losgrößen zu handeln, wird das Risiko als Prozentsatz des Kontostands definiert. Die Funktion zur Berechnung der Positionsgröße setzt dieses Konzept direkt um.
//+------------------------------------------------------------------+ //| Calculates position size based on a fixed percentage risk of the account balance | //+------------------------------------------------------------------+ double CalculatePositionSizeByRisk(double stopDistance){ double amountAtRisk = (riskPerTradePercent / 100.0) * AccountInfoDouble(ACCOUNT_BALANCE); double contractSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_CONTRACT_SIZE); double volume = amountAtRisk / (contractSize * stopDistance); return NormalizeDouble(volume, 2); }
Zunächst wird der Geldbetrag berechnet, den der Händler bereit ist zu riskieren, basierend auf dem Kontostand und dem konfigurierten Risikoprozentsatz. Anschließend wird dieses Risiko unter Berücksichtigung der Kontraktgröße des gehandelten Instruments und der Stop-Loss-Distanz in ein Volumen umgerechnet. Dadurch wird sichergestellt, dass bei jedem Handel ein gleichbleibender Teil des Kontos riskiert wird, unabhängig von der Marktvolatilität oder der Stop-Loss-Größe. Der endgültige Wert wird auf die entsprechende Genauigkeit normiert, um die Kompatibilität mit den Volumenanforderungen des Brokers zu gewährleisten.
Eröffnung einer Kaufposition
Die Funktion zur Ausführung von Käufen regelt alles, was zur Eröffnung eines Kaufs erforderlich ist.
//+------------------------------------------------------------------+ //| Function to open a market buy position | //+------------------------------------------------------------------+ bool OpenBuy(double entryPrice, double stopLoss, double takeProfit, double lotSize){ if(lotSizeMode == MODE_AUTO){ lotSize = CalculatePositionSizeByRisk(lwVolatilityLevels.buyEntryPrice - lwVolatilityLevels.bullishStopLoss); } if(!Trade.Buy(lotSize, _Symbol, entryPrice, stopLoss, takeProfit)){ Print("Error while executing a market buy order: ", GetLastError()); Print(Trade.ResultRetcode()); Print(Trade.ResultComment()); return false; } return true; }
Wenn die automatische Positionsgrößenbestimmung aktiviert ist, berechnet die Funktion die geeignete Losgröße anhand der zuvor definierten Risikologik. Der in dieser Berechnung verwendete Stop-Loss-Abstand wird direkt von den volatilitätsbasierten Werten abgeleitet, sodass das Risiko an die Marktbedingungen angepasst wird. Die Funktion übermittelt dann einen Marktkaufauftrag unter Verwendung des Handelsobjekts. Wenn die Ausführung fehlschlägt, werden detaillierte Fehlerinformationen ausgedruckt, um die Diagnose des Problems zu erleichtern. Wenn die Ausführung erfolgreich war, bestätigt die Funktion den Erfolg und gibt die Kontrolle an den EA zurück.
Eröffnung einer Verkaufsposition
Die Ausführungsfunktion „Verkaufen“ spiegelt die Kauflogik wider, wobei die Richtung umgekehrt ist.
//+------------------------------------------------------------------+ //| Function to open a market sell position | //+------------------------------------------------------------------+ bool OpenSel(double entryPrice, double stopLoss, double takeProfit, double lotSize){ if(lotSizeMode == MODE_AUTO){ lotSize = CalculatePositionSizeByRisk(lwVolatilityLevels.bearishStopLoss - lwVolatilityLevels.sellEntryPrice); } if(!Trade.Sell(lotSize, _Symbol, entryPrice, stopLoss, takeProfit)){ Print("Error while executing a market sell order: ", GetLastError()); Print(Trade.ResultRetcode()); Print(Trade.ResultComment()); return false; } return true; }
Es wird die Positionsgröße anhand des Abwärts-Stopp-Abstands berechnet und ein Marktverkaufsauftrag mit dem entsprechenden Eröffnungskurs, Stopp-Loss und Take-Profit übermittelt. Diese Symmetrie stellt sicher, dass Käufe und Verkäufe einheitlich behandelt werden, was die Wahrscheinlichkeit von Logikfehlern verringert und die Wartung des Codes erleichtert.
Alles in der Tick-Funktion vereinen
Wenn alle Komponenten vorhanden sind, wird die Tick-Funktion zum Kontrollzentrum des EA.
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick(){ ... //--- Long position logic if(direction == TRADE_BOTH || direction == ONLY_LONG){ if(IsCrossOver(lwVolatilityLevels.buyEntryPrice, closePriceMinutesData)){ if(!IsThereAnActiveBuyPosition(magicNumber) && !IsThereAnActiveSellPosition(magicNumber)){ OpenBuy(askPrice, lwVolatilityLevels.bullishStopLoss, lwVolatilityLevels.bullishTakeProfit, positionSize); } } } //--- Short position logic if(direction == TRADE_BOTH || direction == ONLY_SHORT){ if(IsCrossUnder(lwVolatilityLevels.sellEntryPrice, closePriceMinutesData)){ if(!IsThereAnActiveBuyPosition(magicNumber) && !IsThereAnActiveSellPosition(magicNumber)){ OpenSel(bidPrice, lwVolatilityLevels.bearishStopLoss, lwVolatilityLevels.bearishTakeProfit, positionSize); } } } }
Erstens stellt das sicher, dass die Preisdaten auf dem neuesten Stand sind. Dann wertet es die lange und kurze Logik unabhängig voneinander aus, basierend auf der Nutzerkonfiguration. Bei Käufen prüft der EA, ob Käufe überhaupt erlaubt sind. Anschließend wird bei einem Aufwärtskreuzen nach einem Eröffnungsniveau gesucht. Wenn ein Kreuzen erkannt wird und keine aktive Position besteht, wird gekauft.
Das gleiche Verfahren gilt für Verkäufe, wobei das Einstiegsniveau und die Erkennung des Abwärtskreuzens verwendet werden. Diese Struktur stellt sicher, dass der EA nur auf gültige Ausbruchsereignisse reagiert, die Richtungseinstellungen beachtet und die Regel von nur einem Handelsgeschäft zu jeder Zeit durchsetzt.
Verbesserung der visuellen Klarheit während der Prüfung
Bevor wir zum Testen und Backtesten übergehen, fügen wir eine letzte Verbesserung hinzu – die Konfiguration des Charts. Eine spezielle Hilfsfunktion passt das Erscheinungsbild des Charts an, um die Übersichtlichkeit zu verbessern.
//+------------------------------------------------------------------+ //| 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; }
Dies setzt einen sauberen Hintergrund, entfernt das Raster, erzwingt den Kerzenmodus und wendet einen klaren Farbkontrast für Auf- und Abwärtskerzen an. Diese Änderungen haben keine Auswirkungen auf die Handelslogik. Ihr Zweck ist rein optisch. Bei den Backtests und bei der Live-Beobachtung erleichtern saubere Charts das Verständnis dafür, wie der Preis mit Ausbruchsniveaus interagiert und wie Handelsgeschäfte ausgelöst werden.
Die Funktion wird während der Initialisierung 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); }
Wenn die Chart-Konfiguration fehlschlägt, wird der EA nicht mehr geladen. Dadurch wird sichergestellt, dass die Umgebung vor Beginn des Handels richtig vorbereitet ist.
Zu diesem Zeitpunkt ist der Expert Advisor vollständig entwickelt. Bitte kompilieren Sie Ihren Quellcode. Wenn alle Schritte korrekt ausgeführt wurden, sollte die Kompilierung fehlerfrei abgeschlossen werden. Sollten Probleme auftreten, kann die beigefügte Datei lwVolatilityBreakoutExpert.mq5 als Referenz verwendet werden, um die Richtigkeit zu überprüfen.
Backtest-Ergebnisse
Um die Strategie in einer realistischen Umgebung zu validieren, wurde der Expert Advisor am Gold XAUUSD mit dem Zeitrahmen Daily getestet. Der Backtest-Zeitraum erstreckt sich vom 1. Januar 2025 bis zum 30. November 2025 und deckt damit elf Monate der jüngsten Marktaktivitäten zum Zeitpunkt der Erstellung dieses Berichts ab.
Die Ergebnisse sind ermutigend. Ausgehend von einem Anfangsguthaben von zehntausend US-Dollar erzielte das System während des Testzeitraums ein Wachstum von etwas mehr als 60 %. Der erzielte Gewinn beläuft sich auf sechstausendzweihundertdrei Dollar und neunundvierzig Cents.

Noch wichtiger ist, dass die Kapitalkurve einen stetigen Verlauf ohne extreme oder sprunghafte Rückgänge aufweist.

Diese Art von gleichmäßigem Aktienverhalten passt gut zur Philosophie des Volatilitäts-Breakout-Handels, der darauf abzielt, an nachhaltigen Richtungsbewegungen zu partizipieren, anstatt kurzlebigen Schwankungen nachzujagen.
Um es Ihnen zu erleichtern, ähnliche Ergebnisse zu reproduzieren, sind diesem Artikel zwei Dateien beigefügt. Die Datei configurations.ini enthält die Einstellungen der Testumgebung, während die Datei parameters.set die während des Backtests verwendeten Eingabewerte enthält. Sie können diese Dateien direkt in den MetaTrader 5 Strategietester laden und den gleichen Test auf Ihrer Seite durchführen.
Keine Handelsstrategie funktioniert auf allen Märkten oder unter allen Bedingungen gleich gut. Gold hat sein eigenes Volatilitätsprofil und seine eigenen Verhaltenseigenschaften, und die Ergebnisse können abweichen, wenn dieselbe Logik auf Währungen, Indizes oder andere Rohstoffe angewendet wird. Dies bedeutet nicht, dass die Strategie anfällig ist. Stattdessen unterstreicht sie die Bedeutung von Tests und Anpassungen.
Das primäre Ziel dieses Artikels ist nicht die Optimierung. Der Schwerpunkt liegt auf der Umsetzung von Larry Williams‘ Konzept der Volatilitätsausbrüche in ein klares, strukturiertes und automatisiertes Handelssystem. Die Eingabeparameter wurden bewusst flexibel gestaltet, damit Sie sie auf der Grundlage Ihrer eigenen Beobachtungen und Risikotoleranz ausprobieren, testen und verfeinern können. Dieser Prozess der Erkundung ist der Ort, an dem der persönliche Vorteil entwickelt wird.
Als nächsten Schritt sollten Sie weitere Backtests mit verschiedenen Symbolen und Zeitrahmen durchführen, die Range-Multiplikatoren, die Stop-Platzierung und die Ertrags-Werte anpassen und untersuchen, wie sich diese Änderungen auf die Performance auswirken. Durch diszipliniertes Testen und durchdachte Analysen können Sie dieses automatisierte System so anpassen, dass es besser zu Ihren Handelszielen und Marktpräferenzen passt.
Schlussfolgerung
In diesem Artikel haben wir eine komplette Reise vom Konzept bis zur Ausführung unternommen und die Volatilitätsausbruchsprinzipien von Larry Williams in einen voll funktionsfähigen, testbaren MQL5 Expert Advisor umgesetzt. Wir begannen damit, zu verstehen, warum eine abnormale Ausweitung der Spannweite oft die Geburtsstunde bedeutender Marktbewegungen ist, und entwarfen dann sorgfältig einen logischen Rahmen, um die Volatilität zu messen, objektive Einstiegs- und Ausstiegsniveaus zu definieren und ein diszipliniertes Risikomanagement durchzusetzen. Sukzessive setzten wir die Theorie in Code um und sorgten dafür, dass jede Berechnung, Bedingung und Entscheidung einen klaren Zweck hatte, der auf Larry Williams' Originalarbeit beruhte.
Am Ende dieses Prozesses verfügen Sie nun über einen praktischen Entwurf für die Automatisierung einer bewährten Handelsidee sowie über eine saubere und erweiterbare EA-Struktur, die Sie testen, verfeinern und an verschiedene Märkte anpassen können. Noch wichtiger ist, dass Sie bei der Anwendung dieser Strategie nicht mehr von einer manuellen Ausführung oder einem subjektiven Urteil abhängig sind. Stattdessen haben Sie einen systematischen Ansatz, der durch Backtests und Vorwärtstests objektiv bewertet werden kann.
In diesem Artikel geht es nicht nur um den Aufbau eines Handelssystems. Es geht darum, klare Vorstellungen zu haben, wenn man einer Handelslogik in Code realisiert, das Risiko zu respektieren und sich selbst Raum zu geben, um seinen eigenen Vorteil zu entdecken. Mit dieser Grundlage sind Sie gut gerüstet, um weitere Verbesserungen, zusätzliche Filter und eine tiefere Erforschung von volatilitätsbasierten Handelsideen zu erkunden.
Die nachstehende Tabelle enthält eine kurze Beschreibung aller Dateien, die diesem Artikel beigefügt sind.
| Dateiname | Beschreibung | |
|---|---|---|
| 1 | lwVolatilityBreakoutExpert.mq5 | Der vollständige MQL5-Quellcode des Volatility Breakout Expert Advisors wird in diesem Artikel Schritt für Schritt entwickelt. |
| 2 | configurations.ini | Die Strategy Tester-Konfigurationsdatei wird bei den Backtests verwendet, um die Testumgebung zu reproduzieren. |
| 3 | parameters.set | Die Datei mit den Eingabeparametern wird für den Backtest verwendet, dessen Ergebnisse in diesem Artikel besprochen werden. |
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/20745
Warnung: Alle Rechte sind von MetaQuotes Ltd. vorbehalten. Kopieren oder Vervielfältigen untersagt.
Dieser Artikel wurde von einem Nutzer der Website verfasst und gibt dessen persönliche Meinung wieder. MetaQuotes Ltd übernimmt keine Verantwortung für die Richtigkeit der dargestellten Informationen oder für Folgen, die sich aus der Anwendung der beschriebenen Lösungen, Strategien oder Empfehlungen ergeben.
Python-MetaTrader 5 Strategie-Tester (Teil 02): Umgang mit Balken, Ticks und Überladung eingebauter Funktionen in einem Simulator
Aufbau von Volatilitätsmodellen in MQL5 (Teil I): Die erste Implementierung
Erstellen von nutzerdefinierten Indikatoren in MQL5 (Teil 4): Smart WaveTrend Crossover mit zwei Oszillatoren
Larry Williams Marktgeheimnisse (Teil 4): Automatisieren von kurzfristigen hohen und tiefen Umkehrpunkten in MQL5
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.
Sehen Sie sich den neuen Artikel an: Larry Williams Marktgeheimnisse (Teil 5): Die Automatisierung der Volatilitätsausbruchsstrategie in MQL5.
Autor: Chacha Ian Maroa
Nun, ich vermute, dass viele hier mitlesen und wie ich Ihre kontinuierliche Wissenssammlung, Ihre Lektionen und die Weitergabe Ihrer Erkenntnisse zu allen Themen, die Sie präsentieren, sehr genießen. Sie sind ein Gewinn für die Gemeinschaft und wir sind gesegnet, dass Sie uns helfen.
Prost