Vom Einsteiger zum Experten: Optimierung von Liquiditätsstrategien durch strukturelle Bestätigung über mehrere Zeitrahmen in MQL5
Sie sehen wiederholt dasselbe Fehlermuster: Ein technisch perfektes M1–M15-Setup stirbt fast sofort, weil der Preis direkt an ein Liquiditätsniveau im H1/H4/D1 gelaufen ist. Das manuelle Überwachen mehrerer Charts, um den Kontext höherer Zeitrahmen zu bestätigen, ist langsam, fehleranfällig und führt zu entgangenen Einstiegen. Wir benötigen eine technische Lösung mit klaren Akzeptanzkriterien: automatische Erkennung von Liquiditätszonen auf einem gewählten höheren Zeitrahmen, Projektion dieser Zonen auf den aktuellen Chart und Generierung eines einmaligen, nicht wiederholten Einstiegsalarms nur dann, wenn der Preis in eine Zone zurückkehrt und eine formalisierte Umkehrbedingung auf dem niedrigeren Zeitrahmen erfüllt ist. Eingaben und Einschränkungen müssen explizit sein (ZoneTimeframe, LookbackBars, RatioMultiplier, ExtendBars, zulässige Umkehrmuster und Alarm-Drosselung).
Um dies zu lösen, wählen wir eine mehrschichtige Architektur:
- Zonenerkennung – Scannen eines ausgewählten höheren Zeitrahmens nach Base-Impulse-Mustern unter Verwendung eines konfigurierbaren Verhältnisses zur Definition von Angebots- und Nachfragezonen;
- Visuelle Ebene – dauerhaftes Zeichnen von Rechteckobjekten im aktuellen Chart, damit Zonen bei Zeitrahmenwechseln sichtbar bleiben;
- Reaktionsüberwachung – Auswertung jeder geschlossenen Bar des niedrigeren Zeitrahmens auf Zonenüberschneidung und auf eines aus einer kleinen, formalisierten Menge von Umkehrmustern (Engulfing, Pin Bar, Inside-Bar-Ausbruch).
Operativ verwendet der Indikator eine zweistufige Logik in OnCalculate: einen Durchlauf zum Auffüllen historischer Pfeile für die Analyse und einen zweiter Durchlauf zur Generierung eines einzelnen Echtzeit-Alarms pro Zone unter Verwendung zonenspezifischer Trigger-Flags und Alarm-Drosselung. Das Ergebnis ist ein klares, messbares Tool, das fehleranfällige manuelle MTF-Prüfungen durch einen automatisierten, testbaren Arbeitsablauf ersetzt.
Inhalt
Einführung
Bei der Analyse über mehrere Zeitrahmen geht es nicht nur darum, einen höheren Chart zur Bestätigung der Richtung zu prüfen – der tatsächliche Kontext geht viel tiefer. Es geht darum, zu verstehen, wie die übergeordnete Marktausrichtung die kleineren Preisbewegungen steuert, die Sie handeln. Der Makro-Kontext zeigt Ihnen, wo sich große Institutionen positioniert haben, wo wichtige Liquiditätszonen existieren und welcher übergeordnete Trend bzw. welche Marktstimmung dominiert. Der Intraday-Kontext fokussiert sich auf die sich im Tagesverlauf entwickelnde Struktur und darauf, ob der Markt ausbalanciert ist oder sich in einem Trend befindet. Und der Mikro-Kontext ist Ihre Ausführungsebene, auf der Sie den Echtzeit-Orderfluss, die Absorption und Marktfallen beobachten.
Im institutionellen Handel beeinflusst jede Kontextebene die anderen. Wenn der Makro-, Intraday- und Mikro-Kontext in die gleiche Richtung weisen, gewinnen Sie einen statistischen Vorteil bei Ihren Trades. Wenn diese Kontexte jedoch im Widerspruch zueinander stehen – zum Beispiel ein Short-Setup auf dem 1-Minuten-Chart, das direkt in einen Unterstützungsbereich eines höheren Zeitrahmens übergeht –, verliert der Trade seinen Vorteil, selbst wenn er technisch perfekt erscheint.
Hier kommen die Smart Money Concepts (SMC) im ICT-Stil ins Spiel: Liquiditätszonen sind Bereiche, in denen institutionelle Händler bedeutende Orders platziert haben. Diese Zonen bilden sich typischerweise um gleiche Hochs und Tiefs, Hochs und Tiefs des Vortages, Hochs und Tiefs der Hauptsitzungen (Londoner und New Yorker Sitzung) sowie um große runde Zahlen. Wenn der Preis in diesen Liquiditätspools handelt – und beispielsweise gleiche Hochs herausnimmt –, kehrt er oft von einem nahegelegenen Orderblock oder einer strukturellen Zone um.
Das Konzept ist einfach, aber wirkungsvoll: Der Preis greift oft Liquidität ab (nimmt Stops heraus und löst Breakout-Trader aus), bevor er von einem strukturellen Niveau umkehrt, an dem Institutionen ihre Orders platziert haben. Orderblöcke selbst werden typischerweise als die letzte Kerze (oder kleine Gruppe) mit entgegengesetzter Farbe vor einer starken Impulsbewegung definiert, die die Marktstruktur bricht. Für einen bullischen Orderblock bedeutet dies die letzte Abwärtskerze vor einer starken Aufwärtsbewegung, die einen bullischen Bruch der Marktstruktur verursacht. Für einen bärischen Orderblock ist es die letzte Aufwärtskerze vor einer starken Abwärtsbewegung, die einen bärischen Bruch der Marktstruktur verursacht.
Was diesen Ansatz besonders wirkungsvoll macht, ist das Konzept der Premium- und Discount-Zonen. Wenn Sie ein Fibonacci-Retracement vom Swing-Tief zum Swing-Hoch ziehen, wird die 50%-Linie zum Gleichgewichtspunkt. Unterhalb von 50 % liegt die Discount-Zone (günstigere Preise), während oberhalb von 50 % die Premium-Zone (teurere Preise) liegt. In einem bullischen Kontext möchten Sie in einem bullischen Orderblock im Discount kaufen. In einem bärischen Kontext möchten Sie in einem bärischen Orderblock im Premium verkaufen.
Mit diesem Rahmen im Hinterkopf habe ich den ursprünglichen Liquidity Zone Indicator entwickelt – ein Tool, das darauf ausgelegt ist, diese kritischen Zonen automatisch zu identifizieren und direkt im Chart zu visualisieren. Diese grundlegende Arbeit, die in meinem vorherigen Artikel Vom Anfänger zum Experten: Erstellung eines Liquidity Zone Indicators detailliert beschrieben wurde, basierte auf einer entscheidenden quantitativen Erkenntnis: einem messbaren 3:1-Verhältnis zwischen der Tiefe einer Konsolidierungszone und dem Ausmaß des darauffolgenden impulsiven Ausbruchs.
Nehmen wir uns einen Moment Zeit, um die Kernlogik dieses ursprünglichen Indikators zu untersuchen, da sie die Grundlage unserer aktuellen Diskussion bildet:
//+------------------------------------------------------------------+ //| Liquidity Zone Indicator | //| Copyright © 2026 Clemence Benjamin| //| https://www.mql5.com/en/users/billionaire2024/seller | //+------------------------------------------------------------------+ #property copyright "Clemence Benjamin" #property link "https://www.mql5.com/en/users/billionaire2024/seller" #property version "1.00" #property strict #property indicator_chart_window #property indicator_buffers 8 #property indicator_plots 4 //+------------------------------------------------------------------+ //| Input Variables | //+------------------------------------------------------------------+ input int LookbackBars = 1000; //--- Number of bars to look back for zones input double RatioMultiplier = 3.0; //--- Ratio multiplier (3x) input int ExtendBars = 50; //--- Bars to extend rectangle right input bool FillRectangles = true; //--- Fill or just border? input color DemandZoneColor = clrLimeGreen; input color SupplyZoneColor = clrRed; input uchar ZoneOpacity = 40; //--- 0-255 transparency input bool ShowBuffers = true; //--- Show buffer lines on chart input ENUM_LINE_STYLE BufferStyle = STYLE_DASH; //--- Buffer line style input int BufferWidth = 1; //--- Buffer line width //+------------------------------------------------------------------+ //| Global Variables | //+------------------------------------------------------------------+ double myPoint; double Open[], Close[], High[], Low[]; datetime TimeArray[]; //--- Indicator Buffers double DemandZoneHighBuffer[]; double DemandZoneLowBuffer[]; double SupplyZoneHighBuffer[]; double SupplyZoneLowBuffer[]; double DemandZoneSignalBuffer[]; double SupplyZoneSignalBuffer[]; double ZoneStartTimeBuffer[]; double ZoneEndTimeBuffer[]; //+------------------------------------------------------------------+ //| Candle range helper | //+------------------------------------------------------------------+ double CandleRange(const int i) { return(High[i] - Low[i]); } //+------------------------------------------------------------------+ //| Draw a liquidity zone | //+------------------------------------------------------------------+ void DrawZone(const int base_idx, const bool isDemand, const int rates_total) { datetime start_time = TimeArray[base_idx]; datetime end_time = start_time + ExtendBars * PeriodSeconds(); string obj_name = "LiqZone_" + IntegerToString(start_time); //--- Delete existing object if present if(ObjectFind(0, obj_name) >= 0) ObjectDelete(0, obj_name); //--- Determine zone top/bottom double top, bottom; if(isDemand) { top = High[base_idx]; bottom = Low[base_idx]; } else { top = High[base_idx]; bottom = Low[base_idx]; } //--- Create rectangle if(ObjectCreate(0, obj_name, OBJ_RECTANGLE, 0, start_time, top, end_time, bottom)) { color zone_color = isDemand ? DemandZoneColor : SupplyZoneColor; ObjectSetInteger(0, obj_name, OBJPROP_COLOR, zone_color); ObjectSetInteger(0, obj_name, OBJPROP_STYLE, STYLE_SOLID); ObjectSetInteger(0, obj_name, OBJPROP_WIDTH, 1); ObjectSetInteger(0, obj_name, OBJPROP_FILL, FillRectangles); ObjectSetInteger(0, obj_name, OBJPROP_BACK, true); ObjectSetInteger(0, obj_name, OBJPROP_SELECTABLE, false); if(FillRectangles) { color fill_clr = (color)ColorToARGB(zone_color, ZoneOpacity); ObjectSetInteger(0, obj_name, OBJPROP_BGCOLOR, fill_clr); } } //--- Optional buffers for visualization if(ShowBuffers && base_idx < rates_total) { if(isDemand) { DemandZoneHighBuffer[base_idx] = top; DemandZoneLowBuffer[base_idx] = bottom; } else { SupplyZoneHighBuffer[base_idx] = top; SupplyZoneLowBuffer[base_idx] = bottom; } ZoneStartTimeBuffer[base_idx] = start_time; ZoneEndTimeBuffer[base_idx] = end_time; } } //+------------------------------------------------------------------+ //| Calculates indicator values | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int 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 int &spread[]) { //--- Not enough bars to calculate if(rates_total < 5) return(0); //--- Copy data into series arrays int bars_to_process = MathMin(rates_total, 5000); CopyOpen(Symbol(), PERIOD_CURRENT, 0, bars_to_process, Open); CopyClose(Symbol(), PERIOD_CURRENT, 0, bars_to_process, Close); CopyHigh(Symbol(), PERIOD_CURRENT, 0, bars_to_process, High); CopyLow(Symbol(), PERIOD_CURRENT, 0, bars_to_process, Low); CopyTime(Symbol(), PERIOD_CURRENT, 0, bars_to_process, TimeArray); ArraySetAsSeries(Open, true); ArraySetAsSeries(Close, true); ArraySetAsSeries(High, true); ArraySetAsSeries(Low, true); ArraySetAsSeries(TimeArray, true); //--- Iterate over bars to detect zones for(int i = bars_to_process - 3; i >= 0; i--) { int base_idx = i + 2; int impulse_idx = i + 1; double base_range = CandleRange(base_idx); double impulse_range = CandleRange(impulse_idx); //--- Demand zone: both bars bullish, impulse breaks out if(Open[base_idx] < Close[base_idx] && Open[impulse_idx] < Close[impulse_idx] && impulse_range >= base_range * RatioMultiplier) { DrawZone(base_idx, true, rates_total); } //--- Supply zone: both bars bearish, impulse breaks out if(Open[base_idx] > Close[base_idx] && Open[impulse_idx] > Close[impulse_idx] && impulse_range >= base_range * RatioMultiplier) { DrawZone(base_idx, false, rates_total); } } //--- Return total number of processed bars return(rates_total); } //+------------------------------------------------------------------+
Nehmen Sie sich einen Moment Zeit, um dies zu kritisieren. Der ursprüngliche Indikator war ein bedeutender Fortschritt und übersetzte eine statistische Beobachtung erfolgreich in ein automatisiertes, objektives Tool. Die Kernschleife – die Identifizierung einer Basiskerze und die Validierung einer nachfolgenden Impulskerze anhand eines Verhältnisses – ist elegant und effektiv. Die Zonen, die er zeichnet, heben präzise wichtige strukturelle Ebenen im Chart hervor, an denen wahrscheinlich institutionelle Aktivitäten stattgefunden haben. Es lohnt sich, den Testabschnitt des vorherigen Artikels erneut zu lesen, in dem wir ursprünglich den Quellcode hier entwickelt haben.
Als praktisches Handelstool hat er jedoch eine grundlegende Einschränkung: Er ist ein passiver Beobachter. Er zeigt Ihnen das Schlachtfeld – wo die Institutionen ihre Kräfte eingesetzt haben –, aber er liefert kein Signal dafür, wann ein Einstieg sinnvoll ist. Er überwacht nicht die Preisbewegung des niedrigeren Zeitrahmens auf Einstiege, wenn der Preis zu diesen kritischen Zonen zurückkehrt. Ein Trader muss weiterhin mehrere Charts beobachten und auf eine Reaktion warten, was mental anstrengend ist und zu verpassten Gelegenheiten führen kann. Der ursprüngliche Indikator beantwortet das Wo, aber nicht das Wann.
Diese Lücke zwischen Zonenerkennung und tatsächlich nutzbaren Handelssignalen ist der Punkt, an dem viele Handelstools versagen. Wir haben eine Karte mit hoher Wahrscheinlichkeit, aber keine Echtzeit-Anleitung, wann wir tatsächlich einsteigen sollten.
In diesem Artikel werden wir eine vollständige Lösung für dieses Problem entwerfen und aufbauen: ein Reaktionssystem für Multi-Timeframe-Liquiditätszonen. Unser verbesserter Indikator wird nicht nur Zonen auf einem höheren Zeitrahmen erkennen (unter Verwendung der bewährten Logik des ursprünglichen Indikators), sondern auch aktiv den aktuellen, niedrigeren Zeitrahmen daraufhin überwachen, ob der Preis in diese Zonen zurückkehrt. Wenn der Preis in eine Zone eintritt und gleichzeitig ein bestätigtes Umkehrmuster anzeigt – wie eine Engulfing-Kerze, einen Pin-Bar oder einen Inside-Bar-Ausbruch –, zeichnet der Indikator einen Pfeil direkt im Chart und löst einen Alarm aus, der Ihnen ein klares, umsetzbares Signal gibt, das die Struktur des höheren Zeitrahmens mit dem Timing des niedrigeren Zeitrahmens in Einklang bringt.
Diese neue Architektur erfordert ein grundlegendes Umdenken. Der ursprüngliche Indikator arbeitete isoliert auf einem einzelnen Chart. Unser neues System muss in Schichten denken:
- Eine Zonenerkennungsschicht: Diese Schicht arbeitet auf einem vom Benutzer gewählten höheren Zeitrahmen (z. B. H1) und verwendet die ursprüngliche Basis-Impuls-Logik, um Liquiditätszonen zu identifizieren und zu speichern.
- Eine visuelle Schicht: Diese Zonen müssen als dauerhafte Rechtecke im aktuellen Chart gezeichnet werden und sichtbar bleiben, unabhängig davon, auf welchem Zeitrahmen wir handeln.
- Eine Reaktionsüberwachungsebene: Auf dem aktuellen, niedrigeren Zeitrahmen (z. B. M5) wertet diese Ebene jede geschlossene Bar aus. Sie prüft, ob sich die Preisspanne der Bar mit einer aktiven Zone eines höheren Zeitrahmens überschneidet und ob ein Umkehrmuster vorliegt. Wenn beide Bedingungen erfüllt sind, wird ein Signal generiert.
Wenn Sie mit dem Lesen fertig sind, werden Sie verstehen, wie man ein solches System in MQL5 aufbaut, sowie die tieferen Prinzipien der Multi-Timeframe-Analyse, die es effektiv machen. Sie werden sehen, wie institutionelle Trader in Ebenen denken, wie Liquiditätszonen natürliche Unterstützungs- und Widerstandsniveaus bilden und wie die Kombination von Zeitrahmenanalyse mit präzisen Umkehrmustern Ihre Handelsergebnisse dramatisch verbessern kann.
Umsetzung
Der Weg vom Konzept zum funktionierenden Indikator erfordert sorgfältige Planung und systematische Umsetzung. Im Folgenden gehen wir den vollständigen Entwicklungsprozess durch und erläutern jede Komponente und ihre Rolle im Gesamtsystem. Der endgültige Indikator, den wir erstellen werden, stellt einen bedeutenden Fortschritt gegenüber dem Original dar – er identifiziert Zonen, überwacht sie auf Reaktionen und liefert klare visuelle Signale, wenn sich Handelsgelegenheiten ergeben.
Schritt 1: Einrichtung des Indikator-Frameworks und der Eingabeparameter
Jeder MQL5-Indikator beginnt mit Eigenschaftsdeklarationen und Eingabeparametern. Diese definieren, wie der Indikator im Chart erscheint, welche Daten er verwendet und welche Anpassungsoptionen den Tradern zur Verfügung stehen. Für unseren Multi-Timeframe-Reaktionsindikator benötigen wir Eingaben, die sowohl die Zonenerkennung auf höheren Zeitrahmen als auch die Reaktionsüberwachung auf dem aktuellen Zeitrahmen steuern.
Der erste Abschnitt unseres Codes legt diese Grundlagen fest. Wir deklarieren den Indikator so, dass er im Chartfenster (statt in einem separaten Unterfenster) arbeitet, weisen zwei Puffer für unsere Kauf- und Verkaufspfeile zu und definieren zwei Plots – einen für jeden Pfeiltyp. Die Eingabeparameter sind logisch organisiert: zuerst die Einstellungen zur Zonenerkennung auf höheren Zeitrahmen (welcher Zeitrahmen analysiert werden soll, auf wie viele Bars zurückgeblickt werden soll, das Verhältnis zur Erkennung impulsiver Ausdehnungen und wie weit die Rechtecke erweitert werden sollen), gefolgt von visuellen Anpassungsoptionen (Farben, Deckkraft, Fülloptionen) und schließlich den Einstellungen für das Reaktionssignal (Pfeilfarben und -größen).
//+------------------------------------------------------------------+ //| Liquidity Zone Reaction Indicator| //| Copyright © 2026 Clemence Benjamin| //| https://www.mql5.com/en/users/billionaire2024/seller | //+------------------------------------------------------------------+ #property copyright "Clemence Benjamin" #property link "https://www.mql5.com/en/users/billionaire2024/seller" #property version "3.0" #property indicator_chart_window #property indicator_buffers 2 #property indicator_plots 2 //--- Inputs for zone detection (higher timeframe) input ENUM_TIMEFRAMES ZoneTimeframe = PERIOD_H1; // Timeframe for zone detection input int LookbackBars = 1000; // Number of bars on higher TF to look back input double RatioMultiplier = 3.0; // Ratio Multiplier (3x) input int ExtendBars = 50; // Bars to extend rectangle right (on higher TF) input bool FillRectangles = true; // Fill or just border? input color DemandZoneColor = clrLimeGreen; // Demand zone rectangle color input color SupplyZoneColor = clrTomato; // Supply zone rectangle color input uchar ZoneOpacity = 40; // 0-255 transparency //--- Inputs for reaction signals (current timeframe) input color DemandArrowColor = clrLimeGreen; // Buy arrow color input color SupplyArrowColor = clrRed; // Sell arrow color input int ArrowSize = 1; // Arrow width //--- Arrow buffers double BuyArrow[]; double SellArrow[]; //+------------------------------------------------------------------+
Schritt 2: Definition der Zonenstruktur und globalen Variablen
Das Herzstück unseres Indikators ist die Struktur LiquidityZone. Dieser benutzerdefinierte Datentyp kapselt alles, was wir über eine Zone wissen müssen: ihre Preisgrenzen (Hoch und Tief), ihre zeitlichen Grenzen (Startzeit und Ablaufzeit), ihren Typ (Nachfrage oder Angebot) und ob sie bereits ein Signal ausgelöst hat. Indem wir Zonen in einem dynamischen Array speichern, können wir eine unbegrenzte Anzahl aktiver Zonen gleichzeitig verwalten, jede mit ihren eigenen Eigenschaften und ihrem eigenen Status.
//--- Current timeframe data arrays (for reversal patterns) double Open[], Close[], High[], Low[]; datetime TimeArray[]; //--- Global variables double myPoint; int htfPeriodSeconds; // period seconds of the higher timeframe int currentPeriodSeconds; // current timeframe period in seconds datetime lastHtfUpdateTime = 0; // last time zones were updated datetime lastAlertTime = 0; // for alert throttling //+------------------------------------------------------------------+ //| Zone structure | //+------------------------------------------------------------------+ struct LiquidityZone { double high; // zone top price double low; // zone bottom price datetime start_time; // bar time where zone was formed datetime expiry_time; // time when zone expires (start + ExtendBars * htfPeriod) bool demand; // true = demand, false = supply bool triggered; // true if a signal already fired in this zone }; LiquidityZone zones[]; // dynamic array of currently active zones //+------------------------------------------------------------------+
Schritt 3: Initialisierung und Pufferkonfiguration
Die Funktion OnInit() übernimmt alle Einrichtungsaufgaben, die einmalig beim ersten Laden des Indikators ausgeführt werden müssen. Dies umfasst die Berechnung des korrekten Punktwerts (unter Berücksichtigung von 5-stelligen Brokern), die Einrichtung der Pfeilpuffer, die Konfiguration der Plot-Eigenschaften und die Initialisierung der Zeitperiodenvariablen.
//+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { myPoint = Point(); if(_Digits == 5 || _Digits == 3) myPoint *= 10; //--- Set arrow buffers SetIndexBuffer(0, BuyArrow, INDICATOR_DATA); SetIndexBuffer(1, SellArrow, INDICATOR_DATA); //--- Make arrow buffers series so index 0 = newest bar ArraySetAsSeries(BuyArrow, true); ArraySetAsSeries(SellArrow, true); PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_ARROW); PlotIndexSetInteger(0, PLOT_ARROW, 233); // up arrow PlotIndexSetString(0, PLOT_LABEL, "Buy"); PlotIndexSetInteger(0, PLOT_LINE_COLOR, DemandArrowColor); PlotIndexSetInteger(0, PLOT_LINE_WIDTH, ArrowSize); PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_ARROW); PlotIndexSetInteger(1, PLOT_ARROW, 234); // down arrow PlotIndexSetString(1, PLOT_LABEL, "Sell"); PlotIndexSetInteger(1, PLOT_LINE_COLOR, SupplyArrowColor); PlotIndexSetInteger(1, PLOT_LINE_WIDTH, ArrowSize); ArrayInitialize(BuyArrow, EMPTY_VALUE); ArrayInitialize(SellArrow, EMPTY_VALUE); //--- Period seconds for time calculations currentPeriodSeconds = PeriodSeconds(); htfPeriodSeconds = PeriodSeconds(ZoneTimeframe); if(htfPeriodSeconds <= 0) htfPeriodSeconds = 3600; // fallback to 1 hour //--- Initial update of zones (will be done in OnCalculate) lastHtfUpdateTime = 0; return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+
Schritt 4: Bereinigung und Objektverwaltung
Eine ordnungsgemäße Bereinigung ist für Indikatoren auf professionellem Niveau unerlässlich. Wenn der Indikator aus dem Chart entfernt wird, sollten alle von ihm erstellten Objekte – in unserem Fall die Zonenrechtecke – gelöscht werden, um den Chart sauber zu halten. Die Funktion OnDeinit() erledigt dies automatisch und ruft DeleteAllZones() auf, um jedes Objekt zu entfernen, dessen Name mit LiqZone_ beginnt.
//+------------------------------------------------------------------+ //| Deinitialization | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { DeleteAllZones(); } //+------------------------------------------------------------------+ //| Delete all drawn zone rectangles | //+------------------------------------------------------------------+ void DeleteAllZones() { for(int i = ObjectsTotal(0, 0, -1) - 1; i >= 0; i--) { string name = ObjectName(0, i); if(StringFind(name, "LiqZone_") == 0) ObjectDelete(0, name); } ChartRedraw(); } //+------------------------------------------------------------------+
Schritt 5: Zeichnen von Zonenrechtecken als visuelle Referenz
Visuelles Feedback ist für jedes Trading-Tool unerlässlich. Trader müssen auf einen Blick sehen, wo sich Zonen befinden, wie weit sie in die Zukunft reichen und ob es sich um Nachfrage- oder Angebotsbereiche handelt. Die Funktion DrawZone() übernimmt dies, indem sie ein Rechteckobjekt mit den entsprechenden Eigenschaften erstellt – Farbe, Füllstil, Transparenz und Positionierung hinter der Preisbewegung –, sodass die Kerzen nicht verdeckt werden.
//+------------------------------------------------------------------+ //| Draw a single zone rectangle | //+------------------------------------------------------------------+ void DrawZone(datetime start_time, datetime expiry_time, double price_top, double price_bottom, bool isDemand) { string obj_name = "LiqZone_" + IntegerToString(start_time) + "_" + IntegerToString(expiry_time); if(ObjectFind(0, obj_name) >= 0) ObjectDelete(0, obj_name); color zone_color = isDemand ? DemandZoneColor : SupplyZoneColor; if(ObjectCreate(0, obj_name, OBJ_RECTANGLE, 0, start_time, price_top, expiry_time, price_bottom)) { ObjectSetInteger(0, obj_name, OBJPROP_COLOR, zone_color); ObjectSetInteger(0, obj_name, OBJPROP_STYLE, STYLE_SOLID); ObjectSetInteger(0, obj_name, OBJPROP_WIDTH, 1); ObjectSetInteger(0, obj_name, OBJPROP_FILL, FillRectangles); ObjectSetInteger(0, obj_name, OBJPROP_BACK, true); // behind price ObjectSetInteger(0, obj_name, OBJPROP_SELECTABLE, false); if(FillRectangles) { color fill_clr = (color)ColorToARGB(zone_color, ZoneOpacity); ObjectSetInteger(0, obj_name, OBJPROP_BGCOLOR, fill_clr); } } } //+------------------------------------------------------------------+
Schritt 6: Erkennung von Zonen in höheren Zeitrahmen
Das Herzstück unseres Multi-Timeframe-Ansatzes liegt in UpdateZones(). Diese Funktion wird immer dann aufgerufen, wenn eine neue Bar im ausgewählten höheren Zeitrahmen erscheint. Sie kopiert die erforderlichen Preisdaten, sucht nach Basis-Impuls-Mustern, erstellt LiquidityZone-Strukturen für jedes gültige Muster und zeichnet die entsprechenden Rechtecke im Chart.
//+------------------------------------------------------------------+ //| Update zones from higher timeframe data | //+------------------------------------------------------------------+ void UpdateZones() { //--- Delete old rectangles and clear zone array DeleteAllZones(); ArrayResize(zones, 0); //--- Copy higher timeframe data double htf_open[], htf_close[], htf_high[], htf_low[]; datetime htf_time[]; int htf_bars = CopyOpen(Symbol(), ZoneTimeframe, 0, LookbackBars, htf_open); if(htf_bars <= 0) return; CopyClose(Symbol(), ZoneTimeframe, 0, LookbackBars, htf_close); CopyHigh(Symbol(), ZoneTimeframe, 0, LookbackBars, htf_high); CopyLow(Symbol(), ZoneTimeframe, 0, LookbackBars, htf_low); CopyTime(Symbol(), ZoneTimeframe, 0, LookbackBars, htf_time); //--- Work with series (index 0 = most recent) ArraySetAsSeries(htf_open, true); ArraySetAsSeries(htf_close, true); ArraySetAsSeries(htf_high, true); ArraySetAsSeries(htf_low, true); ArraySetAsSeries(htf_time, true); //--- Scan higher timeframe bars for zones for(int i = htf_bars - 5; i >= 2; i--) { int base_idx = i + 2; int impulse_idx = i + 1; if(base_idx >= htf_bars) continue; double base_range = htf_high[base_idx] - htf_low[base_idx]; double impulse_range = htf_high[impulse_idx] - htf_low[impulse_idx]; if(base_range <= 0) continue; //+------------------------------------------------------------------+
Wenn eine gültige Zone gefunden wird, erstellen wir eine neue LiquidityZone-Struktur, füllen sie mit den relevanten Daten (Hoch, Tief, Startzeit berechnet als Basisbarzeit, Ablaufzeit berechnet als Startzeit plus ExtendBars multipliziert mit der Periode des höheren Zeitrahmens in Sekunden), fügen sie unserem dynamischen Array hinzu und zeichnen das entsprechende Rechteck im Chart.
//--- Creating a new liquidity Zone if(htf_open[base_idx] < htf_close[base_idx] && htf_open[impulse_idx] < htf_close[impulse_idx] && impulse_range >= base_range * RatioMultiplier) { LiquidityZone z; z.high = htf_high[base_idx]; z.low = htf_low[base_idx]; z.start_time = htf_time[base_idx]; z.expiry_time = z.start_time + ExtendBars * htfPeriodSeconds; z.demand = true; z.triggered = false; int size = ArraySize(zones); ArrayResize(zones, size + 1); zones[size] = z; DrawZone(z.start_time, z.expiry_time, z.high, z.low, true); } //+------------------------------------------------------------------+
Schritt 7: Definition von Umkehrmustern zur Einstiegsbestätigung
Die Identifizierung von Zonen ist nur die halbe Miete. Die andere Hälfte besteht darin, zu wissen, wann man handeln muss, wenn der Preis in diese Zonen zurückkehrt. Dafür benötigen wir eine zuverlässige Reihe von Umkehrmustern, die eine potenzielle Richtungsänderung signalisieren. Unser Indikator enthält drei klassische Umkehrmuster für sowohl bullische als auch bärische Szenarien: Engulfing-Muster, Pin-Bars und Inside-Bar-Ausbrüche.
//+------------------------------------------------------------------+ //| Bullish Engulfing Pattern | //| Detects bullish reversal when current candle engulfs previous | //| bearish candle body | //+------------------------------------------------------------------+ bool BullishEngulfing(int i) { if(Close[i] > Open[i] && Close[i+1] < Open[i+1] && Close[i] > Open[i+1] && Open[i] < Close[i+1]) return true; return false; } //+------------------------------------------------------------------+ //| Bearish Engulfing Pattern | //| Detects bearish reversal when current candle engulfs previous | //| bullish candle body | //+------------------------------------------------------------------+ bool BearishEngulfing(int i) { if(Close[i] < Open[i] && Close[i+1] > Open[i+1] && Open[i] > Close[i+1] && Close[i] < Open[i+1]) return true; return false; } //+------------------------------------------------------------------+ //| Bullish Pin Bar Pattern | //| Long lower wick indicating rejection of lower prices | //+------------------------------------------------------------------+ bool BullishPinBar(int i) { double body = MathAbs(Close[i] - Open[i]); double lower = MathMin(Open[i], Close[i]) - Low[i]; if(lower > body * 2) return true; return false; } //+------------------------------------------------------------------+ //| Bearish Pin Bar Pattern | //| Long upper wick indicating rejection of higher prices | //+------------------------------------------------------------------+ bool BearishPinBar(int i) { double body = MathAbs(Close[i] - Open[i]); double upper = High[i] - MathMax(Open[i], Close[i]); if(upper > body * 2) return true; return false; } //+------------------------------------------------------------------+ //| Bullish Inside Bar Breakout | //| Inside bar structure followed by bullish breakout | //+------------------------------------------------------------------+ bool BullishInsideBreak(int i) { if(High[i] < High[i+1] && Low[i] > Low[i+1]) if(Close[i] > High[i+1]) return true; return false; } //+------------------------------------------------------------------+ //| Bearish Inside Bar Breakout | //| Inside bar structure followed by bearish breakout | //+------------------------------------------------------------------+ bool BearishInsideBreak(int i) { if(High[i] < High[i+1] && Low[i] > Low[i+1]) if(Close[i] < Low[i+1]) return true; return false; } //+------------------------------------------------------------------+ //| Demand Zone Reversal Detector | //| Combines bullish reversal patterns for demand zones | //+------------------------------------------------------------------+ bool DemandReversal(int i) { if(BullishEngulfing(i)) return true; if(BullishPinBar(i)) return true; if(BullishInsideBreak(i)) return true; return false; } //+------------------------------------------------------------------+ //| Supply Zone Reversal Detector | //| Combines bearish reversal patterns for supply zones | //+------------------------------------------------------------------+ bool SupplyReversal(int i) { if(BearishEngulfing(i)) return true; if(BearishPinBar(i)) return true; if(BearishInsideBreak(i)) return true; return false; } //+------------------------------------------------------------------+
Schritt 8: Die OnCalculate-Logik mit zwei Durchläufen
Die OnCalculate-Funktion ist der Ort, an dem alles zusammenläuft. Sie implementiert einen Ansatz mit zwei Durchläufen, der sowohl die historische Signalanzeige als auch die Generierung von Echtzeit-Alarmen handhabt. Diese Doppelstrategie stellt sicher, dass Trader alle vergangenen Signale sehen können, wenn sie den Indikator laden (entscheidend für das Backtesting und das Verständnis, wie sich das System verhalten hätte), während sie gleichzeitig rechtzeitige Alarme für neue Gelegenheiten erhalten, sobald diese entstehen.
//+------------------------------------------------------------------+ //| Calculates indicator values and updates zones | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int 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 int &spread[]) { //--- Not enough bars to calculate if(rates_total < 5) return(0); //--- Copy current timeframe data into global arrays (as series) int barsNeeded = MathMin(rates_total, 5000); // safe upper limit CopyOpen(Symbol(), PERIOD_CURRENT, 0, barsNeeded, Open); CopyClose(Symbol(), PERIOD_CURRENT, 0, barsNeeded, Close); CopyHigh(Symbol(), PERIOD_CURRENT, 0, barsNeeded, High); CopyLow(Symbol(), PERIOD_CURRENT, 0, barsNeeded, Low); CopyTime(Symbol(), PERIOD_CURRENT, 0, barsNeeded, TimeArray); ArraySetAsSeries(Open, true); ArraySetAsSeries(Close, true); ArraySetAsSeries(High, true); ArraySetAsSeries(Low, true); ArraySetAsSeries(TimeArray, true); //--- Update zones if a new higher timeframe bar appears datetime latestHtfTime = iTime(Symbol(), ZoneTimeframe, 0); if(latestHtfTime != lastHtfUpdateTime) { UpdateZones(); lastHtfUpdateTime = latestHtfTime; } //--- further calculations continue here... return(rates_total); } //+------------------------------------------------------------------+
Der erste Durchlauf durchläuft jede abgeschlossene Bar vom ältesten bis zum neuesten und prüft jede Bar, die innerhalb des Zeitfensters einer Zone liegt, ob der Preis innerhalb dieser Zone liegt und ein passendes Umkehrmuster anzeigt. Für jede dieser Bars setzt sie den entsprechenden Pfeil-Pufferwert auf einen Preis knapp unter (für Käufe) oder über (für Verkäufe) dem Extremwert der Bar, wodurch eine visuelle Markierung direkt im Chart erstellt wird.
//--------------------------------------------------------------- // 1) Loop over ALL completed bars (oldest to newest) and set arrows // This makes historical signals appear on the chart. //--------------------------------------------------------------- for(int i = rates_total - 2; i >= 0; i--) // i = bar index (0 = newest) { bool buySignal = false; bool sellSignal = false; // Check every active zone for(int z = 0; z < ArraySize(zones); z++) { // --- Time validity: bar must be within zone's lifetime --- if(TimeArray[i] < zones[z].start_time || TimeArray[i] > zones[z].expiry_time) continue; // --- Price inside zone? --- if(!PriceInsideZone(i, zones[z], High, Low)) continue; // --- Reversal pattern? --- if(zones[z].demand && DemandReversal(i)) buySignal = true; if(!zones[z].demand && SupplyReversal(i)) sellSignal = true; } // Set arrow (or EMPTY_VALUE if no signal) BuyArrow[i] = buySignal ? Low[i] - 5 * myPoint : EMPTY_VALUE; SellArrow[i] = sellSignal ? High[i] + 5 * myPoint : EMPTY_VALUE; } //+------------------------------------------------------------------+
Der zweite Durchlauf konzentriert sich nur auf die zuletzt abgeschlossene Bar (Index 1). Er führt dieselben Prüfungen durch, berücksichtigt jedoch zusätzlich das ausgelöste Flag – sobald eine Zone einen Alarm generiert, wird kein weiterer mehr erzeugt. Dies verhindert wiederholte Alarme aus derselben Zone, während sich neue Bars bilden, solange der Preis innerhalb dieser Zone bleibt. Wenn ein gültiges Signal gefunden wird, wird ein Alarm mit den relevanten Informationen ausgelöst.
//-------------------------------------------------------------------------- // 2) Real-time alert handling (only for the most recent closed bars | // Uses the 'triggered' flag to avoid repeated alerts from the same zone.| //-------------------------------------------------------------------------- int signal_bar = 1; // last closed bar if(signal_bar < rates_total) { for(int z = 0; z < ArraySize(zones); z++) { // Skip if zone already triggered if(zones[z].triggered) continue; // Time validity (using the bar's time, not TimeCurrent) if(TimeArray[signal_bar] < zones[z].start_time || TimeArray[signal_bar] > zones[z].expiry_time) continue; // Price inside? if(!PriceInsideZone(signal_bar, zones[z], High, Low)) continue; // Reversal? if(zones[z].demand && DemandReversal(signal_bar)) { zones[z].triggered = true; if(TimeArray[signal_bar] != lastAlertTime) { Alert("Demand Zone BUY Reaction ", Symbol(), " ", EnumToString(_Period)); lastAlertTime = TimeArray[signal_bar]; } } else if(!zones[z].demand && SupplyReversal(signal_bar)) { zones[z].triggered = true; if(TimeArray[signal_bar] != lastAlertTime) { Alert("Supply Zone SELL Reaction ", Symbol(), " ", EnumToString(_Period)); lastAlertTime = TimeArray[signal_bar]; } } } } return(rates_total); } //+------------------------------------------------------------------+
Schritt 9: Validierung des Preises innerhalb der Zone
Das letzte Puzzleteil ist eine einfache, aber entscheidende Hilfsfunktion, die prüft, ob die Preisspanne einer gegebenen Bar mit einer Zone überlappt. Diese Funktion wird wiederholt innerhalb der OnCalculate-Logik aufgerufen und muss sowohl präzise als auch effizient sein.
//+------------------------------------------------------------------+ //| Check if a bar is inside a zone | //+------------------------------------------------------------------+ bool PriceInsideZone(int bar, const LiquidityZone &z, const double &high[], const double &low[]) { if(high[bar] >= z.low && low[bar] <= z.high) return true; return false; } //+------------------------------------------------------------------+
Da alle diese Komponenten zusammenarbeiten, haben wir einen umfassenden Multi-Timeframe-Liquiditätszonen-Reaktionsindikator erstellt, der institutionelle Zonen identifiziert, sie auf handelbare Gelegenheiten überwacht und den Trader alarmiert, wenn sich diese Gelegenheiten ergeben.
Tests und Ergebnisse
Beim Testen eines Multi-Timeframe-Indikators ist ein systematischer Ansatz erforderlich, der sowohl die Zonenerkennungslogik als auch die Reaktionsüberwachungsfunktionalität verifiziert. Das Testverfahren sollte historische Genauigkeit, Echtzeit-Performance und die Behandlung von Grenzfällen abdecken. Um eine umfassende Validierung effizient zu erreichen, setzen wir zwei komplementäre Testmodi ein: den Strategietester für eine schnelle historische Auswertung und die Live-Chart-Beobachtung zur Echtzeit-Bestätigung.

