English Русский 日本語
preview
Larry Williams’ Marktgeheimnisse (Teil 11): Erkennen von „Smash-Day“-Umkehrungen mit einem Indikator

Larry Williams’ Marktgeheimnisse (Teil 11): Erkennen von „Smash-Day“-Umkehrungen mit einem Indikator

MetaTrader 5Indikatoren |
101 7
Chacha Ian Maroa
Chacha Ian Maroa

Einführung

Der Versuch, jede starke „Smash-Day“-Umkehr auf dem Chart zu handeln, kann schnell zu Rauschen, Frustration und uneinheitlichen Ergebnissen führen. Auf den ersten Blick erscheint das logisch. Ein starker Ausbruch, auf den unmittelbar ein Scheitern folgt, führt oft zu kräftigen Bewegungen in die entgegengesetzte Richtung. Wenn man jedoch jedes Signal ohne Kontext für bare Münze nimmt, führt dies in der Regel zu Rauschen, Frustration und uneinheitlichen Ergebnissen.

In seinem Buch Long-term Secrets to Short-term Trading bringt Larry Williams einen wichtigen Punkt auf den Punkt. Diese Muster stehen für Momente emotionaler Überreaktionen, in denen die Masse einem scheinbaren Ausbruch hinterherjagt, nur um dann durch eine plötzliche Kehrtwende in die Falle zu tappen. Diese emotionale Falle ist sehr wirkungsvoll, aber sie sollte nicht bedingungslos hingenommen werden. Williams betont immer wieder, dass die besten Ergebnisse erzielt werden, wenn diese Muster mit dem allgemeinen Marktbild übereinstimmen, einschließlich der vorherrschenden Trends und anderer begünstigender Rahmenbedingungen.

Dies stellt diskretionäre Händler vor eine praktische Herausforderung. Wie lassen sich diese seltenen, aber aussagekräftigen Muster schnell und objektiv erkennen, ohne dass daraus ein starres, automatisiertes System entsteht, das den Kontext außer Acht lässt?

Die in diesem Artikel vorgestellte Lösung ist ein benutzerdefinierter MQL5-Indikator, der die „Smash-Days“-Umkehrungen visualisiert. Anstatt Trades automatisch zu eröffnen, zeigt er genau auf, wo sich ein gültiges Muster gebildet hat und wann der Kurs die Trendumkehr bestätigt, indem er das Niveau der „Smash-Bar“ durchbricht. Bei bullischen Umkehrungen erscheint ein deutlicher Aufwärtspfeil, bei bärischen Umkehrungen ein deutlicher Abwärtspfeil. Von diesem Moment an liegt die endgültige Entscheidung im menschlichen Ermessen.

Indem dieser Indikator die objektiven Musterregeln von Larry Williams in klare, zeitnahe Chart-Signale umsetzt, macht er das Erkennen von Mustern weniger von Vermutungen abhängig und ermöglicht es den Tradern dennoch, ihre eigenen Filter anzuwenden, wie beispielsweise Trendrichtung, Auswirkungen von Nachrichten und Marktstruktur. Er dient als Brücke zwischen roher Price Action und durchdachtem diskretionärem Trading und ist keine mechanische Blackbox.


„Smash-Day“-Umkehrungen auf einen Blick erkennen

Eine „Smash-Day“-Umkehr beginnt mit einer starken, emotionalen Bewegung in eine Richtung, die einen Ausbruch zu bestätigen scheint. Der Kurs schloss außerhalb der jüngsten Kursspanne, was darauf hindeutet, dass sich die Dynamik fortsetzen wird. Anstatt diesen Trend fortzusetzen, scheitert der Markt schnell und dreht in der nächsten Sitzung in die entgegengesetzte Richtung zurück. Dieses plötzliche Scheitern lockt späte Breakout-Trader in die Falle und führt oft zu einer starken Bewegung in die entgegengesetzte Richtung.

Nach einem heftigen Kursrückgang zeichnet sich eine bullische Smash-Umkehr ab. Die Smash-Bar schließt unterhalb der Tiefs einer oder mehrerer vorheriger Bars, ist jedoch keine „Outside-Bar“. Dieses Detail ist wichtig, da die Bewegung eher von Druck als von Unentschlossenheit getrieben wird. Wenn die nächste Bar über dem Hoch dieser „Smash-Bar“ steigt, erweist sich der Abwärtsdurchbruch als falsch, und es wird eine Umkehr nach oben signalisiert.

Eine bärische Smash-Umkehr ist das Spiegelbild davon. Die Smash-Bar schließt oberhalb der Höchststände mehrerer vorheriger Bars, ohne den vorherigen Kursbereich zu umschließen. Wenn die nächste Bar unter das Tief dieser „Smash-Bar“ fällt, scheitert der Aufwärtsausbruch, und es kommt zu einer Abwärtsumkehr.

Der Kerngedanke ist einfach. Eine Bewegung, die zunächst stark genug erscheint, um fortgesetzt zu werden, kann plötzlich ihre Position nicht mehr halten. Dieses Scheitern schafft Chancen.

Der vollständige Regelsatz und die Gründe für die einzelnen Bedingungen wurden im vorherigen Artikel dieser Reihe ausführlich behandelt, in dem ein Expert Advisor entwickelt wurde, um diese Muster automatisch zu handeln. In diesem Artikel konzentrieren wir uns auf die visuelle Erkennung. Es werden dieselben objektiven Regeln angewendet, doch anstatt Trades zu eröffnen, markiert der Indikator den Chart, sobald sich eine gültige Trendwende bestätigt. Dadurch lässt sich das Muster sofort erkennen, während die endgültige Handelsentscheidung dem menschlichen Urteilsvermögen überlassen bleibt.


Smash-Muster in klare visuelle Signale umwandeln

Das Ziel dieses Indikators ist es nicht, in unserem Namen zu handeln, sondern dafür zu sorgen, dass wichtige Chart-Momente nicht übersehen werden können. Anstatt jede einzelne Bar einzeln zu überprüfen, um festzustellen, ob gerade eine „Smash-Day“-Umkehr stattgefunden hat, führt der Indikator diese Überprüfung kontinuierlich durch und markiert genau die Bar, bei der die Bestätigung erfolgt.

