English 日本語
preview
Automatisieren von Handelsstrategien in MQL5 (Teil 42): Sitzungsbasiertes System des Opening Range Breakout (ORB)

Automatisieren von Handelsstrategien in MQL5 (Teil 42): Sitzungsbasiertes System des Opening Range Breakout (ORB)

MetaTrader 5Handel |
18 3
Allan Munene Mutiiria
Allan Munene Mutiiria

Einführung

In unserem vorangegangenen Artikel (Teil 41) haben wir ein Handelssystem auf Basis der Kerzenbereichstheorie (CRT) entwickelt, das die Phasen Akkumulation, Manipulation und Distribution AMD in MetaQuotes Language 5 (MQL5) beinhaltet, das Akkumulationsbereiche auf einem bestimmten Zeitrahmen identifiziert, Durchbrüche mit Filterung der Manipulationstiefe erkennt und Umkehrungen durch Schlusskurse der Balken für Eröffnungsgeschäfte in der Distributionsphase bestätigt. In Teil 42 entwickeln wir ein vollständig anpassbares sitzungsbasiertes System für den Opening Range Breakout (ORB).

Mit diesem System können wir die Startzeit und die Dauer jeder Sitzung in Minuten festlegen. Er erfasst automatisch den wahren Höchst- und Tiefststand während dieses Zeitraums in einem ausgewählten Zeitrahmen. Er erkennt Ausbrüche mit einer optionalen Bestätigung des Abschlusses mehrerer Bars, um Fehlsignale zu reduzieren. Das System führt die Handelsgeschäfte nur in Ausbruchsrichtung aus. Stop-Loss- und Take-Profit-Niveaus können dynamisch (basierend auf der Größe der Spanne) oder statisch sein. Trailing Stops können nach Erreichen einer Gewinnschwelle eingesetzt werden. Positionslimits werden pro Richtung durchgesetzt. Wir werden die folgenden Themen behandeln:

  1. Verständnis der Strategie des Opening Range Breakout (ORB)
  2. Implementierung in MQL5
  3. Backtesting
  4. Schlussfolgerung

Am Ende werden Sie ein MQL5-Programm haben, das in der Lage ist, saubere Eröffnungsspannenausbrüche in jeder Marktsitzung zu handeln – London, New York, Asien oder sogar nutzerdefinierte Eröffnungen – und bereit für weitere Anpassungen ist. Fangen wir an!


Verständnis der Strategie des Opening Range Breakout (ORB)

Der Opening Range Breakout (ORB) ist eine klassische Intraday-Momentum-Strategie, die von der anfänglichen Richtungsausrichtung zu Beginn einer Handelssitzung profitiert. Wir definieren „opening range“, die Eröffnungsspanne, als das Hoch und das Tief, die sich in den ersten Minuten (in der Regel 5-60 Minuten) nach der Markteröffnung bilden, und warten dann darauf, dass der Kurs entscheidend über das Hoch der Spanne (Aufwärtsausbruch) oder unter das Tief der Spanne (Abwärtsausbruch) ausbricht, und steigen in die Richtung des Ausbruchs ein. Die Prämisse ist einfach, aber wirkungsvoll: Die Eröffnungsspanne stellt oft den Kampf zwischen Käufern und Verkäufern dar, während der Markt die Nachrichten und den Auftragsfluss der Nacht verdaut. Ein sauberer Ausbruch signalisiert, dass eine Seite die Kontrolle gewonnen hat, was häufig zu einer anhaltenden Richtungsbewegung führt. Das System ist im Allgemeinen einfach. Sehen wir uns unten die verschiedenen Möglichkeiten an, die wir haben.

ORB-STRATEGIE-KONSTELLATIONEN

Unser Plan ist es, ein vollständig sitzungsflexibles ORB-System zu entwickeln, das mit jedem Instrument und jeder Handelssitzung (New York, London, Asien oder sogar nutzerdefinierte Eröffnungen) funktioniert.  Wir werden den Nutzern die Möglichkeit geben, die genaue Startzeit festzulegen. Zum Beispiel 09:30 Uhr für die NYSE oder 08:00 Uhr für London. Die Nutzer können auch die Dauer des Bereichs in Minuten festlegen. Das System berechnet automatisch den wahren Höchst- und Tiefststand für den ausgewählten Zeitrahmen innerhalb dieses Fensters. Bei Bedarf können Nutzer mehrere Bestätigungen mit den Schlusskursen der Balken aktivieren, um einen Ausbruch zu validieren.

Der Algorithmus führt nur ein Handelsgeschäft pro Richtung und Sitzung aus. Wir werden zwei Berechnungsarten für Stop-Loss und Take-Profit anbieten: dynamisch (basierend auf der Größe der Handelsspanne) und statisch, mit anpassbaren Risiko-Ertrags-Verhältnissen. Es werden auch punktebasierte Trailing-Stops verfügbar sein, die bei Erreichen einer Mindestgewinnschwelle aktiviert werden. Darüber hinaus bietet das Tool eine umfangreiche Visualisierung auf dem Chart. Dazu gehören ausgefüllte Bereichsrechtecke, vertikale Markierungen für Sitzungsbeginn und -ende, anhaltende Höchst-/Tiefstwerte und Eröffnungspfeile.

Die Visualisierung ist in unserem Fall ebenso wichtig, wie Sie vielleicht schon bemerkt haben, um Klarheit zu schaffen. Kurz gesagt, hier ist eine visuelle Darstellung unserer Ziele.

RAHMEN FÜR DIE ZIELE


Implementation in MQL5

Um das Programm in MQL5 zu erstellen, öffnen wir den MetaEditor, gehen zum Navigator, suchen den Ordner Experts, klicken auf die Registerkarte „Neu“ und folgen den Anweisungen, um die Datei zu erstellen. Sobald sie erstellt ist, müssen wir in der Programmierumgebung einige Eingabeparameter und globale Variablen deklarieren, die wir im gesamten Programm verwenden werden.

//+------------------------------------------------------------------+
//|                                ORB Opening Range Breakout EA.mq5 |
//|                           Copyright 2025, Allan Munene Mutiiria. |
//|                                   https://t.me/Forex_Algo_Trader |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, Allan Munene Mutiiria."
#property link      "https://t.me/Forex_Algo_Trader"
#property version   "1.00"

#include <Trade\Trade.mqh>

//+------------------------------------------------------------------+
//| Enums                                                            |
//+------------------------------------------------------------------+
enum SLTP_Method {                                                // Define SL/TP method enum
   Dynamic_Method = 0,                                            // Dynamic based on range size
   Static_Method  = 1                                             // Static based on fixed points
};

enum TrailingTypeEnum {                                           // Define trailing type enum
   Trailing_None   = 0,                                           // None
   Trailing_Points = 1                                            // By Points
};

