English Русский 日本語
preview
Larry Williams’ Marktgeheimnisse (Teil 14): Erkennung versteckter Hidden-Smash-Day-Umkehrmuster mit einem benutzerdefinierten Indikator

Larry Williams’ Marktgeheimnisse (Teil 14): Erkennung versteckter Hidden-Smash-Day-Umkehrmuster mit einem benutzerdefinierten Indikator

MetaTrader 5Indikatoren |
24 2
Chacha Ian Maroa
Chacha Ian Maroa

Einführung

Hidden-Smash-Day-Muster lassen sich konzeptionell leicht beschreiben, aber im Chart nur schwer konsistent identifizieren. Das Muster beruht auf mehreren präzisen Bedingungen: Die Bar muss innerhalb eines bestimmten Bereichs ihrer Spanne schließen, der Schlusskurs muss in Relation zur vorherigen Bar stehen und das Setup wird erst nach Bestätigung durch die folgende Sitzung handelbar. Wenn diese Regeln visuell interpretiert werden, können kleine Unterschiede in der Interpretation zu unterschiedlichen Schlussfolgerungen darüber führen, ob ein gültiges Setup vorliegt.

Für algorithmische Trader und MQL5-Entwickler wird diese Mehrdeutigkeit zu einem praktischen Problem. Handelssysteme erfordern deterministische Regeln, die sich bei historischen Daten und im Echtzeitbetrieb identisch verhalten. Konzepte wie „unterer Teil der Bar“ oder „Bestätigung des Smash-Levels“ müssen daher in exakte numerische Bedingungen übersetzt werden, damit die Signalerkennung über verschiedene Durchläufe hinweg konsistent bleibt.

Eine praktische Lösung besteht darin, die Regeln für den Hidden-Smash-Day zu formalisieren und sie in einem Tool zu implementieren, das diese Setups automatisch erkennt. In diesem Artikel wird ein benutzerdefinierter MQL5-Indikator entwickelt, um das Hidden-Smash-Day-Muster mithilfe objektiver Bedingungen zu kodifizieren, wie etwa der Position des Schlusskurses innerhalb der Handelsspanne der Bar, seinem Verhältnis zum vorherigen Schlusskurs und der Bestätigungslogik, die in der nächsten Sitzung folgt.

Wenn ein gültiges Setup erkannt wird, markiert der Indikator das Chart visuell. Ein meergrüner Pfeil erscheint unter gültigen Hidden-Smash-Day-Kauf-Bars, während über gültigen Hidden-Smash-Day-Sell-Bars schwarze Pfeile erscheinen. Diese Signale bieten einen objektiven Referenzpunkt, der Tradern hilft, das Muster schnell zu erkennen und bei Bedarf zusätzliche kontextbezogene Filter anzuwenden.

Der Indikator wurde in erster Linie für algorithmische Trader entwickelt, die das Larry Williams Hidden-Smash-Day Setup objektiv beschreiben und dessen Erkennung automatisieren möchten, während das Signal zugleich in einer diskretionären Marktanalyse genutzt werden kann. Der Rest des Artikels erläutert die Struktur des Indikators, die zur Formalisierung des Musters verwendete Erkennungslogik und wie das Tool sowohl bei historischen Daten als auch bei Echtzeit-Chart-Aktualisierungen funktioniert.


Verständnis der Hidden-Smash-Day-Umkehrmuster

Hidden-Smash-Day-Muster sind eine spezielle Variante der Smash-Day-Umkehrmuster von Larry Williams. Auf den ersten Blick unterstützen diese Bars die aktuelle Marktrichtung. Ein genauerer Blick auf ihre innere Struktur offenbart jedoch eher Schwäche als Stärke. Dieser Widerspruch zwischen Schein und Sein ist es, der dem Muster seinen Namen gibt.

Die Schlüsselidee hinter einem Hidden-Smash-Day ist das Scheitern. Der Markt versucht, sich während der Sitzung stark in eine Richtung zu bewegen, aber diese Bewegung wird vor Handelsschluss wieder zurückgewiesen. Obwohl der Kurs die Sitzung leicht höher oder niedriger beenden mag, erzählt die Lage des Schlusskurses innerhalb der Bar eine ganz andere Geschichte.

Das Hidden-Smash-Day-Kauf-Setup

Ein Setup für Hidden-Smash-Day-Buy beginnt mit einer Bar, die höher schließt als die vorherige Bar. Oberflächlich betrachtet sieht dies bullisch aus. Das wichtige Detail ist jedoch, wo dieser Schlusskurs innerhalb der eigenen Spanne der Bar liegt.

Hidden-Smash-Day-Buy-Bar

Für eine gültige Hidden-Smash-Day-Buy-Bar muss der Schlusskurs im unteren Bereich der Handelsspanne der Bar liegen. Bei den stärksten Versionen des Musters liegt der Schlusskurs zudem unter dem Eröffnungskurs. Dies bedeutet, dass die Käufer bis zum Sitzungsende den Großteil der zuvor erzielten Gewinne nicht halten konnten. Die Rallye stieß auf Verkaufsdruck, und die Kaufbemühungen wurden effektiv neutralisiert.

Dies erzeugt eine Falle. Trader, die sich nur auf den höheren Schlusskurs konzentrieren, könnten die Bar als Stärke interpretieren, während die interne Struktur Erschöpfung signalisiert. Das Muster ist mit dieser einzelnen Bar noch nicht vollständig. Eine Bestätigung ist erforderlich.

Ein bullisches Signal wird nur bestätigt, wenn die folgende Bar über dem Hoch der Hidden-Smash-Day-Bar schließt. Wenn dies geschieht, zeigt es, dass die gescheiterte Bewegung umgekehrt wurde und die Nachfrage mit genügend Stärke zurückgekehrt ist, um die vorherige Ablehnung zu überwinden. Diese Abfolge aus gescheitertem Ausbruchsversuch und unmittelbarer Erholung bildet die Grundlage für das bullische Hidden-Smash-Day-Umkehrmuster.

Das Setup für Hidden-Smash-Day-Sell

Das Setup für Hidden-Smash-Day-Sell ist das Spiegelbild des Kauf-Setups. In diesem Fall schließt die Bar niedriger als die vorherige Bar, was zunächst bärisch erscheint. Wieder einmal erzählt die interne Struktur die wahre Geschichte.

Hidden-Smash-Day-Sell-Bar

Für eine gültige Hidden-Smash-Day-Sell-Bar muss der Schlusskurs im oberen Teil der Spanne der Bar liegen. Bei den stärksten Mustern liegt der Schlusskurs zudem über dem Eröffnungskurs. Dies deutet darauf hin, dass Verkäufer die Kurse während der Sitzung nach unten drückten, aber die Kontrolle nicht behalten konnten. Der Kurs erholte sich vor Handelsschluss in Richtung des Hochs der Bar, was die Schwäche des Verkaufsdrucks offenbart.

Dies erzeugt eine weitere Falle. Trader könnten den Schlusskurs im Minus als Bestätigung der Schwäche interpretieren, während die Bar selbst eine Ablehnung niedrigerer Kurse zeigt.

