English 日本語
preview
Automatisierung des Indikators Market Memory Zones: Bereiche, zu denen der Kurs voraussichtlich zurückkehrt

Automatisierung des Indikators Market Memory Zones: Bereiche, zu denen der Kurs voraussichtlich zurückkehrt

MetaTrader 5Beispiele |
33 0
Hlomohang John Borotho
Hlomohang John Borotho

Inhaltsverzeichnis

  1. Einführung
  2. Überblick über die Automatisierung
  3. Die ersten Schritte
  4. Backtest-Ergebnisse
  5. Schlussfolgerung


Einführung

Im vorangegangenen Artikel haben wir den Indikator Market Memory Zones entwickelt, indem wir Schlüsselbereiche identifiziert haben, in denen der Kurs eine erkennbare Intention des Marktes zeigte – sei es durch Displacement-Bewegungen, strukturelle Übergänge oder Liquiditäts-Sweeps. Wir haben die rohen Kursbewegungen in strukturierte Zonen umgewandelt, die visuell darstellen, wo Ungleichgewichte, Kontrollwechsel oder Liquiditätsereignisse auftraten. Anstatt willkürliche Unterstützungs- und Widerstandszonen zu markieren, wurde der Indikator entwickelt, um Bereiche hervorzuheben, die durch konkretes Marktverhalten bestätigt werden: impulsive Ausweitungen jenseits der normalen Volatilität, eindeutige Change of Character (CHoCH)-Ereignisse sowie entscheidende Liquiditätsabgriffe, auf die eine Trendumkehr folgt.

Nun gehen wir den nächsten logischen Schritt: Wir wandeln diesen analytischen Rahmen in einen vollautomatischen Expert Advisor um, der in der Lage ist, Trades auszuführen. Anstatt Zonen als passive visuelle Anhaltspunkte zu betrachten, wandelt der Automatisierungsprozess sie in strukturierte Entscheidungspunkte um – er erkennt ihre Entstehung in Echtzeit, bewertet ihre Gültigkeit und führt Trades nur dann aus, wenn die Kursreaktion in der Zone die Marktintention bestätigt. Indem wir Bestätigungslogik, Verhaltensfilter und Risikomanagementregeln direkt in das System integrieren, gehen wir von der Beobachtung zur Ausführung über.


Überblick über die Automatisierung

Displacement-Zonen werden automatisch ermittelt, indem ungewöhnlich starke Impulskerzen erkannt werden, die auf Dringlichkeit und ein Ungleichgewicht am Markt hindeuten. Der EA identifiziert diese Zonen, wenn die Spanne einer Kerze die ATR deutlich übersteigt, der Kerzenkörper im Verhältnis zur Gesamtspanne groß ist, nur eine minimale Überlappung mit der vorherigen Kerze vorliegt und die Kerze nahe ihrem Extremwert schließt. Sobald dies erkannt wird, wird der gesamte Kerzenbereich zur Zone, und die Richtung des Schlusskurses bestimmt die Tendenz. Anstatt den Ausbruch selbst zu handeln, wartet der EA darauf, dass sich der Kurs von dieser Zone entfernt und später wieder dorthin zurückkehrt. Ein Kauf wird in einem bullischen Displacement ausgelöst, wenn der Kurs die Zone erneut erreicht und eine Bestätigung auf einem niedrigeren Zeitrahmen zeigt, wie etwa eine Zurückweisung oder einen Wechsel der Mikrostruktur, wobei Stopps außerhalb der Zone platziert und Kursziele auf nahegelegene Strukturhöchststände festgelegt werden. Das Verkaufsszenario spiegelt diese Logik für ein bärisches Displacement wider.

Displacement-Zonen

Strukturübergangszonen werden automatisch ermittelt, indem Brüche in der bisherigen Marktstruktur erkannt werden, die auf einen Kontrollwechsel zwischen Käufern und Verkäufern hindeuten. Der EA verfolgt Swing-Hochs und -Tiefs und erkennt einen Change of Character (CHoCH), wenn der Kurs entgegen dem vorherrschenden Trend ausbricht, beispielsweise wenn in einem Abwärtstrend ein Swing-Hoch durchbrochen wird. Die Zone wird als die letzte entgegengesetzte Kerze vor dem Strukturbruch definiert. Bei einem bullischen Trendwechsel wartet der EA darauf, dass der Kurs in diesen Bereich zurückfällt und die Stärke durch höhere Tiefststände oder bullisch schließende Kerzen bestätigt wird, bevor er eine Kaufposition eröffnet. Die Stopps werden jenseits des Übergangs-Swings gesetzt, und die Kursziele richten sich nach früheren Höchstständen oder Fortsetzungsniveaus. Das Verkaufs-Setup folgt derselben Logik in umgekehrter Richtung.

Strukturübergangszonen

Liquiditäts-Sweep-Zonen werden automatisiert, indem Kerzen erkannt werden, die kurzzeitig über vorherige Höchststände oder unter vorherige Tiefststände steigen bzw. fallen und sich dann schnell wieder innerhalb der Spanne umkehren. Diese Kursbewegungen sind oft Ausdruck von Stop-Hunts, auf die eine starke Tendenz in eine bestimmte Richtung folgt. Der EA markiert die Spanne der Sweep-Kerze als Zone und wartet, bis sich der Kurs davon entfernt hat, bevor er dessen Rückkehr beobachtet. In einem Kaufszenario holt der Preis Liquidität unter einem Tief ab, dreht dann nach oben ab und kehrt später in diesen Bereich zurück; der EA wartet vor dem Einstieg auf eine Bestätigung, beispielsweise darauf, dass kein neues Tief erreicht wird, oder auf eine bullische Engulfing-Formation. Die Stopps werden jenseits des Sweep-Extrems gesetzt, und die Ziele richten sich nach der gegenläufigen Liquidität oder den Widerstandsniveaus. Das Verkaufsszenario spiegelt diese Logik wider, nachdem die Höchststände durchbrochen wurden.

Liquiditäts-Sweep


Die ersten Schritte

//+------------------------------------------------------------------+
//|                                                     Auto MMZ.mq5 |
//|                        GIT under Copyright 2025, MetaQuotes Ltd. |
//|                     https://www.mql5.com/en/users/johnhlomohang/ |
//+------------------------------------------------------------------+
#property copyright "GIT under Copyright 2025, MetaQuotes Ltd."
#property link      "https://www.mql5.com/en/users/johnhlomohang/"
#property version   "1.00"

#include <Trade/Trade.mqh>
#include <Math/Stat/Math.mqh>
CTrade trade;

//+------------------------------------------------------------------+
//| Input Parameters                                                 |
//+------------------------------------------------------------------+
input ENUM_TIMEFRAMES HTF = PERIOD_H1;          // Higher Timeframe
input ENUM_TIMEFRAMES LTF = PERIOD_M5;          // Lower Timeframe
input ENUM_TIMEFRAMES ATF = PERIOD_M15;         // Analysis Timeframe (for zones)
input int             SwingBars = 3;            // Bars for swing detection