//+------------------------------------------------------------------+
//| Input Parameters                                                 |
//+------------------------------------------------------------------+
input ENUM_TIMEFRAMES RangeTF = PERIOD_M5;                        // Timeframe for Opening Range Calculation
input int RangeDurationMinutes = 30;                              // Duration of Opening Range in Minutes
input string SessionStartTime = "09:00";                          // Session Start Time (HH:MM)
input double TradeVolume = 0.01;                                  // Trade Volume Size
input double RR_Ratio = 2.0;                                      // Risk to Reward Ratio
input SLTP_Method SLTP_Approach = Dynamic_Method;                 // SL/TP Calculation Method
input int SL_Points = 50;                                         // SL Points (for Static Method)
input TrailingTypeEnum TrailingType = Trailing_None;              // Trailing Stop Type
input double Trailing_Stop_Points = 20.0;                         // Trailing Stop in Points
input double Min_Profit_To_Trail_Points = 30.0;                   // Min Profit to Start Trailing in Points
input int UniqueID = 987654321;                                   // Unique Trade Identifier
input int MaxPositionsDir = 1;                                     // Max Positions per Direction
input bool UseBreakoutFilter = true;                              // Use Breakout Confirmation Filter
input int ConfirmBars = 1;                                        // Bars to Confirm Breakout on Close (0 to disable)

Wir beginnen die Implementierung, indem wir die Handelsbibliothek mit „#include <Trade\Trade.mqh>“ einbinden, die die Klasse CTrade und die für die Auftragsausführung und das Positionsmanagement erforderlichen Funktionen bereitstellt. Anschließend definieren wir zwei Enumerationen, um die Nutzeroptionen übersichtlich zu gestalten. Die Enumeration „SLTP_Method“ bietet „Dynamic_Method“ für Stop-Loss- und Take-Profit-Niveaus, die auf der tatsächlichen Größe der Eröffnungsspanne basieren, und „Static_Method“ für Berechnungen, die auf festen Punkten basieren. In ähnlicher Weise bietet die Enumeration „TrailingTypeEnum“ „Trailing_None“, um das Trailing zu deaktivieren, und „Trailing_Points“, um das Trailing um eine nutzerdefinierte Anzahl von Punkten zu aktivieren, sobald eine Mindestgewinnschwelle erreicht ist.

Als Nächstes deklarieren wir Eingabeparameter, die das Programm direkt über das Eigenschaftsfenster in hohem Maße konfigurierbar machen. Dazu gehören „RangeTF“ zur Auswahl des Zeitrahmens, der für die Berechnung des Höchst- und Tiefstwertes der Eröffnungsspanne verwendet wird, „RangeDurationMinutes“, um festzulegen, wie viele Minuten nach Sitzungsbeginn die Eröffnungsspanne bilden, „SessionStartTime“ als String im Format „HH:MM“, um festzulegen, wann jede neue Sitzung beginnt (z. B., „09:30“ für die Eröffnung der NYSE, „08:00“ für London usw.), „TradeVolume“ für die Losgröße und der Rest ist selbsterklärend. Wir haben Kommentare zur Verdeutlichung hinzugefügt. Diese Eingaben gewährleisten, dass das System ohne Code-Änderungen perfekt an jeden Markt oder jede Sitzung angepasst werden kann. Als Nächstes brauchen wir die Definition der globalen Variablen.

//+------------------------------------------------------------------+
//| Global Variables                                                 |
//+------------------------------------------------------------------+
CTrade obj_Trade;                                                 //--- Trade object
datetime sessionStart = 0;                                        //--- Session start time
datetime rangeEndTime = 0;                                        //--- Range end time
double rangeHigh = 0.0;                                           //--- Range high
double rangeLow = 0.0;                                            //--- Range low
bool rangeDefined = false;                                        //--- Range defined flag
bool breakoutHigh = false;                                        //--- Breakout high flag
bool breakoutLow = false;                                         //--- Breakout low flag
double breakoutPrice = 0.0;                                       //--- Breakout price
string highLevelObj = "ORB_HighLevel";                            //--- High level object name
string lowLevelObj = "ORB_LowLevel";                              //--- Low level object name
string highTextObj = "ORB_High_Text";                             //--- High text object
string lowTextObj = "ORB_Low_Text";                               //--- Low text object
bool tradedLong = false;                                          //--- Traded long flag
bool tradedShort = false;                                         //--- Traded short flag
datetime lastConfirmTime = 0;                                     //--- Last confirm time

Wir fahren fort, indem wir eine Reihe von globalen Variablen deklarieren, die den Zustand des Programms während jeder Handelssitzung aufrechterhalten und die ordnungsgemäße Verfolgung der Logik des Ausbruchs aus dem Eröffnungsbereich sicherstellen. Wir instanziieren „obj_Trade“ als Instanz der Klasse CTrade, um alle Auftragsausführungen und Positionsänderungen zu verarbeiten. Zu den Zeitvariablen gehören „sessionStart“, um den genauen Zeitpunkt des Beginns einer neuen Sitzung festzuhalten, und „rangeEndTime“, um zu markieren, wann der Eröffnungszeitraum des Bereichs zu Ende ist. Wir verfolgen die Grenzen der Eröffnungsspanne mit „rangeHigh“ (initialisiert auf 0,0) und „rangeLow“, während „rangeDefined“ als boolesches Flag dient, das anzeigt, ob die Spanne der aktuellen Sitzung vollständig festgelegt wurde. Der Rest ist ganz einfach. Danach müssen wir das System initialisieren, indem wir einfach die magische Zahl setzen.

//+------------------------------------------------------------------+
//| EA Start Function                                                |
//+------------------------------------------------------------------+
int OnInit() {
   obj_Trade.SetExpertMagicNumber(UniqueID);                      //--- Set magic number
   return(INIT_SUCCEEDED);                                        //--- Return success
}

In der Ereignisbehandlung von OnInit, die automatisch ausgeführt wird, wenn das Programm zum ersten Mal geladen oder an einen Chart angehängt wird, weisen wir dem Objekt „obj_Trade“ die nutzerdefinierte „UniqueID“ als magische Zahl zu, indem wir „obj_Trade.SetExpertMagicNumber(UniqueID)“ aufrufen. Dadurch wird sichergestellt, dass jedes vom Programm eröffnete Handelsgeschäft diese eindeutige Kennung trägt, was eine präzise Filterung und Verwaltung ermöglicht, selbst wenn mehrere Programme oder manuelle Handelsgeschäfte auf demselben Konto aktiv sind. Abschließend geben wir INIT_SUCCEEDED zurück, um der Plattform zu bestätigen, dass die Initialisierung ohne Probleme abgeschlossen wurde und das Programm einsatzbereit ist. Wir werden einige Hilfsfunktionen definieren, die wir für die Visualisierung verwenden werden, wenn wir die Logik fertig haben, wie unten beschrieben.

