Larry Williams‘ Geheimnisse des Marktes (Teil 7): Eine empirische Untersuchung zum Konzept des Handelstages der Woche
Einführung
Die meisten Handelssysteme beruhen auf Kursmustern, Indikatoren oder Volatilitätsmodellen. Die Zeit wird jedoch oft als neutraler Hintergrund behandelt, als etwas, das lediglich vergeht, während der Preis die eigentliche Arbeit leistet. Montags wird genauso gehandelt wie donnerstags, als ob sich die Märkte über den gesamten Kalender hinweg einheitlich ausdrücken würden.
Larry Williams hat diese Annahme schon vor Jahrzehnten infrage gestellt. Durch umfangreiche Beobachtungen und Tests hat er herausgefunden, dass sich die Märkte an verschiedenen Tagen unterschiedlich verhalten. An manchen Tagen scheinen Ausbruchsversuche leichter zu gelingen, während andere Tage eher zum Scheitern oder Zögern neigen. Diese Idee ist einfach, aber ihre Auswirkungen sind für kurzfristige Händler von großer Bedeutung.
Anstatt Ein- und Ausstiege oder das Risikomanagement zu optimieren, geht dieser Artikel einen Schritt zurück und stellt eine grundsätzlichere Frage. Wenn jeden Tag die gleiche Strategie angewandt wird, tragen dann alle Tage gleichermaßen zu den Ergebnissen bei? Oder haben bestimmte Tage stillschweigend mehr Gewicht als andere? Um dies zu untersuchen, entwerfen wir ein kontrolliertes Experiment, das unnötige Komplexität beseitigt. Es wird ein einziger volatilitätsbasierter Tageseinstieg verwendet, die Trades werden nur für eine Sitzung gehalten und die Performance wird ausschließlich anhand der Gewinnrate bewertet. Indem wir das System auf das Wesentliche reduzieren, lassen wir die Daten klar sprechen.
Das Ziel ist nicht der Aufbau eines profitablen Handelssystems, sondern die Beobachtung des Marktverhaltens durch die Linse der Zeit. Damit legen wir den Grundstein für einen strukturierten Rahmen, mit dem Händler das Konzept des Handelstages der Woche in jedem Markt testen, überprüfen und verfeinern können.
Das Konzept des Handelstages der Woche
Larry Williams stellte fest, dass in den Märkten die Chancen zeitlich nicht gleichmäßig verteilt sind. In seiner Untersuchung war die Preisbewegung nicht zufällig, wenn sie nach Kalendertagen gruppiert wurde. Bestimmte Tage zeigten eine Tendenz zu stärkeren Ausbrüchen, während andere eher zu einem Stillstand oder zu gescheiterten Bewegungen führten. Dieses Verhalten war nicht an einen bestimmten Indikator oder ein Muster gebunden, sondern an die Zeit selbst.
Die wichtigste Erkenntnis ist, dass die Zeit wie ein bedingter Filter wirken kann. Wenn es wahrscheinlicher ist, dass ein Markt an bestimmten Tagen expandiert oder in einen Trend übergeht, weisen die an diesen Tagen getätigten Abschlüsse ein anderes Wahrscheinlichkeitsprofil auf als Abschlüsse, die an weniger reaktionsfähigen Tagen getätigt werden. Williams argumentierte nicht, dass ein bestimmter Tag eine Erfolgsgarantie ist, sondern vielmehr, dass einige Tage statistisch gesehen bessere Bedingungen für eine kurzfristige Beteiligung bieten als andere.
Dieser Gedanke ist besonders bei kurzfristigen Handelssystemen von Bedeutung. Solche Systeme beruhen auf begrenzten Haltedauern und geringen Fehlermargen. Selbst geringfügige Verbesserungen bei der Handelsauswahl können die Ergebnisse erheblich beeinflussen. Wenn eine Strategie jeden Tag die gleiche Leistung erbringt, kann es sein, dass sie unbeabsichtigt einen Durchschnitt aus guten und schlechten Bedingungen bildet. Das Filtern von Trades nach Wochentagen kann das Engagement in Zeiträumen reduzieren, die in der Vergangenheit ein weniger günstiges Verhalten aufwiesen, und so die Gesamteffizienz verbessern, ohne die zentrale Einstiegslogik zu ändern.
Das Konzept des Handelstages der Woche eignet sich gut für empirische Tests, da es klar definiert, messbar und wiederholbar ist. Die Wochentage sind objektive Zeitkategorien, die sich nicht über verschiedene Plattformen oder Datenquellen hinweg ändern. Jeder Handelstag kann eindeutig klassifiziert werden, und Performance-Kennzahlen wie die Gewinnrate können direkt berechnet und verglichen werden. Dies macht das Konzept ideal für statistische Analysen, Walk-Forward-Tests und die Replikation über verschiedene Märkte und Zeiträume hinweg.
Indem man die Zeit als Variable isoliert und die Handelslogik einfach hält, wird es möglich, zu bewerten, ob es eine tagesabhängige Verzerrung gibt und ob sie im Laufe der Zeit bestehen bleibt. Dieser Ansatz steht im Einklang mit Williams' ursprünglichem Schwerpunkt auf Beobachtung und Überprüfung statt auf Annahmen, sodass die Daten das Vorhandensein eines zeitbasierten Marktverhaltens bestätigen oder verwerfen können.
Vereinfachung des Experiments
Beim Testen einer zeitbasierten Markthypothese wird die Komplexität schnell zu einer Belastung. Je mehr Bedingungen, Filter und Verwaltungsregeln einem System hinzugefügt werden, desto schwieriger wird es, zu erkennen, was die Ergebnisse tatsächlich beeinflusst. Da das Ziel dieser Studie darin besteht, zu untersuchen, ob bestimmte Tage durchweg bessere Handelsbedingungen bieten, müssen alle unwesentlichen Komponenten entfernt werden.
Deswegen wird bei diesem Experiment bewusst auf die üblichen Handelsmanagementtechniken wie Stop-Loss, Take-Profit-Ziele, Trailing-Stops und Teilausstiege verzichtet. Diese Instrumente sind zwar für den realen Handel unverzichtbar, aber sie führen zusätzliche Entscheidungsebenen ein, die den Einfluss der Zeit verdecken können. Ein Stop-Loss-Treffer kann zum Beispiel mehr über das Intraday-Rauschen aussagen als darüber, ob ein bestimmter Tag für eine Richtungsbewegung günstig war.
Stattdessen folgt jeder Handel einer einzigen, einheitlichen Regel. Eine Position wird unter Verwendung des volatilitätsbasierten Einstiegs von Larry Williams eröffnet und bis zum Ende des Handelstages gehalten, wo sie unabhängig von Gewinn oder Verlust geschlossen wird. Dadurch wird sichergestellt, dass jeder Handel das gesamte Tagesergebnis erfasst und die Ergebnisse über alle Wochentage hinweg direkt vergleichbar sind.
Die Eingabelogik selbst ist absichtlich minimal. Anstatt sich auf Swing-Bestätigungen oder Mustererkennung zu verlassen, verwendet das System die Spanne des Vortages, um ein Ausbruchsniveau vom heutigen Eröffnungszeitpunkt zu prognostizieren. Dieser Ansatz bleibt nahe am Originalwerk von Williams, während das Signal objektiv und leicht reproduzierbar bleibt. Das System tritt entweder in den Markt ein oder nicht, sodass die Interpretation der Signale nicht mehr zweideutig ist.
Durch diese Vereinfachung der Struktur isoliert das Experiment eine einzige Variable: die Zeit. Jeder beobachtete Unterschied in der Gewinnrate zwischen den Tagen kann daher dem Wochentag zugeschrieben werden und nicht dem Handelsmanagement, der Indikatorabstimmung oder den diskretionären Filtern. Dies schafft eine saubere Ausgangsbasis, die später erweitert werden kann, sobald das Vorhandensein oder Nichtvorhandensein von tagesbezogenen Verzerrungen festgestellt wurde.
Aufbau des Expert Advisors für den Handelstag der Woche im Test
Bevor wir zur Umsetzung übergehen, ist es wichtig, die Erwartungen an diesen Abschnitt zu klären. Ziel ist es nicht, eine fertige Blackbox zu präsentieren, sondern ein kontrolliertes Forschungsinstrument zu konstruieren, mit dem wir Larry Williams' Idee des Handelstages der Woche auf saubere, reproduzierbare Weise testen können. Jede eingeführte Komponente dient einem bestimmten Zweck und unterstützt einen logischen Schritt im Testrahmen.
Voraussetzungen
Um diesen Abschnitt effektiv verfolgen zu können, werden einige Anforderungen vorausgesetzt.
Zunächst setzen wir voraus, dass Sie mit der Programmiersprache MQL5 vertraut sind. Grundlegende Konzepte wie Variablen, Funktionen, bedingte Logik, Schleifen, Enumerationen, Strukturen und die Verwendung von Standardbibliotheken sollten bereits bekannt sein. Wenn diese Grundlagen noch unklar sind, bietet die offizielle MQL5-Referenz einen hervorragenden Ausgangspunkt.
Zweitens ist eine vorherige Erfahrung mit der Handelsplattform MetaTrader 5 erforderlich. Wir verlassen uns auf grundlegende Plattformfunktionen wie das Öffnen von Charts, das Anhängen von Expert Advisors, das Navigieren im Strategietester und das Arbeiten mit verschiedenen Zeitfenstern.
Drittens setzen wir voraus, dass wir mit dem MetaEditor vertraut sind. Die Fähigkeit, neue Quelldateien zu erstellen, Code zu schreiben, Programme zu kompilieren und Kompilierungsfehler zu untersuchen, ist für produktives Lernen in diesem Abschnitt unerlässlich.
Zur Unterstützung des praktischen Lernens wird der fertige Expert Advisor-Quellcode als Anhang mit dem Namen lwTDWStudy.mq5 bereitgestellt. Da wir den EA Schritt für Schritt aufbauen, wird dringend empfohlen, diese Datei als Referenz in einer separaten Registerkarte geöffnet zu lassen. Die Beherrschung von Programmierkonzepten erfordert eine aktive Auseinandersetzung mit dem Thema durch Vergleiche und nicht durch passives Konsumieren des Materials.
Schaffung der EA-Stiftung
Wir beginnen mit der Erstellung einer neuen leeren Datei für den MetaEditor und fügen die anfänglichen Code-Bausteine ein.
//+------------------------------------------------------------------+ //| lwTDWStudy.mq5 | //| Copyright 2026, MetaQuotes Ltd. Developer is Chacha Ian | //| https://www.mql5.com/en/users/chachaian | //+------------------------------------------------------------------+ #property copyright "Copyright 2026, MetaQuotes Ltd. Developer is Chacha Ian" #property link "https://www.mql5.com/en/users/chachaian" #property version "1.00" //+------------------------------------------------------------------+ //| Custom Enumerations | //+------------------------------------------------------------------+ enum ENUM_TDW_MODE { TDW_ALL_DAYS, TDW_SELECTED_DAYS }; //+------------------------------------------------------------------+ //| Standard Libraries | //+------------------------------------------------------------------+ #include <Trade\Trade.mqh> //+------------------------------------------------------------------+ //| User input variables | //+------------------------------------------------------------------+ input group "Information" input ulong magicNumber = 254700680002; input ENUM_TIMEFRAMES timeframe = PERIOD_CURRENT; input group "TDW filters" input ENUM_TDW_MODE tradeDayMode = TDW_SELECTED_DAYS; input bool tradeSunday = false; input bool tradeMonday = true; input bool tradeTuesday = false; input bool tradeWednesday = false; input bool tradeThursday = false; input bool tradeFriday = false; input bool tradeSaturday = false; input group "Volatility Breakout Parameters" input double inpBuyRangeMultiplier = 0.50; input group "Trade and Risk Management" input double positionSize = 0.1; //+------------------------------------------------------------------+ //| Global Variables | //+------------------------------------------------------------------+ //--- Create a CTrade object to handle trading operations CTrade Trade; //--- To hep track current market prices for Buying (Ask) and Selling (Bid) double askPrice; double bidPrice; //--- To store current time datetime currentTime; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(){ //--- Assign a unique magic number to identify trades opened by this EA Trade.SetExpertMagicNumber(magicNumber); return(INIT_SUCCEEDED); }
Auf dieser Grundlage werden Metadaten festgelegt, erforderliche Bibliotheken eingebunden, Nutzereingaben definiert und globale Variablen vorbereitet, die die gesamte spätere Logik unterstützen werden.
Die Enumeration, die den Modus „Handelstag der Woche“ definiert, wird früh eingeführt. Sie ermöglicht es dem EA, in zwei verschiedenen Konfigurationen zu arbeiten. Ein Modus wird täglich ohne Filterung gehandelt und dient als Basis für den Vergleich. Der zweite Modus schränkt den Handel auf vom Nutzer ausgewählte Tage ein und ermöglicht so empirische Tests der tagesbasierten Verzerrung.
Die Einbeziehung der Standard-Handelsbibliothek ermöglicht es uns, die Auftragsausführung und das Positionsmanagement an eine robuste, gut getestete Schnittstelle zu delegieren. Dadurch liegt der Schwerpunkt des EAs auf der Forschungslogik und nicht auf der Abwicklung von Trades auf niedriger Ebene.
Nutzereingaben werden logisch gruppiert. Informationseingaben definieren die magische Zahl und den Zeitrahmen für die Arbeit. Die Filter für den Handelstag bieten Steuerelemente für die Auswahl des Wochentags. Die Parameter des Volatilitätsausbruchs ermöglichen eine Anpassung der Einstiegsprojektion. Handels- und Risikoinputs bestimmen die Positionsgröße. Jede Gruppe spiegelt eine bestimmte konzeptionelle Ebene im System wider.
Globale Variablen werden deklariert, um Preise, Zeit und Zustand zu verfolgen. Diese Variablen bilden den gemeinsamen Speicher, über den alle Komponenten des EA kommunizieren.
Erkennen des Beginns eines neuen Handelstages
Da das Experiment in einem täglichen Entscheidungszyklus abläuft, ist es von entscheidender Bedeutung, den Zeitpunkt der Eröffnung einer neuen Bar zu erkennen. Zu diesem Zweck führen wir eine Hilfsfunktion ein, die den Zeitstempel der letzten Bar mit einem gespeicherten Wert vergleicht.
//+------------------------------------------------------------------+ //| Function to check if there's a new bar on a given chart timeframe| //+------------------------------------------------------------------+ bool IsNewBar(string symbol, ENUM_TIMEFRAMES tf, datetime &lastTm){ datetime currentTm = iTime(symbol, tf, 0); if(currentTm != lastTm){ lastTm = currentTm; return true; } return false; }
Die Funktion erhält das Symbol, den Zeitrahmen und einen Verweis auf die letzte aufgezeichnete Eröffnungszeit der Bar. Wenn eine neue Bar erkannt wird, wird die gespeicherte Zeit aktualisiert, und die Funktion meldet einen Zustandswechsel. Dieser Mechanismus gewährleistet, dass die täglichen Berechnungen unabhängig von der Tickfrequenz genau einmal pro Tag durchgeführt werden.
Um diese Logik zu unterstützen, wird eine globale Datetime-Variable deklariert und beim Start des Experten initialisiert.
//--- To help track new bar open datetime lastBarOpenTime;
Die Initialisierung auf Null garantiert, dass die erste Bar korrekt erkannt wird.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(){ ... //--- Initialize global variables lastBarOpenTime = 0; return(INIT_SUCCEEDED); }
Darstellung von Volatilitätsausbruchsniveaus
Die Volatilitätsausbruchslogik von Larry Williams erfordert zwei abgeleitete Werte: die Spanne des Vortags und das voraussichtliche Einstiegsniveau des aktuellen Tages. Anstatt diese als isolierte Variablen zu verwalten, definieren wir eine eigene Struktur, die beide Werte enthält.
//--- Holds all price levels derived from Larry Williams' volatility breakout calculations struct MqlLwVolatilityLevels { double yesterdayRange; double buyEntryPrice; }; MqlLwVolatilityLevels lwVolatilityLevels;
Diese Struktur fasst zusammenhängende Daten in einer einzigen logischen Einheit zusammen, was die Lesbarkeit verbessert und das Risiko eines inkonsistenten Zustands verringert. Eine Instanz dieser Struktur wird global deklariert und während der Initialisierung auf Null zurückgesetzt, um einen sauberen Ausgangszustand zu gewährleisten.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(){ ... //--- Reset volatility levels ZeroMemory(lwVolatilityLevels); return(INIT_SUCCEEDED); }
Messung der Reichweite des Vortages
Um die tägliche Volatilität zu berechnen, führen wir eine Funktion ein, die den Bereich einer Bar bei einem bestimmten Index zurückgibt. Die Funktion ruft die Höchst- und Tiefstpreise direkt aus den historischen Daten ab und gibt deren Differenz zurück.
//+------------------------------------------------------------------+ //| Returns the price range (high - low) of a bar at the given index | //+------------------------------------------------------------------+ double GetBarRange(const string symbol, ENUM_TIMEFRAMES tf, int index){ double high = iHigh(symbol, tf, index); double low = iLow (symbol, tf, index); if(high == 0.0 || low == 0.0){ return 0.0; } return NormalizeDouble(high - low, Digits()); }
Eine defensive Prüfung stellt sicher, dass sich ungültige Preiswerte nicht im System verbreiten. Durch die Normalisierung wird das Ergebnis an die Genauigkeit des Symbols angepasst. Diese Funktion ist wiederverwendbar und isoliert die Bereichsberechnung von der übergeordneten Logik.
Prognose des Eröffnungskurses
Der Eröffnungskurs für den Ausbruch wird berechnet, indem ein Bruchteil der Spanne des Vortages zum heutigen Eröffnungskurs addiert wird. Diese Berechnung ist in einer kleinen, konzentrierten Funktion gekapselt, die die erforderlichen Eingaben erhält und den voraussichtlichen Preis zurückgibt.
//+------------------------------------------------------------------+ //| Calculates the bullish breakout entry price using today's open and yesterday's range | //+------------------------------------------------------------------+ double CalculateBuyEntryPrice(double todayOpen, double yesterdayRange, double buyMultiplier){ return todayOpen + (yesterdayRange * buyMultiplier); }
Die Isolierung dieser Logik macht die Absicht deutlich und hält die OnTick-Funktion frei von einem arithmetischen Durcheinander.
Aktualisieren der Tageswerte bei einer sich öffnenden Bar
Wenn alle unterstützenden Komponenten vorhanden sind, integrieren wir sie in die Funktion OnTick .
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick(){ ... //--- Run this block only when a new bar is detected on the selected timeframe if(IsNewBar(_Symbol, timeframe, lastBarOpenTime)){ lwVolatilityLevels.yesterdayRange = GetBarRange(_Symbol, timeframe, 1); lwVolatilityLevels.buyEntryPrice = CalculateBuyEntryPrice (askPrice, lwVolatilityLevels.yesterdayRange, inpBuyRangeMultiplier ); } }
Wenn eine neue Tages-Bar erkannt wird, berechnet der EA die gestrige Handelsspanne neu und legt den Einstiegskurs für den neuen Tag fest. Genau in diesem Moment wird jede aktive Position geschlossen. In diesem Versuchsrahmen markiert die Eröffnung eines neuen Tages das Ende des vorangegangenen Handels. Dieser Ansatz garantiert, dass jeder Handel ein vollständiges Tagesergebnis erfasst, und entspricht dem Schwerpunkt der Studie auf dem Tagesverhalten und nicht auf dem Intraday-Management.
Verfolgung der Intraday-Kursbewegung
Um zu erkennen, wann der Kurs das prognostizierte Einstiegsniveau überschreitet, beobachten wir die Schlusskurse auf Minutenebene. Ein globales Array wird definiert, um die letzten einminütigen Schlusskurse zu speichern.
//--- To store minutes data double closePriceMinutesData [];
Bei der Initialisierung des Experten wird das Array als Zeitreihe konfiguriert, sodass die jüngsten Daten stets bei Index Null zugänglich sind.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(){ ... //--- Treat the following arrays as timeseries (index 0 becomes the most recent bar) ArraySetAsSeries(closePriceMinutesData, true); return(INIT_SUCCEEDED); }
Bei jedem Tick wird das Array mit CopyClose aktualisiert.
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick(){ ... //--- Get some minutes data if(CopyClose(_Symbol, PERIOD_M1, 0, 5, closePriceMinutesData) == -1){ Print("Error while copying minutes datas ", GetLastError()); return; } }
Dies bietet ein rollierendes Fenster des jüngsten Preisverhaltens ohne übermäßigen Datenverarbeitungsaufwand.
Erkennen von Ausbruchs-Crossovers
Die Crossover-Erkennungslogik prüft, ob sich der Kurs zwischen zwei aufeinanderfolgenden Minutenschlusskursen von unterhalb des projizierten Niveaus nach oben bewegt hat. Diese Definition stellt sicher, dass Einträge nur bei echten Überschreitungen nach oben und nicht bei wiederholten Berührungen ausgelöst werden.
//+------------------------------------------------------------------+ //| To detect a crossover at a given price level | //+------------------------------------------------------------------+ bool IsCrossOver(const double price, const double &closePriceMinsData[]){ if(closePriceMinsData[1] <= price && closePriceMinsData[0] > price){ return true; } return false; }
Die Funktion ist bewusst einfach gehalten. Sie beantwortet eine einzige Frage und liefert ein eindeutiges boolesches Ergebnis. Durch diese Einfachheit ist die Handelsbedingung leicht zu prüfen und zu begründen.
Implementierung von Filtern für den Handelstag der Woche
Zur Unterstützung des Konzepts „Handelstag der Woche“ werden zwei Hilfsfunktionen eingeführt. Die erste wandelt einen Datumswert in einen numerischen Wochentag um.
//+------------------------------------------------------------------------------------+ //| Returns the day of the week (0 = Sunday, 6 = Saturday) for the given datetime value| //+------------------------------------------------------------------------------------+ int TimeDayOfWeek(datetime time){ MqlDateTime timeStruct = {}; if(!TimeToStruct(time, timeStruct)){ Print("TimeDayOfWeek: TimeToStruct failed"); return -1; } return timeStruct.day_of_week; }
Die zweite prüft, ob der Handel auf der Grundlage des gewählten Modus und der nutzerdefinierten Wochentagsflags erlaubt ist.
//+-----------------------------------------------------------------------------------------------------+ //| Determines whether trading is permitted for the given datetime based on the selected trade-day mode | //+-----------------------------------------------------------------------------------------------------+ bool IsTradingDayAllowed(datetime time) { // Baseline mode: no filtering if(tradeDayMode == TDW_ALL_DAYS){ return true; } int day = TimeDayOfWeek(time); switch(day) { case 0: return tradeSunday; case 1: return tradeMonday; case 2: return tradeTuesday; case 3: return tradeWednesday; case 4: return tradeThursday; case 5: return tradeFriday; case 6: return tradeSaturday; } return false; }
Wenn der EA im Basismodus arbeitet, ist der Handel immer erlaubt. Wenn die Tagesfilterung aktiviert ist, wird die Entscheidung vollständig an die Wochentagskonfiguration delegiert. Durch diese Trennung wird sichergestellt, dass das Basisexperiment und das gefilterte Experiment eine identische Ausführungslogik haben, die sich nur in der zeitlichen Abfolge der Genehmigungen unterscheidet.
Sicheres Positionsmanagement
Da die Studie jeweils nur eine aktive Position zulässt, wird eine Hilfsfunktion verwendet, um alle offenen Positionen zu scannen und zu überprüfen, ob eine zum EA gehörende Kaufposition bereits existiert.
//+------------------------------------------------------------------+ //| To verify whether this EA currently has an active buy position. | | //+------------------------------------------------------------------+ bool IsThereAnActiveBuyPosition(ulong magic){ for(int i = PositionsTotal() - 1; i >= 0; i--){ ulong ticket = PositionGetTicket(i); if(ticket == 0){ Print("Error while fetching position ticket ", GetLastError()); continue; }else{ if(PositionGetInteger(POSITION_MAGIC) == magic && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY){ return true; } } } return false; }
Die magische Zahl stellt sicher, dass nur von dieser EA-Instanz erstellte Positionen berücksichtigt werden.
Eine zweite Funktion behandelt das Schließen von Positionen nach magischen Zahlen.
//+------------------------------------------------------------------+ //| To close all position with a specified magic number | //+------------------------------------------------------------------+ void ClosePositionsByMagic(ulong magic) { for (int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if (PositionSelectByTicket(ticket)) { if (PositionGetInteger(POSITION_MAGIC) == magic) { ulong positionType = PositionGetInteger(POSITION_TYPE); double volume = PositionGetDouble(POSITION_VOLUME); if (positionType == POSITION_TYPE_BUY) { Trade.PositionClose(ticket); } else if (positionType == POSITION_TYPE_SELL) { Trade.PositionClose(ticket); } } } } }
Dieser wird zu Beginn eines jeden neuen Handelstages verwendet, um den vorherigen Handel sauber und konsequent zu beenden.
Trades ausführen
Die Auftragsausführung erfolgt über eine spezielle Funktion, die einen Marktkaufauftrag mit der angegebenen Losgröße eröffnet.
//+------------------------------------------------------------------+ //| Function to open a market buy position | //+------------------------------------------------------------------+ bool OpenBuy(double entryPrice, double lotSize){ if(!Trade.Buy(NormalizeDouble(lotSize, 2), _Symbol, entryPrice)){ Print("Error while executing a market buy order: ", GetLastError()); Print(Trade.ResultRetcode()); Print(Trade.ResultComment()); return false; } return true; }
Fehler werden explizit gemeldet, was die Diagnose von Ausführungsproblemen beim Testen erleichtert. Diese Funktion stellt die letzte Aktion in der Entscheidungskette dar und wird nur aufgerufen, wenn alle vorherigen Bedingungen erfüllt sind.
Vervollständigung der Handelslogik
Der letzte Schritt besteht darin, alle Bedingungen in die Funktion OnTick zu integrieren. Dieser EA ist so konzipiert, dass er Trades für genau einen Handelstag hält: kein Stop-Loss, kein Take-Profit, keine Trailing-Logik. Ein Trade muss am Ende des Handelstages geschlossen werden, nicht früher oder später.
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick(){ ... //--- Run this block only when a new bar is detected on the selected timeframe if(IsNewBar(_Symbol, timeframe, lastBarOpenTime)){ ... //--- Close any active long position if(IsThereAnActiveBuyPosition(magicNumber)){ ClosePositionsByMagic(magicNumber); } } }
Der EA prüft, ob der Preis über das projizierte Einstiegsniveau hinausgeht. Wenn der Basismodus aktiv ist, wird der Handel sofort ausgeführt. Wenn die Tagesfilterung aktiviert ist, muss der Crossover auch an einem erlaubten Handelstag stattfinden.
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick(){ ... if(tradeDayMode == TDW_ALL_DAYS){ if(IsCrossOver(lwVolatilityLevels.buyEntryPrice, closePriceMinutesData )){ OpenBuy(askPrice, positionSize); } } if(tradeDayMode == TDW_SELECTED_DAYS){ if(IsTradingDayAllowed(currentTime)){ if(IsCrossOver(lwVolatilityLevels.buyEntryPrice, closePriceMinutesData)){ OpenBuy(askPrice, positionSize); } } } }
Hier ist die endgültige Form der Funktion OnTick, nachdem alle Komponenten implementiert worden sind:
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick(){ //--- Retrieve current market prices for trade execution askPrice = SymbolInfoDouble (_Symbol, SYMBOL_ASK); bidPrice = SymbolInfoDouble (_Symbol, SYMBOL_BID); //--- Run this block only when a new bar is detected on the selected timeframe if(IsNewBar(_Symbol, timeframe, lastBarOpenTime)){ UpdateSupertrendBandValues(); if(IsSupertrendBullishSignal()){ if(IsThereAnActiveSellPosition(magicNumber)){ ClosePositionsByMagic(magicNumber); Sleep(50); } if(direction == TRADE_BOTH || direction == ONLY_LONG){ OpenBuy(askPrice, CalculateAdaptiveStopLossPrice(POSITION_TYPE_BUY), positionSize); } } if(IsSupertrendBearishSignal()){ if(IsThereAnActiveBuyPosition(magicNumber)){ ClosePositionsByMagic(magicNumber); Sleep(50); } if(direction == TRADE_BOTH || direction == ONLY_SHORT){ OpenSel(bidPrice, CalculateAdaptiveStopLossPrice(POSITION_TYPE_SELL), positionSize); } } } }
Bevor wir zum Testen übergehen, müssen wir sicherstellen, dass die Chartumgebung die Kursentwicklung und die Handelsaktivität klar darstellt. Ein übersichtliches und konsistentes Chart-Layout erleichtert die visuelle Inspektion von Ein- und Ausstiegen sowie des Gesamtverhaltens während des Strategietests. Da dieser Expert Advisor für Forschung und Analyse gedacht ist, ist die Verbesserung der Lesbarkeit der Charts ein kleiner, aber wichtiger Schritt.
Um dies zu erreichen, definieren wir eine nutzerdefinierte Hilfsfunktion, die das Erscheinungsbild des Charts konfiguriert, wenn der Expert Advisor definiert ist. Diese Funktion wendet eine Reihe von visuellen Voreinstellungen an, sodass Kerzen, Hintergrund und Kursbewegungen beim Testen und Wiedergeben leicht zu unterscheiden sind. Nachfolgend finden Sie die Funktionsdefinition, die in dem für nutzerdefinierte MQL5-Funktionen reservierten Abschnitt platziert werden sollte.
//+------------------------------------------------------------------+ //| This function configures the chart's appearance. | //+------------------------------------------------------------------+ bool ConfigureChartAppearance() { if(!ChartSetInteger(0, CHART_COLOR_BACKGROUND, clrWhite)){ Print("Error while setting chart background, ", GetLastError()); return false; } if(!ChartSetInteger(0, CHART_SHOW_GRID, false)){ Print("Error while setting chart grid, ", GetLastError()); return false; } if(!ChartSetInteger(0, CHART_MODE, CHART_CANDLES)){ Print("Error while setting chart mode, ", GetLastError()); return false; } if(!ChartSetInteger(0, CHART_COLOR_FOREGROUND, clrBlack)){ Print("Error while setting chart foreground, ", GetLastError()); return false; } if(!ChartSetInteger(0, CHART_COLOR_CANDLE_BULL, clrSeaGreen)){ Print("Error while setting bullish candles color, ", GetLastError()); return false; } if(!ChartSetInteger(0, CHART_COLOR_CANDLE_BEAR, clrBlack)){ Print("Error while setting bearish candles color, ", GetLastError()); return false; } if(!ChartSetInteger(0, CHART_COLOR_CHART_UP, clrSeaGreen)){ Print("Error while setting bearish candles color, ", GetLastError()); return false; } if(!ChartSetInteger(0, CHART_COLOR_CHART_DOWN, clrBlack)){ Print("Error while setting bearish candles color, ", GetLastError()); return false; } return true; }
Die Funktion funktioniert durch den Aufruf einer Reihe von ChartSetInteger-Befehlen. Jeder Befehl ändert eine bestimmte visuelle Eigenschaft des derzeit aktiven Charts.
Zunächst wird die Hintergrundfarbe des Charts auf Weiß gesetzt. Ein heller Hintergrund verbessert den Kontrast und lässt die Farben der Kerzen deutlich hervortreten. Als Nächstes wird das Chartgitter deaktiviert. Durch das Entfernen des Gitters wird das visuelle Rauschen reduziert und der Fokus bleibt auf der Preisbewegung und nicht auf den Hilfslinien. Der Chartmodus wird dann auf Kerzenansicht eingestellt. Kerzen liefern mehr Informationen als Liniendiagramme und eignen sich besser für die Analyse von Volatilität, Struktur und Intraday-Verhalten.
Danach wird die Vordergrundfarbe auf Schwarz gesetzt. Dadurch wird sichergestellt, dass Charttext und Preisskalen vor dem weißen Hintergrund klar sichtbar bleiben. Die Funktion definiert dann unterschiedliche Farben für bullishe und bearishe Kerzen. Bullishe Kerzen sind meergrün gefärbt, um die Aufwärtsbewegung des Kurses hervorzuheben, während bearishe Kerzen schwarz gefärbt sind, um einen neutralen und lesbaren Kontrast zu erhalten. Die gleiche Farblogik wird auf die Umrisse der Bars im Chart für Aufwärts- und Abwärtsbewegungen angewendet. Auf diese Weise bleiben Kerzenkörper und Umrisse visuell konsistent und leicht zu interpretieren.
Jeder Aufruf von ChartSetInteger wird auf Erfolg geprüft. Wenn ein Konfigurationsschritt fehlschlägt, wird eine Fehlermeldung protokolliert, und die Funktion gibt sofort false zurück. Dadurch kann der Expert Advisor Konfigurationsprobleme frühzeitig erkennen und vermeiden, dass er unter unbeabsichtigten Chartbedingungen läuft. Wenn alle Charteinstellungen erfolgreich angewendet wurden, gibt die Funktion den Wert true zurück und zeigt damit an, dass das Chart zum Testen und Analysieren bereit ist.
Sobald die Funktion definiert ist, wird sie in der Initialisierungsfunktion des Experten aufgerufen. Dadurch wird sichergestellt, dass das Erscheinungsbild des Charts einmalig konfiguriert wird, und zwar direkt beim Start des Expert Advisors.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(){ ... //--- To configure the chart's appearance if(!ConfigureChartAppearance()){ Print("Error while configuring chart appearance", GetLastError()); return INIT_FAILED; } return(INIT_SUCCEEDED); }
In der Funktion OnInit rufen wir die Chartkonfigurationsroutine auf und überprüfen ihr Ergebnis. Wenn die Konfiguration fehlschlägt, bricht der Expert Advisor die Initialisierung ab und meldet das Problem. Wenn dies gelingt, wird die Initialisierung normal fortgesetzt.
Dieser Ansatz stellt sicher, dass jeder Test mit einem sauberen, gut lesbaren Chart-Layout beginnt, was es einfacher macht, das Handelsverhalten zu bewerten, die historische Performance zu überprüfen und visuell zu bestätigen, dass sich die Logik der Strategie während des Tests wie vorgesehen verhält.
An diesem Punkt ist die EA-Logik vollständig. Alle zuvor eingeführten Komponenten fügen sich nun in einen kohärenten Ausführungsablauf ein, der das Forschungsziel genau widerspiegelt.
In diesem Abschnitt wird die Konstruktion eines speziell entwickelten Expert Advisors erläutert, mit dem die Hypothese des Handelstages der Woche getestet werden soll. Das Design legt Wert auf Klarheit, variable Isolierung und Reproduzierbarkeit. Jede Funktion erfüllt eine spezifische Aufgabe und unterstützt eine saubere Trennung zwischen täglicher Entscheidungsfindung, Intraday-Ausführung und zeitbasierter Filterung.
Der fertige Quellcode wird als lwTDWStudy.mq5 bereitgestellt und kann direkt zum Testen verwendet oder für zusätzliche Experimente erweitert werden. Mit dem EA im Einsatz sind wir nun bereit, von der Implementierung zur empirischen Auswertung überzugehen und zu analysieren, ob bestimmte Tage wirklich einen messbaren Handelsvorteil bieten.
Empirische Prüfung des Filters für den Handelstag der Woche
Um die Hypothese des Handelstages der Woche zu untersuchen, wurde eine Reihe von kontrollierten Experimenten für Gold (XAUUSD) mit dem täglichen (D1) Zeitrahmen durchgeführt. Ziel war es, festzustellen, ob die Filterung von Trades nach Wochentagen zu messbaren Unterschieden in der Performance führt.
Es wurden zwei Arten von Experimenten durchgeführt:
1. Grundlegende Tests
Diese Tests ermöglichen es der Strategie, an jedem beliebigen Tag der Woche zu handeln, wenn die Einstiegsbedingung erfüllt ist. Es wird keine zeitbasierte Filterung angewendet. Dadurch wird ein neutraler Bezugspunkt geschaffen.
2. Tests der Handelstage der Woche
Diese Tests beschränken den Handel jeweils auf einen bestimmten Wochentag, sodass die Leistung für jeden Tag unabhängig bewertet werden kann. Alle Tests wurden unter Verwendung einer vierteljährlichen Walk-Forward-Segmentierung durchgeführt, um sicherzustellen, dass die Ergebnisse nicht durch eine einzige günstige Marktphase beeinflusst werden.
Grundlegende Leistung ohne Tagesfilterung
Das Basisexperiment wurde über das gesamte Kalenderjahr durchgeführt.
Test-Konfiguration:
- Period: 1. Januar 2025 bis 30. Dezember 2025
- tradeDayMode: TDW_ALL_DAYS
- Handel an allen Handelstagen erlaubt
Ergebnisse:
| Kennzahl | Wert |
|---|---|
| Gewinnrate | 54.25% |
| Reingewinn | 26.102,15 $ |
Vierteljährliche Walk-Forward-Ergebnisse nach Handelstag
Jedes Quartal wurde unabhängig voneinander mit TDW_SELECTED_DAYS getestet. Es wurde jeweils nur ein Wochentag aktiviert, und die Ergebnisse wurden aufgezeichnet.
Ergebnisse des 1. Quartals:
1. Januar 2025 – 31. März 2025
| Tag | Gewinnrate (%) | Reingewinn ($) |
|---|---|---|
| Montag | 77.00 | 4.444,24 |
| Dienstag | 59.35 | 93.344,24 |
| Mittwoch | 64.22 | –14.112,00 |
| Donnerstag | 57.43 | 9.883,21 |
| Freitag | 72.45 | –1.280,82 |
| Basislinie | 59.64 | 26.102,15 |
Beobachtung:
Nicht alle hohen Gewinnquoten bedeuten auch Rentabilität. Mittwoch und Freitag weisen eine respektable Genauigkeit, aber negative Renditen auf, was zeigt, wie wichtig es ist, die Gewinnrate mit dem Realisierungsgrad zu verbinden.
Ergebnisse des 2. Quartals:
1. April 2025 – 30. Juni 2025
| Tag | Gewinnrate (%) | Reingewinn ($) |
|---|---|---|
| Montag | 100.00 | 33.137,25 |
| Dienstag | 0.00 | –21.054,39 |
| Mittwoch | 92.31 | 44.388,16 |
| Donnerstag | 23.53 | –13.790,47 |
| Freitag | 61.40 | 17.674,23 |
| Basislinie | 61.16 | 48.514,81 |
Beobachtung:
In diesem Quartal ist eine extreme Divergenz im Tagesverlauf zu beobachten. Der Mittwoch dominiert sowohl bei der Genauigkeit als auch bei der Rentabilität, während der Dienstag völlig versagt. Eine solche Streuung ist mit der Annahme des Zufallsmarktes unvereinbar.
Ergebnisse des 3. Quartals:
1. Juli 2025 – 30. September 2025
| Tag | Gewinnrate (%) | Reingewinn ($) |
|---|---|---|
| Montag | 92.787 | 32.767,01 |
| Dienstag | 13.95 | –13.797,71 |
| Mittwoch | 5.91 | –9.466,48 |
| Donnerstag | 54.10 | –4.330,74 |
| Freitag | 58.18 | 16.728,25 |
| Basislinie | 52.41 | 28.616,31 |
Beobachtung:
Der Montag und der Freitag stechen hervor, während der Handel zur Wochenmitte schlecht abschneidet. Auch hier dominiert das tagesabhängige Verhalten die Leistungsergebnisse.
Ergebnisse des 4. Quartals:
1. Oktober 2025 – 30. Dezember 2025
| Tag | Gewinnrate (%) | Reingewinn ($) |
|---|---|---|
| Montag | 61.38 | 20.288,15 |
| Dienstag | 0.00 | –4.677,96 |
| Mittwoch | 60.32 | –31.755,28 |
| Donnerstag | 42.59 | 3.169.84 |
| Freitag | 22.88 | –2.059,73 |
| Basislinie | 64.27 | –1.101,06 |
Beobachtung:
Die Basislinie selbst wird in diesem Quartal unrentabel, während der selektive Tageshandel lebensfähig bleibt. Der Montag zeigt sich weiterhin widerstandsfähig gegenüber den Marktbedingungen.
Was uns die Zahlen verraten
Aus den Daten lassen sich mehrere Schlussfolgerungen ableiten:
Die Leistung ist nicht gleichmäßig über die Woche verteilt. Es gibt Tage, an denen die Ergebnisse besser sind als an anderen, und andere, die die Erwartungen nicht erfüllen. Die Gewinnrate allein ist nicht ausreichend. An manchen Tagen wird eine hohe Genauigkeit erreicht, aber es werden Verluste erwirtschaftet, was die Notwendigkeit unterstreicht, neben der Gewinnquote auch die Rentabilität zu bewerten. Die Tagesfilterung kann die Exposition gegenüber strukturell schwachen Perioden verringern
Der Ausschluss leistungsschwacher Tage verbessert die Stabilität, ohne die Kernlogik der Strategie zu verändern. Der Markt weist eine zeitbasierte Verhaltensverzerrung auf. Die wiederholten vierteljährlichen Muster stützen die Behauptung von Larry Williams, dass der tägliche Handel ebenfalls einen messbaren Vorteil bringt.
Der Filter „Handelstag der Woche“ dient nicht zur Vorhersage der Richtung, sondern als probabilistisches Hilfsmittel, das die Händler auf Zeiten lenkt, in denen Chancen wahrscheinlicher sind, und weg von Tagen, an denen das Risiko die Chancen überwiegt.
Schlussfolgerung
In dieser Studie sollte eine oft ignorierte, aber einfache Idee untersucht werden: dass die Zeit selbst einen Vorteil beim kurzfristigen Handel bieten kann. Indem wir das Konzept des Handelstags der Woche von Larry Williams in einen messbaren, überprüfbaren Rahmen übertragen haben, haben wir die Diskussion von einer Meinung zu einem Beweis gemacht.
Durch kontrollierte Baseline-Tests und vierteljährliche Walk-Forward-Experimente mit Gold haben wir gezeigt, dass die Handelsleistung nicht gleichmäßig über die Woche verteilt ist. Einige Tage brachten durchweg höhere Gewinnquoten und eine höhere Rentabilität, während andere die Erwartungen wiederholt untergruben. Diese Unterschiede blieben über mehrere Marktphasen hinweg bestehen, was die Annahme infrage stellt, dass sich alle Handelstage gleich verhalten.
Noch wichtiger ist, dass dieser Artikel nicht bei den Ergebnissen stehen geblieben ist. Sie zeigte, wie solche zeitbasierten Verzerrungen mit MQL5 objektiv untersucht werden können. Das Design, die Eingabestruktur und die Testmethodik des Expert Advisors bilden eine wiederverwendbare Grundlage, die der Leser an andere Märkte, Zeitrahmen oder Filterkriterien anpassen kann. Während der Schwerpunkt hier auf Rentabilität und Performance lag, kann derselbe Rahmen auf die Untersuchung von Volatilität, Schwankungsbreite, Drawdown-Verhalten und Intraday-Handel ausgeweitet werden.
Am Ende dieses Artikels erhält der Leser mehr als nur die Bestätigung, dass manche Tage besser sind als andere. Sie erhalten ein praktisches Konzept für die Forschung. Eine, die eine selektive Beteiligung, diszipliniertes Filtern und eine tiefere Erforschung des Marktverhaltens anstelle einer blinden Ausführung fördert.
Für Händler und Entwickler gleichermaßen unterstreicht diese Arbeit eine einfache Idee mit bedeutenden Konsequenzen. Wenn Märkte zeitabhängige Tendenzen aufweisen, dann ist es eine Entscheidung, sie zu ignorieren. Sie zu messen, ist ein Vorteil.
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/20941
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.
Einführung in MQL5 (Teil 34): Beherrschung der API- und WebRequest-Funktion in MQL5 (VIII)
Python-MetaTrader 5 Strategietester (Teil 03): MetaTrader 5-ähnliche Handelsoperationen – Handhabung und Verwaltung
Python-MetaTrader 5 Strategietester (Teil 04): Tester 101
Einführung in MQL5 (Teil 33): Beherrschen der API- und WebRequest-Funktion in MQL5 (VII)
- 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.