Wenn sich eine bullische „Smash-Day“-Umkehr bestätigt, wird unterhalb der „Smash-Bar“ ein seegrüner Pfeil eingezeichnet. Dies geschieht in dem Moment, in dem der aktuelle Formationsbar über das Hoch dieses „Smash-Bars“ steigt. Dieser Ausbruch nach oben zeigt uns, dass der starke Verkaufsdruck des Vortages nachgelassen hat und der Kurs versucht, wieder nach oben zu drehen.

Wenn sich eine bärische „Smash-Day“-Umkehr bestätigt, wird oberhalb der „Smash-Bar“ ein schwarzer Pfeil eingezeichnet. Dies tritt ein, sobald der Kurs der sich gerade bildenden Bar unter das Tief der „Smash-Bar“ fällt. Der Abwärtsdurchbruch zeigt, dass der starke Kaufdruck nicht anhalten konnte, was darauf hindeutet, dass der Kurs nun nach unten tendiert.

Diese Pfeile dienen als unmittelbare visuelle Hinweise. Sie zeigen genau die Bar an, bei der deutlich wird, dass der Ausbruch gescheitert ist. Ab diesem Zeitpunkt bleibt die eigentliche Ausführung des Trades dem Ermessen des Traders überlassen. Ein Trader nimmt das Signal möglicherweise nur dann auf, wenn es mit dem übergeordneten Trend übereinstimmt. Manche warten vielleicht auf durch Nachrichten ausgelöste Kursschwankungen oder auf einen bestimmten Wochentag. Der Indikator liefert das Ereignis. Der Händler liefert den Kontext.

Larry Williams betonte zudem, dass die Definition einer „Smash-Bar“ objektiv, aber flexibel sein sollte. In der Praxis bedeutet dies, dass der „Smash-Bar“ über die Extremwerte einer bestimmten Anzahl vorheriger Bars hinausgehen muss. Manche Trader bevorzugen einen kürzeren Lookback-Zeitraum, um mehr Signale zu erfassen. Andere ziehen es vor, weiter in die Vergangenheit zurückzublicken und sich dabei ausschließlich auf die ausgeprägteren Extreme zu konzentrieren. Um beide Ansätze zu unterstützen, stellt der Indikator Eingabeparameter bereit, mit denen die Rückblick-Tiefe frei angepasst werden kann.

Dieses Konzept sorgt für eine strenge und mechanische Logik und berücksichtigt dabei dennoch den persönlichen Handelsstil. Der Indikator beantwortet eine Frage präzise. Soeben wurde eine gültige Smash-Umkehr bestätigt. Was als Nächstes geschieht, hängt von den eigenen Filtern und der eigenen Einschätzung des Traders ab.

Um das Ergebnis besser veranschaulichen zu können, finden Sie hier einen Screenshot des Indikators auf einem Live-Chart.

Smash-Umkehrsignale


Schritt für Schritt zum Indikator

Voraussetzungen, bevor wir beginnen

Bevor man mit der eigentlichen Programmierarbeit beginnt, sind einige Grundkenntnisse erforderlich, damit der Prozess reibungslos verläuft. Wir setzen Kenntnisse der Programmiersprache MQL5 und ihrer grundlegenden Bausteine wie Variablen, Funktionen, Arrays und bedingte Logik voraus. Wir setzen außerdem voraus, dass Sie bereits Erfahrung mit dem MetaTrader 5-Desktop-Terminal haben, einschließlich des Öffnens von Charts und des Einbindens von Indikatoren.

Zudem findet die Entwicklung innerhalb von MetaEditor statt. Daher ist es wichtig, dass Sie sicher im Umgang mit dem Erstellen neuer Quelldateien, dem Kompilieren von Code und der Überprüfung etwaiger Fehler sind, die während der Kompilierung auftreten können. Nachdem diese Grundlagen nun geschaffen sind, können wir zuversichtlich damit fortfahren, den Indikator von Grund auf neu zu entwickeln.

Programmieren anhand der fertigen Version

Der vollständige und voll funktionsfähige Quellcode des Indikators ist diesem Artikel unter dem Namen lwSmashDayReversalIndicator.mq5 beigefügt. Es wird dringend empfohlen, die Beispiele aus der Anleitung selbst nachzuschreiben. Indem man jede Zeile selbst schreibt und das Ergebnis anschließend mit der beigefügten fertigen Datei vergleicht, wird der Lernprozess praxisnah und zuverlässig. Sollte etwas nicht kompilieren oder sich nicht wie erwartet verhalten, dient der beigefügte Quellcode als klare Referenz für eine schnelle Korrektur. Das Ziel besteht nicht nur darin, am Ende einen funktionierenden Indikator zu erhalten, sondern auch darin, zu verstehen, wie die einzelnen Teile genau aufgebaut sind.

Erstellen der Basisdatei des Indikators

Der erste praktische Schritt besteht darin, den MetaEditor zu öffnen und eine neue Quelldatei für einen benutzerdefinierten Indikator zu erstellen. Der Dateiname kann beliebig sein, solange er aussagekräftig ist. Nachdem die leere Datei erstellt wurde, wird der folgende Basiscode darin eingefügt.

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

//+------------------------------------------------------------------+
//| User input variables                                             |
//+------------------------------------------------------------------+
input int smashBuyLookbackBars  = 1;
input int smashSellLookbackBars = 1;

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

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

Dieser erste Block legt die Grundstruktur des Indikators fest. Es führt noch keine Mustererkennung durch. Stattdessen bereitet es die Umgebung vor, auf die sich die spätere Logik stützen wird.

Dieser Startcode lässt sich in mehrere logische Teile unterteilen. Jeder Teil erfüllt einen klaren Zweck und bereitet den Indikator auf zukünftige Erweiterungen vor.

Die Eigenschaften des Indikators

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