// Displacement Zone Parameters
input double          Displacement_ATR_Multiplier = 1.8;    // ATR multiplier for displacement
input double          Displacement_Body_Percent = 60.0;     // Minimum body percentage
input double          Displacement_Overlap_Max = 30.0;      // Maximum overlap with previous candle
input double          Displacement_Close_Extreme = 20.0;    // Close near extreme percentage

// Risk Management
input double          RiskPercent = 1.0;        // Risk per trade (%)
input int             StopLoss_Pips = 150;      // Stop Loss in pips
input double          RiskRewardRatio = 2.0;    // Risk/Reward ratio
input bool            UseDynamicSL = true;      // Use zone-based SL
input bool            UseStructureTP = true;    // Use structure for TP

// Trade Management
input int             MaxTradesPerDay = 10;     // Maximum trades per day
input bool            AllowConsecutiveTrades = true;  // Allow multiple trades in same direction
input double          TrailingStop_ATR = 1.5;   // ATR multiple for trailing stop

// Visualization
input bool            ShowZones = true;         // Show zone rectangles
input bool            ShowArrows = true;        // Show entry arrows
input bool            ShowLabels = true;        // Show trade labels
input bool            DebugMode = true;         // Show debug information

//+------------------------------------------------------------------+
//| Zone Structure                                                   |
//+------------------------------------------------------------------+
enum ZONE_TYPE
{
   ZONE_DISPLACEMENT,
   ZONE_STRUCTURE_TRANSITION,
   ZONE_LIQUIDITY_SWEEP
};

struct TradeZone
{
   datetime          time;
   double            high;
   double            low;
   double            mid;
   ZONE_TYPE         type;
   int               direction;      // 1 for bullish, -1 for bearish
   double            atr;            // ATR at time of zone formation
   datetime          expiry;         // Zone expiry time
   bool              active;
   bool              triggered;
   string            symbol;
   ENUM_TIMEFRAMES   tf;
   
   // Constructor to initialize with default values
   TradeZone()
   {
      Reset();
   }
   
   // Reset method
   void Reset()
   {
      time = 0;
      high = 0;
      low = 0;
      mid = 0;
      type = ZONE_DISPLACEMENT;
      direction = 0;
      atr = 0;
      expiry = 0;
      active = false;
      triggered = false;
      symbol = _Symbol;
      tf = PERIOD_CURRENT;
   }
};

Zu Beginn legen wir die Grundlage für den Expert Advisor, indem wir die Handels- und Statistikbibliotheken importieren, das CTrade-Objekt für die Orderausführung initialisieren und alle konfigurierbaren Eingabewerte definieren, die die Analyse mehrerer Zeitrahmen, die Regeln zur Erkennung von Displacement-Bewegungen, das Risikomanagement, das Handelsmanagement und das Visualisierungsverhalten steuern. Anhand dieser Eingabewerte kann das System Zonen in höheren, niedrigeren und dem Analyse-Zeitrahmen erkennen, die Stärke von Kursbewegungen anhand von ATR-basierten Bedingungen bewerten und das Risiko durch prozentuale Positionsgrößen, Stop-Loss-Logik und Risiko-Ertrags-Verhältnisse steuern.

Anschließend definieren wir einen Enumerationstyp ZONE_TYPE, um Displacement-, Strukturübergangs- und Liquiditäts-Sweep-Zonen zu klassifizieren, gefolgt von einem strukturierten TradeZone-Datenmodell, in dem alle relevanten Zoneninformationen wie Preisgrenzen, Richtung, ATR zum Zeitpunkt der Bildung, Ablaufzeitpunkt, Aktivierungsstatus und Metadaten gespeichert werden. Der Konstruktor und die Methode Reset() stellen sicher, dass jede Zone aus einem sauberen, kontrollierten Zustand startet, und bieten so einen strukturierten und skalierbaren Rahmen für die Verwaltung mehrerer dynamischer Markt-Gedächtniszonen innerhalb des EAs.

//+------------------------------------------------------------------+
//| Global Variables                                                 |
//+------------------------------------------------------------------+
SwingPoint htf_lastHigh, htf_prevHigh;
SwingPoint htf_lastLow, htf_prevLow;
SwingPoint atf_lastHigh, atf_prevHigh;
SwingPoint atf_lastLow, atf_prevLow;

TradeZone zones[100];
int zoneCount = 0;

TradeInfo activeTrades[10];
int activeTradeCount = 0;

datetime lastTradeDay = 0;
int tradesToday = 0;

double currentATR = 0;
int atrHandle = -1;

MqlDateTime today;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   // Initialize ATR indicator
   atrHandle = iATR(_Symbol, PERIOD_CURRENT, 14);
   if(atrHandle == INVALID_HANDLE)
   {
      Print("Failed to create ATR indicator");
      return INIT_FAILED;
   }
   
   // Initialize swing points
   htf_lastHigh.Reset();
   htf_prevHigh.Reset();
   htf_lastLow.Reset();
   htf_prevLow.Reset();
   atf_lastHigh.Reset();
   atf_prevHigh.Reset();
   atf_lastLow.Reset();
   atf_prevLow.Reset();
   
   // Initialize zones array
   for(int i = 0; i < ArraySize(zones); i++)
      zones[i].Reset();
   zoneCount = 0;
   
   // Initialize active trades array
   for(int i = 0; i < ArraySize(activeTrades); i++)
      activeTrades[i].Reset();
   activeTradeCount = 0;
   
   // Initialize trade tracking
   lastTradeDay = 0;
   tradesToday = 0;
   
   // Set magic number for trades
   trade.SetExpertMagicNumber(12345);
   
   Print("EA Initialized. Zone Types: Displacement, Structure Transition, Liquidity Sweep");
   
   return INIT_SUCCEEDED;
}

In diesem Abschnitt legen wir den zentralen globalen Zustand des Expert Advisors fest, indem wir Tracker für Swing-Punkte sowohl für höhere als auch für den Analyse-Zeitrahmen deklarieren, Arrays zur Speicherung von bis zu 100 erkannten Handelszonen und 10 aktiven Trades sowie Variablen zur Verwaltung der täglichen Handelslimits und der ATR-basierten Volatilitätsverfolgung. In der Funktion OnInit() initialisieren wir das ATR-Indikator-Handle für die Volatilitätsberechnungen, setzen alle Swing-Strukturen zurück, um saubere Startwerte zu gewährleisten, löschen und bereiten die Arrays für die Zonen und aktiven Trades vor und setzen die Tageshandelszähler zurück. Insgesamt gewährleistet diese Konfiguration, dass das System in einem kontrollierten, geordneten Zustand startet, mit ordnungsgemäß initialisierten Datenstrukturen, die für die Echtzeit-Zonenerkennung und die Handelsausführung bereit sind.

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   if(atrHandle != INVALID_HANDLE)
      IndicatorRelease(atrHandle);
   
   ObjectsDeleteAll(0, "ZONE_");
   ObjectsDeleteAll(0, "TRADE_");
   ChartRedraw();
   
   Print("EA Deinitialized");
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
   // Update current ATR
   UpdateATR();
   
   // Check for new bars on analysis timeframe
   static datetime lastAtfBar = 0;
   datetime currentAtfBar = iTime(_Symbol, ATF, 0);
   
   if(currentAtfBar != lastAtfBar)
   {
      lastAtfBar = currentAtfBar;
      
      if(DebugMode) Print("New ATF bar: ", TimeToString(currentAtfBar));
      
      // Update market structure
      UpdateMarketStructure();
      
      // Detect new zones
      DetectDisplacementZones();
      DetectStructureTransitionZones();
      DetectLiquiditySweepZones();
      
      // Clean up expired zones
      CleanupZones();
   }
   
   // Check zone entries on every tick
   CheckZoneEntries();
   
   // Manage open positions
   ManageOpenTrades();
   
   // Update visualization
   if(ShowZones) UpdateVisualization();
}

