Entwicklung des Price Action Analysis Toolkit (Teil 28): Werkzeug für den Ausbruch aus der Eröffnungsspanne
Inhalt
- Einführung
- Öffnungsbereich
- Überblick über die Strategie
- EA-Komponenten Aufschlüsselung
- Backtests und Ergebnisse
- Schlussfolgerung
Einführung
Am 6. Mai 2010 erlebten die US-Aktienmärkte den berüchtigten „Flash Crash“, einen atemberaubenden Einbruch, bei dem ein massiver, algorithmusgesteuerter Verkaufsauftrag in E-Mini S&P 500-Futures hektische Hochfrequenz-Liquidationen auslöste und den Dow in nur wenigen Minuten um fast 1.000 Punkte abstürzen ließ, bevor er sich ebenso schnell wieder erholte. Diese dramatische Episode machte eine kritische Schwachstelle deutlich: Die Reaktion auf einen unbestätigten Kurseinbruch, egal wie nachdrücklich, kann dazu führen, dass die Händler auf dem Trockenen sitzen, wenn die Liquidität schwindet und der Markt wieder einbricht.
Ein Ausbruch liegt vor, wenn der Kurs eine klar definierte Grenze, wie z. B. den Höchst- oder Tiefststand des Eröffnungsintervalls der Sitzung, entscheidend überschreitet und damit signalisiert, dass Angebot oder Nachfrage die Gegenseite überwältigt haben. Das Erkennen echter Ausbrüche ist von entscheidender Bedeutung, da echte Ausbrüche oft den Beginn eines anhaltenden Trends markieren, während falsche Ausbrüche, wenn sie zu früh beachtet werden, zu Kursverlusten führen.
Die Strategie „Opening Range Breakout“ (ORB) geht darauf ein, indem sie zunächst die Ober- und Untergrenze dieser Eröffnungsspanne (das auf eine beliebige Dauer konfiguriert werden kann) erfasst und den Bereich auf dem Chart als Rechteck schattiert. Diese Grenzen dienen sowohl als visuelle Orientierungspunkte als auch als präzise Auslöseschwellen. Nur wenn der Kurs das Rechteck durchbricht, diese Begrenzung erneut durchläuft und erneut ausbricht, bestätigt die Strategie den Einstieg, filtert das Rauschen heraus und isoliert die Bewegungen, die von der tatsächlichen Marktüberzeugung getrieben werden.
In diesem Artikel lernen Sie eine professionelle MQL5 Expert Advisor-Implementierung von ORB kennen, die Folgendes beinhaltet:
- gekapselte Bereichserfassung, die das Eröffnungshoch/-tief verfolgt und anzeigt, ohne die Hauptschleife zu überlasten,
- volatilitätsangepasste Stops und Ziele über ein wiederverwendbares ATR-Modul,
- die Logik zur Bestätigung von Wiederholungstests, die echte Ausbrüche von vorübergehenden Ausschlägen unterscheidet,
- die Visualisierung im Chart mit dynamischen Dashboard-Beschriftungen und grafischen Objekten,
- eine klare Zustandsmaschine in OnTick(), um jeden Schritt zu orchestrieren und bei Sitzungsende sauber zurückzusetzen.
Die Eröffnungsspanne
Die Eröffnungsspanne (Opening Range) bezieht sich auf die Höchst- und Tiefstkurse, die in den ersten Minuten einer Handelssitzung, häufig in den ersten 15 oder 30 Minuten, festgestellt werden. Dieser Zeitraum spiegelt die unmittelbare Reaktion des Marktes auf Nachrichten, Wirtschaftsdaten und institutionelle Aktivitäten in der Nacht wider und ist in der Regel durch ein hohes Volumen und hohe Volatilität gekennzeichnet. Händler nutzen die Grenzen der Spanne als Bezugspunkte; Ausbrüche über oder unter ihnen können eine potenzielle Dynamik in diese Richtung signalisieren. Diese Niveaus helfen bei der Planung von Handelsgeschäften mit definierten Einstiegen, Stop-Losses und Zielen, was die Eröffnungsspanne zu einem praktischen Instrument für die frühzeitige Trenderkennung und strukturierte Intraday-Strategien macht.
Die Kenntnis und der effektive Handel mit der Eröffnungsspanne bieten mehrere Vorteile auf den Intraday-Märkten:
| Vorteil | Beschreibung |
|---|---|
| Frühzeitiges Erkennen von Trends | Ein Ausbruch aus der anfänglichen 15-30-Minuten-Spanne signalisiert ein potenzielles Momentum, das Händlern hilft, sich auf Intraday-Bewegungen einzustellen. |
| Klare Handelsregeln | Mit präzisen Hoch/Tief-Grenzen erhalten Sie objektive Einstiegspunkte und Stoppniveaus, die das Rätselraten reduzieren. |
| Integriertes Risikomanagement | Stopps können genau innerhalb der gegenüberliegenden Begrenzung platziert werden, um Risiko und Ertrag im Voraus festzulegen. |
| Zeiteffizienz und Konsistenz | Durch die Beschränkung des Handels auf das morgendliche Zeitfenster wird die Bildschirmzeit reduziert, was das System wiederholbar macht. |
| Marktübergreifende Anwendbarkeit | Funktioniert mit Aktien, Devisen, Futures und Zeitrahmen für mehr Vielseitigkeit im Handel. |
| Volatilitätsvorteil | Nutzt die Liquidität und die engen Spreads, die in der frühen Sitzung zu beobachten waren. |
| Flexibilität der Strategie | Unterstützt Breakout-, Reversal- und Scalping-Taktiken innerhalb eines einheitlichen Rahmens. |
Wir verwenden zwei Hauptmethoden zur Berechnung der Eröffnungsspanne.
Methode 1: Die Spanne von zwei Kerzen
Dieser Ansatz stützt sich auf nur zwei Balken. Nehmen wir zunächst die allerletzte Kerze der vorangegangenen Sitzung, deren Höchst- und Tiefstwerte die gestrigen Schlussextreme definieren. Als Nächstes verwenden wir die Eröffnungskerze der aktuellen Sitzung, deren Hoch und Tief den anfänglichen Handelsschub einfangen. Die Eröffnungsspanne ist einfach der Abstand zwischen dem höchsten Hoch und dem tiefsten Tief dieser beiden Balken. Diese kompakte Berechnung gibt Ihnen eine unmittelbare Momentaufnahme des frühen Momentums und hilft, potenzielle Ausbruchsniveaus für den Tag zu ermitteln.