//+------------------------------------------------------------------+
//| Render Horizontal Level                                          |
//+------------------------------------------------------------------+
void RenderLevel(string objName, double levelVal, color levelClr, string levelDesc) {
   ObjectDelete(ChartID(), objName);                               //--- Delete object
   ObjectCreate(ChartID(), objName, OBJ_HLINE, 0, 0, levelVal);    //--- Create hline
   ObjectSetInteger(ChartID(), objName, OBJPROP_COLOR, levelClr);  //--- Set color
   ObjectSetInteger(ChartID(), objName, OBJPROP_STYLE, STYLE_DOT); //--- Set style
   ObjectSetString(ChartID(), objName, OBJPROP_TOOLTIP, levelDesc); //--- Set tooltip
   ChartRedraw(ChartID());                                         //--- Redraw chart
}

//+------------------------------------------------------------------+
//| Render Vertical Line                                             |
//+------------------------------------------------------------------+
void RenderVLine(string objName, datetime timeVal, color lineClr, string desc) {
   ObjectDelete(ChartID(), objName);                              //--- Delete object
   ObjectCreate(ChartID(), objName, OBJ_VLINE, 0, timeVal, 0);    //--- Create vline
   ObjectSetInteger(ChartID(), objName, OBJPROP_COLOR, lineClr);  //--- Set color
   ObjectSetInteger(ChartID(), objName, OBJPROP_STYLE, STYLE_DOT); //--- Set style
   ObjectSetInteger(ChartID(), objName, OBJPROP_WIDTH, 1);        //--- Set width
   ObjectSetInteger(ChartID(), objName, OBJPROP_BACK, true);      //--- Set back
   ObjectSetInteger(ChartID(), objName, OBJPROP_RAY, true);       //--- Set ray
   ObjectSetInteger(ChartID(), objName, OBJPROP_HIDDEN, true);    //--- Set hidden
   ObjectSetString(ChartID(), objName, OBJPROP_TOOLTIP, desc);    //--- Set tooltip
   ChartRedraw(ChartID());                                        //--- Redraw chart
}

//+------------------------------------------------------------------+
//| Render Text Label                                                |
//+------------------------------------------------------------------+
void RenderText(string objName, datetime timeVal, double priceVal, string textStr, color textClr, int anchorVal) {
   ObjectDelete(ChartID(), objName);                              //--- Delete object
   ObjectCreate(ChartID(), objName, OBJ_TEXT, 0, timeVal, priceVal); //--- Create text
   ObjectSetString(ChartID(), objName, OBJPROP_TEXT, textStr);    //--- Set text
   ObjectSetInteger(ChartID(), objName, OBJPROP_COLOR, textClr);  //--- Set color
   ObjectSetInteger(ChartID(), objName, OBJPROP_ANCHOR, anchorVal); //--- Set anchor
   ObjectSetInteger(ChartID(), objName, OBJPROP_FONTSIZE, 10);    //--- Set fontsize
   ChartRedraw(ChartID());                                        //--- Redraw chart
}

//+------------------------------------------------------------------+
//| Draw Entry Arrow                                                 |
//+------------------------------------------------------------------+
void DrawEntryArrow(datetime timeVal, double priceVal, bool isBuy) {
   string markerName = "EntryMarker_" + IntegerToString(timeVal); //--- Marker name
   ObjectCreate(ChartID(), markerName, OBJ_ARROW, 0, timeVal, priceVal); //--- Create arrow
   int arrowCode = isBuy ? 233 : 234;                             //--- Arrow code
   color arrowClr = isBuy ? clrBlue : clrRed;                     //--- Arrow color
   int anchor = isBuy ? ANCHOR_BOTTOM : ANCHOR_TOP;               //--- Anchor
   ObjectSetInteger(ChartID(), markerName, OBJPROP_ARROWCODE, arrowCode); //--- Set code
   ObjectSetInteger(ChartID(), markerName, OBJPROP_COLOR, arrowClr); //--- Set color
   ObjectSetInteger(ChartID(), markerName, OBJPROP_ANCHOR, anchor); //--- Set anchor
   ChartRedraw(ChartID());                                        //--- Redraw chart
}

//+------------------------------------------------------------------+
//| Count Active Positions by Type                                   |
//+------------------------------------------------------------------+
int ActivePositions(ENUM_POSITION_TYPE posType) {
   int total = 0;                                                 //--- Init total
   for (int pos = PositionsTotal() - 1; pos >= 0; pos--) {        //--- Iterate positions
      if (PositionGetSymbol(pos) == _Symbol && PositionGetInteger(POSITION_MAGIC) == UniqueID && PositionGetInteger(POSITION_TYPE) == posType) { //--- Check position
         total++;                                                    //--- Increment total
      }
   }
   return total;                                                  //--- Return total
}

Hier erstellen wir mehrere Hilfsfunktionen für die Chartvisualisierung und das Positionsmanagement und stellen sicher, dass die Eröffnungsspanne und die Handelssignale klar angezeigt werden, während der Code sauber organisiert bleibt. Die Funktion „RenderLevel“ zeichnet oder aktualisiert persistente horizontale Linien für den Bereich high und low. Es löscht alle vorhandenen Objekte mit dem angegebenen Namen, erstellt ein neues OBJ_HLINE auf dem angegebenen Preisniveau, legt seine Farbe fest (grün für oben, rot für unten), wendet einen gepunkteten Stil an, fügt einen beschreibenden Tooltip hinzu und zeichnet das Chart neu, damit es sofort sichtbar ist.

In ähnlicher Weise setzt die Funktion „RenderVLine“ vertikale Linien, um den Beginn und das Ende der Sitzung zu markieren. Sie entfernt frühere Instanzen, erstellt eine OBJ_VLINE zum angegebenen Zeitpunkt, konfiguriert sie mit blauer Farbe, gepunktetem Stil, Breite 1, Hintergrundplatzierung, Strahlenerweiterung nach rechts, aus der Objektliste ausgeblendet, einem Tooltip, der die genaue Zeit anzeigt, und löst ein Neuzeichnen des Charts mithilfe der Funktion ChartRedraw aus. Die Funktion „RenderText“ fügt anpassbare Textbeschriftungen hinzu, z. B. Start-/Endzeiten oder die Anmerkungen „ORB High“ bzw. „ORB Low“. Sie löscht vorhandene Textobjekte, erstellt einen OBJ_TEXT an den angegebenen Zeit- und Preiskoordinaten, setzt den Textinhalt und andere Eigenschaften.

