English Русский
preview
Larry Williams’ Marktgeheimnisse (Teil 13): Automatisierung von Hidden-Smash-Day-Umkehrmustern

Larry Williams’ Marktgeheimnisse (Teil 13): Automatisierung von Hidden-Smash-Day-Umkehrmustern

MetaTrader 5Experten |
27 1
Chacha Ian Maroa
Chacha Ian Maroa

Einführung

In „Long Term Secrets to Short Term Trading“ stellt Larry Williams den Hidden-Smash-Day als eine ruhigere, eher interne Variante des klassischen Smash-Day vor. Auf dem Chart sieht es einfach aus: Die Bar durchbricht nicht unbedingt ein offensichtliches vorheriges Hoch oder Tief, deutet jedoch auf eine Erschöpfung hin, da der Markt bei der nächsten Sitzung, in der dieses Niveau getestet wird, nicht nachziehen kann. Das Setup ist bewusst subtil gehalten, und Williams macht den entscheidenden Punkt deutlich: Die Hidden-Smash-Day-Bar ist nicht das eigentliche Handelssignal – ein Trade kommt erst nach der Bestätigung in der folgenden Handelssitzung zustande, wenn der Kurs das maßgebliche verborgene Niveau durchbricht.

Genau diese Feinheit ist der Grund, warum dieses Muster beim manuellen Handel so frustrierend ist. Sobald man versucht, dies manuell umzusetzen, artet es in eine Diskussion über Definitionen aus: Wo genau beginnt der untere bzw. obere Bereich der Handelsspanne, was gilt als Bestätigung, ob der Stop an der Smash-Bar-Struktur angesetzt werden soll oder sich mit zunehmender Volatilität ausweiten sollte, und wie kann man vermeiden, dass sich Positionen überschneiden, wenn sich Signale häufen?

Wenn Sie sich als Algorithmus-Trader oder Entwickler mit Williams’ Arbeit beschäftigen, brauchen Sie keine Interpretation – Sie brauchen formale Regeln: identische Bedingungen für alle Instrumente, jedes Mal dieselbe Logik zur Bestätigung der nächsten Sitzung und ein Risikomanagement, das im Strategietester reproduzierbar ist. Das Ziel dieses Artikels ist es, Hidden-Smash-Day in eindeutige Regeln umzusetzen und diese in MQL5 zu implementieren, sodass das Signal, der Einstieg, SL/TP und die Positionsgröße automatisch berechnet und bei jedem Durchlauf konsistent ausgeführt werden – ohne Ermessensspielraum.


Verständnis der Hidden-Smash-Day-Umkehrmuster

Ein Hidden-Smash-Day wird durch die Position des Schlusskurses innerhalb der Spanne der jeweiligen Bar in Verbindung mit einem Vergleich zum Schlusskurs der vorangegangenen Sitzung definiert.

Ein bullisches Hidden-Smash-Day-Setup erfordert vier Bedingungen:

  1. Die Bar muss höher schließen als die vorherige Bar.
  2. Die Spanne der Bar wird von ihrem eigenen Hoch bis zu ihrem eigenen Tief gemessen.
  3. Der Schlusskurs muss innerhalb der unteren 25 Prozent dieser Spanne liegen.
  4. Optional kann für eine strengere Filterung festgelegt werden, dass der Schlusskurs unter dem Eröffnungskurs der Bar liegen muss.

Hidden-Smash-Buy-Bar

Diese Struktur zeigt einen höheren Schlusskurs, der jedoch schwach im unteren Bereich der eigenen Spanne endet, was trotz eines positiven Schlusskurses auf eine interne Erschöpfung hindeutet.

Ein bärischer Hidden-Smash-Day folgt der umgekehrten Logik:

  1. Der Schlusskurs der Bar muss unter dem der vorherigen Bar liegen.
  2. Ihre Spanne wird durch ihr eigenes Hoch und Tief definiert.
  3. Der Schlusskurs muss innerhalb der oberen 25 Prozent dieses Bereichs liegen.
  4. Gegebenenfalls muss der Schlusskurs über dem Eröffnungskurs liegen.

Versteckte Smash Sell-Bar

In beiden Fällen dient die Smash-Bar selbst nur als Setup. Dies löst noch keinen Trade aus. Die Bestätigung muss bei der nächsten abgeschlossenen Bar erfolgen.

In dieser Implementierung gilt ein Signal erst dann als bestätigt, wenn die Bestätigungsbar über das Extrem der Smash-Bar hinaus schließt. Ein Kaufsignal liegt vor, wenn der Schlusskurs einer vollständigen Bar über dem Hoch der Smash-Bar liegt. Ein Verkaufssignal liegt vor, wenn der Schlusskurs einer vollständigen Bar unterhalb des Tiefststands der Smash-Bar liegt.

Diese Regel zur Bestätigung des Schlusskurses wird im gesamten Artikel und im Expert Advisor durchgehend angewendet.


Aus versteckten Smash-Days praktische Handelsregeln machen

Bevor wir irgendetwas automatisieren konnten, mussten wir entscheiden, wie versteckte Smash-Day-Muster auf kontrollierte und wiederholbare Weise gehandelt werden sollten. Dieser Expert Advisor soll nicht jedes mögliche Signal handeln, sondern Larry Williams’ Idee strukturieren und dem Trader zugleich Flexibilität lassen.

Die erste Gestaltungsregel betrifft den Zeitpunkt, zu dem Entscheidungen getroffen werden. Die gesamte Logik zur Mustererkennung und Handelsausführung wird ausschließlich zu Beginn einer neuen Bar ausgewertet. Dadurch wird sichergestellt, dass Hidden-Smash-Day-Bars vollständig ausgebildet sind und die Bestätigungsbars ihre Sitzung abgeschlossen haben. Auf diese Weise vermeiden wir es, auf unvollständige Preisinformationen zu reagieren, und halten uns an die Definition des Musters in der Originalarbeit.

Die zweite Regel lautet: Bestätigung vor dem Einstieg. Ein Hidden-Smash-Day wird niemals für sich allein gehandelt. Bei dieser Umsetzung erfordert die Bestätigung einen Schlusskurs einer vollständig abgeschlossenen Bar, der über das Extrem der Smash-Bar hinausgeht. Für ein Kaufsignal muss die nächste Sitzung über dem Höchststand der Hidden-Smash Bar schließen. Für ein Verkaufs-Setup muss die nächste Sitzung unter ihrem Tiefststand schließen. Alle Bewertungen werden ausschließlich bei der Eröffnung einer neuen Bar durchgeführt, wobei sichergestellt wird, dass sowohl die Smash-Bar als auch die Bestätigungsbar vollständig abgeschlossen sind, bevor ein Handel in Betracht gezogen wird.

Eine wichtige Designentscheidung bei diesem Expert Advisor ist die explizite Steuerung der Handelsrichtung. Das System bietet drei verschiedene Betriebsmodi. Es kann auf Long-Positionen oder auf Short-Positionen beschränkt werden oder es kann beide Richtungen erlauben. Diese Funktion wird bewusst als Benutzereingabe bereitgestellt, da Hidden-Smash-Day-Muster nicht unter allen Marktbedingungen gleich gut funktionieren. In manchen Märkten oder Phasen überwiegen Kaufsignale, während in anderen Fällen Verkaufssignale zuverlässiger sind. Durch die Möglichkeit, die Richtung zu steuern, wird der EA eher zu einem Forschungsinstrument als zu einer starren Blackbox.

Das Risikomanagement wird als zentraler Bestandteil und nicht als nachträglicher Einfall betrachtet. Der Stop-Loss lässt sich auf zwei verschiedene Arten berechnen. Eine Möglichkeit besteht darin, den Stop-Loss auf das strukturelle Niveau des Hidden-Smash-Day zu setzen, wobei der Höchst- oder Tiefststand des Musters als Referenz dient. Die zweite Option nutzt die Marktvolatilität, indem sie ein benutzerdefiniertes Vielfaches der Average True Range anwendet. Durch diesen zweigleisigen Ansatz kann sich das System sowohl an die Preisstruktur als auch an sich ändernde Volatilitätsbedingungen anpassen.