Im Abschnitt Eigenschaften wird festgelegt, wie sich der Indikator im Chart verhält. Der Indikator wird direkt im Hauptchartfenster und nicht in einem separaten Fenster angezeigt. Es werden zwei Plots und zwei Puffer reserviert. In diesen Puffern werden später die Kurswerte gespeichert, an denen Kauf- und Verkaufspfeile erscheinen. Zum jetzigen Zeitpunkt ist noch kein Zeichenstil festgelegt. Die Puffer fungieren als leere Behälter, die darauf warten, gefüllt zu werden.

Einstellungen für Benutzereingaben

Es werden zwei Eingabevariablen deklariert.

//+------------------------------------------------------------------+
//| User input variables                                             |
//+------------------------------------------------------------------+
input int smashBuyLookbackBars  = 1;
input int smashSellLookbackBars = 1;

Diese Werte legen fest, wie viele vorherige Bars der Schlusskurs des „Smash-Bars“ unterschreiten muss. Indem man sie als Eingabewerte beibehält, bleibt der Indikator flexibel. Derselbe Code kann später mit unterschiedlichen Strengeniveaus getestet werden, ohne dass der Quellcode bearbeitet werden muss.
Dies spiegelt Larry Williams’ Vorstellung wider, dass die Stärke des Musters davon abhängt, wie weit der Markt in eine extreme Richtung gedrückt wird.

Zeitrahmen-Referenz

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

Eine Zeitrahmenvariable wird auf den aktuellen Chartzeitraum gesetzt. Dadurch passt sich der Indikator automatisch an das jeweilige Chart an, an das er angehängt ist. In den Indikatoreinstellungen muss kein Zeitrahmen manuell ausgewählt werden. Alle Preisabfragen entsprechen daher der angezeigten Grafik.

Indikator-Puffer

Es werden zwei Arrays deklariert.

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

In jedem Array werden später die Preisniveaus gespeichert, an denen Pfeile eingezeichnet werden sollen. Wenn ein Wert an einem bestimmten Barindex in einen Puffer geschrieben wird, erscheint an diesem Bar ein Pfeil. Wenn ein leerer Wert geschrieben wird, wird nichts gezeichnet. Diese Puffer stellen die visuelle Ausgabe des gesamten Indikators dar.

Initialisierungsphase

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

Die Funktion OnInit wird einmal ausgeführt, wenn der Indikator an das Chart angehängt wird. Hier wird die Chart-Darstellung über eine Hilfsfunktion konfiguriert. Der Hintergrund ist weiß, bullische Bars sind grün dargestellt, bärische Bars sind schwarz dargestellt und das Raster ist ausgeblendet. Dadurch entsteht ein übersichtliches, kontrastreiches Chart, sodass spätere Pfeile und Linien während des Testens gut erkennbar sind. Sollte eine Charteinstellung fehlschlagen, wird die Initialisierung abgebrochen und ein Fehler gemeldet. Dadurch wird verhindert, dass der Indikator in einem unvollständig konfigurierten Zustand läuft.

Berechnungsschleife

//+------------------------------------------------------------------+
//| 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[])
{
   
   return(rates_total);
}

In der Funktion OnCalculate wird die gesamte zukünftige Erkennungslogik untergebracht. Derzeit gibt die Funktion lediglich die Gesamtzahl der Bar zurück. Das bedeutet, dass der Indikator aktiv ist, aber noch keine Analyse durchgeführt hat. In den folgenden Abschnitten wird diese Funktion erweitert, sodass bei jedem neuen Tick und jedem neuen Bar die Pfeilpuffer in Echtzeit aktualisiert werden können.

Hilfsprogramm zur Darstellung von Charts

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

Die Funktion ConfigureChartAppearance fasst alle visuellen Charteinstellungen an einem einzigen Ort zusammen. Durch die Trennung dieser Logik bleibt die Initialisierung übersichtlich und gut lesbar. Sollten später optische Anpassungen erforderlich sein, können diese hier vorgenommen werden, ohne die Hauptlogik zu verändern. Dadurch wird außerdem sichergestellt, dass das Chart bei jeder Einbindung des Indikators einheitlich erstellt wird.

Auch wenn dieser Code noch keine Pfeile zeichnet, bildet er doch eine wichtige Grundlage. Es legt fest, wie viele visuelle Ausgabekomponenten es geben wird, reserviert dafür Speicherplatz, stellt sicher, dass das Chart gut lesbar ist, und richtet die Hauptberechnungsschleife ein, in der später die Logik zur Erkennung von Smash-Tagen ausgeführt wird. Wenn man mit einer klaren und minimalistischen Grundlage beginnt, lässt sich jede neue Funktion Schritt für Schritt hinzufügen, ohne dass Verwirrung entsteht. 

Entwicklung der Logik für den „Smash-Day-Reversal“-Indikator

Zum jetzigen Zeitpunkt verfügt der Indikator über seine Grundstruktur und leere Puffer. Das nächste Ziel besteht darin, diese Puffer mit dem Terminal zu verbinden und anschließend die Logik zu erstellen, die sie an den richtigen Bars mit aussagekräftigen Werten füllt. Der Vorgang umfasst drei einfache Schritte. Zunächst stellen wir sicher, dass genügend historische Daten vorliegen.

Zweitens binden wir unsere Arrays an Indikatorpuffer. Drittens schreiben wir kleine, zielgerichtete Funktionen, die Muster erkennen und die Puffer sowohl im Verlauf als auch in Echtzeit aktualisieren.

Überprüfung, ob genügend historische Daten vorliegen

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

   ...
   
   //--- Ensure there are enough historical bars available before running smash pattern detection
   int totalRates = iBars(_Symbol, timeframe);
   if(totalRates <= smashBuyLookbackBars || totalRates <= smashSellLookbackBars){
      Print("There is not enough historical data!");
      return INIT_FAILED;
   }

   return(INIT_SUCCEEDED);
}

Bevor mit der Mustererkennung begonnen wird, stellen wir sicher, dass der Chart über genügend Bars verfügt, um die erforderlichen Rückblickprüfungen zuverlässig durchführen zu können. Wenn die Anzahl der verfügbaren Bar kleiner oder gleich der gewählten Rückblick-Tiefe ist, bricht der Indikator die Initialisierung ab. Dadurch wird verhindert, dass beim Zugriff auf ältere Bars ein Index außerhalb des zulässigen Bereichs verwendet wird. Diese einfache Sicherheitsmaßnahme stellt sicher, dass alle nachfolgenden Funktionen mit gültigen Daten arbeiten und verhindert Laufzeitfehler.