Für Handelseröffnungen implementieren wir „DrawEntryArrow“, das eine visuelle Markierung direkt auf dem Chart im Moment der Ausführung platziert. Es wird ein eindeutiger Namen unter Verwendung der aktuellen Uhrzeit generiert, ein OBJ_ARROW erstellt, das Wingdings-Symbol 233 (Pfeil nach oben) für Käufe oder 234 (Pfeil nach unten) für Verkäufe ausgewählt, mit blau für Kauf oder rot für Verkauf, es wird korrekt am unteren oder oberen Rand verankert und das Chart neu gezeichnet. Für die Pfeilcodes verfügt MQL5 über spezielle Schriftarten (siehe unten), die Sie nach Belieben wechseln können.

MQL5 WINGDINGS-CODES

Schließlich definieren wir die Funktion „ActivePositions“, um sicher zu zählen, wie viele offene Positionen für einen bestimmten Typ (Kauf oder Verkauf) existieren, die zu diesem Programm gehören. Sie durchläuft alle Positionen in einer Schleife rückwärts, prüft auf ein übereinstimmendes Symbol, eine magische Zahl über „UniqueID“ und den Positionstyp mit POSITION_TYPE_BUY oder „POSITION_TYPE_SELL“ und gibt dann die genaue Anzahl zurück. Damit können wir nun mit der Umsetzung der Strategie beginnen, indem wir zunächst die täglichen Bereiche definieren.

//+------------------------------------------------------------------+
//| Tick Processing Function                                         |
//+------------------------------------------------------------------+
void OnTick() {
   datetime currentTime = TimeCurrent();                          //--- Get current time
   MqlDateTime timeStruct;                                        //--- Time structure
   TimeToStruct(currentTime, timeStruct);                         //--- Convert to struct
   // Determine if a new session has started
   string currentTimeStr = StringFormat("%02d:%02d", timeStruct.hour, timeStruct.min); //--- Format time string
   if (currentTimeStr == SessionStartTime && sessionStart != currentTime - (timeStruct.hour * 3600 + timeStruct.min * 60 + timeStruct.sec)) { //--- Check new session
      sessionStart = currentTime - timeStruct.sec;                //--- Align to minute start
      rangeEndTime = sessionStart + RangeDurationMinutes * 60;    //--- Calc end time
      rangeHigh = 0.0;                                            //--- Reset high
      rangeLow = DBL_MAX;                                         //--- Reset low
      rangeDefined = false;                                       //--- Reset defined
      breakoutHigh = false;                                       //--- Reset high breakout
      breakoutLow = false;                                        //--- Reset low breakout
      tradedLong = false;                                         //--- Reset long traded
      tradedShort = false;                                        //--- Reset short traded
      lastConfirmTime = 0;                                        //--- Reset confirm time
      // Clean previous visuals for current levels
      ObjectDelete(ChartID(), highLevelObj);                      //--- Delete high level
      ObjectDelete(ChartID(), lowLevelObj);                       //--- Delete low level
      ObjectDelete(ChartID(), highTextObj);                       //--- Delete high text
      ObjectDelete(ChartID(), lowTextObj);                        //--- Delete low text
   }
   if (sessionStart == 0) return;                                 //--- Return if no session
   double currBid = SymbolInfoDouble(_Symbol, SYMBOL_BID);        //--- Get bid
   double currAsk = SymbolInfoDouble(_Symbol, SYMBOL_ASK);        //--- Get ask
   // Define the opening range
   if (currentTime < rangeEndTime) {                              //--- Check within range
      rangeHigh = MathMax(rangeHigh, iHigh(_Symbol, RangeTF, 0)); //--- Update high
      rangeLow = MathMin(rangeLow, iLow(_Symbol, RangeTF, 0));    //--- Update low
   } else if (!rangeDefined) {                                    //--- Check not defined
      rangeDefined = true;                                        //--- Set defined
      // Draw the opening range rectangle
      string rectObj = "ORB_Rectangle_" + IntegerToString(sessionStart); //--- Rect name
      ObjectCreate(ChartID(), rectObj, OBJ_RECTANGLE, 0, sessionStart, rangeHigh, rangeEndTime, rangeLow); //--- Create rect
      ObjectSetInteger(ChartID(), rectObj, OBJPROP_COLOR, clrLightBlue); //--- Set color
      ObjectSetInteger(ChartID(), rectObj, OBJPROP_FILL, true);   //--- Set fill
      ObjectSetInteger(ChartID(), rectObj, OBJPROP_BACK, true);   //--- Set back
      ObjectSetInteger(ChartID(), rectObj, OBJPROP_STYLE, STYLE_SOLID); //--- Set style
      ChartRedraw(ChartID());                                     //--- Redraw chart
      // Add vertical lines for start and end
      string startVLineObj = "ORB_StartVLine_" + IntegerToString(sessionStart); //--- Start vline name
      RenderVLine(startVLineObj, sessionStart, clrBlue, "ORB Start at " + TimeToString(sessionStart, TIME_MINUTES)); //--- Render start vline
      string endVLineObj = "ORB_EndVLine_" + IntegerToString(sessionStart); //--- End vline name
      RenderVLine(endVLineObj, rangeEndTime, clrBlue, "ORB End at " + TimeToString(rangeEndTime, TIME_MINUTES)); //--- Render end vline
      // Add time text labels for start and end
      double textOffset = (rangeHigh - rangeLow) * 0.05;          //--- Calc offset
      string startTimeTextObj = "ORB_StartTime_Text_" + IntegerToString(sessionStart); //--- Start text name
      RenderText(startTimeTextObj, sessionStart, rangeLow - textOffset, TimeToString(sessionStart, TIME_MINUTES), clrBlue, ANCHOR_UPPER); //--- Render start text
      string endTimeTextObj = "ORB_EndTime_Text_" + IntegerToString(sessionStart); //--- End text name
      RenderText(endTimeTextObj, rangeEndTime, rangeLow - textOffset, TimeToString(rangeEndTime, TIME_MINUTES), clrBlue, ANCHOR_UPPER); //--- Render end text
      // Render high and low levels
      RenderLevel(highLevelObj, rangeHigh, clrGreen, "ORB High"); //--- Render high level
      RenderLevel(lowLevelObj, rangeLow, clrRed, "ORB Low");      //--- Render low level
      // Add text labels
      RenderText(highTextObj, rangeEndTime, rangeHigh, "ORB High", clrGreen, ANCHOR_RIGHT_LOWER); //--- Render high text
      RenderText(lowTextObj, rangeEndTime, rangeLow, "ORB Low", clrRed, ANCHOR_RIGHT_UPPER); //--- Render low text
   } 
}

In der Ereignisbehandlung von OnTick kopieren wir zunächst die aktuelle Zeit des Servers mit TimeCurrent in „currentTime“ und konvertieren sie über TimeToStruct in eine MqlDateTime-Struktur, um auf einzelne Komponenten wie Stunde und Minute zuzugreifen. Dann formatieren wir die aktuelle Zeit als „HH:MM“-String mit StringFormat und speichern sie in „currentTimeStr“. So sieht die Struktur aus.