Auch die Positionsgröße ist von Grund auf flexibel gestaltet. Der Expert Advisor unterstützt sowohl die manuelle Lot-Größenbestimmung für Trader, die eine feste Positionsgröße bzw. ein fixes Risiko bevorzugen, als auch die automatische Positionsgrößenbestimmung auf Basis eines Prozentsatzes des Kontoguthabens. Wenn die automatische Positionsgrößenanpassung aktiviert ist, wird bei jedem Trade ein gleichbleibender Anteil des Kapitals riskiert, unabhängig vom Symbol oder der Volatilität, was dazu beiträgt, eine stabile langfristige Wertentwicklung aufrechtzuerhalten.

Eine weitere wichtige Regel ist der Ausschluss paralleler Positionen. Der Expert Advisor eröffnet niemals mehr als einen Trade gleichzeitig. Bevor eine neue Order platziert wird, prüft das System stets, ob bereits offene Positionen bestehen. Dadurch werden sich überschneidende Trades vermieden, die Risikokontrolle vereinfacht und die Leistungsanalyse während der Testphase deutlich übersichtlicher gestaltet.

Zusammen legen diese Regeln fest, wie Hidden-Smash-Day-Muster in ein diszipliniertes Handelssystem umgesetzt werden. Jede Entscheidung spiegelt die ursprüngliche Absicht von Larry Williams wider und fügt gleichzeitig die für die Automatisierung, das Testen und die langfristige Bewertung erforderliche Struktur hinzu.


Ausführungslogik der Hidden-Smash-Day-Strategieumsetzung

Bevor man sich den Quellcode ansieht, lässt sich die gesamte Logik des Systems in strukturierter Form zusammenfassen:

Wenn eine neue Bar eröffnet wurde
 Aktualisiere die ATR-Werte

 Wenn es keine offene Position gibt

  Prüfe das Hidden-Smash-Buy-Setup bei Index zwei
  Wenn das Setup gültig ist
   Prüfe, ob die bestätigende Bar über dem Hoch der Smash-Bar schließt
   Wenn bestätigt
    Berechne Stop-Loss
    Berechne Take-Profit
    Berechne die Positionsgröße
    Eröffne eine Buy-Position

  Prüfe das Hidden-Smash-Sell-Setup bei Index zwei
  Wenn das Setup gültig ist
   Prüfe, ob die bestätigende Bar unter dem Tief der Smash-Bar schließt
   Wenn bestätigt
    Berechne Stop-Loss
    Berechne Take-Profit
    Berechne die Positionsgröße
    Eröffne eine Sell-Position

Diese Abfolge stellt sicher, dass:
  • Setup und Bestätigung sind voneinander getrennt.
  • Es werden nur abgeschlossene Bars verwendet.
  • Stop- und Take-Profit-Limits werden vor der Ausführung festgelegt.
  • Das Risiko wird vor dem Absenden der Order berechnet.
  • Es kann jeweils nur eine offene Position bestehen.

Ist diese Struktur einmal definiert, wird der Code zu einem direkten Ausdruck dieser Schritte.


Entwicklung des Expert Advisors Hidden-Smash-Day

Dieser Abschnitt markiert den Beginn der praktischen Umsetzungsphase. Hier beginnen wir damit, den Expert Advisor Hidden-Smash-Day Schritt für Schritt zusammenzustellen, wobei wir uns zunächst auf die Struktur konzentrieren, bevor wir die Handelslogik hinzufügen. Das Ziel in dieser Phase ist es noch nicht, Handel zu betreiben, sondern eine klare und zuverlässige Grundlage zu schaffen, auf der im weiteren Verlauf der Entwicklung komplexere Funktionen aufbauen können.

Bevor wir fortfahren, ist es wichtig, einige Voraussetzungen zu klären. Dieser Abschnitt setzt Kenntnisse der Programmiersprache MQL5 und ihrer grundlegenden Syntax voraus, einschließlich Variablen, Funktionen, Enumerationen und Standardbibliotheken. Außerdem werden Vorkenntnisse im Umgang mit dem MetaTrader-5-Terminal erwartet, insbesondere in Bezug auf die Navigation in Charts, das Einbinden von Expert Advisors und das Durchführen von Tests. Schließlich sind grundlegende Kenntnisse im Umgang mit dem MetaEditor erforderlich, darunter das Erstellen von Quelldateien, das Kompilieren von Code und das Auswerten von Compiler-Meldungen.

Um das aktive Lernen zu fördern, ist die fertige Quelldatei des Expert Advisors diesem Artikel als lwHiddenSmashDayExpert.mq5 beigefügt. Wenn Sie diese Datei in einem separaten Tab geöffnet lassen, während Sie die Anleitung durchgehen, können Sie die neuen Komponenten, sobald sie vorgestellt werden, ganz einfach vergleichen.

Vor diesem Hintergrund erstellen wir zunächst eine neue, leere Expert-Advisor-Datei im MetaEditor und fügen den unten gezeigten Standardcode ein.

//+------------------------------------------------------------------+
//|                                       lwHiddenSmashDayExpert.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>

//+------------------------------------------------------------------+
//| Defines how stop loss levels are determined for smash day trades |
//+------------------------------------------------------------------+
enum ENUM_STOP_LOSS_MODE
{
   SL_ATR_BASED,            
   SL_SMASH_BAR_STRUCTURE
};

//+------------------------------------------------------------------+
//| Defines the trade direction                                      |
//+------------------------------------------------------------------+
enum ENUM_TRADE_DIRECTION
{
   TRADE_LONG,
   TRADE_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 "ATR configuration parameters"
input int32_t atrPeriod          = 14;
input double  atrMultiplier      = 2.0;

input group "Trade and Risk Management"
input ENUM_STOP_LOSS_MODE smashStopLossMode = SL_SMASH_BAR_STRUCTURE;
input double rewardRiskRatio                = 3.0;
input ENUM_TRADE_DIRECTION direction        = TRADE_LONG;
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;

//--- To hep track current market prices for Buying (Ask) and Selling (Bid)
double askPrice;
double bidPrice;

//--- To store current time
datetime currentTime;

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

//--- ATR Values
int atrHandle;
double atrValues [];

//--- Protective stops
double stopLossLevel;
double takeProfitLevel;

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

   //---  Assign a unique magic number to identify trades opened by this EA
   Trade.SetExpertMagicNumber(magicNumber);
   
   //--- Initialize global variables
   lastBarOpenTime = 0;
   
   //--- Initialize the ATR indicator
   atrHandle = iATR(_Symbol, timeframe, atrPeriod);
   if(atrHandle == INVALID_HANDLE){
      Print("Error while initializing the ATR indicator ", GetLastError());
      return(INIT_FAILED);
   }
   
   //--- Treat the following arrays as timeseries (index 0 becomes the most recent bar)
   ArraySetAsSeries(atrValues, true);

   return(INIT_SUCCEEDED);
}

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

   //--- Notify why the program stopped running
   Print("Program terminated! Reason code: ", reason);
   
   //--- Release ATR
   if(atrHandle != INVALID_HANDLE){
      if(IndicatorRelease(atrHandle)){
         Print("The computer memory tracking ATR has been freed.");
      }
   }
}

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

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

Der Code eröffnet noch keine Trades. Stattdessen definiert er die Struktur, die Konfigurationsoptionen und die Basisdienste, auf die sich die EA später stützen wird.

Dateikopf und Identität

//+------------------------------------------------------------------+
//|                                       lwHiddenSmashDayExpert.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"

Im einleitenden Abschnitt wird die Identität des Expert Advisors definiert. Darin sind der Dateiname, der Eigentümer und die Versionsinformationen angegeben. Auch wenn dieser Teil keinen direkten Einfluss auf die Handelslogik hat, spielt er doch eine wichtige Rolle für die Strukturierung des Codes, die Nachvollziehbarkeit der Urheberschaft und die langfristige Wartung. Eine frühzeitige Festlegung dieser Eigenschaften trägt dazu bei, dass zukünftige Überarbeitungen nachvollziehbar und professionell bleiben.