Ein bärisches Signal wird nur bestätigt, wenn die folgende Bar unter dem Tief der Hidden-Smash-Day-Bar schließt. Dieser Durchbruch nach unten bestätigt, dass die versuchte Erholung gescheitert ist und der Verkaufsdruck mit Überzeugung zurückgekehrt ist. Das Muster folgt erneut demselben Thema von Scheitern und unmittelbarer Umkehr.

Anstatt Umkehrungen vorherzusagen, warten Hidden-Smash-Day-Muster darauf, dass der Markt seine eigene Schwäche offenbart, und bestätigen dann den Umschwung durch die Kursbewegung. Dies macht sie besonders nützlich innerhalb eines regelbasierten Handelsrahmens und zu einem starken Kandidaten für die systematische Automatisierung.


Wie der Hidden-Smash-Day-Indikator konzipiert ist

Bevor wir tiefer in die Implementierung eintauchen, ist es wichtig, klar zu verstehen, wie der Indikator konzipiert ist, um Informationen visuell und logisch zu kommunizieren. Ein guter technischer Indikator sollte zwei Dinge gut beherrschen. Er sollte das Muster präzise identifizieren und in einem leicht lesbaren Format darstellen. Dieser Indikator wurde mit beiden Zielen im Hinterkopf entwickelt.

Die visuelle Sprache des Indikators ist bewusst einfach gehalten. Ein meergrüner Aufwärtspfeil wird direkt unter einer Hidden-Smash-Day-Buy-Bar gezeichnet. Dieser Pfeil hebt Momente hervor, in denen der bullische Druck während der Sitzung nachließ, was die Grundlage für eine potenzielle Aufwärtsumkehr bildet. Im Gegensatz dazu wird ein schwarzer Abwärtspfeil über einer Hidden-Smash-Day-Sell-Bar gezeichnet. Dies markiert Situationen, in denen der Verkaufsdruck anfangs dominant erschien, letztendlich aber scheiterte, was oft einer Abwärtsumkehr vorausgeht. Indem die Pfeile direkt an der Bar platziert werden, an der sich das Muster bildet, macht es der Indikator einfach, diese Setups zu erkennen, ohne das Chart zu überladen.

Neben der visuellen Darstellung ist Flexibilität ein zentrales Designelement. Hidden-Smash-Day-Muster können je nach Handelsstil und Bestätigungspräferenzen auf verschiedene Weise interpretiert werden. Aus diesem Grund unterstützt der Indikator zwei Identifikationsmodi, die über Eingabeparameter ausgewählt werden können.

Im ersten Modus wird eine Hidden-Smash-Day-Bar sofort markiert, sobald sie sich bildet und die Kriterien von Larry Williams erfüllt. Dieser Modus ist nützlich für Trader, die frühzeitig auf potenzielle Umkehrungen aufmerksam gemacht werden und das Kursverhalten nach dem Erscheinen des Setups genau beobachten möchten.

Im zweiten Modus wartet der Indikator auf eine Bestätigung, bevor er das Muster markiert. Bei einem Hidden-Smash-Day-Kauf-Setup erfolgt die Bestätigung nur, wenn die nächste Bar über dem Hoch der Hidden-Smash-Day-Bar schließt. Bei einem Verkaufs-Setup erfordert die Bestätigung, dass die nächste Bar unter dem Tief der Hidden-Smash-Day-Bar schließt. Dieser Ansatz filtert schwächere Setups heraus und konzentriert sich nur auf Muster, bei denen die Kursbewegung eine gescheiterte Bewegung eindeutig bestätigt.

Indem diese Modi als konfigurierbare Eingaben bereitgestellt werden, passt sich der Indikator an verschiedene Arbeitsabläufe an, ohne eine einzige Interpretation zu erzwingen. Trader können je nach Strategie und Risikotoleranz zwischen früher Signalerkennung und bestätigten Signalen wählen.

Um zu veranschaulichen, wie all diese Designentscheidungen zusammenwirken, ist unten ein Screenshot des fertigen Indikators auf einem Live-Chart dargestellt.

Indikator-Demo

Dieses Beispiel verdeutlicht, wie klar die Pfeile hervorstechen und wie natürlich sich der Indikator in ein übersichtliches Chart integriert, ohne es zu überladen.


Implementierung des Hidden-Smash-Day-Indikators in MQL5

Nachdem die Grundidee der Hidden-Smash-Day-Umkehrmuster klar definiert ist, besteht der nächste Schritt darin, dieses Konzept in einen funktionierenden benutzerdefinierten Indikator umzusetzen. In diesem Abschnitt beginnen wir mit der praktischen Implementierung unter Verwendung von MQL5. Das Ziel ist hier nicht, voreilig Signale zu generieren, sondern eine saubere, zuverlässige Grundlage zu schaffen, die eine genaue Erkennung und visuelle Markierung von Hidden-Smash-Day-Mustern unterstützt.

Bevor Sie mit dem Schreiben der Logik beginnen, ist es wichtig, die Entwicklungsumgebung ordnungsgemäß vorzubereiten. Dies umfasst ein grundlegendes Verständnis der MQL5-Syntax, Vertrautheit mit dem MetaTrader 5-Terminal und Sicherheit bei der Arbeit im MetaEditor. Mit diesen Voraussetzungen können wir fortfahren und den Indikator Schritt für Schritt aufbauen.

Die vollständige Implementierung des Indikators ist diesem Artikel als lwHiddenSmashDayIndicator.mq5 beigefügt. Es wird dringend empfohlen, die Beispiele aus der Anleitung selbst nachzuschreiben. Das manuelle Schreiben des Codes und der Vergleich mit der beigefügten Version hilft dabei, das Verständnis zu festigen und erleichtert die Fehlersuche, falls Probleme auftreten sollten.

Erstellen des Indikator-Grundgerüsts

Wir beginnen damit, eine neue leere benutzerdefinierte Indikator-Datei in MetaEditor zu erstellen. Der Dateiname kann frei gewählt werden, wobei die Verwendung desselben Namens wie bei der beigefügten Quelle zur Konsistenz beiträgt. Sobald die Datei erstellt ist, wird der anfängliche Standardcode eingefügt.

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

//+------------------------------------------------------------------+
//| Custom Indicator specific directives                             |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_plots 2
#property indicator_buffers 2

//+------------------------------------------------------------------+
//| Defines how Hidden Smash Day patterns are validated              |
//+------------------------------------------------------------------+
enum ENUM_HIDDEN_SMASH_VALIDATION_MODE
{
   HIDDEN_SMASH_BAR_ONLY,
   HIDDEN_SMASH_CONFIRMED
};

//+------------------------------------------------------------------+
//| Hidden Smash Detection Settings                                  |
//+------------------------------------------------------------------+
input ENUM_HIDDEN_SMASH_VALIDATION_MODE hiddenSmashValidationMode = HIDDEN_SMASH_CONFIRMED;

//+------------------------------------------------------------------+
//| Global Variables                                                 |
//+------------------------------------------------------------------+
ENUM_TIMEFRAMES timeframe = PERIOD_CURRENT;

