Larry Williams’ Marktgeheimnisse (Teil 10): Automatisierung von „Smash-Day“-Umkehrmustern in MQL5
Einführung
Märkte bewegen sich nicht allein aufgrund von Logik – Emotionen sind der Motor für die stärksten Kursschwankungen. Angst beschleunigt den Verkauf, Gier veranlasst die Menschen dazu, zu spät zu kaufen. Larry Williams hat diese emotionalen Extreme jahrzehntelang untersucht und gezeigt, dass sich kurzfristige Chancen oft unmittelbar nach einer Überreaktion der Masse ergeben.
Ein deutliches Beispiel hierfür ist die „Smash-Day“-Umkehr: Der Kurs scheint zunächst kräftig auszubrechen, scheitert dann aber schnell. Dieses Scheitern bringt späte Käufer oder Verkäufer in die Falle, und ihre erzwungenen Positionsschließungen treiben die Umkehr oft zusätzlich an.
Williams warnt zudem davor, dass es sich hierbei nicht um ein Signal handelt, das sich einfach per Knopfdruck auslösen lässt – der Kontext spielt eine wichtige Rolle. Das Problem ist, dass die meisten Trader das Muster zwar erkennen, aber nicht wissen, wie es sich in verschiedenen Märkten, Zeitrahmen und Risikoeinstellungen tatsächlich verhält.
Dieser Artikel befasst sich mit dieser Lücke. Wir werden einen Expert Advisor entwickeln, der sich so genau wie möglich an die Regeln von Larry Williams hält und diese emotionslos umsetzt. Das Ziel ist nicht die blinde Automatisierung – vielmehr geht es darum, die Idee überprüfbar zu machen, damit wir messen können, was funktioniert, was nicht und unter welchen Bedingungen.
Analyse der „Smash-Day“-Umkehrmuster
Bevor wir auch nur eine einzige Zeile Code schreiben, müssen wir uns darüber im Klaren sein, was ein „Smash-Day“ eigentlich bedeutet. Bei diesem Muster geht es nicht um raffinierte Chartzeichnungen oder Interpretationen im Nachhinein. Es geht darum, Momente zu erkennen, in denen sich der Markt stark in eine Richtung bewegt, diese Bewegung dann aber nicht durchzieht und dadurch ein emotionales Ungleichgewicht offenbart. Larry Williams stützte diese Idee auf beobachtbares Kursverhalten und nicht auf Meinungen.
Was ist ein „Smash-Day“?
Nach dem Modell von Larry Williams ist ein „Smash-Day“ ein Handelstag, an dem der Kurs die jüngste Kursstruktur scheinbar entscheidend durchbricht und damit eine starke emotionale Reaktion der Anleger auslöst. Dieser Durchbruch überzeugt die Händler davon, dass ein neuer Trend eingesetzt hat. Stopps werden ausgelöst, Ausbruchsorders werden ausgelöst, und das Vertrauen erreicht an einem einzigen Tag seinen Höhepunkt oder bricht zusammen.
Ein „Smash-Day“ wird dadurch definiert, wie sich der Schlusskurs im Vergleich zu den vorherigen Kerzen entwickelt. Auf der Unterseite schließt der Kurs unter vorherigen Tiefs. Auf der Oberseite schließt der Kurs über den vorherigen Hochs. Was diesen Tag so besonders macht, ist nicht die Richtung der Bewegung, sondern die emotionale Reaktion, die sie auslöst. Die Händler verhalten sich so, als hätte der Markt seine wahren Absichten offenbart.
Diese Tage verkörpern emotionale Extreme, weil sie die Marktteilnehmer zu Entscheidungen zwingen. Angst veranlasst Verkäufer dazu, ihre Positionen aufzulösen oder aggressiv Leerverkäufe zu tätigen. Gier treibt Käufer dazu, erst spät auf Kursausbrüche zu reagieren. Der Markt scheint Gewissheit zu bieten, und genau diese Illusion schafft Chancen.
In diesem Punkt unterscheiden sich Smash-Tage von klassischen Ausbruchsmustern. Bei traditionellen Ausbrüchen wird von einer Fortsetzung der Bewegung ausgegangen. Die „Smash-Days“ stellen dies infrage. Larry Williams stellte fest, dass viele auf den ersten Blick vielversprechende Ausbrüche schnell wieder scheitern. Wenn dieses Scheitern sofort eintritt, sitzen die emotional handelnden Anleger, die auf den Ausbruch reagiert haben, plötzlich in der Falle. Diese Falle ist die Grundlage für die Trendwende.
Kauf nach der Umkehrlogik des „Smash-Day“
Eine Kaufumkehr am „Smash-Day“ beginnt mit einem Abwärtsschock.

Der Kurs schließt unter den Tiefstständen einer oder mehrerer vorheriger Kerzen, was darauf hindeutet, dass der Verkaufsdruck den Markt schließlich überwältigt hat. Für die meisten Händler wirkt dies bärisch und überzeugend. Stopps werden ausgelöst, und Short-Positionen werden erst spät im Kursverlauf aufgebaut.
Die Psychologie dahinter ist ganz einfach. Die Händler rechnen mit einer Fortsetzung. Wenn die Kurse unter die jüngsten Tiefststände fallen, halten sie niedrigere Kurse für unvermeidlich. Was sie selten erwarten, ist ein sofortiges Scheitern.
Die Umkehrlogik tritt auf, wenn der Markt sich weigert, den Trend fortzusetzen. Wenn der Kurs wieder über das Hoch des „Smash-Day“ steigt, ist dies ein Zeichen dafür, dass die Verkäufer die Kontrolle verloren haben. Diejenigen, die zu spät verkauft haben, stehen nun unter Druck. Es kommt zu Short-Eindeckungen, und neue Käufer steigen zuversichtlich ein. Das Ergebnis ist oft eine starke Bewegung in die entgegengesetzte Richtung.
In diesem Expert Advisor wird das Muster objektiv definiert. Die „Smash-Day“-Kerze muss unterhalb der Tiefststände einer vom Benutzer festgelegten Anzahl vorheriger Kerzen schließen. Die Kerze darf keine „Outside-Bar“ sein, da eine solche Kerze eher eine gerichtete Bewegung als eine unstrukturierte Marktreaktion signalisiert. Sobald er ermittelt wurde, wird der Höchststand des „Smash-Tages“ zu einem entscheidenden Referenzniveau. Eine Long-Position wird nur dann ausgelöst, wenn der Kurs in der nächsten Kerze dieses Niveau nach oben durchbricht – je nach gewähltem Einstiegsmodus entweder sofort oder nach einer Bestätigung.
Verkauf nach der Umkehrlogik des „Smash-Day“
Die Verkaufsumkehr folgt derselben Logik, jedoch in der entgegengesetzten emotionalen Richtung.