struct MqlDateTime {
   int year;           // Year
   int mon;            // Month
   int day;            // Day
   int hour;           // Hour
   int min;            // Minutes
   int sec;            // Seconds
   int day_of_week;    // Day of week (0-Sunday, 1-Monday, ... ,6-Saturday)
   int day_of_year;    // Day number of the year (January 1st is assigned the number value of zero)
};

Die Aufteilung in eine Struktur hilft uns, die spezifischen Komponenten leicht zu finden. Um den genauen Beginn einer neuen Handelssitzung zu ermitteln, vergleichen wir diese Zeichenfolge mit der nutzerdefinierten „SessionStartTime“. Die zusätzliche Bedingung stellt sicher, dass wir nur einmal pro Tag auslösen, indem wir prüfen, ob „sessionStart“ nicht bereits mit dem aktuellen Tag übereinstimmt, der auf diese Minute ausgerichtet ist (wobei Sekunden abgezogen werden, um zu normalisieren). Wenn eine neue Sitzung beginnt, richten wir „sessionStart“ genau auf den Beginn dieser Minute aus, indem wir die verbleibenden Sekunden abziehen, berechnen „rangeEndTime“ durch Addition von „RangeDurationMinutes“ × 60 Sekunden, setzen „rangeHigh“ auf 0,0 und „rangeLow“ auf den maximalen Double-Wert zurück, um korrekte anfängliche Aktualisierungen zu gewährleisten, löschen alle Flags („rangeDefined“, „breakoutHigh“, „breakoutLow“, „tradedLong“, „tradedShort“, „lastConfirmTime“) und löschen die persistenten Hoch-/Tief-Werte sowie die Textobjekte aus der vorherigen Sitzung, um einen sauberen Neuanfang zu ermöglichen. Wenn noch keine aktive Sitzung erkannt wurde („sessionStart“ == 0), kehren wir einfach zurück, um unnötige Verarbeitung zu vermeiden. Andernfalls werden die aktuellen Geld- und Briefkurse mit der Funktion SymbolInfoDouble abgefragt.

Während der Periode der Bildung des Eröffnungsbereichs (solange „currentTime“ < „rangeEndTime“) werden die Bereichsgrenzen kontinuierlich aktualisiert, indem „rangeHigh“ über „iHigh“ auf das Maximum seines aktuellen Wertes oder das Hoch des letzten Balkens auf „RangeTF“ bei Shift 0 und „rangeLow“ über die Funktion iLow auf das Minimum seines aktuellen Wertes oder das Tief des letzten Balkens setzen. Sobald der Bereich endet und der Bereich noch nicht abgeschlossen ist („!rangeDefined“), setzen wir „rangeDefined“ auf true und fahren fort, den abgeschlossenen Eröffnungsbereich zu visualisieren.

Wir zeichnen ein gefülltes hellblaues Rechteck, das sich von „sessionStart“ bei „rangeHigh“ bis „rangeEndTime“ bei „rangeLow“ erstreckt und einen eindeutigen Namen verwendet, der auf dem Zeitstempel der Sitzung basiert, mit einem einfarbigen Stil und einer Hintergrundplatzierung. Vertikale blaue gepunktete Linien werden über „RenderVLine“ mit beschreibenden Tooltips zu den Start- und Endzeiten hinzugefügt. Die Zeitbeschriftungen werden mit „RenderText“ direkt unter dem Bereich platziert, wobei ein kleiner Abstand von 5 % der Bereichsgröße berechnet und in Blau nach oben verankert wird. Schließlich werden die dauerhaften horizontalen Niveaus mit „RenderLevel“ (grün für oben, rot für unten) und den entsprechenden Textbeschriftungen gerendert, die auf der rechten Seite der Endzeit des Bereichs verankert sind, um sicherzustellen, dass wir immer die genauen Ausbruchsniveaus sehen, auch Stunden oder Tage später. Nach dem Kompilieren erhalten wir folgendes Ergebnis:

ORB BEREICHSEINRICHTUNG

Sobald wir aus einem der Bereiche ausbrechen, bestimmen wir die Richtung und damit die Art des Ausbruchs-Setups und eröffnen den Handel. Ein Kinderspiel. Hier ist die Logik, mit der wir das erreichen.

if (!rangeDefined) return;                                     //--- Return if not defined
// Detect breakout
bool justBreached = false;                                     //--- Init just breached
if (currAsk > rangeHigh && !breakoutHigh) {                    //--- Check high breakout
   breakoutHigh = true;                                        //--- Set high breakout
   justBreached = true;                                        //--- Set just breached
   breakoutPrice = currAsk;                                    //--- Set breakout price
} else if (currBid < rangeLow && !breakoutLow) {               //--- Check low breakout
   breakoutLow = true;                                         //--- Set low breakout
   justBreached = true;                                        //--- Set just breached
   breakoutPrice = currBid;                                    //--- Set breakout price
}
if ((breakoutHigh || breakoutLow) && !(tradedLong || tradedShort)) { //--- Check breakout and not traded
   // Confirm breakout with bar closures if enabled
   bool confirmed = false;                                      //--- Init confirmed
   if (ConfirmBars == 0) {                                      //--- Check no confirm
      confirmed = true;                                         //--- Set confirmed
   } else {                                                     //--- Else
      datetime currConfirmTime = iTime(_Symbol, RangeTF, 0);    //--- Get confirm time
      if (currConfirmTime != lastConfirmTime) {                 //--- Check new confirm
         lastConfirmTime = currConfirmTime;                     //--- Update last confirm
         int confirmCount = 0;                                  //--- Init count
         for (int i = 1; i <= ConfirmBars; i++) {               //--- Iterate bars
            double closePrice = iClose(_Symbol, RangeTF, i);    //--- Get close
            if (breakoutHigh && closePrice > rangeHigh) confirmCount++; //--- Check high
            if (breakoutLow && closePrice < rangeLow) confirmCount++; //--- Check low
         }
         if (confirmCount >= ConfirmBars) confirmed = true;     //--- Set confirmed
      }
   }
   if (confirmed && UseBreakoutFilter) {                        //--- Check confirmed and filter
      // Additional filter logic if needed, but for now assume confirmed
   }
   if (confirmed) {                                             //--- Check confirmed
      double sl = 0.0, tp = 0.0;                                //--- Init SL TP
      if (breakoutHigh && ActivePositions(POSITION_TYPE_BUY) < MaxPositionsDir && !tradedLong) { //--- Check long entry
         if (SLTP_Approach == Dynamic_Method) {                  //--- Check dynamic
            double rangeSize = rangeHigh - rangeLow;             //--- Calc range size
            sl = NormalizeDouble(rangeLow, _Digits);             //--- Set SL
            tp = NormalizeDouble(currAsk + rangeSize * RR_Ratio, _Digits); //--- Set TP
         } else {                                                //--- Static
            sl = NormalizeDouble(currAsk - SL_Points * _Point, _Digits); //--- Set SL
            tp = NormalizeDouble(currAsk + (SL_Points * _Point) * RR_Ratio, _Digits); //--- Set TP
         }
         if (obj_Trade.Buy(TradeVolume, _Symbol, currAsk, sl, tp, "ORB Long Breakout")) { //--- Open buy
            if (obj_Trade.ResultRetcode() == TRADE_RETCODE_DONE) { //--- Check success
               Print("Long Breakout: Entry at ", DoubleToString(currAsk, _Digits), " SL at ", DoubleToString(sl, _Digits), " TP at ", DoubleToString(tp, _Digits)); //--- Log entry
               DrawEntryArrow(currentTime, currBid, true);        //--- Draw arrow
               tradedLong = true;                                 //--- Set long traded
            }
         }
      } else if (breakoutLow && ActivePositions(POSITION_TYPE_SELL) < MaxPositionsDir && !tradedShort) { //--- Check short entry
         if (SLTP_Approach == Dynamic_Method) {                  //--- Check dynamic
            double rangeSize = rangeHigh - rangeLow;             //--- Calc range size
            sl = NormalizeDouble(rangeHigh, _Digits);            //--- Set SL
            tp = NormalizeDouble(currBid - rangeSize * RR_Ratio, _Digits); //--- Set TP
         } else {                                                //--- Static
            sl = NormalizeDouble(currBid + SL_Points * _Point, _Digits); //--- Set SL
            tp = NormalizeDouble(currBid - (SL_Points * _Point) * RR_Ratio, _Digits); //--- Set TP
         }
         if (obj_Trade.Sell(TradeVolume, _Symbol, currBid, sl, tp, "ORB Short Breakout")) { //--- Open sell
            if (obj_Trade.ResultRetcode() == TRADE_RETCODE_DONE) { //--- Check success
               Print("Short Breakout: Entry at ", DoubleToString(currBid, _Digits), " SL at ", DoubleToString(sl, _Digits), " TP at ", DoubleToString(tp, _Digits)); //--- Log entry
               DrawEntryArrow(currentTime, currAsk, false);       //--- Draw arrow
               tradedShort = true;                                //--- Set short traded
            }
         }
      }
   }
}