//+------------------------------------------------------------------+
//| Indicator buffers                                                |
//+------------------------------------------------------------------+
double buySmashArrowBuffer [];
double sellSmashArrowBuffer[];

//+------------------------------------------------------------------+
//| Custom indicator 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);
} 
 
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int32_t  rates_total,
                const int32_t  prev_calculated,
                const datetime &time[],
                const double   &open[],
                const double   &high[],
                const double   &low[],
                const double   &close[],
                const long     &tick_volume[],
                const long     &volume[],
                const int32_t  &spread[])
{  

   ArraySetAsSeries(open,  false);
   ArraySetAsSeries(high,  false);
   ArraySetAsSeries(low,   false);
   ArraySetAsSeries(close, false);

   //--- Temporary buffers used to store price data for rendering custom colored candles
   double lwOpen [];
   double lwHigh [];
   double lwLow  [];
   double lwClose[];
   
   //--- Copy price data into local working buffers to safely manipulate candle values without altering the original price arrays
   ArrayCopy(lwOpen, open);
   ArrayCopy(lwHigh, high);
   ArrayCopy(lwLow, low);
   ArrayCopy(lwClose, close); 

   //--- This block will be executed whenever the indicator is initially attached to a chart
   if(prev_calculated == 0){
      
      //--- Start with clean arrays
      
   }
   
   //--- This block is executed on new bar open
   if(prev_calculated != rates_total && prev_calculated != 0){
      
      //--- Update buffers on new bar open
   
   }
   
   //--- This block is executed on arrival of new price (tick) data
   if(prev_calculated == rates_total){
      
      //--- Update buffers on new tick
      
   }
   
   return(rates_total);
}

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

//+------------------------------------------------------------------+

Dieser anfängliche Code definiert die Struktur des Indikators und bereitet alle wesentlichen Komponenten vor, die später erweitert werden. In diesem Stadium werden weder Handelslogik noch Mustererkennung ausgeführt. Der Fokus liegt auf Organisation, Klarheit und zukünftiger Erweiterbarkeit.

Indikatoreigenschaften und Metadaten

//+------------------------------------------------------------------+
//|                                    lwHiddenSmashDayIndicator.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 erste Abschnitt der Quelldatei definiert allgemeine Metadaten wie Urheberrechtsinformationen, Versionsnummer und Referenzlinks. Diese Deklarationen sind nicht nur Formalitäten. Sie sorgen für Klarheit über die Urheberschaft und helfen bei der Versionsverfolgung, während sich der Indikator weiterentwickelt.

Unmittelbar danach werden indikatorspezifische Anweisungen deklariert. Diese Anweisungen informieren das Terminal darüber, dass der Indikator direkt im Chartfenster gezeichnet wird und dass er zwei Plots und zwei Puffer verwendet. Diese Entscheidung spiegelt das Designziel wider, sowohl bullische als auch bärische Hidden-Smash-Day-Bars visuell mit Pfeilen zu markieren.

Konfiguration des Validierungsmodus

Hidden-Smash-Day-Muster können auf verschiedene Weise interpretiert werden. Einige Trader bevorzugen es, das Muster zu sehen, sobald sich die Bar bildet, während andere eine Bestätigung durch die folgende Bar benötigen. Um beide Ansätze zu unterstützen, wird eine benutzerdefinierte Enumeration definiert.

//+------------------------------------------------------------------+
//| Defines how Hidden Smash Day patterns are validated              |
//+------------------------------------------------------------------+
enum ENUM_HIDDEN_SMASH_VALIDATION_MODE
{
   HIDDEN_SMASH_BAR_ONLY,
   HIDDEN_SMASH_CONFIRMED
};

Die Enumeration für den Validierungsmodus führt zwei klare Optionen ein. Eine Option markiert die Hidden-Smash-Day-Bar sofort basierend auf seiner internen Struktur. Die andere Option markiert die Bar erst nach Bestätigung in der nächsten Sitzung. Diese Auswahl wird als Benutzereingabeparameter bereitgestellt, wodurch sich der Indikator an verschiedene Analysestile anpassen kann, ohne dass Codeänderungen erforderlich sind.

//+------------------------------------------------------------------+
//| Hidden Smash Detection Settings                                  |
//+------------------------------------------------------------------+
input ENUM_HIDDEN_SMASH_VALIDATION_MODE hiddenSmashValidationMode = HIDDEN_SMASH_CONFIRMED;

Durch die frühzeitige Einführung dieser Konfiguration bleibt die Indikatorlogik flexibel und vermeidet fest codierte Annahmen.

Globaler Gültigkeitsbereich und Zeitrahmenbehandlung

Eine globale Zeitrahmenvariable wird deklariert und auf den aktuellen Chart-Zeitrahmen gesetzt.

//+------------------------------------------------------------------+
//| Global Variables                                                 |
//+------------------------------------------------------------------+
ENUM_TIMEFRAMES timeframe = PERIOD_CURRENT;

Dies stellt sicher, dass sich der Indikator automatisch an jeden Chart anpasst, an den er angehängt wird. Unabhängig davon, ob der Chart stündlich, vierstündlich oder täglich ist, gilt dieselbe Logik ohne Änderung.

Dieser Ansatz entspricht den Prinzipien von Larry Williams und ermöglicht es ihm gleichzeitig, über mehrere Zeitrahmen hinweg zu arbeiten.

Indikator-Puffer und visuelle Ausgabe

Es werden zwei Indikator-Puffer deklariert.

//+------------------------------------------------------------------+
//| Indicator buffers                                                |
//+------------------------------------------------------------------+
double buySmashArrowBuffer [];
double sellSmashArrowBuffer[];

Ein Puffer ist für bullische Hidden-Smash-Day-Bars reserviert, der andere für bärische Hidden-Smash-Day-Bars. Diese Puffer speichern später Kurswerte, an denen Pfeile gezeichnet werden sollen.

In diesem Stadium sind die Puffer absichtlich leer. Der Indikator markiert nichts, bis gültige Bedingungen erkannt werden. Dies hält den Chart sauber und vermeidet irreführende Signale.

Die visuelle Absicht ist einfach und bewusst gewählt. Ein meergrüner Pfeil wird unter einem bullischen Hidden-Smash-Day-Bar gezeichnet, während ein schwarzer Pfeil über einem bärischen Hidden-Smash-Day-Bar gezeichnet wird. Diese Wahl von Farbe und Platzierung erzeugt einen unmittelbaren visuellen Kontrast und hilft Tradern, potenzielle Umkehrzonen schnell zu identifizieren.

Logik der Initialisierung

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

Innerhalb der Initialisierungsfunktion konfiguriert der Indikator das Erscheinungsbild des Charts. Der Hintergrund, die Barfarben und die Sichtbarkeit des Rasters werden angepasst, um die Klarheit und Lesbarkeit während der Analyse und des Tests zu verbessern.

Dieser Schritt hat keine Auswirkungen auf Kursdaten oder Indikatorberechnungen. Sein einziger Zweck ist es, eine saubere visuelle Umgebung zu schaffen, die die Mustererkennung erleichtert. Wenn die Chartkonfiguration aus irgendeinem Grund fehlschlägt, lädt der Indikator nicht weiter und meldet den Fehler. Dies schützt vor einer teilweisen oder irreführenden visuellen Ausgabe.