Abbildung 1 zeigt, wie der Strategietester Monate historischer Preisbewegungen für eine schnelle Leistungsbewertung in Minuten komprimiert.
Testansätze
Strategietester-Modus: Live-Charts erfordern das Warten von Tagen oder Wochen, um genügend Signale für eine aussagekräftige Analyse zu sammeln. Der Strategietester löst dies, indem er Monate historischer Daten in Minuten simuliert. Sie können beobachten, wie sich der Indikator unter verschiedenen Marktbedingungen – im Trend, seitwärtslaufend, hohe Volatilität, niedrige Volatilität – verhalten hätte, indem Sie einfach verschiedene Datumsbereiche auswählen. Dieser komprimierte Feedback-Zyklus ist unerlässlich für:
- Die Überprüfung, ob Zonen über verschiedene Marktphasen hinweg korrekt identifiziert werden
- Die Bestätigung, dass Reaktionspfeile auf allen qualifizierenden historischen Bars erscheinen
- Die Feinabstimmung von Eingabeparametern (wie RatioMultiplier) für spezifische Instrumente
- Den Aufbau von Vertrauen in die Logik des Indikators vor dem Live-Einsatz
Live-Chart-Modus (Verifizierung in der realen Welt): Während der Strategietester historisches Vertrauen bietet, validiert das Live-Testen das Echtzeitverhalten:
- Die Bestätigung, dass Alarme korrekt ausgelöst werden, wenn sich neue Bars bilden
- Die Beobachtung, wie der Indikator mit der aktuellen, noch nicht abgeschlossenen Bar umgeht
- Die Sicherstellung, dass Zonenrechtecke korrekt bestehen bleiben, wenn neue Preisdaten eintreffen
- Das Erleben des tatsächlichen Timings und der Häufigkeit von Signalen unter aktuellen Marktbedingungen
Beide Ansätze sind essenziell: Der Strategietester bietet Ihnen Geschwindigkeit, während Live-Tests Ihnen Sicherheit geben. Nachfolgend dokumentieren wir beide Prozesse und ihre kombinierten Ergebnisse.
Test-Prozedur
Teil A: Strategietester
1. Öffnen Sie den MetaTrader 5 Strategietester, wählen Sie EURUSD als Symbol, wählen Sie M5 als Zeitrahmen und legen Sie einen historischen Datumsbereich fest, der signifikante Preisbewegungen enthält (z. B. Januar 2020–März 2020). Aktivieren Sie den Visual Mode, um das Verhalten des Indikators Bar für Bar zu beobachten. Wählen Sie den Indikator im Tester aus.
2. Konfigurieren Sie die Indikatoreingaben: Setzen Sie ZoneTimeframe auf PERIOD_H1 (Analyse des höheren Zeitrahmens), RatioMultiplier auf 2.25 (für Tests auf EURUSD) und andere visuelle Parameter nach Wunsch (Abb. 2 zeigt eine typische Konfiguration).