//+------------------------------------------------------------------+
//| Update Market Structure                                          |
//+------------------------------------------------------------------+
void UpdateMarketStructure()
{
   // Update HTF structure
   UpdateSwingPoints(HTF, htf_lastHigh, htf_prevHigh, htf_lastLow, htf_prevLow);
   
   // Update Analysis TF structure
   UpdateSwingPoints(ATF, atf_lastHigh, atf_prevHigh, atf_lastLow, atf_prevLow);
   
   if(DebugMode && atf_lastHigh.price > 0 && atf_lastLow.price > 0)
   {
      Print("Market Structure - ATF High: ", atf_lastHigh.price, 
            " Low: ", atf_lastLow.price,
            " ATR: ", currentATR);
   }
}

Die Funktion OnDeinit() sorgt für ein ordnungsgemäßes Beenden des Expert Advisors, indem sie das Handle des ATR-Indikators freigibt, um Systemressourcen freizugeben, und alle Chart-Objekte löscht, die mit Zonen und Trades in Verbindung stehen, wobei sie deren Präfixe verwendet. Anschließend wird das Chart aktualisiert, um verbleibende grafische Artefakte zu entfernen, und es wird eine Bestätigungsmeldung protokolliert. Dadurch wird sichergestellt, dass beim Entfernen oder Neustarten des EAs keine übrig gebliebenen Indikatoren, Zeichnungen oder Speicherzuweisungen zukünftige Ausführungen beeinträchtigen, wodurch die Stabilität gewahrt und Ressourcenlecks verhindert werden.

Die Funktion OnTick() bildet das operative Kernstück des EAs und koordiniert die Erkennung, Ausführung und Verwaltungslogik in Echtzeit. Bei jedem Tick aktualisiert das System die aktuelle ATR und prüft, ob sich auf dem Analyse-Zeitrahmen eine neue Kerze gebildet hat, bevor es die Marktstruktur neu berechnet und nach neuen Zonen für Displacement, Structure Transition und Liquidity Sweep sucht. Abgelaufene Zonen werden systematisch bereinigt, während die Einstiegsbedingungen bei jedem Tick kontinuierlich ausgewertet werden, um eine zeitnahe Handelsausführung zu gewährleisten. Offene Positionen werden aktiv verwaltet, und die visuellen Elemente werden aktualisiert, sofern diese Funktion aktiviert ist. Die Funktion UpdateMarketStructure() unterstützt diesen Arbeitsablauf, indem sie die Swing-Punkte sowohl in höheren als auch in Analyse-Zeitrahmen aktualisiert und so sicherstellt, dass der EA stets an den sich verändernden strukturellen Kontext und die Volatilitätsbedingungen angepasst bleibt.

//+------------------------------------------------------------------+
//| Detect Displacement Zones                                        |
//+------------------------------------------------------------------+
void DetectDisplacementZones()
{
   MqlRates rates[];
   ArraySetAsSeries(rates, true);
   int copied = CopyRates(_Symbol, ATF, 0, 5, rates);
   
   if(copied < 2) return;
   
   // Check latest candle for displacement
   MqlRates candle = rates[0];
   MqlRates prevCandle = rates[1];
   
   // Calculate candle metrics
   double range = candle.high - candle.low;
   if(range <= 0) return;
   
   double body = MathAbs(candle.close - candle.open);
   double bodyPercent = (body / range) * 100;
   
   // Calculate overlap with previous candle
   double overlapHigh = MathMin(candle.high, prevCandle.high);
   double overlapLow = MathMax(candle.low, prevCandle.low);
   double overlap = (overlapHigh > overlapLow) ? overlapHigh - overlapLow : 0;
   double overlapPercent = (overlap / range) * 100;
   
   // Check close near extreme (for bullish or bearish)
   double closeToHigh = candle.high - candle.close;
   double closeToLow = candle.close - candle.low;
   double closePercent;
   
   if(candle.close > candle.open) // Bullish candle
      closePercent = (closeToHigh / range) * 100;
   else // Bearish candle
      closePercent = (closeToLow / range) * 100;
   
   // Debug information
   if(DebugMode)
   {
      Print("Checking displacement - Range: ", range, 
            " ATR*Mult: ", currentATR * Displacement_ATR_Multiplier,
            " Body%: ", bodyPercent, " Req: ", Displacement_Body_Percent,
            " Overlap%: ", overlapPercent, " Max: ", Displacement_Overlap_Max,
            " Close%: ", closePercent, " Max: ", Displacement_Close_Extreme);
   }
   
   // Check displacement conditions
   bool isDisplacement = 
      (range >= currentATR * Displacement_ATR_Multiplier) &&
      (bodyPercent >= Displacement_Body_Percent) &&
      (overlapPercent <= Displacement_Overlap_Max) &&
      (closePercent <= Displacement_Close_Extreme);
   
   if(isDisplacement)
   {
      // Check if similar zone already exists (within last 5 bars)
      bool zoneExists = false;
      for(int i = 0; i < zoneCount; i++)
      {
         if(zones[i].active && MathAbs(zones[i].time - candle.time) < PeriodSeconds(ATF) * 5)
         {
            zoneExists = true;
            break;
         }
      }
      
      if(!zoneExists)
      {
         // Create displacement zone
         TradeZone zone;
         zone.time = candle.time;
         zone.high = candle.high;
         zone.low = candle.low;
         zone.mid = (zone.high + zone.low) / 2.0;
         zone.type = ZONE_DISPLACEMENT;
         zone.direction = (candle.close > candle.open) ? 1 : -1;
         zone.atr = currentATR;
         zone.expiry = zone.time + (24 * 60 * 60);  // 24 hour expiry
         zone.active = true;
         zone.triggered = false;
         zone.symbol = _Symbol;
         zone.tf = ATF;
         
         // Add to zones array
         int index = zoneCount % 100;
         zones[index] = zone;
         zoneCount++;
         
         Print("Displacement Zone Detected: ", 
               (zone.direction == 1) ? "BULLISH" : "BEARISH",
               " | High: ", zone.high, " Low: ", zone.low,
               " | Time: ", TimeToString(zone.time));
      }
   }
}