Importieren der Handelsbibliothek

Der nächste Schritt ist das Einbinden der Standard-Trading-Bibliothek.

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

Diese Bibliothek bietet Zugriff auf die Klasse CTrade, die später zur Ausführung von Kauf- und Verkaufsaufträgen verwendet wird. Durch die Nutzung dieser Standardschnittstelle wird die Auftragsausführung sicherer, übersichtlicher und besser auf die interne Handelsabwicklung von MetaTrader abgestimmt.

In dieser Phase binden wir lediglich die Bibliothek ein. Die eigentliche Auftragsausführung wird später eingeführt, sobald die Signallogik eingerichtet ist.

Enumerationen, die das Verhalten beeinflussen

Bevor wir Eingaben oder Logik definieren, führen wir eine Reihe von Enumerationen ein.

//+------------------------------------------------------------------+
//| Defines how stop loss levels are determined for smash day trades |
//+------------------------------------------------------------------+
enum ENUM_STOP_LOSS_MODE
{
   SL_ATR_BASED,            
   SL_SMASH_BAR_STRUCTURE
};

//+------------------------------------------------------------------+
//| Defines the trade direction                                      |
//+------------------------------------------------------------------+
enum ENUM_TRADE_DIRECTION
{
   TRADE_LONG,
   TRADE_SHORT,
   TRADE_BOTH
};

//+------------------------------------------------------------------+
//| To track lot size input mode                                     |
//+------------------------------------------------------------------+
enum ENUM_LOT_SIZE_INPUT_MODE 
{ 
   MODE_MANUAL, 
   MODE_AUTO 
};

Diese Enumerationen formalisieren wichtige Entwurfsentscheidungen und machen das Verhalten der EA explizit und konfigurierbar.

Die erste Enumeration legt fest, wie die Stop-Loss-Niveaus berechnet werden. In einem Modus basiert der Stop auf der Marktvolatilität mittels ATR, im anderen auf der Struktur der Hidden-Smash-Bar. Diese Trennung ist bewusst gewählt und spiegelt zwei unterschiedliche Ansätze der Risikokontrolle wider.

Die zweite Enumeration definiert die Handelsrichtung. Der EA kann so eingestellt werden, dass er ausschließlich Long-Positionen oder ausschließlich Short-Positionen eingeht, oder es kann ihm gestattet werden, in beide Richtungen zu handeln. Dies ist ein entscheidendes Konstruktionsmerkmal, da sich Hidden-Smash-Day-Muster nicht immer unter allen Marktbedingungen symmetrisch verhalten.

Die abschließende Enumeration steuert das Verhalten bei der Lot-Größenbestimmung. Die Handelspositionen können manuell festgelegt oder automatisch auf der Grundlage des Kontorisikos berechnet werden. Diese Unterscheidung ermöglicht es dem EA, sowohl als Ausführungswerkzeug mit fester Größe als auch als risikonormiertes Analysesystem zu fungieren.

Indem wir diese Optionen als Enumerationen definieren, vermeiden wir mehrdeutige boolesche Flags und machen die EA-Konfiguration leichter lesbar und verständlicher.

Konfiguration der Benutzereingaben

Nachdem die Enumerationen definiert sind, wenden wir uns nun den Benutzereingaben zu. Die Eingabefelder sind logisch gruppiert, damit das Einstellungsfenster übersichtlich und intuitiv bleibt.

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

input group "ATR configuration parameters"
input int32_t atrPeriod          = 14;
input double  atrMultiplier      = 2.0;

input group "Trade and Risk Management"
input ENUM_STOP_LOSS_MODE smashStopLossMode = SL_SMASH_BAR_STRUCTURE;
input double rewardRiskRatio                = 3.0;
input ENUM_TRADE_DIRECTION direction        = TRADE_LONG;
input ENUM_LOT_SIZE_INPUT_MODE lotSizeMode  = MODE_AUTO;
input double riskPerTradePercent            = 1.0;
input double positionSize                   = 0.1;

Die Gruppe Information enthält die magische Zahl und den Zeitrahmen. Die magische Zahl stellt sicher, dass die von diesem EA eröffneten Positionen stets unabhängig von anderen Systemen identifiziert und verwaltet werden können.

Die ATR-Konfigurationsgruppe legt den Zeitraum und den Multiplikator fest, die für ATR-basierte Stop-Loss-Aufträge verwendet werden. Diese Werte bestimmen, wie die Volatilität in den Sicherheitsabstand umgerechnet wird.

Der Bereich Handel und Risikomanagement bündelt die wichtigsten verhaltensbezogenen Kontrollmaßnahmen. Hier werden der Stop-Loss-Modus, das Risiko-Ertrags-Verhältnis, die Handelsrichtung, der Modus zur Lot-Größenbestimmung und die Risikoparameter festgelegt. Jeder dieser Faktoren hat direkten Einfluss darauf, wie die Handelspositionen bemessen, abgesichert und gefiltert werden.

Zum jetzigen Zeitpunkt sind diese Eingaben zwar deklariert, werden aber noch nicht verwendet. Ihr Ziel ist es, die zukünftige Logik zu gestalten, anstatt Handelsgeschäfte sofort auszuführen.

Globale Rahmenbedingungen und Marktkontext

Nach der Eingabe deklarieren wir globale Variablen. Diese Variablen ermöglichen es verschiedenen Teilen des EA, den Status auf übersichtliche Weise gemeinsam zu nutzen.

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

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

//--- ATR Values
int atrHandle;
double atrValues [];

//--- Protective stops
double stopLossLevel;
double takeProfitLevel;

Es wird ein CTrade-Objekt erstellt, um die Auftragsausführung später abzuwickeln. Marktpreise, wie beispielsweise Geld- und Briefkurse, werden global gespeichert, damit sie funktionsübergreifend einheitlich wiederverwendet werden können. Die aktuelle Serverzeit wird für die Zeitmessung erfasst.

Um die auf Bars basierende Entscheidungsfindung zu unterstützen, wird eine Variable reserviert, um die Öffnungszeit der letzten Bar zu erfassen. Dies ermöglicht eine präzise Erkennung neuer Handelssitzungen, was für die tägliche Musteranalyse unerlässlich ist.

Außerdem werden ATR-bezogene Variablen deklariert. Der Indikator-Handle verbindet den EA mit dem ATR-Indikator, während das Array die aktuellen ATR-Werte speichert. Diese Werte werden später zur Berechnung volatilitätsbasierter Stop-Loss-Limits herangezogen.

Abschließend werden Platzhalter für Stop-Loss- und Take-Profit-Niveaus definiert. Diese Variablen werden erst dann mit Werten gefüllt, wenn gültige Handelssignale vorliegen.

Initialisierungslogik des Expert Advisors

Die Initialisierungsfunktion bereitet den EA für die Ausführung vor.

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

   //---  Assign a unique magic number to identify trades opened by this EA
   Trade.SetExpertMagicNumber(magicNumber);
   
   //--- Initialize global variables
   lastBarOpenTime = 0;
   
   //--- Initialize the ATR indicator
   atrHandle = iATR(_Symbol, timeframe, atrPeriod);
   if(atrHandle == INVALID_HANDLE){
      Print("Error while initializing the ATR indicator ", GetLastError());
      return(INIT_FAILED);
   }
   
   //--- Treat the following arrays as timeseries (index 0 becomes the most recent bar)
   ArraySetAsSeries(atrValues, true);

   return(INIT_SUCCEEDED);
}

Zunächst wird dem Handelsobjekt die magische Zahl zugewiesen. Dadurch wird sichergestellt, dass alle von diesem EA eröffneten Trades korrekt gekennzeichnet werden.