Abb. 2. Indikator-Eingabeparameter – konfiguriert für H1-Zonenerkennung auf EURUSD M5
3. Führen Sie den visuellen Backtest aus. Beobachten Sie, wie Zonenrechtecke an signifikanten strukturellen Punkten erscheinen, an denen auf eine Konsolidierungsbar eine Impulsbar folgte, die den 3×-Verhältnisschwellenwert erreicht oder überschreitet. Beachten Sie, dass Zonen basierend auf Daten des höheren Zeitrahmens gezeichnet werden, aber in Ihrem M5-Chart erscheinen – die Multi-Timeframe-Visualisierung funktioniert wie vorgesehen.
4. Beobachten Sie während des Fortschreitens der Simulation, ob bzw. wann der Preis in die bestehenden Zonen zurückkehrt. Wenn der Preis in eine Nachfragezone (grünes Rechteck) eintritt und ein bullisches Umkehrmuster bildet, sollte ein Kaufpfeil (Pfeil nach oben) erscheinen. Wenn der Preis in eine Angebotszone (rotes Rechteck) eintritt und ein bärisches Umkehrmuster bildet, sollte ein Verkaufspfeil (Pfeil nach unten) erscheinen.
5. Scrollen Sie nach Abschluss der Simulation durch die Chart-Historie zurück. Überprüfen Sie, ob auf jede Bar, bei der die Bedingungen erfüllt waren, Pfeile erscheinen – dies bestätigt, dass die OnCalculate-Logik mit zwei Durchläufen historische Signale korrekt auffüllt, eine Überprüfung, die auf einem Live-Chart Wochen dauern würde.
Teil B: Live-Chart
1. Hängen Sie den Indikator an einen Live-EURUSD-M5-Chart mit denselben Eingabeeinstellungen an. Lassen Sie den Indikator mehrere Stunden laufen und beobachten Sie sein Verhalten.
2. Beobachten Sie den Live-Chart auf neue Zonenbildungen und Reaktionssignale. Abb. 3 zeigt ein Live-Chart-Beispiel, bei dem H1-Zonen deutlich sichtbar sind und M5-Reaktionspfeile an Umkehrpunkten eingezeichnet wurden.