//+------------------------------------------------------------------+
//| Detect Structure Transition Zones (CHoCH)                        |
//+------------------------------------------------------------------+
void DetectStructureTransitionZones()
{
   // Check for bullish CHoCH (downtrend to uptrend)
   if(atf_prevHigh.price > 0 && atf_lastHigh.price > atf_prevHigh.price &&
      atf_prevLow.price > 0 && atf_lastLow.price > atf_prevLow.price)
   {
      // Bullish transition - look for last bearish candle before break
      MqlRates rates[];
      ArraySetAsSeries(rates, true);
      int startBar = MathMax(0, atf_lastHigh.barIndex - 10);
      int copied = CopyRates(_Symbol, ATF, startBar, 20, rates);
      
      if(DebugMode) Print("Checking Bullish CHoCH - PrevHigh: ", atf_prevHigh.price, 
                        " LastHigh: ", atf_lastHigh.price);
      
      for(int i = 0; i < copied; i++)
      {
         if(rates[i].close < rates[i].open)  // Bearish candle
         {
            CreateStructureTransitionZone(rates[i], 1);
            break;
         }
      }
   }
   
   // Check for bearish CHoCH (uptrend to downtrend)
   if(atf_prevLow.price > 0 && atf_lastLow.price < atf_prevLow.price &&
      atf_prevHigh.price > 0 && atf_lastHigh.price < atf_prevHigh.price)
   {
      // Bearish transition - look for last bullish candle before break
      MqlRates rates[];
      ArraySetAsSeries(rates, true);
      int startBar = MathMax(0, atf_lastLow.barIndex - 10);
      int copied = CopyRates(_Symbol, ATF, startBar, 20, rates);
      
      if(DebugMode) Print("Checking Bearish CHoCH - PrevLow: ", atf_prevLow.price, 
                        " LastLow: ", atf_lastLow.price);
      
      for(int i = 0; i < copied; i++)
      {
         if(rates[i].close > rates[i].open)  // Bullish candle
         {
            CreateStructureTransitionZone(rates[i], -1);
            break;
         }
      }
   }
}

Die Funktion DetectDisplacementZones() analysiert die jüngste Kerze im Analysezeitrahmen und prüft anhand strenger quantitativer Filter, ob es sich um eine echte Displacement-Bewegung handelt. Es berechnet die Gesamtspanne der Kerze, den prozentualen Anteil der Kerzenkörpergröße, die Überlappung mit der vorherigen Kerze und wie nah der Schlusskurs am Extremwert der Kerze liegt. Diese Kennzahlen werden mit ATR-basierten und prozentualen Schwellenwerten verglichen, um eine starke Marktintention mit geringer Überlappung und hohem Momentum zu bestätigen. Wenn alle Displacement-Bedingungen erfüllt sind und noch keine ähnliche Zone aus der jüngsten Vergangenheit existiert, erstellt die Funktion ein neues TradeZone-Objekt, weist diesem Preisgrenzen, Mittelpunkt, Richtung, ATR-Kontext, Ablaufzeit und Aktivierungsstatus zu und speichert es anschließend im zones-Array. Dadurch wird sichergestellt, dass nur statistisch signifikante impulsartige Kursbewegungen als potenzielle Rückkehrzonen erfasst werden.

Die Funktion DetectStructureTransitionZones() konzentriert sich auf die Identifizierung von Change of Character (CHoCH)-Ereignissen durch die Analyse von Veränderungen der Swing-Struktur auf dem Analyse-Zeitrahmen. Ein bullischer Übergang wird erkannt, wenn sich nach einem vorangegangenen Abwärtstrend sowohl höhere Hochs als auch höhere Tiefs bilden, während ein bärischer Übergang festgestellt wird, wenn niedrigere Tiefs und niedrigere Hochs einen vorangegangenen Aufwärtstrend durchbrechen. Sobald sich ein Strukturwechsel bestätigt hat, sucht die Funktion rückwärts nach der letzten entgegengesetzten Kerze vor dem Durchbruch – bei Übergängen von bärisch zu bullisch ist dies eine bärische Kerze, bei Übergängen von bullisch zu bärisch eine bullische Kerze – und nutzt diese, um mithilfe einer speziellen Erstellungsfunktion eine Strukturübergangszone zu erstellen.

//+------------------------------------------------------------------+
//| Detect Liquidity Sweep Zones                                     |
//+------------------------------------------------------------------+
void DetectLiquiditySweepZones()
{
   MqlRates rates[];
   ArraySetAsSeries(rates, true);
   int copied = CopyRates(_Symbol, ATF, 0, 5, rates);
   
   if(copied < 3) return;
   
   // Check for buy-side liquidity sweep (sweep of lows)
   if(atf_lastLow.price > 0 && rates[1].low < atf_lastLow.price)
   {
      // Check if there's a bullish reversal after the sweep
      bool bullishReversal = rates[1].close > rates[1].open || 
                            (rates[0].close > rates[0].open && rates[0].close > rates[1].high);
      
      if(bullishReversal)
      {
         if(DebugMode) Print("Buy-side Liquidity Sweep detected - Swept Low: ", atf_lastLow.price,
                           " Sweep Candle Low: ", rates[1].low);
         
         CreateLiquiditySweepZone(rates[1], 1);  // Bullish reversal
      }
   }
   
   // Check for sell-side liquidity sweep (sweep of highs)
   if(atf_lastHigh.price > 0 && rates[1].high > atf_lastHigh.price)
   {
      // Check if there's a bearish reversal after the sweep
      bool bearishReversal = rates[1].close < rates[1].open || 
                            (rates[0].close < rates[0].open && rates[0].close < rates[1].low);
      
      if(bearishReversal)
      {
         if(DebugMode) Print("Sell-side Liquidity Sweep detected - Swept High: ", atf_lastHigh.price,
                           " Sweep Candle High: ", rates[1].high);
         
         CreateLiquiditySweepZone(rates[1], -1);  // Bearish reversal
      }
   }
}

//+------------------------------------------------------------------+
//| Create Structure Transition Zone                                 |
//+------------------------------------------------------------------+
void CreateStructureTransitionZone(MqlRates &candle, int direction)
{
   // Check if similar zone already exists (within last 5 bars)
   bool zoneExists = false;
   for(int i = 0; i < zoneCount; i++)
   {
      if(zones[i].active && zones[i].type == ZONE_STRUCTURE_TRANSITION &&
         MathAbs(zones[i].time - candle.time) < PeriodSeconds(ATF) * 5)
      {
         zoneExists = true;
         break;
      }
   }
   
   if(!zoneExists)
   {
      TradeZone zone;
      zone.time = candle.time;
      zone.high = candle.high;
      zone.low = candle.low;
      zone.mid = (zone.high + zone.low) / 2.0;
      zone.type = ZONE_STRUCTURE_TRANSITION;
      zone.direction = direction;
      zone.atr = currentATR;
      zone.expiry = zone.time + (12 * 60 * 60);  // 12 hour expiry
      zone.active = true;
      zone.triggered = false;
      zone.symbol = _Symbol;
      zone.tf = ATF;
      
      // Add to zones array
      int index = zoneCount % 100;
      zones[index] = zone;
      zoneCount++;
      
      Print("Structure Transition Zone Detected: ",
            (zone.direction == 1) ? "BULLISH (CHoCH)" : "BEARISH (CHoCH)",
            " | High: ", zone.high, " Low: ", zone.low,
            " | Time: ", TimeToString(zone.time));
   }
}