Sobald der Eröffnungsbereich vollständig definiert ist, kehren wir sofort zurück, wenn „rangeDefined“ immer noch falsch ist, um sicherzustellen, dass keine Ausbruchslogik vorzeitig ausgeführt wird. Anschließend überwachen wir einen Ausbruch: Wenn der aktuelle Briefkurs „rangeHigh“ übersteigt und „breakoutHigh“ noch nicht gesetzt ist, markieren wir einen Ausbruch nach oben, indem wir „breakoutHigh“ auf „true“ setzen, den genauen Ausbruchskurs in „breakoutPrice“ aufzeichnen und vermerken, dass ein neuer Durchbruch stattgefunden hat. Dasselbe tun wir bei einem niedrigen Ausbruch. Wenn mindestens eine Ausbruchsrichtung aktiv ist und in dieser Sitzung weder ein Kauf noch ein Verkauf getätigt wurde („!tradedLong && !tradedShort“), gehen wir zur Bestätigungsphase über. Ist „ConfirmBars“ gleich Null, gilt der Ausbruch sofort als bestätigt. Andernfalls wird bei jedem neuen Balken des Range-Zeitrahmens (der durch den Vergleich der iTime bei Shift 0 mit der „lastConfirmTime“ ermittelt wird) gezählt, wie viele der vorangegangenen „ConfirmBars“-Balken entschieden außerhalb des Bereichs geschlossen haben – über „rangeHigh“ für aufwärts oder unter „rangeLow“ für abwärts. Erst wenn die erforderliche Anzahl von bestätigenden Schlusskursen erreicht ist, setzen wir „bestätigt“ auf true.

Wir beachten die Eingabe „UseBreakoutFilter“ (obwohl sie derzeit nur die Bestätigung weiterleitet – Raum für zukünftige Erweiterungen, wenn Sie weitere Filter hinzufügen möchten). Sobald dies bestätigt ist, berechnen wir die Stop-Loss- und Take-Profit-Niveaus entsprechend der gewählten Methode. Wenn bei einem Ausbruch nach oben die Kaufpositionen unter „MaxPositionsDir“ liegen und noch keine Kaufpositionen gehandelt wurden, verwenden wir den dynamischen Modus, um den Stop-Loss genau am Tiefpunkt des Bereichs (normalisiert) zu platzieren und den Take-Profit bei der aktuellen Nachfrage plus dem vollen Umfang des Bereichs multipliziert mit „RR_Ratio“. Im statischen Modus platzieren wir einen Stop-Loss bei einem festen „SL_Points“ unter dem Briefkurs und nehmen den Gewinn im gleichen Abstand mal dem obigen Multiplikator. Dann führen wir die Kauforder über „obj_Trade.Buy“ aus und protokollieren bei Erfolg (TRADE_RETCODE_DONE) die Details der Eingabe in der Registerkarte Experten, zeichnen mit „DrawEntryArrow“ einen blauen Aufwärtspfeil an der Eingabe und setzen „tradedLong“ auf true, um weitere Kaufpositionen in dieser Sitzung auszuschließen. Die Abwärtsseite spiegelt dies genau. Nach dem Kompilieren erhalten wir folgendes Ergebnis:

BESTÄTIGTES ORB-VERKAUFSSIGNAL

Aus dem Bild können wir ersehen, dass wir Handelsgeschäfte eröffnen, sobald wir einen Ausbruch erkennen. Jetzt müssen wir nur noch die offenen Positionen verwalten, indem wir einen Trailing-Stop anwenden, sobald sich der Markt zu unseren Gunsten entwickelt, wenn wir das möchten.

//+------------------------------------------------------------------+
//| Apply Points Trailing Stop                                       |
//+------------------------------------------------------------------+
void ApplyPointsTrailing() {
   double point = _Point;                                         //--- Get point
   for (int i = PositionsTotal() - 1; i >= 0; i--) {              //--- Iterate positions
      if (PositionGetTicket(i) > 0) {                             //--- Check ticket
         if (PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == UniqueID) { //--- Check symbol magic
            double sl = PositionGetDouble(POSITION_SL);              //--- Get SL
            double tp = PositionGetDouble(POSITION_TP);              //--- Get TP
            double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); //--- Get open
            ulong ticket = PositionGetInteger(POSITION_TICKET);      //--- Get ticket
            if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { //--- Check buy
               double newSL = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID) - Trailing_Stop_Points * point, _Digits); //--- Calc new SL
               if (newSL > sl && SymbolInfoDouble(_Symbol, SYMBOL_BID) - openPrice > Min_Profit_To_Trail_Points * point) { //--- Check conditions
                  obj_Trade.PositionModify(ticket, newSL, tp);       //--- Modify position
               }
            } else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) { //--- Check sell
               double newSL = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK) + Trailing_Stop_Points * point, _Digits); //--- Calc new SL
               if (newSL < sl && openPrice - SymbolInfoDouble(_Symbol, SYMBOL_ASK) > Min_Profit_To_Trail_Points * point) { //--- Check conditions
                  obj_Trade.PositionModify(ticket, newSL, tp);       //--- Modify position
               }
            }
         }
      }
   }
}