Als Nächstes wird die Variable zur Barverfolgung initialisiert. Durch die Einstellung auf Null wird sichergestellt, dass der erste erkannte Barwechsel korrekt verarbeitet wird.

Der ATR-Indikator wird anschließend unter Verwendung des konfigurierten Zeitrahmens und der konfigurierten Periode initialisiert. Sollte dieser Schritt fehlschlagen, wird der EA sofort beendet, da für einen der unterstützten Stop-Loss-Modi ATR-Werte erforderlich sind.

Schließlich wird das ATR-Werte-Array als Zeitreihe konfiguriert. Dadurch wird sichergestellt, dass der aktuellste ATR-Wert immer unter Index Null verfügbar ist, was zukünftige Berechnungen vereinfacht.

Nach Abschluss der Initialisierung ist der EA vollständig einsatzbereit, jedoch noch nicht für den Handel aktiv.

Deinitialisierung und Bereinigung von Ressourcen

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

   //--- Notify why the program stopped running
   Print("Program terminated! Reason code: ", reason);
   
   //--- Release ATR
   if(atrHandle != INVALID_HANDLE){
      if(IndicatorRelease(atrHandle)){
         Print("The computer memory tracking ATR has been freed.");
      }
   }
}

Wenn der Expert Advisor entfernt oder das Terminal heruntergefahren wird, wird die Deinitialisierungsfunktion aufgerufen.

Hier wird eine Beendigungsmeldung protokolliert, und das ATR-Indikator-Handle wird freigegeben. Das Freigeben von Indikator-Handles ist wichtig, um Speicherlecks zu vermeiden und ein ordnungsgemäßes Herunterfahren zu gewährleisten, insbesondere bei wiederholten Tests.

Die Tick-Funktion als Platzhalter

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

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

In dieser frühen Phase erfüllt die Tick-Funktion lediglich grundlegende Aufgaben. Sie aktualisiert die Marktpreise und speichert die aktuelle Serverzeit.

Es wurden noch keine Handelsentscheidungen getroffen. Dies ist beabsichtigt. Die Tick-Funktion wird auf ein Minimum beschränkt, bis die gesamte Erkennungs- und Risikologik definiert ist. Dieser Ansatz verhindert eine unnötige Komplexität in einem zu frühen Entwicklungsstadium und sorgt dafür, dass jeder Entwicklungsschritt zielgerichtet bleibt.

Die Grundlagen schaffen

Derzeit führt der Expert Advisor keine Handelsgeschäfte durch. Das ist so vorgesehen.

Was wir bisher aufgebaut haben, ist ein stabiles Gerüst. Es definiert Konfigurationsoptionen, legt den Marktkontext fest, bereitet den Zugriff auf Indikatoren vor und gewährleistet ein einwandfreies Start- und Abschaltverhalten. Jedes hier hinzugefügte Element dient dazu, die nachfolgende Logik bzw. Implementierung zu tragen.

In den nächsten Schritten werden wir damit beginnen, Mustererkennung, Signalbestätigung und Ausführungsregeln vorzustellen. Da die Grundlagen bereits vorhanden sind, werden sich diese Ergänzungen nahtlos und vorhersehbar in die bestehende Struktur einfügen.

Gerade dieses schrittweise Vorgehen sorgt dafür, dass die EA auch bei zunehmender Komplexität lesbar, testbar und erweiterbar bleibt.

Nachdem die Grundlagen nun geschaffen sind, beginnen wir nun damit, die Handelslogik Stück für Stück zusammenzusetzen. Jede Ergänzung erfüllt einen klaren Zweck und untermauert die zuvor im Entwurf getroffenen Entscheidungen. In diesem Abschnitt geht es nicht um Schnelligkeit, sondern um Klarheit. Wir stellen jeweils eine Komponente vor, erläutern ihre Funktion und zeigen, wie sie sich in die Gesamtstruktur des Expert Advisors einfügt.

Den Beginn einer neuen Handelssitzung erkennen

Hidden-Smash-Day-Muster werden anhand abgeschlossener Bars ausgewertet. Aus diesem Grund werden alle Handelsentscheidungen in diesem Expert Advisor bei der Eröffnung einer neuen Bar getroffen. Um dieses Verhalten zu unterstützen, definieren wir zunächst eine kleine Hilfsfunktion, die uns anzeigt, wann sich auf dem ausgewählten Zeitrahmen eine neue Bar gebildet hat. 

//+------------------------------------------------------------------+
//| 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 sollte in den Abschnitt Hilfsfunktionen des Codes aufgenommen werden. Die Funktion vergleicht den Eröffnungszeitpunkt der letzten Bar mit einem zuvor gespeicherten Zeitstempel. Wenn sich der Wert ändert, entsteht eine neue Bar. Der Zeitstempel wird dann per Referenz aktualisiert, wodurch die Funktion über mehrere Ticks hinweg konsistent funktioniert. Um diese Logik zu unterstützen, wird eine globale Variable benötigt, in der die zuletzt bekannte Öffnungszeit der Bar gespeichert wird.

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

Diese Variable wird beim Start des Experten initialisiert, um eine einwandfreie Zustandsverfolgung zu gewährleisten.

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

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

Ab diesem Zeitpunkt verfügt der Expert Advisor über eine zuverlässige Möglichkeit, die Logik nur einmal pro Bar auszuführen.

Aktualisierung der ATR-Werte für das Risikomanagement

Einer der von diesem EA unterstützten Stop-Loss-Modi nutzt die Average True Range. Um die ATR-Werte auf dem neuesten Stand zu halten, definieren wir eine Funktion, die den ATR-Puffer aktualisiert, sobald eine neue Bar gebildet wird.

//+------------------------------------------------------------------+
//| To update ATR values                                             |
//+------------------------------------------------------------------+
void UpdateATRValues(){
   
   //--- Get some ATR Values
   int numberOfCopiedATRValues = CopyBuffer(atrHandle, 0, 0, 5, atrValues);
   if(numberOfCopiedATRValues == -1){
      Print("Error while copying ATR values: ", GetLastError());
   }
}

Diese Funktion sollte zusammen mit anderen Hilfsfunktionen platziert werden. Die Funktion lädt die aktuellsten ATR-Werte in ein Zeitreihen-Array, wobei der Index 0 stets den neuesten Wert darstellt. Durch diese Gestaltung bleibt die Logik zur Berechnung des Stop-Loss einfach und übersichtlich.

In OnTick werden die ATR-Werte unmittelbar nach der Erkennung einer neuen Bar aktualisiert.

//+------------------------------------------------------------------+
//| Returns true if the bar at index forms a Hidden Smash Day Buy Bar |
//| Logic aligned with indicator implementation                       |
//+------------------------------------------------------------------+
bool IsHiddenSmashDayBuyBar(string symbol, ENUM_TIMEFRAMES tf, int index, double closePercentThreshold = 25.0, bool allowBullishClose = true, bool allowBearishClose = true){

   //--- We need at least one previous bar
   if(index < 1){
      return false;
   }

   double high  = iHigh(symbol, tf, index);
   double low   = iLow(symbol, tf, index);
   double open  = iOpen(symbol, tf, index);
   double close = iClose(symbol, tf, index);

   double prevClose = iClose(symbol, tf, index + 1);

   double range = high - low;
   if(range <= 0.0)
      return false;

   //--- 1. Must close higher than previous bar
   if(close <= prevClose)
      return false;

   //--- 2. Close must be in lower portion of its own range
   double closePositionPercent = ((close - low) / range) * 100.0;
   if(closePositionPercent > closePercentThreshold)
      return false;

   //--- 3. Optional candle direction filter
   if(close > open && !allowBullishClose)
      return false;

   if(close < open && !allowBearishClose)
      return false;

   return true;
}

Diese Funktion prüft, ob der Schlusskurs innerhalb des unteren Teils der Spanne der Bar liegt, wie durch den prozentualen Schwellenwert definiert. Optionale Parameter ermöglichen Flexibilität hinsichtlich der Frage, ob bullische oder bärische Schlusskurse zulässig sind, was Larry Williams’ Feststellung widerspiegelt, dass beide Fälle gültig sein können.