Die Funktion DetectLiquiditySweepZones() automatisiert die Erkennung von Stop-Hunts, indem sie die jüngsten Kerzen nach Kursbewegungen absucht, die über frühere Swing-Hochs oder -Tiefs hinausgehen. Sie prüft, ob der Kurs vorübergehend ein bekanntes Swing-Niveau durchbricht, und bestätigt anschließend, dass eine Trendumkehr folgt – entweder noch innerhalb derselben Kerze oder in der nächsten. Wird ein vorheriges Tief durchbrochen und folgt darauf eine bullische Bestätigung, entsteht eine Liquiditäts-Sweep auf der Kaufseite; wird hingegen ein vorheriges Hoch durchbrochen und folgt darauf eine bärische Bestätigung, bildet sich eine Liquiditäts-Sweep auf der Verkaufsseite. Debug-Ausgaben sorgen für Transparenz während der Erkennung.

Die Funktion CreateStructureTransitionZone() regelt die Erstellung einer CHoCH-basierten Zone, sobald ein Strukturbruch identifiziert wurde. Bevor eine neue Zone erstellt wird, wird zunächst geprüft, ob innerhalb eines kürzlichen Zeitfensters bereits eine ähnliche aktive Strukturübergangszone existiert, um Doppelungen zu vermeiden. Wird keine entsprechende Zone aus der jüngeren Vergangenheit gefunden, initialisiert das System ein neues TradeZone-Objekt anhand der Kerze, die dem strukturellen Bruch vorausging, und legt dabei die Kursgrenzen, den Mittelpunkt, die Richtung (bullisch oder bärisch), den ATR-Kontext sowie eine Laufzeit von 12 Stunden fest. Die Zone wird anschließend mithilfe eines rollierenden Indexmechanismus im Zonen-Array gespeichert, zur Überwachung aktiviert und auf dem Terminal protokolliert, wodurch sichergestellt wird, dass jeder strukturelle Übergang sauber erfasst und innerhalb des Speicherrahmens der EA verwaltet wird.

//+------------------------------------------------------------------+
//| Check Zone Entries                                               |
//+------------------------------------------------------------------+
void CheckZoneEntries()
{
   // Reset daily trade count if new day
   TimeToStruct(TimeCurrent(), today);
   if(lastTradeDay != today.day)
   {
      tradesToday = 0;
      lastTradeDay = today.day;
      if(DebugMode) Print("New day started. Trade counter reset.");
   }
   
   // Check if we can take more trades today
   if(MaxTradesPerDay > 0 && tradesToday >= MaxTradesPerDay)
   {
      if(tradesToday == MaxTradesPerDay)
         Print("Maximum daily trades (", MaxTradesPerDay, ") reached for today.");
      return;
   }
   
   double currentBid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double currentAsk = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   
   for(int i = 0; i < zoneCount; i++)
   {
      if(!zones[i].active || zones[i].triggered) continue;
      
      // Check if zone is expired
      if(TimeCurrent() > zones[i].expiry)
      {
         zones[i].active = false;
         continue;
      }
      
      // Check BUY entries (bullish zones)
      if(zones[i].direction == 1)
      {
         // Check if price is returning to zone (using Ask for buys)
         if(currentAsk >= zones[i].low && currentAsk <= zones[i].high)
         {
            // Get LTF confirmation
            if(CheckLTFConfirmation(true))
            {
               Print("BUY Signal: Price in ", ZoneTypeToString(zones[i].type), 
                     " zone | Entry: ", currentAsk, " Zone: [", zones[i].low, "-", zones[i].high, "]");
               ExecuteZoneTrade(true, zones[i], currentAsk);
               zones[i].triggered = true;
               tradesToday++;
               break;  // Take only one trade per tick
            }
         }
      }
      // Check SELL entries (bearish zones)
      else if(zones[i].direction == -1)
      {
         // Check if price is returning to zone (using Bid for sells)
         if(currentBid >= zones[i].low && currentBid <= zones[i].high)
         {
            // Get LTF confirmation
            if(CheckLTFConfirmation(false))
            {
               Print("SELL Signal: Price in ", ZoneTypeToString(zones[i].type), 
                     " zone | Entry: ", currentBid, " Zone: [", zones[i].low, "-", zones[i].high, "]");
               ExecuteZoneTrade(false, zones[i], currentBid);
               zones[i].triggered = true;
               tradesToday++;
               break;  // Take only one trade per tick
            }
         }
      }
   }
}

//+------------------------------------------------------------------+
//| Check LTF Confirmation                                           |
//+------------------------------------------------------------------+
bool CheckLTFConfirmation(bool forBuy)
{
   MqlRates ltfRates[];
   ArraySetAsSeries(ltfRates, true);
   int copied = CopyRates(_Symbol, LTF, 0, 5, ltfRates);
   
   if(copied < 3) return false;
   
   // For BUY confirmation
   if(forBuy)
   {
      // Simple confirmation: bullish candle closing above midpoint
      if(ltfRates[0].close > ltfRates[0].open && 
         ltfRates[0].close > ((ltfRates[0].high + ltfRates[0].low) / 2))
      {
         return true;
      }
      
      // Alternative: bullish engulfing
      if(ltfRates[0].close > ltfRates[0].open && 
         ltfRates[0].close > ltfRates[1].high && 
         ltfRates[0].open < ltfRates[1].low)
      {
         return true;
      }
   }
   // For SELL confirmation
   else
   {
      // Simple confirmation: bearish candle closing below midpoint
      if(ltfRates[0].close < ltfRates[0].open && 
         ltfRates[0].close < ((ltfRates[0].high + ltfRates[0].low) / 2))
      {
         return true;
      }
      
      // Alternative: bearish engulfing
      if(ltfRates[0].close < ltfRates[0].open && 
         ltfRates[0].close < ltfRates[1].low && 
         ltfRates[0].open > ltfRates[1].high)
      {
         return true;
      }
   }
   
   return false;
}