//--- Call the function per tick in the "OnTick" event handler

if (TrailingType == Trailing_Points && PositionsTotal() > 0) { //--- Check trailing
   ApplyPointsTrailing();                                      //--- Apply trailing
}

Hier implementieren wir die Funktion „ApplyPointsTrailing“, um den Stop-Loss dynamisch nachzuziehen, wenn der Modus „Trailing_Points“ ausgewählt ist, und so Gewinne zu sichern, wenn sich der Markt zu unseren Gunsten bewegt. Die Funktion beginnt mit der Speicherung des Punktwerts des Symbols in „point“ mit _Point. Dann wird rückwärts durch alle offenen Positionen iteriert, um alle Änderungen ohne Indexkonflikte sicher zu verarbeiten. Für jedes gültige Ticket überprüfen wir, ob die Position zum aktuellen Symbol gehört und unsere magische Nummer „UniqueID“ trägt. Wir rufen den aktuellen Stop-Loss, Take-Profit, den offenen Preis und die Ticketnummer ab.

Bei Kaufpositionen berechnen wir einen potenziellen neuen Stop-Loss, indem wir „Trailing_Stop_Points“ × point vom aktuellen Geldkurs (normalisiert auf die Ziffern des Symbols) abziehen. Wir wenden die Änderung nur an, wenn dieses neue Niveau höher ist als der bestehende Stop-Loss (Verschärfung) und der unrealisierte Gewinn den Punkt „Min_Profit_To_Trail_Points“ × point überschreitet, um sicherzustellen, dass wir nur nach einem sinnvollen Puffer nachziehen. Die Position wird über „obj_Trade.PositionModify“ aktualisiert, wobei der ursprüngliche Take-Profit erhalten bleibt. Die Logik für Verkaufspositionen spiegelt dies genau. Schließlich wird am Ende von OnTick geprüft, ob das Trailing aktiviert ist („TrailingType == Trailing_Points“) und ob es offene Positionen gibt. Wenn dies der Fall ist, rufen wir bei jedem Tick sofort „ApplyPointsTrailing“ auf und bieten so ohne Verzögerung eine Gewinnabsicherung in Echtzeit. Schließlich müssen wir unsere Visualisierungsobjekte löschen, wenn wir das Programm aus dem Chart entfernen.

//+------------------------------------------------------------------+
//| EA Stop Function                                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int code) {
   ObjectDelete(ChartID(), highLevelObj);                         //--- Delete high level
   ObjectDelete(ChartID(), lowLevelObj);                          //--- Delete low level
   ObjectDelete(ChartID(), highTextObj);                          //--- Delete high text
   ObjectDelete(ChartID(), lowTextObj);                           //--- Delete low text
   // Clean dynamic objects
   ObjectsDeleteAll(ChartID(), "ORB_Rectangle_", OBJ_RECTANGLE);  //--- Delete rectangles
   ObjectsDeleteAll(ChartID(), "ORB_StartVLine_", OBJ_VLINE);     //--- Delete start vlines
   ObjectsDeleteAll(ChartID(), "ORB_EndVLine_", OBJ_VLINE);       //--- Delete end vlines
   ObjectsDeleteAll(ChartID(), "ORB_StartTime_Text_", OBJ_TEXT);  //--- Delete start texts
   ObjectsDeleteAll(ChartID(), "ORB_EndTime_Text_", OBJ_TEXT);    //--- Delete end texts
   ObjectsDeleteAll(ChartID(), "EntryMarker_", OBJ_ARROW);        //--- Delete entry markers
}

In der Funktion OnDeinit, die ausgeführt wird, wenn das Programm aus dem Chart entfernt oder das Terminal heruntergefahren wird, löschen wir zunächst die vier persistenten Objekte mit ihrem Namen: die hohen und niedrigen horizontalen Ebenen über „highLevelObj“ und „lowLevelObj“ und ihre Textbeschriftungen mit „highTextObj“ und „lowTextObj“. Anschließend verwenden wir ObjectsDeleteAll, um jedes dynamisch erstellte Objekt aus der aktuellen und allen vorherigen Sitzungen zu entfernen. Diese vollständige Bereinigung verhindert die Ansammlung von Objekten in mehreren Sitzungen oder beim Neuladen von Charts. Nach dem Kompilieren erhalten wir das folgende Ergebnis, wenn der Trailing-Stop aktiviert ist.

GIF DES KOMPLETTEN ORB

Anhand der Visualisierung können wir sehen, dass wir die Bereiche definieren, Positionen eröffnen und sie verwalten, indem wir bei Bedarf Trailing Stops anwenden und so unsere Ziele erreichen. Bleibt nur noch der Backtest des Programms, und das wird im nächsten Abschnitt behandelt.


Backtest

Nach einem gründlichen Backtest erhalten wir folgende Ergebnisse.

Backtest-Grafik:

GRAPH

Bericht des Backtests:

BERICHT


Schlussfolgerung

Zusammenfassend haben wir das sitzungsbasierte System Opening Range Breakout (ORB) in MQL5 entwickelt, das nutzerdefinierte Sitzungsstartzeiten und Eröffnungsbereichsdauern in Minuten erlaubt, automatisch das korrekte Hoch und Tief auf einem ausgewählten Zeitrahmen bestimmt, Ausbrüche mit optionaler Bestätigung durch die Schlusskurse mehrerer Balken erkennt und Handelsgeschäfte nur in der Ausbruchsrichtung ausführt.

Haftungsausschluss: Dieser Artikel ist nur für Bildungszwecke gedacht. Der Handel ist mit erheblichen finanziellen Risiken verbunden, und die Volatilität der Märkte kann zu Verlusten führen. Gründliche Backtests und sorgfältiges Risikomanagement sind entscheidend, bevor Sie dieses Programm auf den Live-Märkten einsetzen.

Mit dieser sitzungsbasierten Strategie des Opening Range Breakout sind Sie für den Handel mit Intraday-Breakout-Setups in jeder beliebigen Marktsitzung gerüstet und können Ihre Handelsreise weiter optimieren. Viel Spaß beim Handeln!

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