Verknüpfung von Arrays mit Indikatorpuffern

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

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

   return(INIT_SUCCEEDED);
}

Nach der Validierung der Daten werden die Arrays, die die Pfeilwerte enthalten, mithilfe von SetIndexBuffer innerhalb der Initialisierungsroutine mit den Pufferindizes verknüpft. Jeder Pufferindex entspricht einer grafischen Darstellung im Chart. Puffer Null wird für Kaufpfeile verwendet. Puffer 1 wird für Verkaufspfeile verwendet. Ab diesem Zeitpunkt wird durch das Schreiben eines Preiswerts in ein Pufferelement ein grafisches Objekt genau an dieser Bar platziert. Wenn Sie EMPTY_VALUE eingeben, wird es ausgeblendet.

Erkennen von „Outside-Bars“

Eine kleine Hilfsfunktion prüft, ob eine Bar den Bereich der vorherigen Bar vollständig umschließt.

//+-----------------------------------------------------------------------------+
//| Checks whether the bar at the given index fully engulfs the prior bar range |
//+-----------------------------------------------------------------------------+
bool IsOutsideBar(double &open[], double &high[], double &low[], double &close[], int index){

   double high0 = high[index];
   double low0  = low [index];

   double high1 = high[index - 1];
   double low1  = low [index - 1];

   return (high0 > high1 && low0 < low1);
}

Eine „Outside-Bar“ wird bei der Smash-Erkennung ignoriert, da sie eine Ausdehnung in beide Richtungen darstellt und keinen eindeutigen emotionalen Impuls in eine Richtung signalisiert. Indem man diese Bar frühzeitig herausfiltert, wird die nachfolgende Logik übersichtlicher und objektiver. Diese Funktion dient als gemeinsamer Baustein sowohl für bullische als auch für bärische Smash-Checks.

Erkennen einer bullischen Smash-Umkehr

//+-----------------------------------------------------------------------------------+
//| Detects a Smash Day Buy Reversal where the close breaks below multiple prior lows |
//+-----------------------------------------------------------------------------------+
bool IsSmashDayBuyReversal(double &open[], double &high[], double &low[], double &close[],
                           int index,
                           int lookbackBars)
{
   // Bar must not be an outside bar
   if(IsOutsideBar(open, high, low, close, index)){
      return false;
   }

   double close1 = close[index];
   double close2 = close[index + 1];
   double high1  = high[index];

   // Validate close breaks below N prior lows
   for(int i = index-1; i>=(index - lookbackBars); i--){
   
      double priorLow = low[i];

      if(close1 >= priorLow){
         return false;
      }      
   }

   return close2 > high1;
}

Eine bullische Smash-Umkehr wird erkannt, wenn drei Bedingungen erfüllt sind. Die Bar darf keine „Outside-Bar“ sein. Sein Schlusskurs muss unter die Tiefststände einer bestimmten Anzahl früherer Bars fallen. Die nächste Bar muss wieder über dem Hoch der Smash-Bar steigen. Diese endgültige Bestätigung zeigt, dass der Durchbruch gescheitert ist und die Käufer die Kontrolle zurückgewonnen haben. Wenn alle Bedingungen erfüllt sind, gibt die Funktion true zurück, und das Tief dieser Bar wird in den Kaufpuffer geschrieben.

Erkennen einer bärischen Smash-Umkehr

//+-------------------------------------------------------------------------------------+
//| Detects a Smash Day Sell Reversal where the close breaks above multiple prior highs |
//+-------------------------------------------------------------------------------------+
bool IsSmashDaySellReversal(double &open[], double &high[], double &low[], double &close[],
                            int index,
                            int lookbackBars)
{
   // Bar must not be an outside bar
   if(IsOutsideBar(open, high, low, close, index)){
      return false;
   }

   double close1 = close[index];
   double close2 = close[index + 1];
   double low1   = low  [index];

   // Validate close breaks above N prior highs
   for(int i = index-1; i>=(index - lookbackBars); i--){
      
      double priorHigh = high[i];

      if(close1 <= priorHigh){
         return false;
      }
      
   }

   return close2 < low1;
}

Die bärische Logik spiegelt die bullische wider. Die Bar darf keine „Outside-Bar“ sein. Der Schlusskurs muss über die Hochs der vorherigen Bars steigen. Der nächste Bar muss wieder unterhalb des Tiefs der „Smash-Bar“ schließen. Dies deutet darauf hin, dass ein Ausbruch nach oben gescheitert ist und die Verkäufer die Oberhand gewonnen haben. Wird dies erkannt, wird der Höchstwert dieses Bars in den Verkaufspuffer geschrieben.

Alle historischen Muster erfassen

Wenn der Indikator zum ersten Mal auf das Chart angewendet wird, muss er den gesamten historischen Datenverlauf durchgehen und jedes gültige Smash-Muster markieren. Diese Aufgabe wird von zwei Abbildungsfunktionen übernommen.

//+-------------------------------------------------------------------------------------------------+
//| Scans historical price data to identify buy-side smash day reversals and populate the buy arrow |
//+-------------------------------------------------------------------------------------------------+
void MapBuySmashDayReversals(double &open[], double &high[], double &low[], double &close[]){
   int totalRates = ArraySize(open);
   for(int i = smashBuyLookbackBars; i < totalRates - 1; i++){
      if(IsSmashDayBuyReversal(open, high, low, close, i, smashBuyLookbackBars)){
         buySmashArrowBuffer[i] = low[i];
      }else{
         buySmashArrowBuffer[i] = EMPTY_VALUE;
      }
   }
}