Berechnungs-Framework

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int32_t  rates_total,
                const int32_t  prev_calculated,
                const datetime &time[],
                const double   &open[],
                const double   &high[],
                const double   &low[],
                const double   &close[],
                const long     &tick_volume[],
                const long     &volume[],
                const int32_t  &spread[])
{  

   ArraySetAsSeries(open,  false);
   ArraySetAsSeries(high,  false);
   ArraySetAsSeries(low,   false);
   ArraySetAsSeries(close, false);

   //--- Temporary buffers used to store price data for rendering custom colored candles
   double lwOpen [];
   double lwHigh [];
   double lwLow  [];
   double lwClose[];
   
   //--- Copy price data into local working buffers to safely manipulate candle values without altering the original price arrays
   ArrayCopy(lwOpen, open);
   ArrayCopy(lwHigh, high);
   ArrayCopy(lwLow, low);
   ArrayCopy(lwClose, close); 

   //--- This block will be executed whenever the indicator is initially attached on a chart
   if(prev_calculated == 0){
      
      //--- Start with clean arrays
      
   }
   
   //--- This block is executed on new bar open
   if(prev_calculated != rates_total && prev_calculated != 0){
      
      //--- Update buffers on new bar open
   
   }
   
   //--- This block is executed on arrival of new price (tick) data
   if(prev_calculated == rates_total){
      
      //--- Update buffers on new tick
      
   }
   
   return(rates_total);
}

Die Berechnungsfunktion ist der Ort, an dem letztendlich die gesamte Indikatorlogik angesiedelt sein wird. Vorerst etabliert sie einen strukturierten Arbeitsablauf, der verschiedene Ausführungsszenarien voneinander trennt.

Kurs-Arrays werden sorgfältig behandelt, indem sie in lokale Arbeitspuffer kopiert werden. Dies ermöglicht eine sichere Datenmanipulation, ohne die ursprüngliche, vom Terminal bereitgestellte Zeitreihe der Kurse zu verändern.

Drei Ausführungspfade sind klar voneinander getrennt. Ein Pfad behandelt den Fall, dass der Indikator zum ersten Mal an einen Chart angehängt wird. Ein weiterer behandelt das Eintreffen einer neuen Bar. Der letzte Pfad behandelt eingehende Tick-Daten, während sich die aktuelle Bar bildet.

Diese Trennung ist beabsichtigt. Hidden-Smash-Day-Muster hängen von abgeschlossenen Bars und einer Bestätigungslogik ab. Durch die frühzeitige Organisation des Ausführungsablaufs stellen wir sicher, dass die Mustererkennung zum richtigen Zeitpunkt erfolgt und keine Signale neu zeichnet oder instabile Signale erzeugt.

In diesem Stadium sind diese Blöcke Platzhalter. Ihr Vorhandensein signalisiert, wo später Logik hinzugefügt wird, und stellt sicher, dass der Indikator auf kontrollierte und vorhersehbare Weise wächst.

Mit dieser Grundlage ist der nächste Schritt, die eigentliche Erkennungslogik für Hidden-Smash-Day Kauf- und Verkaufs-Setups einzuführen und sie mit den Indikatorpuffern zu verbinden. Von hier an baut jede Ergänzung natürlich auf dem auf, was bereits definiert wurde.

Zuerst stellen wir sicher, dass die Chart-Umgebung sauber und lesbar ist. Zweitens definieren wir wiederverwendbare Funktionen, die Hidden-Smash-Day-Muster genau so identifizieren, wie sie von Larry Williams beschrieben wurden. Drittens verbinden wir diese Funktionen mit dem Indikator-Lebenszyklus, sodass Muster historisch, bei neuen Bars und in Echtzeit erkannt werden. Jeder Schritt baut direkt auf dem vorherigen auf, wodurch der Indikator strukturiert, vorhersehbar und leicht zu warten bleibt.

Vorbereitung des Charts für visuelle Klarheit

Bevor eine Erkennungslogik angewendet wird, passen wir die Darstellung des Charts an, um sicherzustellen, dass visuelle Signale sowohl während des Tests als auch im Live-Betrieb leicht zu interpretieren sind.

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

Die Funktion ConfigureChartAppearance zentralisiert alle Regeln zur Chart-Gestaltung an einem einzigen Ort. Sie stellt einen hellen Hintergrund ein, entfernt unnötige Gitterlinien und wendet kontrastierende Farben auf bullische und bärische Bars an. Dies schafft eine neutrale visuelle Umgebung, in der die Pfeile des Indikators deutlich sichtbar bleiben.

Der Aufruf dieser Funktion innerhalb von OnInit stellt sicher, dass der Chart einmalig konfiguriert wird, unmittelbar nachdem der Indikator angehängt wurde, und beeinträchtigt nicht die Kursberechnungen oder Pufferaktualisierungen zu einem späteren Zeitpunkt.

Registrierung und Vorbereitung der Indikator-Puffer

Nachdem der Chart vorbereitet ist, besteht der nächste Schritt darin, die Indikator-Puffer zu initialisieren und zu registrieren. Der Indikator verwendet zwei Puffer:

  • Ein Puffer speichert Werte für bullische Hidden-Smash-Day-Bars.
  • Der zweite Puffer speichert Werte für bärische Hidden-Smash-Day-Bars.

Beide Puffer werden explizit auf Nicht-Zeitreihen-Indizierung gesetzt.

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit(){

   ...
   
   //--- Set arrays as series
   ArraySetAsSeries(buySmashArrowBuffer,  false);
   ArraySetAsSeries(sellSmashArrowBuffer, false);

   return(INIT_SUCCEEDED);
}

Dies bedeutet, dass Index 0 die älteste Bar in der Historie darstellt und nicht den aktuellsten. Diese Entscheidung ist bewusst und entscheidend, da die gesamte Erkennungslogik beim Durchlaufen historischer Daten von vorwärts indizierten Arrays ausgeht.

Nachdem die Richtung des Index-Puffers festgelegt wurde, werden die Puffer mit SetIndexBuffer registriert.

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit(){

   ...
   
   //--- Bind arrays to indicator buffers
   SetIndexBuffer(0, buySmashArrowBuffer,  INDICATOR_DATA);
   SetIndexBuffer(1, sellSmashArrowBuffer, INDICATOR_DATA);

   return(INIT_SUCCEEDED);
}

Von diesem Punkt an weiß MetaTrader genau, wo Daten gelesen werden müssen, wenn Pfeile im Chart dargestellt werden.

Definition der Erkennungslogik für Hidden-Smash-Day-Bars

Nachdem die Pufferinfrastruktur eingerichtet ist, können wir nun die Funktionen definieren, die Hidden-Smash-Day-Muster identifizieren. Es werden zwei Basisfunktionen erstellt, um die Basismuster zu erkennen:

Eine identifiziert bullische Hidden-Smash-Day-Bars.