Es wird eine gespiegelte Funktion definiert, um bärische Hidden-Smash-Day-Bars zu erkennen.

//+--------------------------------------------------------------------+
//| Returns true if the bar at index forms a Hidden Smash Day Sell Bar |
//| Logic aligned with indicator implementation                        |
//+--------------------------------------------------------------------+
bool IsHiddenSmashDaySellBar(string symbol, ENUM_TIMEFRAMES tf, int index, double closePercentThreshold = 25.0, bool allowBullishClose = true, bool allowBearishClose = true){

   //--- We need at least one previous bar
   if(index < 1){
      return false;
   }

   double high  = iHigh(symbol, tf, index);
   double low   = iLow(symbol, tf, index);
   double open  = iOpen(symbol, tf, index);
   double close = iClose(symbol, tf, index);

   double prevClose = iClose(symbol, tf, index + 1);

   double range = high - low;
   if(range <= 0.0)
      return false;

   //--- 1. Must close lower than previous bar
   if(close >= prevClose)
      return false;

   //--- 2. Close must be in upper portion of its own range
   double closePositionPercent = ((high - close) / range) * 100.0;
   if(closePositionPercent > closePercentThreshold)
      return false;

   //--- 3. Optional candle direction filter
   if(close > open && !allowBullishClose)
      return false;

   if(close < open && !allowBearishClose)
      return false;

   return true;
}

Diese beiden Funktionen bilden die Grundlage der Mustererkennung. Zum jetzigen Zeitpunkt werden noch keine Handelssignale generiert. Wir ermitteln lediglich infrage kommende Bars.

Bestätigung gültiger Handelssignale

Ein Hidden-Smash-Day wird erst nach der Bestätigung wirksam. Larry Williams erklärt, dass eine Bestätigung vorliegt, wenn die folgende Sitzung bzw. die bestätigende Bar jenseits des Extrempunkts der Smash-Bar schließt. Um diese Regel zu formalisieren, definieren wir eine Bestätigungsfunktion für bullische Setups.

//+------------------------------------------------------------------+
//| Confirms a Hidden Smash Day Buy signal using a confirming bar    |
//+------------------------------------------------------------------+
bool IsHiddenSmashDayBuySignal(int confirmingBarIndex){

   int smashBarIndex = confirmingBarIndex + 1;

   //--- Verify smash bar exists and is valid
   if(!IsHiddenSmashDayBuyBar(_Symbol, timeframe, smashBarIndex))
      return false;

   //--- Confirmation requires a close above the smash bar high
   if(iClose(_Symbol, timeframe, confirmingBarIndex) >
      iHigh (_Symbol, timeframe, smashBarIndex)){
      return true;
   }

   return false;
}

Die Logik prüft, ob ein gültiger Hidden-Smash-Bar vorliegt und ob die nächste Bar über seinem Höchststand schließt.

Eine gespiegelte Funktion bestätigt bärische Signale.

//+------------------------------------------------------------------+
//| Confirms a Hidden Smash Day Sell signal using a confirming bar   |
//+------------------------------------------------------------------+
bool IsHiddenSmashDaySellSignal(int confirmingBarIndex){

   int smashBarIndex = confirmingBarIndex + 1;

   //--- Verify smash bar exists and is valid
   if(!IsHiddenSmashDaySellBar(_Symbol, timeframe, smashBarIndex))
      return false;

   //--- Confirmation requires a close below the smash bar low
   if(iClose(_Symbol, timeframe, confirmingBarIndex) <
      iLow  (_Symbol, timeframe, smashBarIndex)){
      return true;
   }

   return false;
}

Zu diesem Zeitpunkt kann der Expert Advisor gültige Handelssignale objektiv erkennen.

Durchsetzung der Regel „Immer-nur-eine-Position“

Um das Risiko unter Kontrolle zu halten und die Logik vorhersehbar zu gestalten, ist der EA so konzipiert, dass er zu jedem Zeitpunkt nur eine offene Position hält. Zwei Hilfsfunktionen sorgen dafür, dass diese Regel eingehalten wird.

//+------------------------------------------------------------------+
//| 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 überprüfen alle offenen Positionen und geben true zurück, wenn bereits ein Trade mit der Magic Number des EAs aktiv ist. Bevor eine neue Position eröffnet wird, werden beide Prüfungen durchgeführt.

Berechnung von Stop-Loss- und Take-Profit-Niveaus

Sobald ein gültiges Signal erkannt wird, müssen die Schutzniveaus berechnet werden. Die Stop-Loss-Funktion unterstützt zwei Modi: auf ATR basierend und auf der Smash-Bar-Struktur basierend.

//+------------------------------------------------------------------+
//| Computes the stop loss level based on direction and SL mode      |
//+------------------------------------------------------------------+
double ComputeStopLossLevel(ENUM_TRADE_DIRECTION tDirection,
                            ENUM_STOP_LOSS_MODE  slMode,
                            int smashBarIndex)
{
   double slLevel = 0.0;

   //--- ATR based stop loss
   if(slMode == SL_ATR_BASED)
   {
      double atrValue = atrValues[0] * atrMultiplier;

      if(tDirection == TRADE_LONG)
         slLevel = askPrice - atrValue;
      else
         slLevel = bidPrice + atrValue;
   }
   //--- Smash bar structure based stop loss
   else if(slMode == SL_SMASH_BAR_STRUCTURE)
   {
      if(tDirection == TRADE_LONG)
         slLevel = iLow(_Symbol, timeframe, smashBarIndex);
      else
         slLevel = iHigh(_Symbol, timeframe, smashBarIndex);
   }

   return NormalizeDouble(slLevel, Digits());
}

Im ATR-Modus wird der Stop-Loss in einem Vielfachen des aktuellen ATR-Werts vom Einstiegskurs entfernt platziert. Im Strukturmodus wird der Stop-Loss am Höchst- oder Tiefstkurs der Smash-Bar selbst platziert. Diese Flexibilität ermöglicht es, verschiedene Risikostrategien zu testen, ohne den Code ändern zu müssen.

Das Take-Profit-Niveau wird anhand eines festen Risiko-Ertrags-Verhältnisses berechnet.

//+------------------------------------------------------------------+
//| Computes the take profit level using risk reward ratio           |
//+------------------------------------------------------------------+
double ComputeTakeProfitLevel(ENUM_TRADE_DIRECTION tDirection,
                              double stopLoss)
{
   double entryPrice;
   double riskDistance;
   double takeProfit;

   if(tDirection == TRADE_LONG)
   {
      entryPrice   = askPrice;
      riskDistance = entryPrice - stopLossLevel;
      takeProfit   = entryPrice + (riskDistance * rewardRiskRatio);
   }
   else
   {
      entryPrice   = bidPrice;
      riskDistance = stopLossLevel - entryPrice;
      takeProfit   = entryPrice - (riskDistance * rewardRiskRatio);
   }

   return NormalizeDouble(takeProfit, Digits());
}

Indem der EA den Take-Profit direkt an das Risiko koppelt, sorgt er für eine konsistente Positionsgrößenbestimmung und eine konsistente Erwartungslogik.

Trades ausführen

Es wird eine Hilfsfunktion definiert, um die automatische Positionsgrößenbestimmung zu berechnen.