//+--------------------------------------------------------------------------------------------------------------------+
//| Scans historical price data to identify sell-side smash day reversals and populate the sell arrow and line buffers |
//+--------------------------------------------------------------------------------------------------------------------+
void MapSelSmashDayReversals(double &open[], double &high[], double &low[], double &close[]){
   int totalRates = ArraySize(open);
   for(int i = smashSellLookbackBars; i < totalRates - 1; i++){
      if(IsSmashDaySellReversal(open, high, low, close, i, smashSellLookbackBars)){
         sellSmashArrowBuffer[i] = high[i];
      }else{
         sellSmashArrowBuffer[i] = EMPTY_VALUE;
      }
   }
}

Man scannt und füllt den Kaufpuffer. Das andere Programm liest den Verkaufspuffer ein und füllt ihn. Jeder Bar wird mithilfe der Erkennungsfunktionen geprüft. Wird ein gültiges Muster gefunden, wird der Puffer mit dem Extremwert der Bar gefüllt. Andernfalls wird das Pufferelement auf EMPTY_VALUE gesetzt. In diesem Schritt wird die gesamte visuelle Chronik auf einmal erstellt.

Puffer in Echtzeit aktualisieren

Nach der anfänglichen Zuordnung muss der Indikator weiterhin auf neue Kursdaten reagieren. Es werden zwei Aktualisierungsmodi verwendet. Wenn ein neuer Bar eröffnet wird, wird der zuvor abgeschlossene Bar überprüft und festgeschrieben, sofern er eine bestätigte Smash-Umkehr bildet.

//+----------------------------------------------------------------------------------------------------------------+
//|Updates the buy arrow buffer in real time when a bullish smash reversal is detected on the latest completed bar |
//+----------------------------------------------------------------------------------------------------------------+
void UpdateBuySmashArrowBufferOnTick (double &open[], double &high[], double &low[], double &close[], int32_t rates_total){
   
   if(IsSmashDayBuyReversal(open, high, low, close, rates_total - 2, smashBuyLookbackBars)){
      buySmashArrowBuffer[rates_total - 2] = low[rates_total - 2];
   }else{
      buySmashArrowBuffer[rates_total - 2] = EMPTY_VALUE;
   }   
}

//+-----------------------------------------------------------------------------------------------------------------+
//|Updates the sell arrow buffer in real time when a bearish smash reversal is detected on the latest completed bar |
//+-----------------------------------------------------------------------------------------------------------------+
void UpdateSellSmashArrowBufferOnTick(double &open[], double &high[], double &low[], double &close[], int32_t rates_total){
     
   if(IsSmashDaySellReversal(open, high, low, close, rates_total - 2, smashSellLookbackBars)){
      sellSmashArrowBuffer[rates_total - 2] = high[rates_total - 2];
   }else{
      sellSmashArrowBuffer[rates_total - 2] = EMPTY_VALUE;
   }   
}

Wenn Kursdaten innerhalb des aktuellen Bars eintreffen, wird der zuletzt abgeschlossene Bar erneut überprüft.

//+-----------------------------------------------------------------------------------------------------+
//|Updates the buy arrow buffer at the moment a new bar forms to mark confirmed bullish smash reversals |
//+-----------------------------------------------------------------------------------------------------+
void UpdateBuySmashArrowBufferOnNewBar (double &open[], double &high[], double &low[], double &close[], int32_t rates_total){
   
   if(IsSmashDayBuyReversal(open, high, low, close, rates_total - 3, smashBuyLookbackBars)){
      buySmashArrowBuffer[rates_total - 3] = low[rates_total - 3];
   }else{
      buySmashArrowBuffer[rates_total - 3] = EMPTY_VALUE;
   }   
}

//+------------------------------------------------------------------------------------------------------+
//|Updates the sell arrow buffer at the moment a new bar forms to mark confirmed bearish smash reversals |
//+------------------------------------------------------------------------------------------------------+
void UpdateSellSmashArrowBufferOnNewBar(double &open[], double &high[], double &low[], double &close[], int32_t rates_total){
     
   if(IsSmashDaySellReversal(open, high, low, close, rates_total - 3, smashSellLookbackBars)){
      sellSmashArrowBuffer[rates_total - 3] = high[rates_total - 3];
   }else{
      sellSmashArrowBuffer[rates_total - 3] = EMPTY_VALUE;
   }   
}

Dadurch wird der Pfeil sofort nach der Bestätigung angezeigt, ohne dass auf einen weiteren Bar gewartet werden muss. Diese kleinen Aktualisierungsfunktionen betreffen nur den aktuellsten relevanten Index. Dadurch bleibt die Berechnung überschaubar und schnell.

Aufbereitung von Preisdaten für eine sichere Verarbeitung

Die von der Plattform bereitgestellten Preis-Arrays sind schreibgeschützt. Um frei mit ihnen arbeiten zu können, werden ihre Werte in lokale Arrays kopiert.

//+------------------------------------------------------------------+
//| 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[])
{  
   ...

   //--- 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);
   
   return(rates_total);
}

Die Reihenfolge der Indizes wird ebenfalls geändert, sodass der Index Null auf den ältesten Bar und der letzte Index auf den neuesten Bar verweist. Alle Hilfsfunktionen gehen von dieser zeitlichen Reihenfolge aus. Dieser Vorbereitungsschritt gewährleistet eine einheitliche Indizierung und verhindert, dass plattforminterne Daten verändert werden.

Erstladung im Vergleich zu Live-Updates

Die Berechnungsroutine unterscheidet zwischen zwei Momenten. Beim ersten Anbringen des Indikators werden alle historischen Muster erfasst und beide Puffer auf EMPTY_VALUE initialisiert, bevor Signale geschrieben werden.

//+------------------------------------------------------------------+
//| 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){
      ArrayInitialize(buySmashArrowBuffer,  EMPTY_VALUE);
      ArrayInitialize(sellSmashArrowBuffer, EMPTY_VALUE);
      
      //---
      MapBuySmashDayReversals(lwOpen, lwHigh, lwLow, lwClose);
      MapSelSmashDayReversals(lwOpen, lwHigh, lwLow, lwClose);
      
   }
   
   return(rates_total);
}

Danach löst jeder neue Bar und jeder eingehende Tick nur noch kleine, gezielte Aktualisierungen mithilfe der Echtzeit-Aktualisierungsfunktionen aus.