//+------------------------------------------------------------------+
//| Identifies a Bullish Hidden Smash Bar at a specific index        |
//| Larry Williams definition applied to any timeframe               |
//+------------------------------------------------------------------+
bool IsHiddenSmashBuyBarAtIndex(
   const int i,
   const double &open[],
   const double &high[],
   const double &low[],
   const double &close[],
   const bool requireCloseBelowOpen = false
)
{
   // We need a previous bar to confirm an up close
   if(i < 1)
      return false;

   // 1. Must close higher than the previous bar
   if(close[i] <= close[i - 1])
      return false;

   // 2. Use the bar's own range
   double range = high[i] - low[i];
   if(range <= 0.0)
      return false;

   // 3. Close must be in the lower 25 percent of the bar range
   double lowerQuarter = low[i] + (range * 0.25);
   if(close[i] > lowerQuarter)
      return false;

   // 4. Best patterns only if requested
   if(requireCloseBelowOpen && close[i] >= open[i])
      return false;

   return true;
}

Die andere identifiziert bärische Hidden-Smash-Day-Bars.

//+------------------------------------------------------------------+
//| Identifies a Bearish Hidden Smash Bar at a specific index        |
//| Larry Williams definition applied to any timeframe               |
//+------------------------------------------------------------------+
bool IsHiddenSmashSellBarAtIndex(
   const int i,
   const double &open[],
   const double &high[],
   const double &low[],
   const double &close[],
   const bool requireCloseAboveOpen = false
)
{
   // We need a previous bar to confirm a down close
   if(i < 1)
      return false;

   // 1. Must close lower than the previous bar
   if(close[i] >= close[i - 1])
      return false;

   // 2. Use the bar's own range
   double range = high[i] - low[i];
   if(range <= 0.0)
      return false;

   // 3. Close must be in the upper 25 percent of the bar range
   double upperQuarter = high[i] - (range * 0.25);
   if(close[i] < upperQuarter)
      return false;

   // 4. Best patterns only if requested
   if(requireCloseAboveOpen && close[i] <= open[i])
      return false;

   return true;
}

Jede Funktion bewertet eine einzelne Bar an einem gegebenen Index und wendet die Regeln von Larry Williams präzise an. Für bullische Setups muss die Bar höher schließen als die vorherige Bar, während sie innerhalb des unteren Viertels ihrer eigenen Spanne endet. Für bärische Setups wird die Logik gespiegelt: Ein tieferer Schlusskurs und ein Ende innerhalb des oberen Viertels der Handelsspanne der Bar sind erforderlich.

Optionale Bedingungen ermöglichen die Durchsetzung der strengsten Versionen des Musters, wie etwa die Anforderung, dass der Schlusskurs für qualitativ besonders starke Setups unter oder über dem Eröffnungskurs liegen muss. Durch die Isolierung dieser Logik in dedizierte Funktionen bleibt der Indikator modular und später leicht erweiterbar.

Bestätigung von Hidden-Smash-Day-Mustern

Larry Williams betonte, dass das Verhalten der folgenden Bar die stärksten Hidden-Smash-Day-Muster bestätigt. Um dies zu unterstützen, werden zwei Bestätigungsfunktionen eingeführt. Ein bullisches Muster wird nur bestätigt, wenn die nächste Bar über dem Hoch der Hidden-Smash-Day-Bar schließt.

//+------------------------------------------------------------------+
//| Returns true if a Hidden Smash Day Buy pattern is confirmed      |
//| Confirmation requires next bar to close above smash bar high     |
//+------------------------------------------------------------------+
bool IsConfirmedHiddenSmashBuyAtIndex(const double &open[],
                                      const double &high[],
                                      const double &low[],
                                      const double &close[],
                                      int index
                                      )
{
   int confirmationIndex = index + 1;

   // Ensure confirmation bar exists
   if(confirmationIndex >= ArraySize(close))
      return false;

   // Smash bar must be valid
   if(!IsHiddenSmashBuyBarAtIndex(index, open, high, low, close))
      return false;

   // Confirmation close above smash bar high
   if(close[confirmationIndex] > high[index])
      return true;

   return false;
}

Ein bärisches Muster wird nur bestätigt, wenn die nächste Bar unter dem Tief der Hidden-Smash-Day-Bar schließt.

//+------------------------------------------------------------------+
//| Returns true if a Hidden Smash Day Sell pattern is confirmed     |
//| Confirmation requires next bar to close below smash bar low      |
//+------------------------------------------------------------------+
bool IsConfirmedHiddenSmashSellAtIndex(const double &open[],
                                       const double &high[],
                                       const double &low[],
                                       const double &close[],
                                       int index
                                       )
{
   int confirmationIndex = index + 1;

   // Ensure confirmation bar exists
   if(confirmationIndex >= ArraySize(close))
      return false;

   // Smash bar must be valid
   if(!IsHiddenSmashSellBarAtIndex(index, open, high, low, close))
      return false;

   // Confirmation close below smash bar low
   if(close[confirmationIndex] < low[index])
      return true;

   return false;
}

Diese Bestätigungsfunktionen verwenden die Erkennungslogik ohne Bestätigung wieder und fügen einen Validierungsschritt hinzu. Dieser Ansatz vermeidet Duplikate und stellt eine konsistente Musterbewertung im gesamten Indikator sicher.

Zuordnung der Muster bei der Initialisierung

Wenn der Indikator erstmals an einen Chart angehängt wird, wurden noch keine historischen Muster verarbeitet. Um dies zu handhaben, wird eine dedizierte Initialisierungs-Mapping-Funktion eingeführt.

//+------------------------------------------------------------------+
//| Scans historical bars and maps Hidden Smash patterns on load     |
//+------------------------------------------------------------------+
void MapHiddenSmashPatternsOnInitialization(
   const int rates_total,
   const double &open[],
   const double &high[],
   const double &low [],
   const double &close[],
   int hidden_SmashValidationMode,
   double closePercentThreshold = 25.0
)
{
   //--- Safety check
   if(rates_total <= 1)
      return;

   //--- Loop through all historical bars
   for(int i = 1; i <= rates_total - 1; i++)
   {
      //--- Default to empty
      buySmashArrowBuffer[i]  = EMPTY_VALUE;
      sellSmashArrowBuffer[i] = EMPTY_VALUE;

      //--- Mode 1: Bar only identification
      if(hiddenSmashValidationMode == HIDDEN_SMASH_BAR_ONLY)
      {
         if(IsHiddenSmashBuyBarAtIndex(i, open, high, low, close))
         {
            buySmashArrowBuffer[i] = low[i];
         }

         if(IsHiddenSmashSellBarAtIndex(i, open, high, low, close))
         {
            sellSmashArrowBuffer[i] = high[i];
         }
      }
      //--- Mode 2: Confirmed pattern identification
      else if(hiddenSmashValidationMode == HIDDEN_SMASH_CONFIRMED)
      {
         if(IsConfirmedHiddenSmashBuyAtIndex(open, high, low, close,
                                             i))
         {
            buySmashArrowBuffer[i] = low[i];
         }

         if(IsConfirmedHiddenSmashSellAtIndex(open, high, low, close,
                                              i))
         {
            sellSmashArrowBuffer[i] = high[i];
         }
      }
   }
}