//+------------------------------------------------------------------+
//| Calculates position size using OrderCalcProfit for accuracy      |
//+------------------------------------------------------------------+
double CalculatePositionSizeByRisk(ENUM_ORDER_TYPE orderType, double entryPrice, double stopLossPrice){

   //--- Amount willing to risk
   double amountAtRisk = (riskPerTradePercent / 100.0) *
                         AccountInfoDouble(ACCOUNT_BALANCE);

   //--- Calculate loss for 1 lot
   double lossPerLot = 0.0;

   if(!OrderCalcProfit(orderType,
                       _Symbol,
                       1.0,              // 1 lot
                       entryPrice,
                       stopLossPrice,
                       lossPerLot))
   {
      Print("OrderCalcProfit failed: ", GetLastError());
      return 0.0;
   }

   // Loss will be negative for losing scenario
   lossPerLot = MathAbs(lossPerLot);

   if(lossPerLot <= 0.0)
      return 0.0;

   //--- Raw volume
   double volume = amountAtRisk / lossPerLot;

   //--- Apply broker constraints
   double minLot   = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double maxLot   = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
   double lotStep  = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);

   // Normalize to step
   volume = MathFloor(volume / lotStep) * lotStep;

   if(volume < minLot)
      volume = minLot;

   if(volume > maxLot)
      volume = maxLot;

   return NormalizeDouble(volume, 2);
}

Zwei einfache Wrapper-Funktionen übernehmen die Ausführung der Handelsgeschäfte.

//+------------------------------------------------------------------+
//| Calculates position size using OrderCalcProfit for accuracy      |
//+------------------------------------------------------------------+
double CalculatePositionSizeByRisk(ENUM_ORDER_TYPE orderType, double entryPrice, double stopLossPrice){

   //--- Amount willing to risk
   double amountAtRisk = (riskPerTradePercent / 100.0) *
                         AccountInfoDouble(ACCOUNT_BALANCE);

   //--- Calculate loss for 1 lot
   double lossPerLot = 0.0;

   if(!OrderCalcProfit(orderType,
                       _Symbol,
                       1.0,              // 1 lot
                       entryPrice,
                       stopLossPrice,
                       lossPerLot))
   {
      Print("OrderCalcProfit failed: ", GetLastError());
      return 0.0;
   }

   // Loss will be negative for losing scenario
   lossPerLot = MathAbs(lossPerLot);

   if(lossPerLot <= 0.0)
      return 0.0;

   //--- Raw volume
   double volume = amountAtRisk / lossPerLot;

   //--- Apply broker constraints
   double minLot   = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double maxLot   = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
   double lotStep  = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);

   // Normalize to step
   volume = MathFloor(volume / lotStep) * lotStep;

   if(volume < minLot)
      volume = minLot;

   if(volume > maxLot)
      volume = maxLot;

   return NormalizeDouble(volume, 2);
}