//+------------------------------------------------------------------+
//| 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){
      
      //---
      UpdateBuySmashArrowBufferOnNewBar (lwOpen, lwHigh, lwLow, lwClose, rates_total);
      UpdateSellSmashArrowBufferOnNewBar(lwOpen, lwHigh, lwLow, lwClose, rates_total);
   
   }   

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

Durch diese Aufteilung bleibt die Logik übersichtlich und effizient.

Nachfolgend sehen wir die endgültige Form der Funktion OnCalculate nach Abschluss der Indikatorentwicklung dargestellt.

//+------------------------------------------------------------------+
//| 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){
      ArrayInitialize(buySmashArrowBuffer,  EMPTY_VALUE);
      ArrayInitialize(sellSmashArrowBuffer, EMPTY_VALUE);
      
      //---
      MapBuySmashDayReversals(lwOpen, lwHigh, lwLow, lwClose);
      MapSelSmashDayReversals(lwOpen, lwHigh, lwLow, lwClose);
      
   }
   
   //--- This block is executed on new bar open
   if(prev_calculated != rates_total && prev_calculated != 0){
      
      //---
      UpdateBuySmashArrowBufferOnNewBar (lwOpen, lwHigh, lwLow, lwClose, rates_total);
      UpdateSellSmashArrowBufferOnNewBar(lwOpen, lwHigh, lwLow, lwClose, rates_total);
   
   }
   
   //--- This block is executed on arrival of new price (tick) data
   if(prev_calculated == rates_total){
      
      //---
      UpdateBuySmashArrowBufferOnTick (lwOpen, lwHigh, lwLow, lwClose, rates_total);
      UpdateSellSmashArrowBufferOnTick(lwOpen, lwHigh, lwLow, lwClose, rates_total);      
   }
   
   return(rates_total);
}

Diese Funktion dient als zentrale Ausführungsroutine des Indikators und koordiniert die Mustererkennung sowie die Pufferaktualisierungen auf kontrollierte und effiziente Weise.

Zu Beginn jedes Aufrufs werden die Kurs-Arrays in eine nicht serielle Indizierung umgewandelt. Dies ist beabsichtigt, da alle zugehörigen Hilfsfunktionen von vorwärts indizierten Daten ausgehen, bei denen ältere Bars zuerst und neuere Bars zuletzt erscheinen. Die Beibehaltung eines einheitlichen Indizierungsmodells verhindert subtile Logikfehler im weiteren Verlauf des Erkennungsprozesses.

Anschließend werden lokale Arbeits-Arrays erstellt und mit Kopien der Preisdaten gefüllt. Die vom Terminal bereitgestellten Quell-Arrays sind schreibgeschützt, sodass sie durch Kopieren sicher bearbeitet und in verschiedenen Hilfsfunktionen wiederverwendet werden können, ohne die Originaldaten zu verändern.

Wenn der Indikator zum ersten Mal in ein Chart eingefügt wird, führt die Funktion eine vollständige Analyse der historischen Daten durch. Alle Indikatorpuffer werden mit leeren Werten initialisiert, um einen sauberen Ausgangszustand zu gewährleisten. Anschließend wird jede gültige „Smash-Day“-Umkehr in der verfügbaren Historie erkannt und markiert. Dadurch wird sichergestellt, dass das Chart sofort mit allen relevanten Signalen gefüllt wird.

Bei nachfolgenden Aufrufen unterteilt die Funktion ihre Logik in zwei Fälle: ob sich ein neuer Bar gebildet hat und ob innerhalb des aktuellen Bars neue Kursdaten eingegangen sind. Wenn eine neue Bar eröffnet wird, werden bestätigte Smash-Reversals aus der kürzlich geschlossenen Bar ausgewertet und in die Puffer geschrieben. Wenn ausschließlich Tick-Daten empfangen werden, prüft die Funktion auf eine Echtzeit-Bestätigung von Smash-Umkehrungen und aktualisiert die aktuellsten Pufferwerte entsprechend.

Diese Struktur stellt sicher, dass historische Muster, neu bestätigte Bars und aktuelle Kursbewegungen korrekt verarbeitet werden, ohne dass es zu Doppelzählungen oder fehlenden Signalen kommt. Die Funktion gibt stets die Gesamtzahl der berechneten Bar zurück, wodurch das Terminal inkrementelle Aktualisierungen effizient verwalten kann.

Pfeile im Chart sichtbar machen.

//+------------------------------------------------------------------+
//| 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, "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, "Smash Sell bar");
   
   return(INIT_SUCCEEDED);
}

Selbst nachdem die Puffer gefüllt sind, wird nichts angezeigt, bis dem Terminal mitgeteilt wird, wie sie dargestellt werden sollen. Jeder Puffer ist als Pfeildiagramm dargestellt. Unter den bullischen „Smash-Bars“ wird ein seegrüner Pfeil eingezeichnet. Über den bärischen „Smash-Bars“ wird ein schwarzer Pfeil eingezeichnet. Pfeilcodes, Farben, Breite, vertikale Verschiebung und leere Werte werden alle bei der Initialisierung festgelegt. Dadurch werden die Rohdaten aus dem Puffer in sichtbare Chartsignale umgewandelt.

Dem Indikator einen eindeutigen Namen geben

Es wird ein kurzer, beschreibender Name vergeben, damit der Indikator im Chart und im Navigator-Fenster leicht zu erkennen ist.

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

   ...
   
   //--- General indicator configurations
   IndicatorSetString(INDICATOR_SHORTNAME, "Larry Williams Market Structure Indicator");

   return(INIT_SUCCEEDED);
}

Dieses kleine Detail verbessert die Benutzerfreundlichkeit und verleiht dem Tool den letzten Schliff.

Endergebnis

Am Ende dieses Prozesses erfüllt der Indikator drei wesentliche Aufgaben. Es durchsucht die Vergangenheit und markiert jede gültige Smash-Umkehr. Es überwacht jeden neuen Bar und aktualisiert bestätigte Signale. Es reagiert auf aktuelle Kursänderungen und zeigt neue Signale sofort an.