Hier implementieren wir die zentrale Ausführungs-Engine, die entscheidet, wann aus einer erkannten ‚Market Memory Zone‘ ein konkreter Trade wird. Die Funktion beginnt damit, die täglichen Handelslimits zu verwalten, den Zähler zu Beginn eines neuen Handelstags zurückzusetzen und weitere Einstiege zu verhindern, sobald die maximale Anzahl an Trades erreicht ist. Anschließend ruft es die aktuellen Geld- und Briefkurse ab und durchläuft alle aktiven, noch nicht ausgelösten Zonen. Für jede Zone werden zunächst die Ablaufbedingungen überprüft, um sicherzustellen, dass veraltete Zonen deaktiviert werden. Kehrt der Kurs innerhalb der Grenzen einer gültigen Zone zurück, prüft der EA, ob es sich um ein bullisches oder bärisches Setup handelt, und fordert anschließend eine Bestätigung auf einem niedrigeren Zeitrahmen an, bevor er einen Trade ausführt. Sobald ein Handel platziert wurde, wird die Zone als ausgelöst markiert, um doppelte Einstiege zu verhindern, und die tägliche Handelsanzahl wird erhöht, wodurch eine disziplinierte Ausführungssteuerung gewährleistet wird.

Die Funktion CheckLTFConfirmation() führt vor dem Absenden einer Order eine Verhaltensprüfung durch und dient dabei als Verfeinerungsfilter, um blinden Handel allein auf Basis eines Levels zu vermeiden. Bei Kaufsignalen bestätigt es entweder eine starke bullische Kerze, die über ihrem Mittelpunkt schließt, oder ein bullisches Engulfing-Muster; bei Verkaufssignalen sucht es nach den bärischen Entsprechungen. Indem der EA Momentum-Signale aus dem niedrigeren Zeitrahmen verlangt, stellt er sicher, dass Einstiegspunkte auf Reaktionen und Tendenzen basieren und nicht auf bloßen Preiskontakten innerhalb einer Zone.

//+------------------------------------------------------------------+
//| Execute Zone Trade                                               |
//+------------------------------------------------------------------+
void ExecuteZoneTrade(bool isBuy, TradeZone &zone, double entryPrice)
{
   // Check if position already exists for this symbol
   if(PositionSelect(_Symbol))
   {
      if(!AllowConsecutiveTrades)
      {
         Print("Position already exists and AllowConsecutiveTrades is false, skipping trade");
         return;
      }
   }
   
   ENUM_ORDER_TYPE orderType = isBuy ? ORDER_TYPE_BUY : ORDER_TYPE_SELL;
   
   // Calculate stop loss
   double stopLoss = CalculateZoneStopLoss(isBuy, zone, entryPrice);
   
   // Calculate take profit
   double takeProfit = CalculateZoneTakeProfit(isBuy, zone, entryPrice, stopLoss);
   
   // Calculate lot size
   double volume = CalculateLotSize(entryPrice, stopLoss);
   
   if(volume <= 0)
   {
      Print("Invalid lot size calculated: ", volume, ". Trade cancelled.");
      return;
   }
   
   // Execute trade
   string comment = StringFormat("%s_%s_%s",
      (isBuy ? "BUY" : "SELL"),
      ZoneTypeToString(zone.type),
      TimeToString(TimeCurrent(), TIME_MINUTES));
   
   bool success = trade.PositionOpen(_Symbol, orderType, volume, 
                                     entryPrice, stopLoss, takeProfit, comment);
   
   if(success)
   {
      ulong ticket = trade.ResultOrder();
      Print("Trade Executed Successfully: ", comment,
            " | Ticket: ", ticket,
            " | Entry: ", entryPrice,
            " | SL: ", stopLoss,
            " | TP: ", takeProfit,
            " | Lots: ", volume);
      
      // Store trade info
      if(activeTradeCount < ArraySize(activeTrades))
      {
         activeTrades[activeTradeCount].entryTime = TimeCurrent();
         activeTrades[activeTradeCount].entryPrice = entryPrice;
         activeTrades[activeTradeCount].stopLoss = stopLoss;
         activeTrades[activeTradeCount].takeProfit = takeProfit;
         activeTrades[activeTradeCount].direction = isBuy ? 1 : -1;
         activeTrades[activeTradeCount].zone = zone;
         activeTrades[activeTradeCount].ticket = ticket;
         activeTradeCount++;
      }
   }
   else
   {
      Print("Trade failed: Error Code=", trade.ResultRetcode(),
            " Description=", trade.ResultRetcodeDescription());
   }
}

//+------------------------------------------------------------------+
//| Calculate Zone Stop Loss                                         |
//+------------------------------------------------------------------+
double CalculateZoneStopLoss(bool isBuy, TradeZone &zone, double entryPrice)
{
   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   
   if(UseDynamicSL)
   {
      // Zone-based stop loss with buffer
      double buffer = 50 * point;  // 50 pip buffer
      if(isBuy)
      {
         double sl = zone.low - buffer;
         // Ensure SL is below entry
         if(sl >= entryPrice)
            sl = entryPrice - (100 * point);
         return NormalizeDouble(sl, _Digits);
      }
      else
      {
         double sl = zone.high + buffer;
         // Ensure SL is above entry
         if(sl <= entryPrice)
            sl = entryPrice + (100 * point);
         return NormalizeDouble(sl, _Digits);
      }
   }
   else
   {
      // Fixed pip stop loss
      double slDistance = StopLoss_Pips * 10 * point;
      if(isBuy)
         return NormalizeDouble(entryPrice - slDistance, _Digits);
      else
         return NormalizeDouble(entryPrice + slDistance, _Digits);
   }
}

//+------------------------------------------------------------------+
//| Calculate Zone Take Profit                                       |
//+------------------------------------------------------------------+
double CalculateZoneTakeProfit(bool isBuy, TradeZone &zone, double entry, double sl)
{
   double risk = MathAbs(entry - sl);
   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   
   if(UseStructureTP)
   {
      if(isBuy)
      {
         // Take profit at next structure high
         double target = entry + (risk * RiskRewardRatio);
         
         if(atf_lastHigh.price > entry)
            target = atf_lastHigh.price;
         else if(htf_lastHigh.price > entry)
            target = htf_lastHigh.price;
         
         // Ensure minimum distance
         double minDistance = 50 * point;
         if(target - entry < minDistance)
            target = entry + (risk * RiskRewardRatio);
         
         return NormalizeDouble(target, _Digits);
      }
      else
      {
         // Take profit at next structure low
         double target = entry - (risk * RiskRewardRatio);
         
         if(atf_lastLow.price < entry)
            target = atf_lastLow.price;
         else if(htf_lastLow.price < entry)
            target = htf_lastLow.price;
         
         // Ensure minimum distance
         double minDistance = 50 * point;
         if(entry - target < minDistance)
            target = entry - (risk * RiskRewardRatio);
         
         return NormalizeDouble(target, _Digits);
      }
   }
   else
   {
      // Fixed risk/reward ratio
      if(isBuy)
         return NormalizeDouble(entry + (risk * RiskRewardRatio), _Digits);
      else
         return NormalizeDouble(entry - (risk * RiskRewardRatio), _Digits);
   }
}