Diese Funktion durchläuft alle verfügbaren historischen Bars und bewertet jeden einzelnen gemäß dem gewählten Validierungsmodus. Im ungefilterten Erkennungsmodus werden Bars einzeln bewertet. Wenn der Bestätigungsmodus ausgewählt ist, werden die Bars zusammen mit der bestätigenden Folge-Bar bewertet.

Jedes gültige Muster führt dazu, dass ein Pfeilwert in den entsprechenden Puffer geschrieben wird. Alle anderen Bars bleiben leer, wodurch sichergestellt wird, dass nur echte Hidden-Smash-Day-Muster angezeigt werden. Diese Logik wird einmal innerhalb des Blocks prev_calculated == 0 ausgeführt, um unnötige Neuberechnungen zu vermeiden.

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int32_t  rates_total,
                const int32_t  prev_calculated,
                const datetime &time[],
                const double   &open[],
                const double   &high[],
                const double   &low[],
                const double   &close[],
                const long     &tick_volume[],
                const long     &volume[],
                const int32_t  &spread[])
{  

   ...

   //--- This block will be executed whenever the indicator is initially attached on a chart
   if(prev_calculated == 0){
      
      //--- Start with clean arrays
      ArrayInitialize(buySmashArrowBuffer,  EMPTY_VALUE);
      ArrayInitialize(sellSmashArrowBuffer, EMPTY_VALUE);
      
      //--- Map all hidden smash bar patterns
      MapHiddenSmashPatternsOnInitialization(rates_total, lwOpen, lwHigh, lwLow, lwClose, hiddenSmashValidationMode);
      
   }
   
   ...
   
   return(rates_total);
}

Aktualisierung von Mustern bei Bildung neuer Bars

Märkte bleiben nicht statisch, daher muss der Indikator auf neue Bars reagieren, sobald sie sich bilden. Wenn eine neue Bar erscheint, wertet der Indikator die zuletzt abgeschlossene Bar aus und aktualisiert die Pufferwerte entsprechend.

//+------------------------------------------------------------------+
//| Evaluates hidden smash patterns on new bar formation             |
//| Updates indicator buffers for the recently completed bar         |
//+------------------------------------------------------------------+
void ProcessHiddenSmashOnNewBar(
   const double &open[],
   const double &high[],
   const double &low[],
   const double &close[],
   int rates_total
)
{
   int completedBarIndex = rates_total - 2;
   int currentBarIndex   = rates_total - 1;

   //--- Safety check
   if(completedBarIndex < 0)
      return;

   //--- Always clear buffers for involved bars
   buySmashArrowBuffer [completedBarIndex] = EMPTY_VALUE;
   sellSmashArrowBuffer[completedBarIndex] = EMPTY_VALUE;

   buySmashArrowBuffer [currentBarIndex]   = EMPTY_VALUE;
   sellSmashArrowBuffer[currentBarIndex]   = EMPTY_VALUE;

   //--- Mode 1: Detect bar only
   if(hiddenSmashValidationMode == HIDDEN_SMASH_BAR_ONLY)
   {
      if(IsHiddenSmashBuyBarAtIndex(completedBarIndex, open, high, low, close))
         buySmashArrowBuffer[completedBarIndex] = low[completedBarIndex];

      if(IsHiddenSmashSellBarAtIndex(completedBarIndex, open, high, low, close))
         sellSmashArrowBuffer[completedBarIndex] = high[completedBarIndex];

      return;
   }

   //--- Mode 2: Confirmed smash
   if(hiddenSmashValidationMode == HIDDEN_SMASH_CONFIRMED)
   {
      int smashBarIndex = completedBarIndex - 1;
      if(smashBarIndex < 0)
         return;

      if(IsHiddenSmashBuyBarAtIndex(smashBarIndex, open, high, low, close))
      {
         if(close[completedBarIndex] > high[smashBarIndex])
            buySmashArrowBuffer[smashBarIndex] = low[smashBarIndex];
      }

      if(IsHiddenSmashSellBarAtIndex(smashBarIndex, open, high, low, close))
      {
         if(close[completedBarIndex] < low[smashBarIndex])
            sellSmashArrowBuffer[smashBarIndex] = high[smashBarIndex];
      }
   }
}

Dies stellt sicher, dass Muster zeitnah erkannt werden, ohne die gesamte Historie neu zu verarbeiten. Eine separate Logik handhabt die ungefilterte Erkennung und die bestätigte Erkennung, wodurch sichergestellt wird, dass Pfeile je nach gewähltem Modus am korrekten Barindex erscheinen.

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int32_t  rates_total,
                const int32_t  prev_calculated,
                const datetime &time[],
                const double   &open[],
                const double   &high[],
                const double   &low[],
                const double   &close[],
                const long     &tick_volume[],
                const long     &volume[],
                const int32_t  &spread[])
{  
   ...

   //--- This block is executed on new bar open
   if(prev_calculated != rates_total && prev_calculated != 0){
      
      //--- Update buffers on new bar open
      ProcessHiddenSmashOnNewBar(lwOpen, lwHigh, lwLow, lwClose, rates_total);
   
   }
   
   ...
   
   return(rates_total);
}

Dieser Ansatz gleicht Leistung mit Genauigkeit aus und hält den Indikator auch auf niedrigeren Zeitrahmen reaktionsfähig.

Unterstützung von Echtzeit-Tick-Updates

Um den Indikator unter Live-Marktbedingungen nutzbar zu machen, ist auch eine Echtzeit-Tick-Verarbeitung implementiert.

//+------------------------------------------------------------------+
//| Evaluates hidden smash patterns on tick updates                  |
//| Supports real-time detection and confirmation logic              |
//+------------------------------------------------------------------+
void ProcessHiddenSmashOnTick(
   const double &open[],
   const double &high[],
   const double &low[],
   const double &close[],
   int rates_total
)
{
   int currentBarIndex   = rates_total - 1;
   int completedBarIndex = rates_total - 2;

   if(currentBarIndex < 0)
      return;

   //--- Always reset current bar buffer values
   buySmashArrowBuffer [currentBarIndex] = EMPTY_VALUE;
   sellSmashArrowBuffer[currentBarIndex] = EMPTY_VALUE;

   //--- Mode 1: Bar-only detection in real time
   if(hiddenSmashValidationMode == HIDDEN_SMASH_BAR_ONLY)
   {
      if(IsHiddenSmashBuyBarAtIndex(currentBarIndex, open, high, low, close))
         buySmashArrowBuffer[currentBarIndex] = low[currentBarIndex];

      if(IsHiddenSmashSellBarAtIndex(currentBarIndex, open, high, low, close))
         sellSmashArrowBuffer[currentBarIndex] = high[currentBarIndex];

      return;
   }

   //--- Mode 2: Confirmed smash evaluated continuously
   if(hiddenSmashValidationMode == HIDDEN_SMASH_CONFIRMED)
   {
      int smashBarIndex = completedBarIndex;
      if(smashBarIndex < 0)
         return;

      if(IsHiddenSmashBuyBarAtIndex(smashBarIndex, open, high, low, close))
      {
         if(close[currentBarIndex] > high[smashBarIndex])
            buySmashArrowBuffer[smashBarIndex] = low[smashBarIndex];
      }

      if(IsHiddenSmashSellBarAtIndex(smashBarIndex, open, high, low, close))
      {
         if(close[currentBarIndex] < low[smashBarIndex])
            sellSmashArrowBuffer[smashBarIndex] = high[smashBarIndex];
      }
   }
}