Der Kurs schließt über den jüngsten Höchstständen der Kerzen, was bei den Käufern für Begeisterung und Zuversicht sorgt. Breakout-Trader steigen aggressiv ein, da sie davon überzeugt sind, dass sich der Aufwärtstrend fortsetzen wird.
Dieser nach oben gerichtete „Smash-Day“ steht für Gier im Markt. Die Anleger befürchten, den Anschluss zu verpassen, und kaufen erst spät, in der Annahme, dass sich der Aufwärtstrend fortsetzen wird. Allerdings sind Aufwärtsbewegungen, die besonders stark erscheinen, oft am anfälligsten für Rückschläge.
Die Trendumkehr gilt als bestätigt, wenn der Kurs den Ausbruch nicht aufrechterhalten kann. Fällt der Markt wieder unter das Tief des „Smash-Tages“, ist dies ein Zeichen dafür, dass die Käufer in der Falle sitzen. Spät eingegangene Long-Positionen schreiben nun rote Zahlen. Wenn sie aussteigen, nimmt der Verkaufsdruck zu, was den Abwärtstrend oft noch beschleunigt.
Der EA definiert dieses Muster mit derselben Objektivität. Die „Smash-Day“-Kerze muss über den Höchstständen einer bestimmten Anzahl vorhergehender Kerzen schließen und darf keine „Outside-Bar“ sein. Das Tief dieser Kerze wird zum Schlüsselniveau. Eine Short-Position wird erst dann eröffnet, wenn der Kurs mit der nächsten Kerze unter dieses Niveau fällt, um sicherzustellen, dass das Scheitern des Ausbruchs real ist und nicht nur spekulativ angenommen wird.
Indem sowohl Kauf- als auch Verkaufs-Umkehrsignale nach denselben Prinzipien strukturiert werden, bleibt das System symmetrisch, messbar und entspricht weiterhin der ursprünglichen Absicht von Larry Williams.
Wie der „Smash-Day“-EA aufgebaut ist und warum
Bevor wir uns die Ergebnisse oder die Performance ansehen, ist es wichtig zu verstehen, wie dieser Expert Advisor aufgebaut ist und warum bestimmte Regeln festgelegt wurden. Das Ziel besteht hier nicht darin, eine komplexe Handelsmaschine zu entwickeln, sondern Larry Williams’ „Smash-Day“-Ideen in ein übersichtliches, testbares Framework zu übertragen, das sowohl dem Marktverhalten als auch den praktischen Grenzen der Automatisierung Rechnung trägt.
Dieser EA ist in erster Linie als Forschungs- und Validierungswerkzeug konzipiert. Jede Regel dient dazu, Unklarheiten zu beseitigen, Überanpassung zu verringern und sicherzustellen, dass das, was wir testen, genau dem entspricht, was das Muster beschreibt – nicht mehr und nicht weniger.
Eine Musterfamilie, ein System nach dem anderen
Wir konzentrieren uns auf zwei eng miteinander verbundene Muster: „Smash-Days“-Kaufumkehrungen und „Smash-Days“-Verkaufsumkehrungen. Obwohl sie Spiegelbilder voneinander sind, werden sie unabhängig voneinander ausgewertet und können über Eingabeparameter ein- oder ausgeschaltet werden.
Der EA kann jederzeit so konfiguriert werden, dass er ausschließlich Kauf-Umkehrsignale, ausschließlich Verkaufs-Umkehrsignale oder beides handelt. Unabhängig vom gewählten Modus sorgt das System stets dafür, dass nur eine Position aktiv ist. Diese Entscheidung ist bewusst getroffen worden. „Smash-Day“-Umkehr sind diskrete Ereignisse und keine kontinuierlichen Signale. Die Zulassung mehrerer Positionen würde Ursache und Wirkung verwischen und die Interpretation der Leistung erschweren. Da jeweils nur eine Position gehalten wird, lässt sich jeder Trade direkt auf ein einzelnes „Smash-Day“-Ereignis zurückführen.
Klare und objektive Musterregeln
Sowohl „Smash-Day“-Kauf- als auch Verkaufs-Umkehr werden durch strenge, messbare Regeln definiert. Für eine „Smash-Day“-Kaufumkehr muss die zuletzt geschlossene Kerze unterhalb der Tiefs einer vom Benutzer festgelegten Anzahl vorheriger Kerzen schließen. Diese Zahl ist konfigurierbar, sodass wir untersuchen können, wie sich oberflächliche oder tiefgreifende Abwärtsdurchbrüche auf die Ergebnisse auswirken. Die Smash-Bar darf zudem keine „Outside-Bar“ sein. Dadurch werden Kerzen vermieden, die sich in beide Richtungen ausdehnen und oft eher Rauschen als eine bestimmte Richtung signalisieren. Sobald ein gültiger „Smash-Day“ identifiziert wurde, muss der Markt ein Scheitern nachweisen. Ein Long-Trade kommt nur dann in Betracht, wenn der Kurs über das Hoch des Smash-Day ansteigt bzw. darüber ausbricht. Dies zeigt, dass die Verkäufer die Kontrolle verloren haben und die Trendwende bereits im Gange ist.
Die gleiche Logik gilt auch für Kursumkehren am „Smash-Day“, allerdings in umgekehrter Richtung. Die „Smash“-Kerzen müssen über den Höchstständen der vorherigen Kerzen schließen, dürfen keine „Outside-Bar“ sein, und der Kurs muss später unter das Tief dieses „Smash“-Tages fallen, um das Scheitern zu bestätigen. Diese Regeln sind bewusst streng gehalten. Wenn sich ein Muster nicht eindeutig beschreiben lässt, kann es nicht zuverlässig getestet werden.
Einstiegsbestätigung und Ausführungssteuerung
Nicht alle Händler sind sich einig, wie viele Bestätigungen ausreichend sind. Manche bevorzugen eine sofortige Ausführung, während andere erst auf das Schließen einer vollständigen Kerze als Bestätigung des Ausbruchs warten. Um diesem Unterschied Rechnung zu tragen, unterstützt der EA zwei Eröffnungsmodi.
Im ersten Modus erfolgt der Einstieg sofort, sobald der Kurs das Niveau überschreitet. Im zweiten Modus wird gewartet, bis die aktuelle Kerze jenseits dieses Niveaus schließt. Beide Ansätze sind zulässig, und diese Flexibilität ermöglicht es uns, zu untersuchen, wie sich der Zeitpunkt der Bestätigung auf die Ergebnisse auswirkt, ohne die Logik des Kernmusters zu ändern.
Risikomanagement, das dem Muster entspricht
Die Risikokontrolle ist einfach gehalten und entspricht der ursprünglichen Absicht von Larry Williams. Bei Kauf-Umkehrsignalen wird der Stop-Loss auf das Tief des „Smash-Tages“ gesetzt. Bei Verkaufsumkehren wird er auf das Hoch des „Smash-Day“ gesetzt. Diese Niveaus markieren den Punkt, an dem das Muster eindeutig ungültig ist.
Der Take Profit wird über ein benutzerdefinierbares Chance-Risiko-Verhältnis festgelegt. Dadurch bleiben die Ausstiegsstrategien markt- und zeitunabhängig, objektiv und skalierbar.
Auch die Positionsgröße lässt sich flexibel anpassen. Einfachheitshalber können wir eine feste Losgröße verwenden oder die Positionsgröße automatisch anhand eines Prozentsatzes des Kontoguthabens berechnen. Wenn die automatische Positionsgrößenanpassung ausgewählt ist, wird bei jedem Trade ein gleichbleibender Anteil des Kapitals riskiert, sodass die Ergebnisse die Performance der Strategie widerspiegeln und nicht durch die Positionsgröße verzerrt werden.
Diese Struktur ermöglicht es uns, die Umkehrungen am „Smash-Day“ so zu untersuchen, wie sie tatsächlich sind – und nicht so, wie wir sie uns wünschen würden. Außerdem schafft es eine klare Grundlage für zukünftige Variationen, Filter und diskretionäre Zusatzfilter, ohne die Integrität des ursprünglichen Musters zu beeinträchtigen.
Entwicklung des Expert Advisors „Smash-Day Reversal“
Dieser Abschnitt markiert den Übergang von Ideen und Regeln zur tatsächlichen Umsetzung. Wir sprechen nicht mehr darüber, was „Smash-Day-Reversals“ sind oder warum sie funktionieren. Wir setzen diese Logik nun in einen Expert Advisor um, der diese Ideen auf kontrollierte und wiederholbare Weise ausführen, testen und validieren kann.
Bevor wir mit dem Schreiben der Logik beginnen, ist es wichtig, die Erwartungen festzulegen. Hier geht es um die praktische Umsetzung. Konzepte lassen sich am besten verstehen, wenn man sie umsetzt, beobachtet und hinterfragt. Aus diesem Grund empfehlen wir, parallel zu dieser Anleitung selbst zu programmieren, anstatt nur passiv mitzulesen.
Um diesen Vorgang zu unterstützen, ist die vollständige, funktionsfähige Quelldatei diesem Artikel als „lwSmashDayReversalExpert.mq5“ beigefügt. Wenn wir die Datei in einem separaten Tab geöffnet lassen, während wir den Text durchgehen, können wir Ideen miteinander abgleichen, Annahmen überprüfen und verstehen, wie sich die einzelnen Teile in das Gesamtbild einfügen.
Voraussetzungen für das Mitmachen
Um diesen Abschnitt in vollem Umfang nutzen zu können, werden einige Grundkenntnisse vorausgesetzt. Zunächst sind Kenntnisse der Programmiersprache MQL5 erforderlich. Grundlegende Konzepte wie Variablen, Funktionen, Schleifen, bedingte Logik, Enumerationen, Strukturen und Standardbibliotheken sollten bereits verstanden sein. Falls diese Grundlagen bei Ihnen noch nicht vollständig sitzen, bietet die offizielle MQL5-Referenz einen hervorragenden Einstieg.
Zweitens sind Vorkenntnisse im Umgang mit der MetaTrader-5-Plattform erforderlich. Dazu gehören das Navigieren in Charts, das Hinzufügen von Expert Advisors, das Öffnen des Strategietesters sowie die Verwaltung grundlegender Plattformfenster wie beispielsweise des Navigators.
Drittens wird erwartet, dass Sie mit dem MetaEditor vertraut sind. Wir werden Quelldateien erstellen, Code kompilieren und auftretende Fehler überprüfen. Dies sind unverzichtbare Fähigkeiten für jede ernsthafte MQL5-Entwicklungsarbeit. Sind diese Voraussetzungen erfüllt, können wir mit dem Aufbau des EA von Grund auf beginnen.
Mit Boilerplate-Code die Grundlagen schaffen
Jeder robuste Expert Advisor beginnt mit einer sauberen, gut strukturierten Grundlage.
//+------------------------------------------------------------------+ //| lwSmashDayReversalExpert.mq5 | //| Copyright 2026, MetaQuotes Ltd. Developer is Chacha Ian | //| https://www.mql5.com/en/users/chachaian | //+------------------------------------------------------------------+ #property copyright "Copyright 2026, MetaQuotes Ltd. Developer is Chacha Ian" #property link "https://www.mql5.com/en/users/chachaian" #property version "1.00" //+------------------------------------------------------------------+ //| Standard Libraries | //+------------------------------------------------------------------+ #include <Trade\Trade.mqh> //+------------------------------------------------------------------+ //| Custom Enumerations | //+------------------------------------------------------------------+ enum ENUM_SMASH_ENTRY_MODE{ ENTRY_ON_LEVEL_CROSS, ENTRY_ON_BAR_CLOSE }; enum ENUM_SMASH_TRADE_MODE{ SMASH_TRADE_BUY_ONLY, SMASH_TRADE_SELL_ONLY, SMASH_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 "Smash Day Pattern Rules" input int smashBuyLookbackBars = 1; input int smashSellLookbackBars = 1; input group "Smash Day Entry Settings" input ENUM_SMASH_ENTRY_MODE smashEntryMode = ENTRY_ON_LEVEL_CROSS; input ENUM_SMASH_TRADE_MODE smashTradeMode = SMASH_TRADE_BOTH; input group "Trade and Risk Management" input ENUM_LOT_SIZE_INPUT_MODE lotSizeMode = MODE_AUTO; input double riskPerTradePercent = 1.0; input double positionSize = 0.1; input double riskRewardRatio = 3.0; //+------------------------------------------------------------------+ //| Global Variables | //+------------------------------------------------------------------+ //--- Create a CTrade object to handle trading operations CTrade Trade; //--- To hep track current market prices for Buying (Ask) and Selling (Bid) double askPrice; double bidPrice; //--- To store current time datetime currentTime; struct MqlSmashDayPatternState{ //--- Pattern detection flags bool hasBuySmashSetup; bool hasSellSmashSetup; //--- Reference breakout levels from smash bar double buyBreakoutLevel; double sellBreakoutLevel; //--- Pattern bar reference data datetime smashBarTime; //--- Entry status tracking bool entryPending; //--- Stop-Loss levels double buyStopLoss; double sellStopLoss; }; MqlSmashDayPatternState smashState; //--- To store minutes data double closePriceMinutesData []; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(){ //--- Assign a unique magic number to identify trades opened by this EA Trade.SetExpertMagicNumber(magicNumber); //--- Reset ZeroMemory(smashState); //--- Treat the following arrays as timeseries (index 0 becomes the most recent bar) ArraySetAsSeries(closePriceMinutesData, true); 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); currentTime = TimeCurrent(); //--- Get some minutes data if(CopyClose(_Symbol, PERIOD_M1, 0, 7, closePriceMinutesData) == -1){ Print("Error while copying minutes datas ", GetLastError()); return; } } //--- UTILITY FUNCTIONS //+------------------------------------------------------------------+
Der folgende Code bildet diese Grundlage. Zum jetzigen Zeitpunkt gibt es noch keine Handelslogik. Stattdessen definieren wir die Identität, die Konfiguration, die Datenstrukturen und die Umgebung, in der die Logik später ausgeführt wird. Dieser Ansatz hält die Komplexität in Grenzen und stellt sicher, dass jede Logikebene einen klaren Zweck erfüllt.
Dateikopf und Eigenschaften
//+------------------------------------------------------------------+ //| lwSmashDayReversalExpert.mq5 | //| Copyright 2026, MetaQuotes Ltd. Developer is Chacha Ian | //| https://www.mql5.com/en/users/chachaian | //+------------------------------------------------------------------+ #property copyright "Copyright 2026, MetaQuotes Ltd. Developer is Chacha Ian" #property link "https://www.mql5.com/en/users/chachaian" #property version "1.00"
Der einleitende Abschnitt definiert die Identität der Quelldatei und enthält Metadaten, die in MetaTrader angezeigt werden. Dazu gehören der Dateiname, Angaben zum Autor, die Versionsnummer und ein Link zur Quelle. Diese Informationen haben zwar keinen Einfluss auf die Ausführung, sind jedoch für die langfristige Wartung, die Versionsverfolgung und die Verteilung von entscheidender Bedeutung.
Einbinden von Standardbibliotheken
//+------------------------------------------------------------------+ //| Standard Libraries | //+------------------------------------------------------------------+ #include <Trade\Trade.mqh>
Wir binden die Trade-Bibliothek ein, um Zugriff auf die Klasse CTrade zu erhalten. Diese Klasse bietet eine übersichtliche und zuverlässige Schnittstelle zum Öffnen, Verwalten und Schließen von Positionen. Indem wir auf die Standardbibliothek zurückgreifen statt auf benutzerdefinierten Code zur Auftragsabwicklung, verringern wir das Fehlerrisiko und verbessern die Lesbarkeit.
Benutzerdefinierte Enumerationen definieren
//+------------------------------------------------------------------+ //| Custom Enumerations | //+------------------------------------------------------------------+ enum ENUM_SMASH_ENTRY_MODE{ ENTRY_ON_LEVEL_CROSS, ENTRY_ON_BAR_CLOSE }; enum ENUM_SMASH_TRADE_MODE{ SMASH_TRADE_BUY_ONLY, SMASH_TRADE_SELL_ONLY, SMASH_TRADE_BOTH }; enum ENUM_LOT_SIZE_INPUT_MODE { MODE_MANUAL, MODE_AUTO };
Enumerationen dienen dazu, abstrakte Entscheidungen in explizite und kontrollierte Auswahlmöglichkeiten umzuwandeln. Wir definieren drei zentrale Enumerationen.
Die erste Option legt fest, wie Einträge ausgelöst werden. Ein Trade kann entweder sofort eröffnet werden, sobald der Kurs ein Ausbruchsniveau überschreitet, oder erst, nachdem sich die Kerze vollständig geschlossen hat und die Kursbewegung bestätigt wurde.
Der zweite legt fest, welche „Smash-Day“-Muster für den Handel zugelassen sind. Es kann zwischen „Nur kaufen“, „Nur verkaufen“ oder „Beides“ gewählt werden. Dies ist für Forschung und Tests wichtig, da es uns ermöglicht, richtungsabhängiges Verhalten zu isolieren.
Der dritte Parameter steuert das Verhalten bei der Positionsgrößenbestimmung. Die Losgröße kann fest vorgegeben oder automatisch auf der Grundlage des Risikos berechnet werden. Diese Enumerationen bilden das Rückgrat der Flexibilität in dem EA, ohne die Ausführungslogik zu verkomplizieren.
Vom Benutzer einzugebende Parameter
//+------------------------------------------------------------------+ //| User input variables | //+------------------------------------------------------------------+ input group "Information" input ulong magicNumber = 254700680002; input ENUM_TIMEFRAMES timeframe = PERIOD_CURRENT; input group "Smash Day Pattern Rules" input int smashBuyLookbackBars = 1; input int smashSellLookbackBars = 1; input group "Smash Day Entry Settings" input ENUM_SMASH_ENTRY_MODE smashEntryMode = ENTRY_ON_LEVEL_CROSS; input ENUM_SMASH_TRADE_MODE smashTradeMode = SMASH_TRADE_BOTH; input group "Trade and Risk Management" input ENUM_LOT_SIZE_INPUT_MODE lotSizeMode = MODE_AUTO; input double riskPerTradePercent = 1.0; input double positionSize = 0.1; input double riskRewardRatio = 3.0;
Die Eingaben sind logisch gruppiert, um die Konfiguration intuitiv zu gestalten. Die Gruppe „Information“ legt die magische Zahl und den Zeitrahmen fest. Die magische Zahl stellt sicher, dass dieser EA nur seine eigenen Positionen verwaltet, während der Zeitrahmen festlegt, wo „Smash-Day“-Muster ausgewertet werden sollen.
Die Gruppe „Smash-Day Pattern Rules“ legt fest, wie streng die Musterqualifikation sein soll. Die Lookback-Parameter legen fest, wie viele vorhergehende Kerzen überschritten werden müssen, damit ein „Smash-Day“ als gültig gilt. Dies wirkt sich unmittelbar auf die Musterhäufigkeit und die Selektivität aus.
Die Gruppe „Smash-Day Entry Settings“ legt das Ausführungsverhalten und die Handelsrichtung fest. Diese Parameter legen fest, wie aggressiv oder konservativ die Einstiegslogik sein soll und ob Long-, Short- oder beide Arten von Trades zulässig sind.
Die Gruppe „Handel und Risikomanagement“ legt die Positionsgröße und die Renditeerwartungen fest. Das Risiko kann fest oder dynamisch sein, und die Take-Profit-Niveaus werden aus einem konfigurierbaren Risiko-Ertrags-Verhältnis abgeleitet.
Globale Handelsobjekte und Marktstatus
//+------------------------------------------------------------------+ //| Global Variables | //+------------------------------------------------------------------+ //--- Create a CTrade object to handle trading operations CTrade Trade; //--- To hep track current market prices for Buying (Ask) and Selling (Bid) double askPrice; double bidPrice; //--- To store current time datetime currentTime;
Wir erstellen eine einzelne Instanz des CTrade-Objekts. Dieses Objekt wird später für die gesamte Handelsausführung zuständig sein. Außerdem definieren wir Variablen, um die aktuellen Geld- und Briefkurse sowie die Serverzeit zu erfassen. Diese Werte werden bei jedem Tick aktualisiert und dienen als Echtzeit-Datenfeed für die Ausführungslogik.
Strukturierung des Zustands des „Smash-Day“-Musters
Eine der wichtigsten Entwurfsentscheidungen in dieser EA ist die Verwendung einer speziellen Struktur zur Verfolgung des Status des „Smash-Day“-Musters.
Die Struktur MqlSmashDayPatternState dient als Speicher.
struct MqlSmashDayPatternState{ //--- Pattern detection flags bool hasBuySmashSetup; bool hasSellSmashSetup; //--- Reference breakout levels from smash bar double buyBreakoutLevel; double sellBreakoutLevel; //--- Pattern bar reference data datetime smashBarTime; //--- Entry status tracking bool entryPending; //--- Stop-Loss levels double buyStopLoss; double sellStopLoss; }; MqlSmashDayPatternState smashState;
Dadurch können wir ein Muster einmalig erkennen und anschließend das Kursverhalten beobachten, ohne die historischen Kerzen immer wieder neu auswerten zu müssen.
Innerhalb dieser Struktur verfolgen wir, ob ein gültiges „Smash“-Setup für einen Kauf oder Verkauf vorliegt, die aus der „Smash“-Kerze abgeleiteten Ausbruchsniveaus, den Zeitpunkt der „Smash“-Kerze und ob derzeit ein Einstieg ansteht.
Außerdem speichern wir Stop-Loss-Niveaus, die direkt aus der Smash-Bar abgeleitet werden. Dadurch werden alle musterbezogenen Informationen an einem Ort zusammengefasst und die Verbreitung globaler Variablen verhindert. Diese Struktur wird später die Verbindung zwischen Mustererkennung und Handelsausführung bilden.
Verarbeitung von Preisdaten zur Erkennung von Intrabar-Durchbrüchen
Um Kursüberschreitungen zuverlässig zu erkennen, benötigen wir Zugriff auf aktuelle Schlusskurse im Minutentakt.
//--- To store minutes data double closePriceMinutesData [];
Wir weisen ein Array zur Speicherung der Minutendaten zu und legen es explizit als Zeitreihe fest. Dadurch wird sichergestellt, dass sich der Index Null immer auf den aktuellsten Wert bezieht.
Diese Daten werden später dazu verwendet, Kursbewegungen in Echtzeit bei der Durchbrechung von Kursniveaus zu erkennen, wenn der Einstiegsmodus auf „Sofortausführung“ eingestellt ist.
Initialisierung und Bereinigung
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(){ //--- Assign a unique magic number to identify trades opened by this EA Trade.SetExpertMagicNumber(magicNumber); //--- Reset ZeroMemory(smashState); //--- Treat the following arrays as timeseries (index 0 becomes the most recent bar) ArraySetAsSeries(closePriceMinutesData, true); return(INIT_SUCCEEDED); }
Die Funktion OnInit weist dem Handelsobjekt die magische Zahl zu, löscht die „Smash-Day“-Zustandsstruktur und bereitet das Minutendaten-Array vor. Dadurch wird sichergestellt, dass der EA bei jedem Anfügen in einem sauberen, vorhersehbaren Zustand startet.
Die Funktion OnDeinit gibt den Grund für die Beendigung an. Dies ist beim Testen und Debuggen nützlich.
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason){ //--- Notify why the program stopped running Print("Program terminated! Reason code: ", reason); }
Einrichtung des OnTick-Frameworks
Die Funktion OnTick führt derzeit nur grundlegende Aufgaben aus.
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick(){ //--- Retrieve current market prices for trade execution askPrice = SymbolInfoDouble (_Symbol, SYMBOL_ASK); bidPrice = SymbolInfoDouble (_Symbol, SYMBOL_BID); currentTime = TimeCurrent(); //--- Get some minutes data if(CopyClose(_Symbol, PERIOD_M1, 0, 7, closePriceMinutesData) == -1){ Print("Error while copying minutes datas ", GetLastError()); return; } }
Sie aktualisiert die Geld- und Briefkurse, erfasst die aktuelle Uhrzeit und aktualisiert die Minuten-Schlusskurse. Es wurden noch keine Handelsentscheidungen getroffen. Dies ist beabsichtigt. Derzeit erstellen wir das Grundgerüst der EA. In den folgenden Abschnitten werden Mustererkennung, Zustandsverwaltung und Handelsausführung auf diesem Framework aufgesetzt. Damit verfügen wir nun über eine stabile und erweiterbare Grundlage. Der EA weiß, wer er ist, wie er sich verhalten soll und wie er Informationen über erkannte „Smash-Day“-Muster speichern muss.
Nachdem diese Grundlagen nun geschaffen sind, können wir damit beginnen, die Logik zu implementieren, die „Smash-Day“-Umkehrungen erkennt und diese in umsetzbare Handelssignale bzw. konkrete Trade-Setups umwandelt.
Erkennung neuer Handelstage und Verfolgung des Musterzustands
Die „Smash-Day“-Logik wird einmal pro abgeschlossener Tageskerze ausgewertet. Aus diesem Grund fügen wir als ersten Baustein eine Funktion hinzu, mit der erkannt werden kann, wann innerhalb des ausgewählten Zeitraums eine neue Kerze beginnt. Dies wird mithilfe einer kleinen Hilfsfunktion erreicht. Fügen Sie die folgende Funktion in den Abschnitt mit den Hilfsfunktionen der Quelldatei ein.
//--- 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 Eröffnungszeit der aktuellen Kerze mit der Zeit der zuletzt erfassten Kerzen. Wenn sich die Uhrzeit geändert hat, hat sich eine neue Kerze gebildet.
Der dritte Parameter wird per Referenz übergeben. Dadurch kann die Funktion die gespeicherte Zeit aktualisieren, sobald ein neuer Bar erkannt wird. Mit anderen Worten: Diese Funktion prüft nicht nur, ob eine neue Kerze vorliegt, sondern merkt sich auch, dass sie bereits darauf reagiert hat. Um dieses Verhalten zu unterstützen, fügen Sie im Abschnitt „Globale Variablen“ eine globale Variable hinzu.
//--- To help track new bar open datetime lastBarOpenTime;
Diese Variable enthält den Zeitstempel der letzten Kerze, die bereits verarbeitet wurde. Setzen Sie den Wert innerhalb der Initialisierungsfunktion auf Null, damit der allererste Tick nach dem Anfügen des EAs als neues Bar-Ereignis behandelt wird.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(){ //--- Initialize global variables lastBarOpenTime = 0; return(INIT_SUCCEEDED); }
Ab diesem Zeitpunkt werden alle täglichen Entscheidungen nur noch einmal pro neuer Kerze getroffen. Dadurch werden doppelte Signale vermieden und die Logik bleibt übersichtlich und vorhersehbar.
Ablehnung von „Outside-Bars“
Eine der Gestaltungsregeln für „Smash-Day“-Umkehrungen lautet, dass die „Smash“-Kerze nicht den gesamten vorherigen Kerzen überdecken darf. Diese Art von Kerzen steht für ein anderes Marktverhalten und muss herausgefiltert werden. Fügen Sie die folgende Hilfsfunktion im Abschnitt „Utility“ ein.
//+-----------------------------------------------------------------------------+ //| Checks whether the bar at the given index fully engulfs the prior bar range | //+-----------------------------------------------------------------------------+ bool IsOutsideBar(string symbol, ENUM_TIMEFRAMES tf, int index){ double high0 = iHigh(symbol, tf, index); double low0 = iLow (symbol, tf, index); double high1 = iHigh(symbol, tf, index + 1); double low1 = iLow (symbol, tf, index + 1); return (high0 > high1 && low0 < low1); }
Diese Funktion vergleicht den Bereich der aktuellen Kerze mit dem Bereich der vorherigen Kerze. Sind sowohl der Höchst- als auch der Tiefstwert höher bzw. niedriger, handelt es sich um eine Outside-Bar, die bei der Musterprüfung ausgeschlossen wird. Dieser einfache Filter schützt die Strategie davor, auf Kerzen mit extremer Volatilität zu reagieren, die nicht der von uns gesuchten klaren „Smash“-Struktur entsprechen.
Erkennen von Umkehrungen bei „Smash-Day“-Käufen
Wir definieren nun den ersten echten Mustererkennungsalgorithmus. Fügen Sie die folgende Funktion unterhalb der Funktion für die „Outside-Bars“ ein.
//+-----------------------------------------------------------------------------------+ //| Detects a Smash Day Buy Reversal where the close breaks below multiple prior lows | //+-----------------------------------------------------------------------------------+ bool IsSmashDayBuyReversal(string symbol, ENUM_TIMEFRAMES tf, int index, int lookbackBars) { // Bar must not be an outside bar if(IsOutsideBar(symbol, tf, index)) return false; double close1 = iClose(symbol, tf, index); // Validate close breaks below N prior lows for(int i = 2; i <= lookbackBars + 1; i++) { double priorLow = iLow(symbol, tf, index + i); if(close1 >= priorLow) return false; } return true; }
Diese Logik prüft drei Dinge. Erstens darf es sich bei der Kerze nicht um eine „Outside-Bar“ handeln. Zweitens betrachten wir den Schlusskurs der Smash-Bar. Drittens vergleichen wir diesen Wert genau mit den Tiefstständen mehrerer vorheriger Kerzen. Liegt der Schlusskurs unter all diesen früheren Tiefstständen, wurde der Markt stark nach unten gedrückt und unter jüngster Unterstützung geschlossen. Das ist genau der emotionale Ausverkauf, den wir erkennen wollen. Der Eingabeparameter steuert die Anzahl der zuvor überprüften Bars. Dadurch wird das Muster je nach den Vorlieben des Benutzers mehr oder weniger streng.
Erkennen von Umkehrungen bei „Smash-Day“-Verkäufen
Die Verkäuferseite ist das Spiegelbild der Kauflogik. Fügen Sie die folgende Funktion direkt nach dem Kaufdetektor ein.
//+-------------------------------------------------------------------------------------+ //| Detects a Smash Day Sell Reversal where the close breaks above multiple prior highs | //+-------------------------------------------------------------------------------------+ bool IsSmashDaySellReversal(string symbol, ENUM_TIMEFRAMES tf, int index, int lookbackBars) { // Bar must not be an outside bar if(IsOutsideBar(symbol, tf, index)) return false; double close1 = iClose(symbol, tf, index); // Validate close breaks above N prior highs for(int i = 2; i <= lookbackBars + 1; i++) { double priorHigh = iHigh(symbol, tf, index + i); if(close1 <= priorHigh) return false; } return true; }
Hier prüfen wir, ob sich der Smash-Kerzen oberhalb der Höchststände mehrerer vorhergehender Kerzen schließt. Dies ist der Ausdruck eines emotional bedingten Kaufansturms, der späte Käufer oft in die Falle lockt, wenn sich der Aufwärtstrend nicht fortsetzt. Zusammen ermöglichen uns diese beiden Funktionen eine objektive Erkennung von Panik bei Kursrückgängen und Euphorie bei Kursanstiegen.
Zurücksetzen des Musterzustands an jedem neuen Tag
Jede neue Tageskerze muss mit einem sauberen internen Zustand beginnen. Frühere Durchbruchniveaus dürfen nicht in den nächsten Tag hineinreichen. Fügen Sie diese Funktion dem Abschnitt der Hilfsfunktionen hinzu.
//+--------------------------------------------------------------------+ //| Resets all Smash Day detection flags and breakout reference levels | //+--------------------------------------------------------------------+ void ResetSmashDaySetupState(){ smashState.hasBuySmashSetup = false; smashState.hasSellSmashSetup = false; smashState.buyBreakoutLevel = iHigh(_Symbol, timeframe, 1); smashState.sellBreakoutLevel = iLow(_Symbol, timeframe, 1); smashState.smashBarTime = iTime(_Symbol, timeframe, 1); }
Diese Funktion löscht die Erkennungsflags und aktualisiert die Referenzwerte anhand des gerade abgeschlossenen Bars. Von diesem Zeitpunkt an beginnt jeder neue Tag von Neuem, und die Mustererkennung wird erneut ausgeführt. Das ist wichtig, da „Smash-Day“-Setups nur einen Tag lang gültig sind.
Erkennung von Ausbrüchen in Echtzeit
Die Strategie unterstützt zwei Einstiegsstrategien. Man steigt sofort ein, sobald der Kurs ein Niveau durchbricht. Der andere wartet auf Kerzen, die jenseits gewisser Niveaus schließen. Für eine sofortige Erfassung müssen wir Kurskreuzungen anhand von Minutendaten erkennen. Fügen Sie die folgenden Hilfsfunktionen hinzu.
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+ //| 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; }
Hier werden die Schlusskurse der letzten zwei Minuten miteinander verglichen. Wenn der Kurs unterhalb dieses Niveaus lag und nun darüber liegt, haben wir einen Ausbruch. Wenn der Kurs über diesem Niveau lag und nun darunter liegt, haben wir einen Durchbruch. Das ermöglicht eine schnelle und präzise Bestätigung noch am selben Tag.
Nur eine Position gleichzeitig zulassen
Bevor wir einen Trade eröffnen, müssen wir sicherstellen, dass keine Position dieses EAs bereits aktiv ist. Fügen Sie diese beiden Funktionen hinzu.
//+------------------------------------------------------------------+ //| 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 geben „true“ zurück, wenn ein passender Trade vorhanden ist. Jede spätere Einstiegsentscheidung ruft diese Prüfungen auf, um die Ein-Trade-Regel durchzusetzen.
Automatische Positionsgrößenanpassung auf Basis des Kontorisikos
Wenn die automatische Positionsgrößenanpassung aktiviert ist, wird das Handelsvolumen so berechnet, dass bei jedem Trade nur ein fester Prozentsatz des Kontostands einem Risiko ausgesetzt ist. Fügen Sie die folgende Hilfsfunktion im Abschnitt „Utility“ ein:
//+------------------------------------------------------------------+ //| 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); }
Diese Funktion rechnet den ausgewählten Risikoprozentsatz auf der Grundlage der Stop-Loss-Distanz in eine Lotgröße um. Weitere Stopps führen zu kleineren Losgrößen, während engere Stopps größere Losgrößen zur Folge haben, wobei das pro Trade eingesetzte Risiko konstant bleibt.
Prognose der Take-Profit-Niveaus
Der Take-Profit-Punkt richtet sich nach dem Risiko-Ertrags-Verhältnis. Fügen Sie diese beiden Funktionen hinzu.
//+------------------------------------------------------------------+ //| Computes the bullish take profit level based on entry price, stop loss, and risk to reward ratio | //+------------------------------------------------------------------+ double GetBuyTakeProfit(double entryPrice, double stopLoss){ double riskDistance = entryPrice - stopLoss; double rewardDistance = riskDistance * riskRewardRatio; rewardDistance = MathAbs(rewardDistance); return NormalizeDouble((entryPrice + rewardDistance), Digits()); } //+------------------------------------------------------------------+ //| Computes the bearish take profit level based on entry price, stop loss, and risk to reward ratio | //+------------------------------------------------------------------+ double GetSellTakeProfit(double entryPrice, double stopLoss){ double riskDistance = stopLoss - entryPrice; double rewardDistance = riskDistance * riskRewardRatio; rewardDistance = MathAbs(rewardDistance); return NormalizeDouble((entryPrice - rewardDistance), Digits()); }
Sie berechnen den Abstand zwischen Einstiegspunkt und Stop-Loss, multiplizieren ihn mit dem gewählten Verhältnis und leiten daraus den Kurszielwert ab. Dadurch bleibt der Ertrag stets proportional zum Risiko.
Eröffnung von Positionen
Nun fassen wir die Ausführung in zwei einfache Funktionen zusammen.
//+------------------------------------------------------------------+ //| Function to open a market buy position | //+------------------------------------------------------------------+ bool OpenBuy(double entryPrice, double stopLoss, double takeProfit, double lotSize){ if(lotSizeMode == MODE_AUTO){ lotSize = CalculatePositionSizeByRisk(entryPrice - stopLoss); } 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; } //+------------------------------------------------------------------+ //| Function to open a market sell position | //+------------------------------------------------------------------+ bool OpenSel(double entryPrice, double stopLoss, double takeProfit, double lotSize){ if(lotSizeMode == MODE_AUTO){ lotSize = CalculatePositionSizeByRisk(stopLoss - entryPrice); } 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; }
Sie übernehmen die automatische Größenanpassung und leiten den Auftrag anschließend über das Handelsobjekt weiter. Die Ausführungslogik ist nun vollständig von der Erkennungslogik getrennt.
Alles unter einem Dach bei OnTick
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick(){ //--- Retrieve current market prices for trade execution askPrice = SymbolInfoDouble (_Symbol, SYMBOL_ASK); bidPrice = SymbolInfoDouble (_Symbol, SYMBOL_BID); currentTime = TimeCurrent(); //--- Get some minutes data if(CopyClose(_Symbol, PERIOD_M1, 0, 7, closePriceMinutesData) == -1){ Print("Error while copying minutes datas ", GetLastError()); return; } //--- Execute this block on new bar formation if(IsNewBar(_Symbol, timeframe, lastBarOpenTime)){ //--- if(smashEntryMode == ENTRY_ON_BAR_CLOSE){ //--- if(smashState.hasBuySmashSetup && smashState.entryPending){ if(!IsThereAnActiveBuyPosition(magicNumber) && !IsThereAnActiveSellPosition(magicNumber)){ if(smashTradeMode == SMASH_TRADE_BUY_ONLY || smashTradeMode == SMASH_TRADE_BOTH){ OpenBuy(askPrice, smashState.buyStopLoss, GetBuyTakeProfit(askPrice, smashState.buyStopLoss), positionSize); smashState.entryPending = false; } } } //--- if(smashState.hasSellSmashSetup && smashState.entryPending){ if(!IsThereAnActiveBuyPosition(magicNumber) && !IsThereAnActiveSellPosition(magicNumber)){ if(smashTradeMode == SMASH_TRADE_SELL_ONLY || smashTradeMode == SMASH_TRADE_BOTH){ OpenSel(bidPrice, smashState.sellStopLoss, GetSellTakeProfit(bidPrice, smashState.sellStopLoss), positionSize); smashState.entryPending = false; } } } } //--- ResetSmashDaySetupState(); //--- if(IsSmashDayBuyReversal(_Symbol, timeframe, 1, smashBuyLookbackBars)){ smashState.hasBuySmashSetup = true; smashState.entryPending = true; smashState.buyStopLoss = iLow(_Symbol, timeframe, 1); } //--- if(IsSmashDaySellReversal(_Symbol, timeframe, 1, smashSellLookbackBars)){ smashState.hasSellSmashSetup = true; smashState.entryPending = true; smashState.sellStopLoss = iHigh(_Symbol, timeframe, 1); } } //--- if(smashEntryMode == ENTRY_ON_LEVEL_CROSS){ //--- if(smashState.hasBuySmashSetup && smashState.entryPending){ // --- if(IsCrossOver(smashState.buyBreakoutLevel, closePriceMinutesData)){ if(!IsThereAnActiveBuyPosition(magicNumber) && !IsThereAnActiveSellPosition(magicNumber)){ if(smashTradeMode == SMASH_TRADE_BUY_ONLY || smashTradeMode == SMASH_TRADE_BOTH){ OpenBuy(askPrice, smashState.buyStopLoss, GetBuyTakeProfit(askPrice, smashState.buyStopLoss), positionSize); } smashState.hasBuySmashSetup = false; smashState.entryPending = false; } } } //--- if(smashState.hasSellSmashSetup && smashState.entryPending){ // --- if(IsCrossUnder(smashState.sellBreakoutLevel, closePriceMinutesData)){ if(!IsThereAnActiveBuyPosition(magicNumber) && !IsThereAnActiveSellPosition(magicNumber)){ if(smashTradeMode == SMASH_TRADE_SELL_ONLY || smashTradeMode == SMASH_TRADE_BOTH){ OpenSel(bidPrice, smashState.sellStopLoss, GetSellTakeProfit(bidPrice, smashState.sellStopLoss), positionSize); } smashState.hasSellSmashSetup = false; smashState.entryPending = false; } } } } }
Innerhalb der OnTick-Funktion aktualisieren wir zunächst die Kurse und die Minutendaten. Dann reagieren wir auf eine neue Tageskerze. In einer neuen Zeile führen wir drei Schritte nacheinander aus.
1. Verarbeitung verzögerter Einstiege, wenn der Eröffnungsmodus auf den Schlusskurs wartet
2. Den internen „Smash-Day“-Status zurücksetzen
3. Neue Smash-Muster auf der fertigen Kerze erkennen
Danach verarbeiten wir außerhalb des neuen Kerzenblocks Echtzeit-Breakout-Einstiege, wenn der Sofort-Einstiegsmodus aktiv ist. Diese Struktur stellt Folgendes sicher:
- Die Mustererkennung erfolgt einmal täglich
- Die Überwachung von Ausbrüchen erfolgt kontinuierlich
- Einstiege wiederholen sich nie
- Es kann jeweils nur eine Position bestehen.
Die „Smash State“-Flags steuern den Ablauf von der Erkennung bis zum Einstieg und schalten sich nach der Ausführung automatisch aus. Diese klare Trennung zwischen Erkennung und Ausführung sorgt dafür, dass das Verhalten vorhersehbar und leicht nachvollziehbar bleibt.
Verbesserung der visuellen Klarheit während der Prüfung
Vor dem Testen nehmen wir die Einstellungen für die Sichtbarkeit des Charts vor.
//+------------------------------------------------------------------+ //| 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; }
Fügen Sie die Funktion ConfigureChartAppearance im Abschnitt „Utility“ hinzu und rufen Sie sie in OnInit auf.
//+------------------------------------------------------------------+ //| 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 werden klare Farben für Kerzen und den Hintergrund festgelegt, sodass Trades und Kursbewegungen bei visuellen Backtests leicht zu erkennen sind. Damit ist der Expert Advisor fertiggestellt. Alle wesentlichen Teile sind vorhanden. Erkennung neuer Handelstage, Erkennung von „Smash“-Mustern, Überwachung von Ausbrüchen, risikobasierte Positionsgrößenbestimmung, Durchsetzung der Ein-Position-Regel und automatische Zurücksetzung des Status
Die vollständige Quelldatei wird als lwSmashDayReversalExpert.mq5 bereitgestellt. Wir verfügen nun über ein voll funktionsfähiges Analyse-Tool, das die „Smash-Day“-Umkehrmuster von Larry Williams in präzise, überprüfbare und wiederholbare Handelsregeln umsetzt.
Testen der „Smash-Day Buy Reversal“-Strategie bei Gold
Um zu beurteilen, wie sich diese Idee in der Praxis bewährt, wurde ein kontrollierter Backtest für Gold auf Tagesbasis durchgeführt. Der Test umfasste Marktdaten für ein ganzes Jahr, vom ersten Tag des Januars 2025 bis zum letzten Tag des Dezembers 2025.
Da nur der „Smash-Day Buy“-Modus aktiviert war, durfte das System ausschließlich Long-Positionen eingehen. Die Positionsgröße wurde auf den automatischen Risikomodus eingestellt, wobei bei jedem Trade 1 % des aktuellen Kontostands riskiert wurde. Das bedeutet, dass die Positionsgröße mit dem Kontostand wächst und schrumpft und das Risiko von einem Handel zum nächsten konstant bleibt.
Der Test begann mit einem Anfangsguthaben von 10.000 $. Im Laufe des Jahres erzielte das System einen Nettogewinn von insgesamt 2307,25 Dollar.

Das entspricht einer Kapitalrendite von über zwanzig Prozent. Die Gewinnquote lag bei vierundsechzig Prozent.
Zwar ist die Gewinnquote nicht besonders hoch, doch die Gesamt-Equity-Kurve vermittelt ein aussagekräftigeres Bild. Die Entwicklung des Kontos verläuft stetig und gleichmäßig, ohne starke Einbrüche.

Es gibt weder dramatische Einbrüche der Equity noch lange Seitwärtsphasen. Stattdessen steigt die Kurve allmählich und kontrolliert an, was darauf hindeutet, dass Verluste gut eingedämmt werden und sich Gewinne im Laufe der Zeit verzinsen können. Dieses Verhalten ist eine direkte Folge zweier gestalterischer Entscheidungen – erstens wird bei jedem Trade nur ein kleiner fester Anteil des Kontoguthabens riskiert. Zweitens werden Trades nur dann getätigt, wenn sich ein klares, objektives Muster abzeichnet, anstatt ein ständiges Marktengagement zu erzwingen.
Um diesen Test vollständig reproduzierbar zu machen, werden zusammen mit diesem Artikel zwei Dateien bereitgestellt. Die Konfigurationsdatei enthält die Einstellungen für die Testumgebung. Die Parameterdatei enthält die genauen Eingabewerte, die vom Expert Advisor verwendet werden. Wenn man diese Dateien in den Strategietester lädt, sollten sich die gleichen Ergebnisse für dasselbe Symbol und denselben Zeitraum reproduzieren lassen.
Dieser einzelne Test beweist nicht, dass das Muster in jedem Markt oder in jedem Jahr immer funktioniert. Dies zeigt, dass die Strategie unter einer klaren, genau definierten Konfiguration in diesem Zeitraum ein stabiles Wachstum bei kontrolliertem Risiko im Goldmarkt erzielte. Die eigentliche Stärke dieses Projekts liegt in seiner Flexibilität. Alle wesentlichen Verhaltensmerkmale, wie beispielsweise die Lookback-Tiefe, der Einstiegsmodus und das Risikoniveau, lassen sich über Eingabeparameter ändern. Dadurch lassen sich unzählige Variationen ausprobieren.
Weitere Tests mit anderen Symbolen, unterschiedlichen Jahren und alternativen Parameterwerten könnten neue Stärken oder Schwächen aufzeigen. Verschiedene Kombinationen könnten einen noch größeren Vorteil bringen. Die Durchführung unabhängiger Experimente wird nachdrücklich empfohlen. Erkenntnisse, Ideen und Verbesserungsvorschläge können im Kommentarbereich geteilt werden, damit die Forschung gemeinschaftlich weiterentwickelt werden kann.
Schlussfolgerung
In dieser Arbeit wurde eine auf Ermessensentscheidungen basierende Handelsidee von Larry Williams in ein vollständig objektives und überprüfbares Handelssystem umgewandelt. Das „Smash-Day“-Umkehrmuster, das auf emotional bedingten Kursausbrüchen basiert, die schnell wieder zurückfallen, wurde in klare Regeln gefasst, die eine Maschine erkennen und ohne zu zögern umsetzen kann.
Es wurde ein Expert Advisor entwickelt, um diese Bedingungen in Echtzeit zu erkennen, das Risiko automatisch zu steuern und Trades mit strenger Disziplin auszuführen. Das System eröffnet jeweils nur eine Position, nutzt klar definierte Stop-Loss- und Gewinnziele und passt die Positionsgröße an einen festen Prozentsatz des Kontorisikos an. Dadurch wird ein nur vage beschriebenes Marktverhalten zu einem strukturierten Forschungsinstrument.
Ein Ganzjahrestest mit Gold ergab ein stetiges Kontowachstum, kontrollierte Drawdowns und eine konstante Wertsteigerung. Dies zeigt, dass das Muster nicht nur in Charts optisch ansprechend ist, sondern auch unter realen Marktbedingungen quantifiziert, gemessen und bewertet werden kann.
Noch wichtiger ist, dass das Programm für die Erkundung konzipiert wurde und nicht für blinde Automatisierung. Jede wichtige Regel kann über Eingabeparameter angepasst werden. Dies ermöglicht die weitere Untersuchung verschiedener Lookback-Tiefen, Einstiegsstrategien und Risikoniveaus für beliebige Wertpapiere oder Zeitrahmen. Der Leser ist nicht auf das hier vorgestellte Beispiel beschränkt.
Es ist gelungen, eine Brücke zwischen Handelspsychologie und programmierbarer Logik zu schlagen. Emotionale Fallstricke, die früher nur mit bloßem Auge erkannt werden konnten, lassen sich nun innerhalb von Sekunden anhand jahrelanger historischer Daten analysieren. Dies eröffnet Möglichkeiten für eingehendere Forschung, eine schnellere Überprüfung von Ideen und eine sicherere Entscheidungsfindung.
Die „Smash-Day“-Umkehr ist nur eines von vielen Mustern. Derselbe Vorgang lässt sich auf viele andere Konzepte aus der klassischen Handelsliteratur anwenden. Durch die Kombination aus klaren Regeln, strenger Risikokontrolle und systematischen Tests wird es möglich, Intuition von Fakten zu trennen.
Der nächste Schritt ist das eigenständige Experimentieren. Durch die Durchführung neuer Tests, die Anpassung von Parametern und den Vergleich der Ergebnisse über verschiedene Märkte hinweg lassen sich möglicherweise noch aussagekräftigere Varianten dieses Ansatzes aufzeigen. Der Austausch dieser Erkenntnisse trägt dazu bei, die Forschung voranzutreiben, und verwandelt einen einzelnen Artikel in einen wachsenden Fundus an praktischem Wissen.
Anhänge und deren Verwendung
Um die Reproduzierbarkeit und weitere Forschungsarbeiten zu erleichtern, sind alle wesentlichen Ressourcen, die in diesem Projekt verwendet wurden, diesem Artikel beigefügt. Mit diesen Dateien lassen sich dieselbe Handelslogik, dieselben Umgebungseinstellungen und dieselben Testparameter laden, ohne dass eine manuelle Neukonfiguration erforderlich ist.
Mit diesem Aufbau lassen sich die vorgestellten Ergebnisse reproduzieren, der gesamte Quellcode einsehen und die Eingabewerte anpassen, um neue Ideen zu erproben. Auf diese Weise wird der Expert Advisor nicht nur zu einem fertigen Werkzeug, sondern zu einem Ausgangspunkt für weitergehende Experimente.
Die folgende Tabelle fasst die einzelnen beigefügten Dateien und ihren Zweck zusammen.
| Dateiname | Beschreibung |
|---|---|
| lwSmashDayReversalExpert.mq5 | Vollständiger Quellcode eines MQL5-Expert Advisors, der „Smash-Day“-Umkehrungen implementiert |
| configurations.ini | Konfiguration der Strategietester-Umgebung für einen einheitlichen Backtest-Aufbau |
| parameters.set | Voreinstellung der Eingabeparameter, die zur Erzeugung der dargestellten Backtest-Ergebnisse verwendet wurde |
Die Quelldatei kann direkt im MetaEditor geöffnet werden, um sie zu prüfen, zu bearbeiten und zu kompilieren. Die Konfigurationsdatei kann in den Strategietester geladen werden, um die Testumgebung exakt nachzubilden. Die Parameterdatei kann auf der Registerkarte „Tester-Eingaben“ angewendet werden, um sofort dieselben Handelseinstellungen zu laden, die in den ausgewiesenen Ergebnissen verwendet wurden.
Zusammen bilden diese Dateien ein einsatzbereites Forschungspaket. Sie ermöglichen es, die Strategie zu überprüfen, unter verschiedenen Marktbedingungen einem Stresstest zu unterziehen und um zusätzliche Filter oder Ideen zu erweitern.
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/21127
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.
Handelsdisziplin in Code verankern (Teil 1): Mit MQL5 strukturelle Disziplin im Live-Trading schaffen
Entwicklung eines Toolkits zur Price-Action-Analyse (Teil 59): Einsatz geometrischer Asymmetrie zur Erkennung präziser Ausbrüche aus fraktalen Konsolidierungsphasen
Entwicklung eines Toolkits zur Price-Action-Analyse (Teil 60): Objektive Swing-basierte Trendlinien für die Strukturanalyse
Der MQL5-Standardbibliotheks-Explorer (Teil 7): Interaktive Positionskennzeichnung mit CCanvas
- 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.