Alle Pfeile werden direkt in das Chart eingezeichnet, und zwar genau an den Bars, an denen die Trendwenden stattfinden. Dies bietet eine übersichtliche visuelle Orientierungshilfe, die später mit Trend-, Zeit- oder anderen Filtern kombiniert werden kann.

Auf dieser Grundlage wird das „Smash-Day-Reversal“-Konzept zu einem praktischen visuellen Hilfsmittel, das schnelle und objektive Ermessensentscheidungen unterstützt.


Testen und Überprüfen der Indikatorausgabe

Nachdem die Logik des Indikators vollständig implementiert ist, besteht der nächste Schritt darin, zu überprüfen, ob alles wie erwartet kompiliert und dargestellt wird. In dieser Phase sollte der Quellcode in MetaEditor kompiliert werden. Wenn alle vorherigen Schritte korrekt befolgt wurden, sollte der Kompilierungsprozess ohne Fehler oder Warnungen abgeschlossen werden. Eine erfolgreiche Kompilierung bestätigt, dass die Indikatorstruktur, die Pufferzuordnungen und die Berechnungslogik alle konsistent sind.

Sollten Kompilierungsfehler auftreten, ist es am effektivsten, den aktuellen Quellcode mit der beigefügten Referenzdatei lwSmashDayReversalIndicator.mq5 zu vergleichen. Anhand dieses Vergleichs lassen sich in der Regel fehlende Zeilen, falsch platzierte Blöcke oder kleine Syntaxfehler leicht erkennen, die sich möglicherweise bei der Implementierung eingeschlichen haben.

Sobald der Indikator erfolgreich kompiliert wurde, kann er im MetaTrader-Terminal an ein Chart angehängt werden. An dieser Stelle sollten an gültigen Umkehrpunkten des „Smash-Day“ Pfeile erscheinen.

Um das Endergebnis besser veranschaulichen zu können, wird in diesem Abschnitt ein Screenshot gezeigt, auf dem der Indikator auf den NASDAQ-100-Aktienindex im Stunden-Zeitrahmen angewendet ist.

Das NAS100-Stunden-Chart

Die Pfeile markieren bullische und bärische Smash-Umkehrungen deutlich direkt im Kurschart, sodass leicht zu erkennen ist, wie sich der Indikator unter realen Marktbedingungen verhält. Damit ist die Testphase abgeschlossen und es wurde bestätigt, dass der Indikator wie vorgesehen funktioniert.


Der Einsatz des „Smash-Day-Reversal“-Indikators in der Handelspraxis

Nachdem der Indikator vollständig implementiert und getestet wurde, besteht der nächste Schritt darin, zu verstehen, wie er in einem praktischen Handelsablauf angewendet werden kann. Der Indikator ist als Entscheidungshilfe konzipiert und nicht als eigenständiges Handelssystem. Seine Hauptaufgabe besteht darin, die Bildung von „Smash-Day-Reversal“-Mustern direkt im Chart objektiv hervorzuheben, sodass Trader vor dem Handeln nach eigenem Ermessen und unter Berücksichtigung des Kontexts entscheiden können.

Wenn sich eine bullische „Smash-Day-Reversal“-Formation bildet, erscheint ein seegrüner Pfeil unterhalb der „Smash-Bar“, sobald der Kurs die Umkehr durch einen Ausbruch über das Hoch des Bars bestätigt; ebenso wird eine bärische „Smash-Day“-Umkehr durch einen schwarzen Pfeil oberhalb des „Smash-Bars“ markiert, sobald der Kurs den Ausbruch nach unten bestätigt. Dank dieser visuellen Hinweise entfällt die Notwendigkeit, historische Barcharts manuell zu durchsuchen, und die Aufmerksamkeit wird auf potenzielle Wendepunkte gelenkt, sobald diese sich abzeichnen.

In der Praxis können Händler diese Signale mit dem allgemeinen Marktkontext kombinieren. Manche entscheiden sich vielleicht dafür, ausschließlich in Richtung des vorherrschenden Trends zu handeln, während andere möglicherweise einen höheren Zeitrahmen nutzen, um Signale zu filtern. Weitere Faktoren wie aktuelle Nachrichtenereignisse, Volatilitätsbedingungen oder der Zeitpunkt der Handelssitzung können die Entscheidungsfindung zusätzlich verfeinern. Der Indikator reagiert neutral auf diese Filter und stellt das Rohmuster konsistent und wiederholbar dar.

Mithilfe der konfigurierbaren Lookback-Eingaben können Händler den Grad der Strenge bei der Definition des „Smash-Day“ anpassen. Ein kürzerer Rückblick erzeugt häufigere Signale, während ein längerer Rückblick nur stärkere emotionale Extreme hervorhebt. Dank dieser Flexibilität eignet sich der Indikator für eine Vielzahl von Instrumenten und Handelsstilen, ohne dass seine zugrunde liegende Logik verändert werden muss.

Vor allem aber hilft der Indikator dabei, ein subtiles visuelles Muster in ein klares, objektives Chartelement umzuwandeln. Auf diese Weise fördert es eine disziplinierte Analyse, verringert emotionale Verzerrungen und ermöglicht es den Händlern, sich auf die Qualität der Ausführung statt auf die Erkennung von Mustern zu konzentrieren.


Schlussfolgerung

In diesem Artikel sind wir über die Theorie hinausgegangen und haben Larry Williams’ Konzepte zur „Smash-Day“-Umkehr in ein praktisches, visuelles Trading-Tool umgesetzt. Das Ergebnis ist ein maßgeschneiderter MQL5-Indikator, der „Smash-Day“-Umkehrungen objektiv identifiziert, die genauen Bars hervorhebt, in denen emotionale Extreme auftreten, und den genauen Zeitpunkt markiert, an dem der Kurs die Umkehr bestätigt. Schon allein dadurch entfällt ein Großteil des Rätselratens, das oft mit dem diskretionären Musterhandel einhergeht.

Noch wichtiger ist, dass der Indikator dazu konzipiert wurde, die Entscheidungsfindung zu unterstützen, anstatt sie zu ersetzen. „Smash-Day“-Umkehrsignale sind am aussagekräftigsten, wenn sie im Zusammenhang mit der Trendrichtung, dem Marktumfeld oder zeitlichen Faktoren betrachtet werden. Indem der Indikator diese Muster im Chart deutlich hervorhebt, ermöglicht er es, den Kontext ruhig und konsequent einzuschätzen, anstatt im Moment emotional zu reagieren.