Bei jedem eingehenden Tick wertet der Indikator die aktuelle Bar aus und passt die Pufferwerte dynamisch an.

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int32_t  rates_total,
                const int32_t  prev_calculated,
                const datetime &time[],
                const double   &open[],
                const double   &high[],
                const double   &low[],
                const double   &close[],
                const long     &tick_volume[],
                const long     &volume[],
                const int32_t  &spread[])
{  
   ...

   //--- This block is executed on arrival of new price (tick) data
   if(prev_calculated == rates_total){
      
      //--- Update buffers on new tick
      ProcessHiddenSmashOnTick(lwOpen, lwHigh, lwLow, lwClose, rates_total);
      
   }
   
   return(rates_total);
}

Dies ermöglicht es, dass noch unbestätigte Hidden-Smash-Day-Bars sofort bei ihrer Entstehung erscheinen und bestätigte Muster aktualisiert werden, sobald die Bestätigungsbedingungen erfüllt sind. Diese Echtzeit-Reaktionsfähigkeit macht den Indikator zu einem praktischen Instrument für eine diskretionäre Marktanalyse und aktives Monitoring.

Konfiguration der visuellen Ausgabe mit Pfeil-Plots

Selbst mit korrekten Pufferwerten erscheint nichts im Chart, es sei denn, dem Indikator wird mitgeteilt, wie er seine Daten darstellen soll. Die pfeilbasierten Plots werden in OnInit über die Funktionen PlotIndexSetInteger, PlotIndexSetDouble und PlotIndexSetString konfiguriert.

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit(){

   ...
   
   //--- Configure Graphic Plots   
   PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_ARROW);
   PlotIndexSetInteger(0, PLOT_ARROW, 233);
   PlotIndexSetInteger(0, PLOT_LINE_COLOR, clrSeaGreen);
   PlotIndexSetInteger(0, PLOT_ARROW_SHIFT, +20);
   PlotIndexSetInteger(0, PLOT_LINE_WIDTH, 2);
   PlotIndexSetDouble (0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetString (0, PLOT_LABEL, "Hidden Smash Buy Bar");
   
   PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_ARROW);
   PlotIndexSetInteger(1, PLOT_ARROW, 234);
   PlotIndexSetInteger(1, PLOT_LINE_COLOR, clrBlack);
   PlotIndexSetInteger(1, PLOT_ARROW_SHIFT, -20);
   PlotIndexSetInteger(1, PLOT_LINE_WIDTH, 2);
   PlotIndexSetDouble (1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetString (1, PLOT_LABEL, "Hidden Smash Sell bar");
   
   //--- General indicator configurations
   IndicatorSetString(INDICATOR_SHORTNAME, "Larry Williams Market Structure Indicator");

   return(INIT_SUCCEEDED);
}

Bullische Hidden-Smash-Day-Bars werden mit Aufwärtspfeilen markiert, die unter dem Kurs platziert sind. Bärische Hidden-Smash-Day-Bars werden mit Abwärtspfeilen markiert, die über dem Kurs platziert sind. Farbe, Größe, Verschiebung und Beschriftungen werden explizit definiert, um eine konsistente Darstellung über Symbole und Zeitrahmen hinweg zu gewährleisten. Sobald diese Plots konfiguriert sind, ist der Indikator visuell vollständig.

In diesem Stadium ist der Indikator voll funktionsfähig. Er erkennt Hidden-Smash-Day-Muster nach den Regeln von Larry Williams, unterstützt mehrere Validierungsmodi, aktualisiert sich dynamisch bei Marktveränderungen und stellt klare visuelle Signale im Chart dar.

Die vollständige Implementierung ist in der beigefügten Quelldatei mit dem Namen lwHiddenSmashDayIndicator.mq5 enthalten. In der Praxis ist es vorzuziehen, auf die beigefügte Datei zu verweisen, anstatt den vollständigen Quellcode in den Artikel einzubetten.

Dieser Abschnitt schließt die vollständige Entwicklung des Hidden-Smash-Day-Indikators ab und bereitet die Grundlage für Tests, Interpretation und weitere Experimente.


Tests und visuelle Inspektion

Wir beginnen mit der Kompilierung des Indikator-Quellcodes in MetaEditor. Wenn alle Schritte sorgfältig befolgt wurden, sollte der Code ohne Fehler oder Warnungen kompilieren. Eine erfolgreiche Kompilierung bestätigt, dass alle Funktionen korrekt definiert, Puffer ordnungsgemäß registriert und die Indikatorlogik strukturell einwandfrei sind.

Sollten Kompilierungsfehler auftreten, ist der sicherste Ansatz, die aktuelle Arbeitsdatei mit dem beigefügten Quellcode namens lwHiddenSmashDayIndicator.mq5 zu vergleichen. Kleine Unterschiede in Funktionssignaturen oder Pufferhandhabung können leicht zu Problemen führen, und ein Abgleich mit der Referenzimplementierung hilft, diese schnell zu lösen.

Sobald die Kompilierung erfolgreich ist, kann der Indikator an ein Chart angehängt werden. Nach dem Laden sollten sofort Pfeile auf historischen Bars erscheinen, auf denen basierend auf dem gewählten Validierungsmodus gültige Hidden-Smash-Day-Muster identifiziert wurden. Bullische Muster werden mit meergrünen Pfeilen unter dem Kurs markiert, während bärische Muster mit schwarzen Pfeilen über dem Kurs markiert werden.

Hier ist ein Screenshot, der zeigt, wie der fertige Indikator auf einem Live-Chart aussieht.

Hidden-Smash-Day-Bar-Muster

Diese visuelle Bestätigung hilft dabei, sowohl die Erkennungslogik als auch die Darstellungskonfiguration zu validieren.

Von hier aus lohnt es sich, den Indikator über verschiedene Symbole und Zeitrahmen hinweg zu untersuchen. Da die Musterlogik auf die eigene Spanne jeder Bar angewendet wird, passt sie sich natürlich sowohl an Intraday-Charts als auch an höhere Zeitrahmen an. Die Beobachtung, wie sich Hidden-Smash-Day-Muster unter verschiedenen Marktbedingungen verhalten, kann neue Forschungsideen und praktische Anwendungen eröffnen.


Schlussfolgerung

Dieser Artikel befasste sich mit einer praktischen Herausforderung in der technischen Analyse. Hidden-Smash-Day-Umkehrmuster sind konzeptionell einfach, doch ihre konsistente Erkennung auf einem Chart kann schwierig sein, da ihre Setups von mehreren präzisen strukturellen Bedingungen abhängen. Dazu gehören das Verhältnis zwischen aufeinanderfolgenden Schlusskursen, die Position des Schlusskurses innerhalb der Handelsspanne der Bar und die Bestätigung durch die folgende Handelssitzung. Ohne objektive Regeln können verschiedene Beobachter denselben Chart unterschiedlich interpretieren.