Letzte Kommentare | Zur Diskussion im Händlerforum (3)
linfo2
linfo2 | 26 Nov. 2025 in 22:36
Hallo Allan und vielen Dank für Ihre kontinuierliche Beiträge , schön zusammen als Sie , ich frage mich, ob Sie irgendwelche Lösungen für die Automatisierung der Öffnungszeit haben ? in der Regel verwende ich Broker Zeit ändern, aber es ist nicht immer genau für mich, wie ich in NZ bin mein Broker ist in AU gibt es Faktoren wie austalias Offset und Zeiten, wenn es ein Tokio Offset und ein New York Offset . Ich hatte Schwierigkeiten, dies zu erreichen, und bin für jeden Vorschlag dankbar. chat gpt gibt mir ein Skript, das die Sommerzeit für jedes Land prüft, aber ich frage mich, ob es eine bessere Lösung gibt.
Allan Munene Mutiiria
Allan Munene Mutiiria | 27 Nov. 2025 in 08:09
linfo2 Öffnungszeit haben ? in der Regel verwende ich Broker Zeit ändern, aber es ist nicht immer genau für mich, wie ich in NZ bin mein Broker ist in AU gibt es Faktoren wie austalias Offset und Zeiten, wenn es ein Tokio Offset und ein New York Offset . Ich habe Probleme damit, dies zum Funktionieren zu bringen, alle Vorschläge sind willkommen. chat gpt gibt mir ein Skript, das jedes Land Sommerzeit Daten überprüft, fragte sich, ob es eine eloquentere Lösung war

Hallo. Danke für die freundliche Rückmeldung. Sie können die Zeit in Ihrem Code definieren, indem Sie die lokale Zeit anstelle der Zeit des Brokers verwenden, oder Sie können Ihre Zeit definieren. Siehe Beispiel.

Lokale Zeit:

TimeLocal()

Sie können auch die direkte Zeit gemäß den Einstellungen Ihres Computers über den Handelsserver verwenden:

TimeTradeServer()

GMT-Zeit:

TimeGMT()

Sie können auch Ihr eigenes Datum und Ihre eigene Uhrzeit wie unten angegeben definieren:

datetime my_time = D'2025.11.27 11:07'
MqlDateTime my_struct_time;

Es liegt ganz bei Ihnen, den besten Ansatz zu wählen. Vielen Dank!

Stanislav Korotky
Stanislav Korotky | 27 Nov. 2025 in 11:46
linfo2 Öffnungszeit haben ? in der Regel verwende ich Broker Zeit ändern, aber es ist nicht immer genau für mich, wie ich in NZ bin mein Broker ist in AU gibt es Faktoren wie austalias Offset und Zeiten, wenn es ein Tokio Offset und ein New York Offset . Ich habe Schwierigkeiten, dies zu bekommen, um zu arbeiten, alle Vorschläge geschätzt. Chat gpt gibt mir mir ein Skript, das jedes Land Sommerzeit Daten prüft, fragte sich, ob es eine eloquente Lösung war

Ihr Problem ist nicht klar genug. Sie können aber die umfangreiche Bibliothek Local Timezones and Local Session Hours oder das einfachere TimeServerDaylightSavings ausprobieren. Ohne Zeitanpassungen können Sie Ihre Strategie nicht zuverlässig an einer Historie testen, die in der Regel von Sommerzeit- und Zeitzonenumstellungen betroffen ist. Oder Sie möchten vielleicht den Daylight (DST) Schedule des Brokers ermitteln, um Zeitzonenänderungen online zu erkennen.

Leider bietet die integrierte MQL5-API keine fertige und aussagekräftige Lösung.

Die „Griechen“ in Black-Scholes automatisieren: Fortgeschrittenes Scalping und Mikrostrukturhandel Die „Griechen“ in Black-Scholes automatisieren: Fortgeschrittenes Scalping und Mikrostrukturhandel
Gamma und Delta wurden ursprünglich als Risikomanagement-Tools zur Absicherung von Optionsrisiken entwickelt, entwickelten sich aber im Laufe der Zeit zu leistungsstarken Instrumenten für fortgeschrittenes Scalping, Orderflow-Modellierung und Mikrostrukturhandel. Heute dienen sie als Echtzeit-Indikatoren für die Preisempfindlichkeit und das Liquiditätsverhalten und ermöglichen es den Händlern, kurzfristige Schwankungen mit bemerkenswerter Präzision zu antizipieren.
Marktpositionierungskodex für den VGT mit Kendall’schen Tau und Distanzkorrelation Marktpositionierungskodex für den VGT mit Kendall’schen Tau und Distanzkorrelation
In diesem Artikel wollen wir untersuchen, wie ein komplementäres Indikatorpaar zur Analyse der jüngsten 5-Jahres-Historie des Vanguard Information Technology Index Fund ETF verwendet werden kann. Durch die Betrachtung von zwei Algorithmen, dem Kendall’schen Tau und der Distance-Korrelation, versuchen wir nicht nur ein ideales Indikatorpaar für den Handel mit dem VGT auszuwählen, sondern auch geeignete Signalmuster-Paarungen dieser beiden Indikatoren.
MetaTrader 5 Machine Learning Blueprint (Teil 6): Entwicklung eines produktionsgerechten Caching-Systems MetaTrader 5 Machine Learning Blueprint (Teil 6): Entwicklung eines produktionsgerechten Caching-Systems
Sind Sie es leid, Fortschrittsbalken zu beobachten, anstatt Handelsstrategien zu testen? Die herkömmliche Zwischenspeicherung versagt bei Financial ML, sodass Sie mit verlorenen Berechnungen und frustrierenden Neustarts konfrontiert werden. Wir haben eine ausgeklügelte Caching-Architektur entwickelt, die den besonderen Herausforderungen von Finanzdaten gerecht wird: zeitliche Abhängigkeiten, komplexe Datenstrukturen und die ständige Gefahr einer Verzerrung durch Vorausschau. Unser dreischichtiges System sorgt für drastische Geschwindigkeitsverbesserungen, während es veraltete Ergebnisse automatisch ungültig macht und kostspielige Datenlecks verhindert. Warten Sie nicht länger auf Berechnungen, sondern beginnen Sie mit der Iteration in dem Tempo, das der Markt verlangt.
Die Grenzen des maschinellen Lernens überwinden (Teil 8): Nichtparametrische Strategieauswahl Die Grenzen des maschinellen Lernens überwinden (Teil 8): Nichtparametrische Strategieauswahl
Dieser Artikel zeigt, wie man ein Blackbox-Modell konfiguriert, um automatisch starke Handelsstrategien mit einem datengesteuerten Ansatz zu entdecken. Indem wir die gegenseitige Information nutzen, um die lernfähigsten Signale zu priorisieren, können wir intelligentere und anpassungsfähigere Modelle erstellen, die herkömmliche Methoden übertreffen. Die Leser werden auch lernen, häufige Fallstricke wie den übermäßigen Rückgriff auf oberflächliche Metriken zu vermeiden und stattdessen Strategien zu entwickeln, die auf aussagekräftigen statistischen Erkenntnissen beruhen.