//+------------------------------------------------------------------+
//| Function to open a market buy position                           |
//+------------------------------------------------------------------+
bool OpenBuy(double entryPrice, double stopLoss, double takeProfit, double lotSize){
   
   if(lotSizeMode == MODE_AUTO){
      lotSize = CalculatePositionSizeByRisk(ORDER_TYPE_BUY, 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 OpenSell(double entryPrice, double stopLoss, double takeProfit, double lotSize){
   
   if(lotSizeMode == MODE_AUTO){
      lotSize = CalculatePositionSizeByRisk(ORDER_TYPE_SELL, entryPrice, stopLoss);
   }
   
   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;
}

Wenn die automatische Lot-Größenbestimmung aktiviert ist, wird die Lot-Größe auf der Grundlage des konfigurierten Risikoprozentsatzes berechnet. Andernfalls wird die manuell festgelegte Positionsgröße verwendet. Diese Funktionen trennen die Handelsausführung von der Signallogik und verbessern so die Lesbarkeit und Wartbarkeit.

Alles in OnTick vereinen

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

   //--- Retrieve current market prices for trade execution
   askPrice    = SymbolInfoDouble (_Symbol, SYMBOL_ASK);
   bidPrice    = SymbolInfoDouble (_Symbol, SYMBOL_BID);
   currentTime = TimeCurrent();
   
   //--- Execute on new bar open
   if(IsNewBar(_Symbol, timeframe, lastBarOpenTime)){
   
      //--- Update ATR Values
      UpdateATRValues();
      
      if(IsHiddenSmashDayBuySignal(1)) {
         
         Print("New Bar!!!");
         stopLossLevel   = ComputeStopLossLevel(TRADE_LONG, smashStopLossMode, 2);
         takeProfitLevel = ComputeTakeProfitLevel(TRADE_LONG, stopLossLevel);
         
         if(!IsThereAnActiveBuyPosition(magicNumber) && !IsThereAnActiveSellPosition(magicNumber)){
            if(direction == TRADE_LONG || direction == TRADE_BOTH){
               OpenBuy(askPrice, stopLossLevel, takeProfitLevel, positionSize);
            }
         }      
      }
      
      if(IsHiddenSmashDaySellSignal(1)){
         
         Print("New Bar!!!");
         stopLossLevel   = ComputeStopLossLevel(TRADE_SHORT, smashStopLossMode, 2);
         takeProfitLevel = ComputeTakeProfitLevel(TRADE_SHORT, stopLossLevel);
         
         if(!IsThereAnActiveBuyPosition(magicNumber) && !IsThereAnActiveSellPosition(magicNumber)){
            if(direction == TRADE_SHORT || direction == TRADE_BOTH){
               OpenSell(bidPrice, stopLossLevel, takeProfitLevel, positionSize);
            }
         } 
      }
   }
}

Alle Komponenten werden innerhalb der Funktion OnTick zusammengeführt. Bei jeder neuen Bar führt der EA Folgendes aus:

  1. Aktualisiert die ATR-Werte
  2. Prüft auf bestätigte Kauf- oder Verkaufssignale
  3. Überprüft, ob keine aktive Position vorliegt
  4. Wendet eine Filterung nach Handelsrichtung an
  5. Berechnet Stop-Loss und Take-Profit
  6. Führt den Handel aus

Dieser strukturierte Ablauf stellt sicher, dass Handelsgeschäfte nur dann getätigt werden, wenn alle Bedingungen erfüllt sind, und dass jede Entscheidung auf der Grundlage vollständiger Kursinformationen getroffen wird.

Vorbereitung des Charts für übersichtliche Tests

Damit ist die Logik des Expert Advisors nun vollständig. Bevor wir zur Testphase übergehen, ist noch ein weiterer praktischer Schritt erforderlich. Wir müssen sicherstellen, dass die bei den Tests verwendete visuelle Umgebung übersichtlich und gut lesbar ist.

Beim Testen von Strategien geht es nicht nur um Leistungszahlen. Es geht auch um Beobachtung. Wir möchten die Kursentwicklung, die Kerzenstruktur und die Platzierung der Trades klar und ohne visuelle Störfaktoren erkennen können. Die Standardeinstellungen für Charts sind oft unübersichtlich und können wichtige Details verdecken, insbesondere wenn man Ein- und Ausstiege Bar für Bar überprüft.

Um dies zu beheben, definieren wir eine kleine Hilfsfunktion, deren einzige Aufgabe darin besteht, das Erscheinungsbild des Charts zu konfigurieren.

//+------------------------------------------------------------------+
//| 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;
}

Diese Funktion sollte gegen Ende der Quelldatei zusammen mit anderen Hilfsfunktionen eingefügt werden. Die Funktion wendet ein kontrastreiches Design mit weißem Hintergrund und deutlich unterscheidbaren bullischen und bärischen Kerzen an. Die Gitterlinien sind deaktiviert, um Störungen zu reduzieren, und das Chart ist ausdrücklich auf den Kerzenchart-Modus eingestellt. Jede Einstellung wird überprüft, und etwaige Fehler werden sofort gemeldet. Dieser Ansatz stellt sicher, dass bei der visuellen Überprüfung von Handelsgeschäften die Kursstruktur und die Ausführungspunkte leicht zu interpretieren sind.

Nachdem die Funktion definiert ist, besteht der letzte Schritt darin, sie bei der Initialisierung des Experten aufzurufen. Dadurch wird sichergestellt, dass das Chart einmalig konfiguriert wird, bevor die Handelslogik in Gang gesetzt wird.

Innerhalb der Funktion OnInit fügen wir den folgenden Block hinzu.

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

Indem wir diesen Aufruf in OnInit platzieren, stellen wir sicher, dass die visuelle Umgebung bereit ist, bevor mit dem Testen oder der Live-Ausführung begonnen wird. Sollte die Chartkonfiguration aus irgendeinem Grund fehlschlagen, wird der Expert Advisor sofort gestoppt, anstatt in einem unbeabsichtigten Zustand weiterzulaufen.

Nachdem dieser letzte Schritt abgeschlossen ist, ist der Expert Advisor nicht nur logisch vollständig, sondern auch ordnungsgemäß für die Analyse und das Testen vorbereitet. Sowohl die Entscheidungslogik als auch das visuelle Feedback greifen nun ineinander, was bei der Bewertung einer musterbasierten Strategie wie dem Hidden-Smash-Day von entscheidender Bedeutung ist.

Zu diesem Zeitpunkt ist der Expert Advisor voll funktionsfähig. Die vollständige Implementierung ist in der beigefügten Datei lwHiddenSmashDayExpert.mq5 enthalten, sodass Leser die Logik einsehen, testen und erweitern können, ohne große Codeabschnitte aus dem Artikel kopieren zu müssen.

Dieser strukturierte Ansatz spiegelt die Philosophie wider, die hinter Larry Williams’ Arbeit steht: klare Regeln, disziplinierte Umsetzung und Respekt vor der Marktstruktur. Nachdem die Kernlogik nun steht, besteht der nächste Schritt darin, zu testen und zu bewerten, wie sich diese verborgenen Muster in verschiedenen Märkten und unter unterschiedlichen Bedingungen verhalten.


Testen des Expert Advisors Hidden-Smash-Day

Nach Abschluss der Entwicklungsphase besteht der nächste Schritt darin, zu überprüfen, ob sich der Expert Advisor genau wie vorgesehen verhält. Dies erfolgt in zwei Schritten. Zunächst bestätigt eine visuelle Prüfung der Live-Charts, dass das System Hidden-Smash Bars korrekt erkennt und Positionen gemäß den festgelegten Regeln eröffnet. Zweitens ermöglicht das historische Backtesting eine Bewertung der Strategie unter kontrollierten Bedingungen.

Visuelle Überprüfung anhand eines Charts

Der erste Schritt besteht darin, sicherzustellen, dass der Expert Advisor Hidden-Smash-Day-Muster korrekt erkennt und Trades erst nach einer ordnungsgemäßen Bestätigung ausführt.

An dieser Stelle werden zwei Screenshots gezeigt. Eine davon zeigt eine aktive Long-Position an.

Long-Position

Die andere zeigt eine aktive Short-Position, die vom Expert Advisor eröffnet wurde.

Short-Position

Im Beispiel für einen Long-Trade schließt die Hidden-Smash Bar im unteren Bereich ihrer eigenen Spanne, liegt aber dennoch über dem Schlusskurs der vorherigen Bar. Damit ist die strukturelle Voraussetzung für einen Bullish Hidden-Smash-Day erfüllt. Die nächste Bar schließt dann über dem Höchststand dieser Smash-Bar und bestätigt damit die Trendumkehr. Sobald diese Bestätigungsbar vollständig abgeschlossen ist, eröffnet der Expert Advisor bei Eröffnung der neuen Bar eine Long-Position.

Das Beispiel für eine Short-Position spiegelt dieselbe Logik wider. Die Hidden-Smash-Bar schließt im oberen Bereich seiner Spanne, wobei der Schlusskurs unter dem Schlusskurs der vorherigen Bar liegt. Damit ist das bärische Hidden-Smash-Setup etabliert. Die folgende Sitzung schließt dann unterhalb des Tiefststands der Smash Bar und bestätigt damit das Signal. Bei Eröffnung der nächsten Bar erlaubt der Expert Advisor eine Short-Position.

Diese Beispiele bestätigen, dass das System die zuvor in diesem Artikel festgelegten Regeln korrekt anwendet. Die Setup-Bar wird korrekt erkannt, bei einer abgeschlossenen Bar ist eine Bestätigung erforderlich, und Trades werden erst ausgeführt, nachdem die Signalbedingungen erfüllt sind.

Test der historischen Wertentwicklung

Nachdem sichergestellt wurde, dass sich die Handelslogik auf dem Chart korrekt verhält, besteht der nächste Schritt darin, das System anhand historischer Daten zu bewerten.

Es wurde ein historischer Backtest für Gold (XAUUSD) auf Tagesbasis durchgeführt. Der Testzeitraum begann am 1. Januar 2025 und erstreckte sich bis zum 28. Februar 2026, wodurch er etwas mehr als ein Jahr der Marktaktivität umfasste.

Im Rahmen dieses Tests wurde der Expert Advisor so konfiguriert, dass sowohl Hidden-Smash-Day-Kauf- als auch Verkaufsszenarien zugelassen wurden. Die automatische Positionsgrößenbestimmung wurde aktiviert, wobei bei jedem Trade ein Prozent des Kontoguthabens riskiert wurde.

Um die vollständige Reproduzierbarkeit der Ergebnisse zu gewährleisten, sind dem Artikel zwei Begleitdateien beigefügt. Die erste Datei mit dem Namen configurations.ini enthält die Umgebungseinstellungen des Strategy Testers. Die zweite Datei mit dem Namen parameters.set enthält die genauen Eingabeparameter, die während des Tests verwendet wurden.

Backtest-Ergebnisse

Testbericht

Der Test begann mit einem Anfangsguthaben von 10.000 Dollar. Während des Testzeitraums erzielte das System einen Nettogewinn von 1.371,64 Dollar, was einer Rendite von knapp über dreizehn Prozent entspricht. Die Trefferquote während des Tests lag bei 100 %. In diesem speziellen Beobachtungszeitraum wurden ausschließlich Long-Positionen ausgelöst.

Die unten stehende Kapitalkurve zeigt einen gleichmäßigen Aufwärtstrend ohne abrupte Einbrüche oder starke Rückgänge.

Kapitalkurven

Vordefinierte Stop-Loss-Regeln begrenzten das Verlustrisiko, und die Ein-Position-Regel verhinderte überlappende Engagements.

Auch wenn diese Ergebnisse auf Basis nur einer Konfiguration und eines einzigen Marktes stammen, bestätigen sie doch, dass der Expert Advisor die Hidden-Smash-Day-Logik konsequent umsetzt und unter den getesteten Bedingungen ein stabiles Kapitalverhalten aufweist.

Mit der Strategie experimentieren

Eines der Hauptziele dieses Projekts ist es, ein strukturiertes Forschungsinstrument bereitzustellen und nicht etwa ein starres Handelssystem. Der Expert Advisor stellt mehrere Parameter zur Verfügung, mit denen experimentiert werden kann. Der Richtungsmodus, die Stop-Loss-Methode, das Risiko-Ertrags-Verhältnis, die ATR-Konfiguration und der Risikoprozentsatz können alle angepasst werden, ohne den Quellcode zu ändern.

Durch die Durchführung weiterer Tests mit anderen Symbolen, in anderen Zeitrahmen oder Parameterkombinationen lassen sich möglicherweise Situationen aufdecken, in denen sich das verborgene Smash-Day-Muster anders verhält oder eine bessere Performance erzielt. Es wird ausdrücklich empfohlen, diese Varianten auszuprobieren. Alle interessanten Erkenntnisse oder Verbesserungsvorschläge, die während der Tests gewonnen wurden, können in den Kommentaren zum Artikel geteilt werden, damit andere, die die Serie verfolgen, von der Diskussion profitieren können.

Nach diesem Artikel können Sie

  • Hidden-Smash-Day-Setups mithilfe präziser struktureller Regeln objektiv erkennen,
  • Signale anhand von abgeschlossenen Bars bestätigen, deren Schlusskurs über dem Extremwert der Smash-Bar liegt,
  • Trades automatisch bei neuen Bars durchführen, ohne dabei eigene Ermessensentscheidungen zu treffen,
  • das Risiko entweder mithilfe von strukturellen Stopps oder ATR-basierten Stopps steuern,
  • die Strategie im Strategietester von MetaTrader mit reproduzierbaren Einstellungen konsistent testen.


Systemeinschränkungen

Diese Implementierung konzentriert sich ausschließlich auf das Kernmuster Hidden-Smash-Day und dessen Bestätigungslogik. Mehrere Faktoren, die die Handelsperformanz beeinflussen könnten, werden bewusst ausgeklammert.

Der Expert Advisor wendet weder Trendfilter noch Marktregimefilter an. Dabei werden Schwankungen der Spreads, Handelssitzungen oder Nachrichtenereignisse nicht berücksichtigt. Auch die Behandlung von Lücken und fortgeschrittene Techniken zum Positionsmanagement fallen nicht in den Umfang dieser Implementierung.

Diese Auslassungen sind beabsichtigt. Ziel dieses Artikels ist es, eine klare und überprüfbare Grundlage zu schaffen, die die ursprüngliche Struktur des Musters widerspiegelt. Weitere Filter und Erweiterungen können in zukünftigen Experimenten oder späteren Teilen dieser Reihe untersucht werden.


Schlussfolgerung

In diesem Artikel wurde das Umkehrmuster Hidden-Smash-Day in einen vollständigen und testbaren MQL5-Expert-Advisor umgesetzt.

Die Setup-Regeln wurden anhand messbarer Bedingungen definiert, die auf der Spanne der Bar selbst und deren Verhältnis zum vorherigen Schlusskurs basieren. Eine Bestätigung wurde streng definiert als ein Schlusskurs einer vollständig abgeschlossenen Bar jenseits des Smash-Bar-Extrems. Handelsentscheidungen werden ausschließlich bei Eröffnung einer neuen Bar getroffen, um Unklarheiten bei unvollständigen Bars zu vermeiden.

Das Risikomanagement wurde direkt in das System integriert. Ein Stop-Loss kann strukturell auf dem Niveau der Smash-Bar gesetzt oder anhand des ATR berechnet werden. Der Gewinn ergibt sich aus einem festen Verhältnis von Ertrag zu Risiko. Bei der automatischen Positionsgrößenbestimmung wird OrderCalcProfit verwendet, um ein einheitliches finanzielles Risiko über alle Instrumente hinweg zu gewährleisten.

Nachdem Sie diesen Artikel gelesen haben, sind Sie nun in der Lage:

  • Hidden-Smash-Day-Setups objektiv zu erkennen;
  • eine konsistente Schlusskurs-Bestätigungsregel anzuwenden;
  •  Trades nur bei vollständig geschlossenen Bars durchzuführen;
  • zwischen strukturellen und volatilitätsbasierten Stopps zu wählen.
  • das Risiko über eine präzise prozentbasierte Positionsrisikosteuerung zu kontrollieren
  • die Testergebnisse anhand der bereitgestellten Konfigurationsdateien nachzustellen.

Das Endergebnis ist ein kompilierfertiger Expert Advisor, der das Hidden-Smash-Day-Muster ohne eigenmächtige Interpretation umsetzt. Das Framework kann getestet, angepasst und erweitert werden, wobei die ursprüngliche Regelstruktur erhalten bleibt.


Übersicht über angehängte Dateien

Um die Reproduktion und weitere Forschungsarbeiten zu erleichtern, sind alle in diesem Artikel verwendeten und zitierten Dateien im Anhang beigefügt. Die folgende Tabelle enthält eine kurze Beschreibung der einzelnen Dateien und ihres Zwecks. Diese Anhänge ermöglichen es, die Strategie eindeutig zu überprüfen, zu testen und zu erweitern.

Dateiname Beschreibung
lwHiddenSmashDayExpert.mq5 Der vollständige Quellcode des Expert Advisors, der in diesem Artikel entwickelt und erläutert wurde.
configurations.ini Konfiguration der Strategietester-Umgebung, die während des Backtests verwendet wurde.
parameters.set Der Eingabeparametersatz, der zur exakten Reproduktion der dargestellten Backtest-Ergebnisse verwendet wurde.
Jede Datei erfüllt im Forschungsprozess eine bestimmte Funktion. Der Quellcode ermöglicht die Überprüfung und Anpassung der Handelslogik, während die Konfigurations- und Parameterdateien dafür sorgen, dass Testbedingungen und -ergebnisse exakt reproduziert werden können. 


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

Beigefügte Dateien |
configurations.ini (1.49 KB)
parameters.set (1.37 KB)
Letzte Kommentare | Zur Diskussion im Händlerforum (1)
Mustafa Nail Sertoglu
Mustafa Nail Sertoglu | 6 März 2026 in 16:23

Danke für die Idee und die geteilten Codes...

Mit genau denselben Einstellungen hat der EA 4 Kauf-Trades und 2 SL / 2 TP ausgeführt – Gewinn 508 USD // Ich glaube, das liegt an den Unterschieden zwischen den Brokern ?!?


Ich habe D1, H1 und M5 als EA-Zeitrahmen ausprobiert, aber es wurden genau dieselben Trades zu denselben Zeitpunkten mit denselben SL- und TP-Ergebnissen ausgeführt.

Die Übertragung der Trading-Signale in einem universalen Expert Advisor. Die Übertragung der Trading-Signale in einem universalen Expert Advisor.
In diesem Artikel wurden die verschiedenen Möglichkeiten beschrieben, um die Trading-Signale von einem Signalmodul des universalen EAs zum Steuermodul der Positionen und Orders zu übertragen. Es wurden die seriellen und parallelen Interfaces betrachtet.
Entwicklung eines Toolkits zur Price-Action-Analyse (Teil 62): Entwicklung eines adaptiven Systems in MQL5 zur Erkennung paralleler Kanäle und den Ausbrüchen. Entwicklung eines Toolkits zur Price-Action-Analyse (Teil 62): Entwicklung eines adaptiven Systems in MQL5 zur Erkennung paralleler Kanäle und den Ausbrüchen.
Dieser Artikel stellt ein adaptives System zur Erkennung paralleler Kanäle und den Ausbrüchen daraus in MQL5 vor. Darin wird erläutert, wie Swing-Punkte ermittelt, Kanäle konstruiert und dynamisch neu berechnet werden und wie Ausbrüche durch persistente Signale bestätigt und visualisiert werden. Das Framework vereint Trendliniengeometrie, ATR-basierte Filterung und Retest-Validierung, um eine zuverlässige Kursanalyse in Echtzeit für professionelle Chartanalysen und Handelsentscheidungen zu ermöglichen.
Eine alternative Log-datei mit der Verwendung der HTML und CSS Eine alternative Log-datei mit der Verwendung der HTML und CSS
In diesem Artikel werden wir eine sehr einfache, aber leistungsfähige Bibliothek zur Erstellung der HTML-Dateien schreiben, dabei lernen wir auch, wie man eine ihre Darstellung einstellen kann (nach seinem Geschmack) und sehen wir, wie man es leicht in seinem Expert Advisor oder Skript hinzufügen oder verwenden kann.
Einführung in MQL5 (Teil 42): Leitfaden für Einsteiger zur Dateiverarbeitung in MQL5 (IV) Einführung in MQL5 (Teil 42): Leitfaden für Einsteiger zur Dateiverarbeitung in MQL5 (IV)
In diesem Artikel wird gezeigt, wie man einen MQL5-Indikator erstellt, der eine CSV-Datei mit der Handelshistorie ausliest, die Werte für „Profit($)“ und die Gesamtzahl der Trades extrahiert und die Entwicklung des kumulierten Saldos berechnet. Wir zeichnen die Kurve in einem separaten Indikatorfenster ein, passen die Y-Achse automatisch an und zeichnen horizontale und vertikale Achsen zur Orientierung ein. Der Indikator wird zeitgesteuert aktualisiert und nur dann neu gezeichnet, wenn neue Trades auftreten. Optionale Beschriftungen zeigen den Gewinn und Verlust pro Trade an, um die Performance und Drawdowns direkt im Chart beurteilen zu können.