Um diese Mehrdeutigkeit zu beseitigen, wurde das Konzept des Hidden-Smash-Day von Larry Williams in diesem Artikel in ein präzises Erkennungsmodell übersetzt und als benutzerdefinierter MQL5-Indikator namens lwHiddenSmashDayIndicator.mq5 implementiert. Der Indikator bewertet abgeschlossene Bars anhand expliziter Regeln, die das Muster beschreiben. Er prüft das Verhältnis zwischen dem Schlusskurs und der vorherigen Bar, bestimmt, ob der Schlusskurs innerhalb des definierten Bereichs der Handelsspanne der Bar liegt, und identifiziert gültige Kauf- und Verkauf-Setups. Wenn ein Setup erkannt wird, markiert der Indikator es direkt im Chart mithilfe visueller Pfeile, wodurch das Muster sofort sichtbar wird.

Der Indikator wurde so konzipiert, dass er sich sowohl bei historischen Daten als auch bei Live-Charts konsistent verhält. Während der Initialisierung scannt er historische Bars, um zuvor gebildete Setups abzubilden. Während des Betriebs bewertet er neue abgeschlossene Bars und aktualisiert Signale in Echtzeit, sobald neue Kursdaten eintreffen. Dieser Lebenszyklus-Ansatz stellt sicher, dass Signale über verschiedene Instrumente und Zeitrahmen hinweg stabil und reproduzierbar bleiben.

Über den fertigen Indikator hinaus demonstriert die Implementierung mehrere nützliche Entwicklungstechniken für MQL5-Programmierer. Dazu gehören modulare Funktionen zur Mustererkennung, eine strukturierte Verwaltung von Indikatorpuffern, kontrolliertes Scannen der Historie während der Initialisierung sowie Echtzeit-Aktualisierungen auf Basis neuer Barereignisse.

Nach dem Studium dieses Artikels können wir:
  • Hidden-Smash-Day Kauf- und Verkauf-Setups objektiv auf einem Chart erkennen
  • Das Umkehrmuster von Larry Williams direkt mithilfe eines benutzerdefinierten Indikators visualisieren
  • Das Muster konsistent über verschiedene Instrumente und Zeitrahmen hinweg untersuchen
  • Die Erkennungslogik für Forschungszwecke oder zur Integration in automatisierte Systeme erweitern
  • Zusätzliche Kontextfilter bei der Analyse potenzieller Handelsmöglichkeiten anwenden
Der resultierende Indikator dient daher sowohl diskretionären als auch algorithmischen Zwecken. Er bietet eine klare visuelle Referenz für Trader, die das Hidden-Smash-Day-Muster untersuchen, und stellt gleichzeitig eine strukturierte Grundlage bereit, die zu automatisierten Handelssystemen oder umfassenderen Forschungsrahmen erweitert werden kann.


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

Beigefügte Dateien |
Letzte Kommentare | Zur Diskussion im Händlerforum (2)
Israr Hussain Shah
Israr Hussain Shah | 16 März 2026 in 16:08
Danke dafür
Chacha Ian Maroa
Chacha Ian Maroa | 16 März 2026 in 16:26
Israr Hussain Shah #:
Danke dafür
Gern geschehen
Der MQL5-Standardbibliotheks-Explorer (Teil 9): Verwendung von ALGLIB zur Filterung übermäßiger MA-Crossover-Signale Der MQL5-Standardbibliotheks-Explorer (Teil 9): Verwendung von ALGLIB zur Filterung übermäßiger MA-Crossover-Signale
Bei Seitwärtsbewegungen des Kurses sehen sich Händler mit übermäßigen Signalen aus mehreren Kreuzungen gleitender Durchschnitte konfrontiert. Heute besprechen wir, wie ALGLIB ungefilterte Kursdaten vorverarbeitet, um gefilterte Crossover-Ebenen bzw. -Darstellungen zu erzeugen, die bei ihrem Auftreten auch Alarme oder Benachrichtigungen auslösen können. Nehmen Sie an dieser Diskussion teil, um zu erfahren, wie eine mathematische Bibliothek in MQL5-Programmen genutzt werden kann.
Vereinheitlichte Validierungspipeline gegen Backtest-Overfitting Vereinheitlichte Validierungspipeline gegen Backtest-Overfitting
Dieser Artikel erklärt, warum Standard-Walk-Forward und k-fache Cross-Validation Ergebnisse bei Finanzdaten systematisch zu positiv erscheinen lassen, und zeigt dann, wie dies behoben werden kann. V-in-V erzwingt strikte Datenpartitionen und verankertes Walk-Forward über Zeitfenster hinweg, CPCV bereinigt Datenlecks mittels Purging und Embargo und aggregiert die Performance auf Pfadebene, und CSCV misst die Wahrscheinlichkeit von Backtest-Overfitting. Anwender erhalten einen kohärenten Rahmen zur Bewertung der Robustheit über verschiedene Marktregime hinweg und der Verlässlichkeit der Strategieauswahl.
Integration von MQL5 mit Datenverarbeitungspaketen (Teil 8): Einsatz von Graph Neural Networks zur Erkennung von Liquiditätszonen Integration von MQL5 mit Datenverarbeitungspaketen (Teil 8): Einsatz von Graph Neural Networks zur Erkennung von Liquiditätszonen
Dieser Artikel zeigt, wie man die Marktstruktur in MQL5 als Graph darstellt, indem Swing-Highs/-Lows in Knoten mit Merkmalen umgewandelt und durch Kanten miteinander verbunden werden. Es wird ein Graph Neural Network trainiert, um potenzielle Liquiditätszonen zu bewerten, das Modell nach ONNX exportiert und für die Echtzeit-Inferenz in einem Expert Advisor verwendet. Die Leser lernen, wie man die Daten-Pipeline aufbaut, das Modell integriert, Zonen im Chart visualisiert und die Signale für eine regelbasierte Handelsausführung nutzt.
Vom Einsteiger zum Experten: Optimierung von Liquiditätsstrategien durch strukturelle Bestätigung über mehrere Zeitrahmen in MQL5 Vom Einsteiger zum Experten: Optimierung von Liquiditätsstrategien durch strukturelle Bestätigung über mehrere Zeitrahmen in MQL5
Die Abstimmung von Liquiditätsstrukturen höherer Zeitrahmen mit Umkehrmustern niedrigerer Zeitrahmen kann sowohl die Wahrscheinlichkeit als auch die Richtung der nächsten Preisbewegung stark beeinflussen. Durch die Integration struktureller Liquiditätszonen aus höheren Zeitrahmen mit präzisen Umkehrbestätigungen auf niedrigeren Zeitrahmen können Trader das Einstiegs-Timing und die Qualität ihrer Trades insgesamt verbessern. Dieser Artikel zeigt, wie man liquiditätsbasierte Handelsstrategien durch strukturelle Bestätigung auf höheren Zeitrahmen verstärkt – und wie man diesen Ansatz effektiv mit MQL5 umsetzt.