Der Entwicklungsprozess selbst dient ebenfalls als Blaupause. Wir haben eine Marktidee für den diskretionären Handel analysiert, objektive Regeln definiert und diese Schritt für Schritt mithilfe von übersichtlichem und modularen MQL5-Code umgesetzt. Dieser Ansatz lässt sich wiederverwenden, um andere Kursmuster zu untersuchen, Varianten zu testen oder zusätzliche Tools zu entwickeln, die den persönlichen Handelsansätzen entsprechen.

Nun kann der Indikator weiter erforscht und getestet werden. Unterschiedliche Rückblickzeiträume, Zeitrahmen und Märkte können neue Erkenntnisse liefern, die zuvor nicht offensichtlich waren. Die Leser sind dazu aufgefordert, zu experimentieren, zu beobachten, wie sich diese Muster unter verschiedenen Bedingungen verhalten, und ihre Erkenntnisse in den Kommentaren zum Artikel mitzuteilen. Gerade in diesem Prozess des Testens und Beobachtens lassen sich echte Handelsvorteile entdecken.

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

Letzte Kommentare | Zur Diskussion im Händlerforum (7)
Chacha Ian Maroa
Chacha Ian Maroa | 29 März 2026 in 04:10
surya_1981 #:
Können wir für diesen Indikator einen EA entwickeln?
Auf jeden Fall. Das ist möglich.
Oraine James
Oraine James | 16 Apr. 2026 in 14:17
Wird dieser Indikator neu berechnet oder gibt es eine Verzögerung?
Chacha Ian Maroa
Chacha Ian Maroa | 16 Apr. 2026 in 15:36
Oraine James #:
Wird dieser Indikator neu berechnet oder gibt es eine Verzögerung?
Das ist er nicht.
Ojames
Ojames | 23 Apr. 2026 in 03:27
Chacha Ian Maroa #:
Das ist nicht

Die Pfeile werden verzögert

Vladimir Lovec
Vladimir Lovec | 7 Juli 2026 in 08:15
Ojames #:

Die Zeiger bleiben stehen

Diese Anzeige ist endgültig.
Entwicklung eines Toolkits zur Price-Action-Analyse (Teil 61): Durchbrüche struktureller schräg verlaufender Trendlinien mit 3-Swing-Bestätigung Entwicklung eines Toolkits zur Price-Action-Analyse (Teil 61): Durchbrüche struktureller schräg verlaufender Trendlinien mit 3-Swing-Bestätigung
Wir stellen ein Tool zur Erkennung von Ausbrüchen aus schrägen Trendlinien vor, das auf einer Validierung anhand von drei Swings basiert, um objektive Signale aus der Price‑Action zu generieren. Das System automatisiert die Erkennung von Swings, die Erstellung von Trendlinien und die Bestätigung von Ausbrüchen anhand einer Kreuzungslogik, um Störsignale zu reduzieren und die Ausführung zu standardisieren. Der Artikel erläutert die Strategievorgaben, zeigt die MQL5-Implementierung und gibt einen Überblick über die Testergebnisse; das Tool ist für die Analyse und die Bestätigung von Signalen gedacht, nicht für den automatisierten Handel.
Entwicklung eines Toolkits zur Price-Action-Analyse (Teil 60):  Objektive Swing-basierte Trendlinien für die Strukturanalyse Entwicklung eines Toolkits zur Price-Action-Analyse (Teil 60): Objektive Swing-basierte Trendlinien für die Strukturanalyse
Wir stellen einen regelbasierten Ansatz für Trendlinien vor, der Indikator-Pivots vermeidet und geordnete Swings nutzt, die direkt aus unverarbeiteten Kursdaten abgeleitet werden. Der Artikel behandelt die Swing-Erkennung, die Bewertung der Swing-Größe mittels ATR oder fester Schwellenwerte sowie die Validierung von Aufwärts- und Abwärtsstrukturen und setzt diese Regeln anschließend in MQL5 mit einer Darstellung ohne Repainting und selektiver Anzeige um. Sie erhalten eine klare, reproduzierbare Methode zur Ermittlung struktureller Unterstützungs- und Widerstandsniveaus, die über verschiedene Marktbedingungen hinweg tragfähig bleibt.
Einführung in MQL5 (Teil 39): Leitfaden für Anfänger zur Dateiverwaltung in MQL5 (I) Einführung in MQL5 (Teil 39): Leitfaden für Anfänger zur Dateiverwaltung in MQL5 (I)
Dieser Artikel bietet anhand eines praktischen, projektbasierten Arbeitsablaufs eine Einführung in die Dateiverwaltung in MQL5. Sie verwenden „FileSelectDialog“, um eine CSV-Datei auszuwählen oder zu erstellen, öffnen diese mit „FileOpen“ und schreiben strukturierte Kopfzeilen mit Kontoinformationen wie Kontoname, Kontostand, Kontologin, Datumsbereich und Zeitpunkt der letzten Aktualisierung. Das Ergebnis ist eine klare Grundlage für ein wiederverwendbares Handelsjournal und sichere Dateivorgänge in MetaTrader 5.
Handelsdisziplin in Code verankern (Teil 1): Mit MQL5 strukturelle Disziplin im Live-Trading schaffen Handelsdisziplin in Code verankern (Teil 1): Mit MQL5 strukturelle Disziplin im Live-Trading schaffen
Disziplin wird dann zuverlässig, wenn sie durch die Gestaltung des Systems und nicht durch Willenskraft entsteht. Mithilfe von MQL5 implementiert der Artikel Echtzeit-Beschränkungen – Obergrenzen für die Handelshäufigkeit und tägliche, auf dem Eigenkapital basierende Stopps –, die das Verhalten überwachen und bei Verstößen Maßnahmen auslösen. Die Leser erhalten eine praktische Vorlage für Steuerungsebenen, die die Umsetzung unter Marktdruck stabilisieren.