Die Funktion ExecuteZoneTrade() verwaltet den gesamten Prozess der Ausführung eines Trades, sobald ein gültiger Zoneneintritt bestätigt wurde. Zunächst wird geprüft, ob für das Wertpapier bereits eine Position besteht, und die Einstellung AllowConsecutiveTrades wird berücksichtigt, um ein unerwünschtes Aufstocken von Positionen zu verhindern. Die Funktion ermittelt anschließend die Orderart (Kauf oder Verkauf), berechnet anhand einer speziellen, auf Zonen basierenden Logik einen Stop-Loss und einen Take-Profit und ermittelt auf der Grundlage von Risikoparametern die entsprechende Lotgröße. Ist das berechnete Volumen gültig, sendet es den Trade über PositionOpen() und fügt einen strukturierten Kommentar hinzu, der die Richtung, den Zonentyp und den Zeitstempel enthält. Bei erfolgreicher Ausführung werden die Handelsdetails zur späteren Verwaltung und Nachverfolgung im Array activeTrades gespeichert; sollte die Order fehlschlagen, protokolliert das System den Rückgabecode und die Beschreibung des Brokers zu Debugging-Zwecken.

Die Stop-Loss- und Take-Profit-Berechnungen sind so ausgelegt, dass sie mit dem Market Memory-Konzept im Einklang stehen. Wenn UseDynamicSL aktiviert ist, wird der Stop-Loss mit einem Sicherheitspuffer außerhalb der Zonengrenze platziert, wodurch eine logische Ungültigkeitserklärung gewährleistet wird, falls der Kurs die Zone vollständig durchbricht; andernfalls wird ein fester, auf Pips basierender Stop angewendet. Der Take-Profit kann dynamisch auf die jüngsten strukturellen Hochs oder Tiefs aus der Analyse oder einem höheren Zeitrahmen ausgerichtet werden, wenn UseStructureTP aktiviert ist, wobei jedoch eine Mindestabstandsanforderung eingehalten wird, um zu enge Ziele zu vermeiden. Ist das strukturbasierte Targeting deaktiviert, wird stattdessen ein festgelegtes Risiko-Ertrags-Verhältnis angewendet.

//+------------------------------------------------------------------+
//| Update Visualization                                             |
//+------------------------------------------------------------------+
void UpdateVisualization()
{
   ObjectsDeleteAll(0, "ZONE_");
   ObjectsDeleteAll(0, "TRADE_");
   
   // Draw zones
   int activeZoneCount = 0;
   for(int i = 0; i < zoneCount; i++)
   {
      if(zones[i].active)
      {
         DrawZone(zones[i], i);
         activeZoneCount++;
      }
   }
   
   // Draw structure levels
   if(ShowLabels)
   {
      if(atf_lastHigh.price > 0)
         CreateHorizontalLine("ATF_High", atf_lastHigh.price, clrRed, STYLE_DASH);
      
      if(atf_lastLow.price > 0)
         CreateHorizontalLine("ATF_Low", atf_lastLow.price, clrBlue, STYLE_DASH);
      
      if(htf_lastHigh.price > 0)
         CreateHorizontalLine("HTF_High", htf_lastHigh.price, clrDarkRed, STYLE_DOT);
      
      if(htf_lastLow.price > 0)
         CreateHorizontalLine("HTF_Low", htf_lastLow.price, clrDarkBlue, STYLE_DOT);
   }
   
   // Show zone count in corner
   if(ShowLabels)
   {
      string labelText = "Active Zones: " + IntegerToString(activeZoneCount);
      CreateLabel("ZoneCount", labelText, 10, 180, clrWhite);
   }
}

//+------------------------------------------------------------------+
//| Draw Zone                                                        |
//+------------------------------------------------------------------+
void DrawZone(TradeZone &zone, int index)
{
   string name = "ZONE_" + IntegerToString(index);
   
   // Calculate zone width (4 bars forward)
   datetime endTime = zone.time + (PeriodSeconds(zone.tf) * 4);
   
   // Draw rectangle
   if(ObjectCreate(0, name, OBJ_RECTANGLE, 0, zone.time, zone.high, endTime, zone.low))
   {
      // Set color based on zone type and direction
      color zoneColor;
      int zoneStyle = STYLE_SOLID;
      
      switch(zone.type)
      {
         case ZONE_DISPLACEMENT:
            zoneColor = (zone.direction == 1) ? clrLimeGreen : clrIndianRed;
            zoneStyle = STYLE_SOLID;
            break;
         case ZONE_STRUCTURE_TRANSITION:
            zoneColor = (zone.direction == 1) ? clrDodgerBlue : clrOrangeRed;
            zoneStyle = STYLE_DASH;
            break;
         case ZONE_LIQUIDITY_SWEEP:
            zoneColor = (zone.direction == 1) ? clrGold : clrMagenta;
            zoneStyle = STYLE_DOT;
            break;
         default:
            zoneColor = clrGray;
      }
      
      ObjectSetInteger(0, name, OBJPROP_COLOR, zoneColor);
      ObjectSetInteger(0, name, OBJPROP_STYLE, zoneStyle);
      ObjectSetInteger(0, name, OBJPROP_WIDTH, 2);
      ObjectSetInteger(0, name, OBJPROP_BACK, true);
      ObjectSetInteger(0, name, OBJPROP_FILL, true);
      ObjectSetInteger(0, name, OBJPROP_ZORDER, 0);
      
      // Add label
      if(ShowLabels)
      {
         string labelName = name + "_LABEL";
         if(ObjectCreate(0, labelName, OBJ_TEXT, 0, zone.time, zone.high))
         {
            string typeText;
            switch(zone.type)
            {
               case ZONE_DISPLACEMENT: typeText = "DISP"; break;
               case ZONE_STRUCTURE_TRANSITION: typeText = "CHoCH"; break;
               case ZONE_LIQUIDITY_SWEEP: typeText = "LIQ"; break;
               default: typeText = "UNK";
            }
            
            string directionText = (zone.direction == 1) ? "BULL" : "BEAR";
            ObjectSetString(0, labelName, OBJPROP_TEXT, typeText + " " + directionText);
            ObjectSetInteger(0, labelName, OBJPROP_COLOR, clrWhite);
            ObjectSetInteger(0, labelName, OBJPROP_FONTSIZE, 8);
            ObjectSetInteger(0, labelName, OBJPROP_BACK, true);
         }
      }
      
      if(DebugMode && ShowZones)
         Print("Drawing zone: ", name, " Type: ", ZoneTypeToString(zone.type), 
               " Dir: ", zone.direction, " High: ", zone.high, " Low: ", zone.low);
   }
}

Die Funktion UpdateVisualization() verwaltet alle grafischen Elemente im Chart, um sicherzustellen, dass die Darstellung den aktuellen internen Zustand des EAs korrekt widerspiegelt. Zunächst werden zuvor gezeichnete Bereiche und Handelsobjekte gelöscht, um Doppelungen oder veraltete Darstellungen zu vermeiden. Anschließend durchläuft das Programm alle gespeicherten Zonen und zeichnet nur diejenigen neu, die weiterhin aktiv sind, wodurch der Chart mit der aktuellen Market-Memory-Logik synchronisiert bleibt. Ist die Beschriftungsanzeige aktiviert, zeichnet die Funktion zudem horizontale Linien ein, die die jüngsten Swing-Hochs und -Tiefs sowohl aus der Analyse als auch aus höheren Zeitrahmen darstellen und so einen klaren strukturellen Kontext liefern.