Zunächst berechnen wir die genaue Uhrzeit, zu der Ihre Handelssitzung beginnt (z. B. 09:30 Uhr lokale Serverzeit). Wir können dies hart kodieren oder es über SymbolInfoSessionTrade berechnen.
// Example: use SymbolInfoSessionTrade to get today's session start MqlDateTime nowStruct; TimeToStruct(TimeCurrent(), nowStruct); datetime from, to; SymbolInfoSessionTrade(_Symbol, (ENUM_DAY_OF_WEEK)nowStruct.day_of_week, SessionIndex, from, to); // 'from' now holds seconds since midnight; convert to full datetime: datetime todayStart = (TimeCurrent() - TimeCurrent()%86400) + from;
Wir ermitteln den Index des allerersten M1-Balkens bei oder nach todayStart, und nehmen dann den nächsten Balken (Index+1) als letzten Balken von gestern.
// Find bar numbers int firstBarToday = iBarShift(_Symbol, PERIOD_M1, todayStart, false); int lastBarYesterday = firstBarToday + 1;Wir verwenden die integrierte Serienfunktionen, um den Höchst-/Tiefstwert eines jeden Balkenindex zu ermitteln.
double highYesterday = iHigh(_Symbol, PERIOD_M1, lastBarYesterday); double lowYesterday = iLow (_Symbol, PERIOD_M1, lastBarYesterday); double highToday = iHigh(_Symbol, PERIOD_M1, firstBarToday); double lowToday = iLow (_Symbol, PERIOD_M1, firstBarToday);Wir nehmen das Maximum der beiden Höchstwerte und das Minimum der beiden Tiefstwerte, um die Eröffnungsspanne zu bilden, und berechnen Sie dann deren Größe.
double openingHigh = MathMax(highYesterday, highToday); double openingLow = MathMin (lowYesterday, lowToday); double openingSize = openingHigh - openingLow; PrintFormat("Opening Range → High: %.5f Low: %.5f Size: %.5f", openingHigh, openingLow, openingSize);
Methode 2
Anstatt bestimmte Kerzen zu verwenden, wird bei diesem Ansatz die Eröffnungsspanne durch die höchsten und niedrigsten Kurse definiert, die in den ersten Minuten nach der Markteröffnung erreicht werden. Indem wir diese frühen Extremwerte verfolgen, erfassen wir die anfängliche Stimmung und Dynamik des Tages in Echtzeit. Diese Eröffnungshochs und -tiefs dienen dann als Ausbruchsschwellen. Sobald sich der Kurs über sie hinausbewegt, signalisiert er einen potenziellen Trend für den Rest der Sitzung.