Abb. 3. H1-Liquiditätszonen (Rechtecke) und M5-Reaktionspfeile, bei denen Umkehrmuster innerhalb der Zonen auftraten.
3. Überwachen Sie das Terminalfenster auf Alarmmeldungen. Wenn eine neue Bar innerhalb einer Zone mit einem Umkehrmuster schließt, sollte ein Alarm im Format „Demand Zone BUY Reaction EURUSD PERIOD_M5“ oder „Supply Zone SELL Reaction EURUSD PERIOD_M5“ ausgelöst werden. Abb. 4 zeigt eine Sammlung solcher Alarme, die während des Live-Tests erfasst wurden.

Abb. 4. Echtzeit-Benachrichtigungen wurden generiert, als der Preis in Zonen mit Umkehrmustern eintrat (erfasst nach längerer Live-Beobachtung).
Beobachtete Ergebnisse
Der kombinierte Testansatz lieferte konsistente Ergebnisse sowohl bei der historischen Simulation als auch bei der Live-Beobachtung:
Genauigkeit der Zonenerkennung: Sowohl im Strategietester als auch im Live-Modus stimmten die Zonen des höheren Zeitrahmens konsistent mit signifikanten strukturellen Niveaus überein. Wenn der Preis diese Zonen erneut besuchte, zeigte er häufig Reaktionen – was die institutionelle Relevanz dieser Bereiche bestätigt. Wir verwendeten ein Verhältnis von 2,25 anstelle des Standardverhältnisses von 3,0 bei EURUSD und XAUUSD, während volatilere Instrumente wie der Volatility 10 (1s) Index ein niedrigeres Verhältnis (2,0) erforderten, um aussagekräftige Zonen zu generieren – genau wie die ursprüngliche Untersuchung nahelegte.
Signalqualität und -frequenz: Nicht jeder Zonenbesuch erzeugte ein Signal – nur solche mit klaren Umkehrmustern. Diese Filterung erzeugte relativ seltene, aber überzeugende Signale, was mit einem reduzierten Overtrading einhergeht. Der Strategietester zeigte, dass der Indikator bei EURUSD-Signale nur an strukturell signifikanten Niveaus generierte.
Historische Signalvisualisierung: Das Zwei-Pass-Design funktionierte im Strategietester einwandfrei, wobei Pfeile auf allen historischen Reaktionsbars sichtbar waren. Dies machte das Backtesting intuitiv – sofort zu sehen, wo das System in der Vergangenheit Einstiege signalisiert hätte, bietet einen starken Einblick in sein Verhalten.
Alarmzuverlässigkeit: Während des Live-Tests wurden Alarme bei neuen Signalen konsistent und ohne Spam ausgelöst, dank des Trigger-Flag-Mechanismus und der lastAlertTime-Drosselung. Abb. 4 oben zeigt eine repräsentative Stichprobe von Alarmen, die über einige Stunden der Live-Beobachtung erfasst wurden.
Diese Beobachtungen bekräftigen eine entscheidende Schlussfolgerung aus unserer ursprünglichen Untersuchung: Während das 3:1-Verhältnis eine statistisch starke Basis bietet, erfordert eine optimale Performance Anpassungsfähigkeit an das spezifische Instrument. Der anpassbare RatioMultiplier-Eingabewert ermöglicht es Tradern, den Indikator auf ihre bevorzugten Märkte zu kalibrieren, was ihn zu einem flexiblen Tool anstelle einer starren Formel macht.
Die erfolgreiche Testphase bestätigt, dass unsere Multi-Timeframe-Architektur wie beabsichtigt funktioniert: Zonen höherer Zeitrahmen werden erkannt und visualisiert, Reaktionen in niedrigeren Zeitrahmen werden überwacht und klare Signale werden nur dann generiert, wenn sowohl der strukturelle Kontext als auch die Einstiegsbestätigung übereinstimmen. Dies verwandelt den ursprünglichen passiven Zonenindikator in einen aktiven Handelsbegleiter, der Einstiege präzise steuert.
Schlussfolgerung
Im Laufe dieses Artikels haben wir einen einfachen Zonen-Erkennungsindikator in ein umfassendes Multi-Timeframe-Reaktionssystem verwandelt. Wir begannen mit dem Kernkonzept – dass Liquiditätszonen in höheren Zeitrahmen Kontext bieten, während Umkehrmuster in niedrigeren Zeitrahmen das Timing liefern – und bauten eine vollständige MQL5-Implementierung darum herum auf.
Wir haben ein Tool geschaffen, das institutionelle Handelsprinzipien verkörpert: Top-Down-Analyse, strukturelle Bestätigung und präzises Ausführungs-Timing. Der Indikator scannt automatisch höhere Zeitrahmen nach Zonen, in denen Institutionen wahrscheinlich Aufträge platziert haben, zeichnet diese Zonen direkt in den aktuellen Chart, sodass sie in jedem betrachteten Zeitrahmen sichtbar bleiben, und überwacht dann jede Bar auf potenzielle Reaktionen. Wenn der Preis in eine Zone eintritt und ein bestätigtes Umkehrmuster zeigt – eine Engulfing-Kerze, einen Pin-Bar oder einen Inside-Bar-Ausbruch –, zeichnet der Indikator einen Pfeil und löst einen Alarm aus, was Ihnen ein klares, umsetzbares Signal gibt.
Das Zwei-Pass-Design stellt sicher, dass Sie alle historischen Signale sehen können, wenn Sie den Indikator laden, was das Backtesting intuitiv und informativ macht. Sie können durch die Preishistorie zurückscrollen und genau sehen, wo das System Einstiege signalisiert hätte, wie diese Signale abgeschnitten haben und unter welchen Marktbedingungen das System glänzt oder Schwierigkeiten hat.
Die Prinzipien, die wir hier implementiert haben, gelten für jeden Handelsansatz: Beginnen Sie mit dem Gesamtbild, identifizieren Sie wichtige Niveaus, an denen Institutionen wahrscheinlich aktiv sind, warten Sie darauf, dass der Preis zu diesen Niveaus zurückkehrt, und suchen Sie nach einer Bestätigung, bevor Sie handeln. Dieser Top-Down-Ansatz unterscheidet professionelle Trader von Amateuren, die isoliert auf einem einzigen Zeitrahmen handeln.
Mit Blick auf die Zukunft könnte dieser Indikator auf zahlreiche Arten erweitert werden. Zusätzliche Umkehrmuster könnten hinzugefügt werden, wie Morgen-/Abendsterne, Harami-Muster oder Drei-Bar-Umkehrungen. Die Logik zur Zonenerkennung könnte verbessert werden, um Premium-/Discount-Zonen mithilfe von Fibonacci-Retracements zu berücksichtigen. Sitzungsfilter könnten hinzugefügt werden, um Signale nur während spezifischer Handelssitzungen wie der Eröffnung in London oder New York zu generieren. Die Möglichkeiten sind endlos.
Ich ermutige Sie, den Indikator herunterzuladen, ihn auf Ihren eigenen Charts zu testen und ihn an Ihren Handelsstil anzupassen. Experimentieren Sie mit verschiedenen Zeitrahmenkombinationen – versuchen Sie H4-Zonen mit M15-Einstiegen für Swing-Trading oder M15-Zonen mit M1-Einstiegen für Scalping. Passen Sie den Multiplikator des Verhältnisses an, um die Zonenhäufigkeit zu steuern. Modifizieren Sie die Umkehrmuster, damit sie zu dem passen, was in Ihren spezifischen Märkten funktioniert.
Ich habe den Quellcode sowohl als Lernressource als auch als praktisches Tool beigefügt. Studieren Sie ihn, verstehen Sie ihn und machen Sie ihn sich zu eigen. Wenn Sie Fragen, Kommentare oder Verbesserungsvorschläge haben, teilen Sie diese bitte im Kommentarbereich unten mit. Die besten Handelstools entwickeln sich durch Feedback aus der Community und Zusammenarbeit.
Denken Sie daran: Der Markt ist eine Geschichte, die über mehrere Zeitrahmen hinweg erzählt wird. Lernen Sie, die ganze Geschichte zu lesen, nicht nur den letzten Absatz, und Ihr Handel wird nie wieder derselbe sein.
Wichtige Erkenntnisse
| Wichtige Lektion | Beschreibung: |
|---|---|
| Multi-Zeitrahmen-Ausrichtung: | Höhere Zeitrahmen bieten strukturellen Kontext und institutionelle Ausrichtung, während niedrigere Zeitrahmen präzises Timing für den Einstieg bieten. Wenn beides übereinstimmt, steigt die Handelswahrscheinlichkeit signifikant. |
| Liquiditätszonen als strukturelle Ebenen: | Bereiche, in denen Institutionen Aufträge platzieren (Nachfrage-/Angebotszonen), fungieren als natürliche Unterstützungs- und Widerstandsebenen. Der Preis kehrt oft zu diesen Zonen zurück, bevor er fortfährt oder umkehrt. |
| Umkehrmuster bieten Bestätigung: | Sich innerhalb einer Zone zu befinden, reicht nicht aus – warten Sie auf Bestätigungsmuster (Engulfing, Pin Bars, Inside-Bar-Ausbrüche), die eine institutionelle Reaktion auf dieser Ebene zeigen. |
| Zwei-Pass-Signalverarbeitung: | Trennen Sie die historische Signalanzeige von der Echtzeit-Alarmgenerierung. Dies ermöglicht es Händlern, vergangene Signale zur Analyse zu sehen, während gleichzeitig Alarm-Spam in der Gegenwart verhindert wird. |
| Korrekte Pufferindizierung: | Pfeil-Puffer müssen als Zeitreihen (ArraySetAsSeries) festgelegt werden, um sie an Preis-Arrays auszurichten. Ohne dies erscheinen Pfeile auf den falschen Bars und historische Signale verschwinden. |
| Objektbasierte visuelle Rückmeldung: | Die Verwendung von OBJ_RECTANGLE für Zonen stellt sicher, dass sie bei Zeitrahmenänderungen sichtbar bleiben und für optimale Sichtbarkeit mit Farben, Füllungen und Transparenz angepasst werden können. |
| Verwaltung dynamischer Arrays: | Die Verwendung eines dynamischen Arrays von Zonenstrukturen ermöglicht die Handhabung einer unbegrenzten Anzahl aktiver Zonen, jede mit ihren eigenen Eigenschaften und ihrem ausgelösten Status. |
| Zeitbasierter Ablauf: | Zonen sollten nach einer bestimmten Anzahl von Bars (ExtendBars) ablaufen, um zu verhindern, dass veraltete Ebenen das Chart überladen und falsche Signale erzeugen. |
| Alarm-Drosselung: | Verfolgen Sie lastAlertTime, um mehrere Alarme für dieselbe Bar zu verhindern und klare, nicht wiederholende Benachrichtigungen sicherzustellen. |
| Modulare Musterfunktionen: | Trennen Sie jedes Umkehrmuster in seine eigene Funktion und kombinieren Sie diese dann in DemandReversal/SupplyReversal. Dies macht das Hinzufügen neuer Muster einfach und wartbar. |
Anlagen
| Dateiname | Version | Typ | Beschreibung |
|---|---|---|---|
| Liquidity_Zone_Reaction_Indicator.mq5 | 3.0 | MQL5-Indikator | Vollständiger Multi-Timeframe-Indikator für Liquiditätszonenreaktionen mit Zonenrechtecken, Pfeilsignalen und Alarmen. |
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/21581
Warnung: Alle Rechte sind von MetaQuotes Ltd. vorbehalten. Kopieren oder Vervielfältigen untersagt.
Dieser Artikel wurde von einem Nutzer der Website verfasst und gibt dessen persönliche Meinung wieder. MetaQuotes Ltd übernimmt keine Verantwortung für die Richtigkeit der dargestellten Informationen oder für Folgen, die sich aus der Anwendung der beschriebenen Lösungen, Strategien oder Empfehlungen ergeben.
Vereinheitlichte Validierungspipeline gegen Backtest-Overfitting
Entwicklung eines Toolkits zur Price-Action-Analyse (Teil 64): Manuell gezeichnete Trendlinien mit der automatisierten Überwachung synchronisieren
Eine alternative Log-datei mit der Verwendung der HTML und CSS
MetaTrader 5 – Leitfaden für maschinelles Lernen (Teil 8): Bayes’sche Hyperparameter-Optimierung mit Purged Cross-Validation und Trial Pruning
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.