Die Funktion DrawZone() übernimmt die detaillierte Darstellung jeder einzelnen Zone. Es erstellt ein nach vorne gerichtetes Rechteck, das sich aus dem Startzeitpunkt und den Preisgrenzen der Zone ergibt, und dehnt es über mehrere Kerzen in die Zukunft aus, um ihren Einflussbereich zu veranschaulichen. Jedem Zonentyp – Displacement, Structure Transition (CHoCH) oder Liquidity Sweep – ist eine eigene Farbe und ein eigener Linienstil zugeordnet, wobei bullische und bärische Richtungen optisch voneinander unterschieden werden. Optionale Textbeschriftungen geben den Zonentyp und die Richtung an (z. B. DISP BULL oder CHoCH BEAR), sodass die Interpretation auf einen Blick möglich ist.


Backtest-Ergebnisse

Das Backtesting wurde auf dem H1-Zeitrahmen über einen Testzeitraum von 1. Juni 2025 bis 14. August 2025 mit den Standardeinstellungen ausgewertet:

Kapitalkurven

Backtest-Ergebnisse


Schlussfolgerung

Zusammenfassend lässt sich sagen, dass wir das Konzept der Market Memory Zones von einem visuellen Analysewerkzeug in eine vollautomatische Handelsmaschine umgewandelt haben, indem wir dessen strukturelle Logik direkt in den Expert Advisor integriert haben. Wir haben eine systematische Erkennung von Displacement Candles, Strukturübergängen (CHoCH) und Liquiditäts-Sweeps implementiert und diese Zonen anschließend in einem kontrollierten Ringpuffer gespeichert, um die langfristige Stabilität während des Backtestings und der Live-Ausführung zu gewährleisten. Jede Zone enthält nun Kontextdaten wie Richtung, ATR-Bedingungen, Ablaufzeitpunkt und Strukturverweise, sodass der EA das Kursverhalten in Echtzeit überwachen kann. Automatisierte Einstiegslogik, Bestätigung auf einem niedrigeren Zeitrahmen, dynamische Stop-Loss-Platzierung, strukturbasierte Take-Profit-Ziele und risikobasierte Positionsgrößenbestimmung vollenden den Übergang von der diskretionären Interpretation zur regelgesteuerten Ausführung.

Zusammenfassend lässt sich sagen, dass die Automatisierung von Market Memory Zones emotionale Verzerrungen beseitigt und gleichzeitig die strukturelle Intelligenz hinter der Strategie bewahrt. Das System verfolgt kontinuierlich, wohin der Kurs voraussichtlich zurückkehren wird, überprüft Reaktionen anhand von Bestätigungen aus mehreren Zeitrahmen und führt Trades mit vordefiniertem Risikomanagement aus – wodurch der gesamte Prozess konsistent, skalierbar und überprüfbar wird. Durch die Umwandlung des Preisgedächtnisses in strukturierte, programmierbare Logik gewinnen Händler an Klarheit und Wiederholbarkeit und erhalten die Möglichkeit, die Performance über verschiedene Instrumente und Zeiträume hinweg zu optimieren.

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

Beigefügte Dateien |
Auto_MMZ.mq5 (41.48 KB)
Vom Anfänger zum Experten: Automatisierung von Intraday-Strategien Vom Anfänger zum Experten: Automatisierung von Intraday-Strategien
Wir setzen das Konzept des EMA-50-Retests in einen verhaltensgesteuerten Expert Advisor für den Intraday-Handel um. Die Studie formalisiert Trendrichtung, EMA-Interaktionen (Pierce-and-Close), Reaktionsbestätigungen und optionale Filter und implementiert diese anschließend in MQL5 mithilfe modularer Funktionen und ressourcensicherer Handles. Durch visuelle Tests im Strategy Tester wird die Richtigkeit der Signale überprüft. Das Ergebnis ist eine übersichtliche Vorlage für die Codierung diskretionär gehandelter Abpraller.
MQL5 Trading Tools (Teil 20): Grafiken auf Zeichenflächen mit statistischer Korrelations- und linearer Regressionsanalyse MQL5 Trading Tools (Teil 20): Grafiken auf Zeichenflächen mit statistischer Korrelations- und linearer Regressionsanalyse
In diesem Artikel erstellen wir in MQL5 ein canvasbasiertes grafisches Tool für statistische Korrelations- und lineare Regressionsanalysen zwischen zwei Symbolen, das sich per Drag & Drop verschieben und in der Größe anpassen lässt. Wir nutzen ALGLIB für Regressionsberechnungen, dynamische Achsenbeschriftungen, Datenpunkte und ein Statistikfeld, in dem Steigung, Achsenabschnitt, Korrelation und R-Quadrat angezeigt werden. Diese interaktive Visualisierung liefert wertvolle Erkenntnisse für Pair-Trading-Strategien und bietet anpassbare Designs, Rahmen sowie Echtzeit-Aktualisierungen bei neuen Bars.
MQL5-Handelswerkzeuge (Teil 21): Hinzufügen eines Cyberpunk-Theme zu Regressionsdiagrammen MQL5-Handelswerkzeuge (Teil 21): Hinzufügen eines Cyberpunk-Theme zu Regressionsdiagrammen
In diesem Artikel erweitern wir das Tool zur Darstellung von Regressionsdiagrammen in MQL5 um einen Cyberpunk-Modus mit Neon-Leuchteffekten, Animationen und holografischen Effekten für eine eindrucksvolle Visualisierung. Wir integrieren die Umschaltung zwischen Themenmodi, dynamische Hintergründe mit Sternen, leuchtende Rahmen sowie Neonpunkte und -linien, wobei die Kompatibilität mit dem Standardmodus gewährleistet bleibt. Dieses System mit zwei Themenmodi wertet die Analyse von Symbolpaaren durch eine futuristische Ästhetik auf und unterstützt Echtzeitaktualisierungen sowie Interaktionen für aufschlussreiche Handelserkenntnisse.
Vom Neuling zum Experten:  Erweiterung einer Liquiditätsstrategie mit Trendfiltern Vom Neuling zum Experten: Erweiterung einer Liquiditätsstrategie mit Trendfiltern
Der Artikel erweitert eine liquiditätsbasierte Strategie um einen einfachen Trendfilter: Liquiditätszonen sollen nur in Richtung des EMA(50) gehandelt werden. Darin werden Filterregeln erläutert, die wiederverwendbare Klasse „TrendFilter.mqh“ sowie die EA-Integration in MQL5 vorgestellt und Tests mit und ohne Filter miteinander verglichen. Die Leser profitieren von einer klaren Trendorientierung, weniger übermäßigen Handelsaktivitäten in Gegentrendphasen und einsatzbereiten Quelldateien.