Zunächst berechnen wir den genauen Zeitstempel, zu dem die aktuelle Handelssitzung beginnt (z. B. 09:30 Uhr). Wir verwenden SymbolInfoSessionTrade, um die Sekunden „from“ zu erhalten und sie in eine vollständige Datumsangabe umzuwandeln.
// Calculate the session’s opening datetime MqlDateTime nowStruct; TimeToStruct(TimeCurrent(), nowStruct); datetime fromSec, toSec; SymbolInfoSessionTrade(_Symbol, (ENUM_DAY_OF_WEEK)nowStruct.day_of_week, SessionIndex, fromSec, toSec); // Build a full datetime from today’s midnight plus the session offset datetime sessionStart = (TimeCurrent() - TimeCurrent() % 86400) + fromSec;
Als Nächstes wird eine Schleife über jeden Minutenbalken in den ersten RangeMinutes nach sessionStart gezogen, wobei der höchste Höchst- und der niedrigste Tiefstwert ermittelt wird.
double orHigh = -DBL_MAX; double orLow = DBL_MAX; // Find the bar index at or just after sessionStart int startIdx = iBarShift(_Symbol, TF, sessionStart, false); // Loop through the first RangeMinutes bars (M1 timeframe) for(int i = startIdx; i >= startIdx - (RangeMinutes - 1); i--) { if(i < 0) break; // safety check double h = iHigh(_Symbol, TF, i); double l = iLow (_Symbol, TF, i); orHigh = MathMax(orHigh, h); orLow = MathMin(orLow, l); }
Schließlich gibt es noch orHigh und orLow. Wir können die Größe der Spanne berechnen und den aktuellen Preis (Bid) mit diesen Niveaus vergleichen, um Signale zu generieren.
double openingSize = orHigh - orLow; PrintFormat("Opening Range (Method 2): High=%.5f Low=%.5f Size=%.5f", orHigh, orLow, openingSize); // Breakout detection double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); if(bid > orHigh) Alert("Breakout Long at price " + DoubleToString(bid, _Digits)); else if(bid < orLow) Alert("Breakout Short at price " + DoubleToString(bid, _Digits));
Überblick über die Strategie
Dieser EA automatisiert die Strategie eines Ausbruchs aus der Eröffnungsspanne, indem er zunächst die Ober- und Untergrenzen der Eröffnungsperiode des Marktes ermittelt. Zu Beginn jeder Sitzung wird der Kurs zum Zeitpunkt der Eröffnung der Sitzung aufgezeichnet und dann kontinuierlich der Höchst- und Tiefstkurs über die nächsten RangeMinutes (z. B. 15 Minuten) aktualisiert. Nach dem Schließen des Fensters werden horizontale Linien und ein Rechteck auf dem Chart gezeichnet, um den Bereich, in dem die frühe Volatilität stattfand, visuell zu markieren. Ein ATR-Filter (mit einer konfigurierbaren ATR-Periode und einem Multiplikator) stellt sicher, dass Handelssignale nur dann ausgelöst werden, wenn die Volatilität ein sinnvolles Niveau erreicht hat.
Nachdem die Spanne definiert ist, achtet der EA auf einen zweistufigen Ausbruch: Zunächst muss der Kurs außerhalb der Spanne schließen; anschließend muss er bis zur Grenze zurückgehen und dann wieder darüber schließen (der „Retest“). Wenn diese erneute Bestätigung erfolgt, zeichnet der EA einen Auf- oder Abwärtspfeil am Einstiegsbalken, berechnet Stop-Loss- und Take-Profit-Levels auf der Grundlage der ATR und gibt Warnungen (auf dem Bildschirm, per E-Mail und/oder Push-Benachrichtigung) aus, die das Signal ankündigen. Ein Dashboard auf dem Chart wird ständig mit dem aktuellen Status des EA, dem ATR-Wert und der Bandbreite aktualisiert, und alles wird bei der nächsten Sitzung oder um Mitternacht sauber zurückgesetzt.
Dieser EA automatisiert die Strategie eines Ausbruchs aus der Eröffnungsspanne, indem er zunächst die Ober- und Untergrenzen der Eröffnungsperiode des Marktes ermittelt. Zu Beginn jeder Sitzung wird der Kurs zum Zeitpunkt der Eröffnung der Sitzung aufgezeichnet und dann kontinuierlich der Höchst- und Tiefstkurs über die nächsten RangeMinutes (z. B. 15 Minuten) aktualisiert. Nach dem Schließen des Fensters werden horizontale Linien und ein Rechteck auf dem Chart gezeichnet, um den Bereich, in dem die frühe Volatilität stattfand, visuell zu markieren. Ein ATR-Filter (mit einer konfigurierbaren ATR-Periode und einem Multiplikator) stellt sicher, dass Handelssignale nur dann ausgelöst werden, wenn die Volatilität ein sinnvolles Niveau erreicht hat.
Nachdem die Spanne definiert ist, achtet der EA auf einen zweistufigen Ausbruch: Zunächst muss der Kurs außerhalb der Spanne schließen; anschließend muss er bis zur Grenze zurückgehen und dann wieder darüber schließen (der „Retest“). Wenn diese erneute Bestätigung erfolgt, zeichnet der EA einen Auf- oder Abwärtspfeil am Einstiegsbalken, berechnet Stop-Loss- und Take-Profit-Levels auf der Grundlage der ATR und gibt Warnungen (auf dem Bildschirm, per E-Mail und/oder Push-Benachrichtigung) aus, die das Signal ankündigen. Ein Dashboard auf dem Chart wird ständig mit dem aktuellen Status des EA, dem ATR-Wert und der Bandbreite aktualisiert, und alles wird bei der nächsten Sitzung oder um Mitternacht sauber zurückgesetzt.
EA-Komponenten Aufschlüsselung
1. Dateikopf und Eigenschaften
Oben geben wir mit #property unser Copyright, den Link und die Version an. Die Direktive #property strict weist den Compiler an, moderne MQL5-Regeln durchzusetzen (keine impliziten Casts, obligatorische Funktionsprototypen usw.), was dazu beiträgt, subtile Bugs bei der Kompilierung zu erkennen. Durch das Setzen von #property link kann jeder, der den EA in MetaEditor betrachtet, zu unserem MQL5-Community-Profil durchklicken, was die Versionskontrolle und die Urheberschaft verstärkt. Sie können auch #property description verwenden, um Ihre eigenen Anmerkungen einzubetten, die im Eigenschaftsdialog des EA angezeigt werden, sodass es für die Leser einfacher wird, ihre Einstellungen ohne zusätzlichen UI-Code zu dokumentieren.
//+------------------------------------------------------------------+ //| ORB Breakout EA| //| Copyright 2025, MetaQuotes Ltd.| //| https://www.mql5.com/en/users/lynnchris| //+------------------------------------------------------------------+ #property copyright "Copyright 2025, MetaQuotes Ltd." #property link "https://www.mql5.com/en/users/lynnchris" #property version "1.0" #property description "Opening‑Range Breakout with ATR confirmation" #property strict
2. Eingabe-Parameter
Wir gruppieren die vom Nutzer veränderbaren Einstellungen unter eindeutigen Kommentaren: Sitzungsindex und Bereichslänge, ATR-Filtereinstellungen, Pfeilcodes/Farben und Warnmeldungen. In MQL5 werden Eingabevariablen automatisch im Dialogfeld Eigenschaften des EA angezeigt, wobei die richtigen Typen und sogar Enums (wie ENUM_TIMEFRAMES für Zeitrahmen) als Dropdowns dargestellt werden - Sie müssen Ihre eigene GUI nicht von Hand erstellen. Wenn wir jedoch eine bestimmte Liste erzwingen wollten, könnten wir unser eigenes enum ArrowSymbol { UP=233, DOWN=234 } definieren, um die Auswahl zur Kompilierungszeit einzuschränken. Eingaben können auch schreibgeschützt werden, wenn Sie sie vor der Bearbeitung im laufenden Betrieb schützen wollen.
//--- session & range input int SessionIndex = 0; // 0 = first session input int RangeMinutes = 15; // minutes to capture range //--- ATR filter input ENUM_TIMEFRAMES TF = PERIOD_M1; // ATR timeframe input int ATRPeriod = 14; // ATR look‑back input double ATRMultiplier = 1.5; // ATR * multiplier //--- arrows & alerts input int ArrowUpCode = 233; // wingdings ↑ input int ArrowDnCode = 234; // wingdings ↓ input color ArrowUpColor = clrLime; // long arrow input color ArrowDnColor = clrRed; // short arrow input bool SendEmailAlert = false; // email on signal input bool PushNotify = false; // push on signal input string EmailSubject = "ORB Signal"; // mail subject
3. Die Klasse RangeCapture
Die Kapselung der Logik für den Öffnungsbereich in einer eigenen Klasse CRangeCapture sorgt für Ordnung in unserem OnTick() und unterstreicht die objektorientierte Struktur von MQL5. Wir speichern die Startzeit und den sich entwickelnden Höchst-/Tiefstkurs mit den Methoden Init(), Update() und IsDefined(). Denken Sie daran, dass MQL5-Klassen nicht automatisch initialisiert werden, sodass explizite Aufrufe von Init() obligatorisch sind. Indem wir hi und lo als double beibehalten, nutzen wir auch die 64-Bit-Gleitkommagenauigkeit von MQL5, die für FX-Preise unerlässlich ist. Sie könnten diese Klasse erweitern, um den Höchst-/Tiefststand jedes Ticks in einem internen Puffer zu protokollieren, wenn Sie dies später wünschen. Dies veranschaulicht, wie sich Klassen unter Beibehaltung der ursprünglichen Schnittstelle weiterentwickeln können.
class CRangeCapture { private: datetime startTime; double hi, lo; public: void Init(datetime t, double price) { startTime = t; hi = lo = price; } void Update(double price, datetime now) { if(now < startTime + RangeMinutes*60) { hi = MathMax(hi, price); lo = MathMin(lo, price); } } bool IsDefined(datetime now) const { return(now >= startTime + RangeMinutes*60); } double High() const { return hi; } double Low() const { return lo; } }; static CRangeCapture g_range;
4. Die Klasse ATRModule
Hier verpacken wir den eingebauten ATR-Indikator-Handle (iATR) in der Klasse CATRModule. In Init() erstellen wir das Handle und prüfen auf INVALID_HANDLE, um Probleme mit Symbolen oder Zeitrahmen zu vermeiden. Die Methode Value() ruft CopyBuffer nur einmal pro Tick auf, was wesentlich effizienter ist als der wiederholte Aufruf von iATR innerhalb von OnTick(). Durch die Zwischenspeicherung des Handles werden Speicherlecks vermieden und der Overhead reduziert. Wenn Sie IndicatorRelease() in Release() aufrufen, geben Sie dieses Handle frei. Ohne dieses Handle kann die Liste der Indikatoren auf der Registerkarte „Indikatoren“ des Terminals langsam und überfüllt sein. Dieses Muster lässt sich sauber skalieren, wenn Sie zusätzliche Indikatoren (EMA, Bollinger Bands) in eigene Module verpacken.
class CATRModule { private: int handle; public: bool Init() { handle = iATR(_Symbol, TF, ATRPeriod); return(handle != INVALID_HANDLE); } double Value() const { double buf[]; if(handle != INVALID_HANDLE && CopyBuffer(handle, 0, 0, 1, buf) == 1) return buf[0] * ATRMultiplier; return 0.0; } void Release() { if(handle != INVALID_HANDLE) IndicatorRelease(handle); } }; static CATRModule g_atr;
5. Die Klasse zum Test der Logik
Die Klasse CRetestSignal implementiert unser Muster „break, retest, re-break“ mit drei einfachen Booleschen Werten. Wir halten breakLong, breakShort und retested intern und stellen nur die Methoden Reset(), OnBreak() und CheckRetest() zur Verfügung. Dadurch werden Implementierungsdetails von OnTick() verborgen, sodass sich die Leser auf das „Was“ und nicht auf das „Wie“ konzentrieren können. Beachten Sie, dass wir den letzten MqlRates-Balken per Referenz übergeben und so Kopieraufwand sparen. Sollten Sie jemals mehrere Zeitrahmen unterstützen müssen, können Sie CheckRetest() so erweitern, dass es ein Array von MqlRates oder einen Zeitrahmen-Parameter akzeptiert, was die Flexibilität der Methodenüberladung in MQL5 demonstriert.
class CRetestSignal { private: bool breakLong, breakShort, retested; public: void Reset() { breakLong = breakShort = retested = false; } void OnBreak(double close, double h, double l) { breakLong = (close > h); breakShort = (close < l); retested = false; } bool CheckRetest(const MqlRates &r, bool &isLong) { if(breakLong) { if(!retested && r.low <= g_range.High()) { retested = true; isLong = true; return false; } if(retested && r.close > g_range.High()) { isLong = true; return true; } } else if(breakShort) { if(!retested && r.high >= g_range.Low()) { retested = true; isLong = false; return false; } if(retested && r.close < g_range.Low()) { isLong = false; return true; } } return false; } }; static CRetestSignal g_retest;
6. Das Dashboard On-Chart
Um Live-Feedback zu geben, erstellt CDashboard ein einfaches OBJ_LABEL in der oberen linken Ecke. Sie sehen, wie Init(), Update() und Delete() den Lebenszyklus dieses Etiketts verwalten. Das gleiche Muster funktioniert für OBJ_TEXT, OBJ_RECTANGLE oder jeden anderen Objekttyp. Die Beschriftung wird bei jedem Tick aktualisiert, aber da das wiederholte Setzen des gleichen Textes billig ist, bleibt die Leistung hoch. Wenn Sie noch weiter optimieren wollten, könnten Sie die letzte Zeichenkette zwischenspeichern und ObjectSetString() nur dann aufrufen, wenn sie sich tatsächlich ändert. Dies zeigt, wie kleine Änderungen in der Objektverwaltung in tick-intensiven EAs zu mikroskopisch kleinen Leistungssteigerungen führen können.
class CDashboard { private: string name; public: void Init() { name = "ORB_Info"; if(ObjectFind(0, name) < 0) { ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, name, OBJPROP_XDISTANCE, 10); ObjectSetInteger(0, name, OBJPROP_YDISTANCE, 30); } } void Update(const string &txt) { ObjectSetString(0, name, OBJPROP_TEXT, txt); } void Delete() { if(ObjectFind(0, name) >= 0) ObjectDelete(0, name); } }; static CDashboard g_dash;
7. Handelsschnittstelle & Benachrichtigungen
Obwohl wir hier keine Aufträge senden, fügen wir einen statischen CTrade-Handel ein, um zu zeigen, wie Sie später echte Trades integrieren können. Noch wichtiger ist, dass wir bei einem bestätigten Signal einen Pfeil (OBJ_ARROW) mit vom Nutzer gewählten Wingdings-Codes und Farben zeichnen und dann Alert(), SendNotification() und SendMail() auslösen. Dieser Dreiklang demonstriert das in MQL5 integrierte Ereignis- und Nachrichtensystem, das keine externen Bibliotheken benötigt. Sie können sogar PlaySound() oder EventChartCustom() für Web-Hooks einfügen, um den Lesern die Bandbreite der integrierten Kommunikationskanäle zu zeigen.
static CTrade trade; // ... inside your retest-confirmation block: string msg = StringFormat("%s Signal @%.5f SL=%.5f TP=%.5f", isLong ? "LONG" : "SHORT", r[0].close, sl, tp); Alert(msg); if(PushNotify) SendNotification(msg); if(SendEmailAlert) SendMail(EmailSubject, msg); // draw arrow on chart: string arrowName = "ORB_Arrow_" + IntegerToString((int)r[0].time); ObjectCreate(0, arrowName, OBJ_ARROW, 0, r[0].time, isLong ? r[0].low - 5 * _Point : r[0].high + 5 * _Point); ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, isLong ? ArrowUpCode : ArrowDnCode); ObjectSetInteger(0, arrowName, OBJPROP_COLOR, isLong ? ArrowUpColor : ArrowDnColor);
8. OnInit() und OnDeinit()
In OnInit() initialisieren wir unser ATR-Modul und das Dashboard und geben INIT_FAILED zurück, wenn irgendetwas schief geht. Dieses Muster stellt sicher, dass der EA nie in einem halb kaputten Zustand läuft. In OnDeinit() geben wir den ATR-Handle verantwortungsvoll frei und löschen alle Chart-Objekte, um zu verhindern, dass verwaiste Indikatoren oder Objekte zurückbleiben, wenn Sie den EA neu laden oder entfernen. Diese Praxis ist im Produktionscode von entscheidender Bedeutung: Koppeln Sie jedes iXXX-Handle immer mit IndicatorRelease() und jedes ObjectCreate() entweder mit ObjectDelete() in OnDeinit() oder mit bedingter Logik in Ihrer Reset-Routine.
int OnInit() { if(!g_atr.Init()) return INIT_FAILED; g_dash.Init(); return INIT_SUCCEEDED; } void OnDeinit(const int reason) { g_atr.Release(); ObjectDelete(0, "ORB_High"); ObjectDelete(0, "ORB_Low"); ObjectDelete(0, "ORB_Range"); g_dash.Delete(); }
9. OnTick()
Das Herzstück des EA ist OnTick(). Wir verwenden statische bool inited und statische int state, sodass sie über Aufrufe hinweg bestehen bleiben. Auf diese Weise erreicht MQL5 einen Pro-EA-Speicher ohne globale oder externen Speicher. Zunächst berechnen wir die Startzeit der Sitzung und setzen sie einmal pro Tag zurück, was ein gängiges Muster für die Intraday-Logik darstellt. Dann durchläuft ein Schalter(zustand) sauber unsere vier Stufen (Capture, Break, Retest, Done). Da MQL5 keine Coroutine-artigen Yields unterstützt, ist die Verwendung eines Zustandsautomaten der idiomatische Weg, um mehrstufige Strategien in eine Single-Tick-Verarbeitung zu zerlegen. Außerdem wird so jeder Zweig klein und testbar gehalten.
void OnTick() { static bool inited = false; static int state = 0; static datetime sessionStart; if(!inited) { // compute sessionStart, init g_range & g_retest, Alert inited = true; state = 0; } // fetch latest MqlRates r[0] and bid/ask switch(state) { case 0: // Capture g_range.Update(bid, TimeCurrent()); if(g_range.IsDefined(TimeCurrent())) state = 1; break; case 1: // Break if(r[0].close > g_range.High() || r[0].close < g_range.Low()) { g_retest.OnBreak(r[0].close, g_range.High(), g_range.Low()); state = 2; } break; case 2: // Retest { bool isLong; if(g_retest.CheckRetest(r[0], isLong)) state = 3; } break; case 3: // Done break; } }
10. Mitternachts-Reset
Schließlich vergleichen wir today = now - now%86400 mit einer statischen Datumsangabe lastDay. Sobald sich das Datum ändert, löschen wir die alten Objekte und setzen unsere Flags zurück, ohne dass ein „if hour==0“-Hack nötig ist. Dieses Muster funktioniert für jeden tagesbasierten EA: Null-Balken, tägliche Pivot-Routinen, Tagesendberichte usw. Wenn man die Leser ermutigt, sich diese Redewendung zu eigen zu machen, können sie subtile Fehler vermeiden, wenn die Uhren Mitternacht überschreiten oder wenn die Sommerzeit umgestellt wird.
// at the end of OnTick(): static datetime lastDay = 0; datetime today = TimeCurrent() - TimeCurrent() % 86400; if(today != lastDay) { lastDay = today; inited = false; state = 0; ObjectDelete(0, "ORB_High"); ObjectDelete(0, "ORB_Low"); ObjectDelete(0, "ORB_Range"); }
Backtests und Ergebnisse
Beim Backtesting wird Ihre Handelsstrategie, genau wie in Ihrem EA beschrieben, gegen historische Marktdaten getestet, um zu sehen, wie sie sich in der Vergangenheit entwickelt hätte. Damit können Sie:
- Überprüfen Sie, ob Ihre Regeln sinnvolle Ergebnisse liefern
- Messung von Schlüsselkennzahlen wie Gewinnrate, Drawdown und Gewinnfaktor
- Optimieren Sie die Eingabeparameter (z. B. Bereichslänge, ATR-Multiplikator), um Kombinationen zu finden, die in der Vergangenheit am besten funktioniert haben.
Im MetaTrader 5 speist der Strategy Tester jeden historischen Tick in OnTick() ein, also:
- OnInit() richtet alles ein (ATR-Handle, Chart-Objekte, Anfangszustand)
- OnTick() steuert die Bereichserfassung, die Breakout/Retest-Logik, das Zeichnen von Pfeilen, die Warnmeldungen und die Dashboard-Aktualisierungen bei jedem simulierten Tick
- OnDeinit() räumt nach dem Test auf
Mit anderen Worten: Der gleiche Codepfad, den Sie in einem Live-Chart verwenden, wird vom Tester für einen „Backtest“ genutzt.

Die obige GIF-Animation zeigt den Opening Range Breakout EA auf einem EURUSD M15 Chart während eines Backtests. Im Hauptfenster sehen Sie ein schattiertes Rechteck, das den Eröffnungsspanne markiert und von zwei horizontalen Linien am oberen und unteren Rand dieses Anfangsintervalls begrenzt wird. Dieses visuelle Framing zeigt sofort, wo der EA signifikante Kursbewegungen erwartet.
Jeder grüne Pfeil auf dem Chart bedeutet einen bestätigten Kauf-Einstieg. Die EA-Logik „Durchbruch → erneuter Test → erneuter Durchbruch“ sorgt dafür, dass der Kurs zunächst die obere Begrenzung durchbrechen, dann erneut testen und schließlich wieder über ihr schließen muss, bevor ein Pfeil erscheint. Durch diese zweistufige Bestätigung werden falsche Ausbrüche herausgefiltert und nur dann Signale gegeben, wenn ein echtes Momentum vorhanden ist.
Unterhalb des Charts protokolliert das Journalfenster alle wichtigen Ereignisse: den Beginn der Sitzung, die Definition des Bereichs, die Erkennung des Ausbruchs und das endgültige Signal mit den genauen Einstiegs-, Stop-Loss- und Take-Profit-Werten. Diese Protokolleinträge spiegeln die internen Zustandsübergänge des EA wider und machen transparent, wie und wann Entscheidungen getroffen werden.
Dieses Beispiel zeigt, wie die ORB-Strategie die Volatilität in der Frühphase erfasst, echte Ausbrüche bestätigt und wiederholbare, positive Signale auf dem M15-Zeitrahmen des EURUSD erzeugt.

Ich habe diesen EA auch am AUD/USD mit dem M5-Zeitrahmen getestet, um eine klarere Sicht auf die Intraday-Kursentwicklung zu erhalten. Siehe das obige Chart.
Schlussfolgerung
Der Opening Range Breakout EA, den wir in MQL5 entwickelt haben, verwandelt das einfache Konzept eines Preiskorridors zu Beginn der Session in eine disziplinierte, automatisierte Strategie. Durch die Modularisierung der einzelnen Komponenten - Range Capture, volatilitätsbasierte Stopps, Retest-Validierung und On-Chart-Feedback - haben wir eine Codebasis geschaffen, die sowohl einfach zu warten als auch schnell genug für den Live-Einsatz ist.
Dieser Ansatz befasst sich mit zwei zentralen Intraday-Herausforderungen: der Unterscheidung zwischen echtem Momentum und flüchtigen Ausschlägen und der Risikodimensionierung in Übereinstimmung mit den Echtzeit-Marktbedingungen. Die Bestätigungssequenz „Break → Retest → Re-Break“ verhindert falsche Bewegungen, während die von der ATR abgeleiteten Stop-Loss- und Take-Profit-Levels sich dynamisch an die sich entwickelnde Volatilität anpassen. Auf diese Weise liefert der EA konsistente Signale mit hoher Überzeugungskraft, genau die Art von Einstiegssignalen, die turbulenten Märkten standhalten und von echter Preisbewegung profitieren.
Jetzt ist es an der Zeit, es zu Ihrem eigenen zu machen. Kompilieren Sie den EA in MetaEditor, führen Sie Backtests mit verschiedenen Symbolen und Sitzungen durch und experimentieren Sie mit Eingaben wie Bereichsdauer und ATR-Multiplikator. Beobachten Sie, wie das Rechteck, die Linien und Pfeile auf Ihrem Chart zum Leben erwachen, und folgen Sie den Journalprotokollen, um zu sehen, wie sich jede Entscheidung entfaltet. Mit diesem ORB-Framework sind Sie in der Lage, die täglichen Eröffnungsschwankungen in wiederholbare, vertrauenserweckende Trades zu verwandeln. Auf einen besseren Einstieg und ein klügeres Risikomanagement.
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/18486
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.
Automatisieren von Handelsstrategien in MQL5 (Teil 20): Multi-Symbol-Strategie mit CCI und AO
MetaTrader 5 Machine Learning Blueprint (Teil 1): Datenlecks und Zeitstempelfehler
MQL5-Assistenz-Techniken, die Sie kennen sollten (Teil 69): Verwendung der Muster von SAR und RVI
Meistern der Log-Einträge (Teil 7): Protokolle auf dem Chart anzeigen
- 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.