
Aufbau des Kerzenmodells Trend Constraint (Teil 9): Expert Advisor für mehrere Strategien (III)
Einführung
Beim algorithmischen Handel stellt die Ermittlung optimaler Einstiegspunkte innerhalb eines vorherrschenden Trends nach wie vor eine große Herausforderung dar, da viele Strategien Schwierigkeiten haben, den richtigen Zeitpunkt zu erwischen oder häufig falsche Signale erzeugen, was zu einer suboptimalen Performance führt. Dieses Problem ist besonders ausgeprägt bei täglichen Trends, bei denen geringe Schwankungen die Ausführungsgenauigkeit stören können.
Die Divergenz bietet eine robuste Lösung, indem sie als Filter fungiert, um potenzielle Umkehrungen oder Fortsetzungen durch Diskrepanzen zwischen Kursbewegungen und Momentum-Indikatoren zu erkennen. Durch die Integration der Divergenzerfassung in den Trend Constraint Expert Advisor können Händler ihre Präzision bei der Ermittlung von Einstiegsniveaus erheblich verbessern.
Dieser Ansatz verbessert die Handelsgenauigkeit und gewährleistet in Verbindung mit den fortschrittlichen Funktionen von MQL5 einen konsistenten und effizienten Handel. In diesem Artikel befassen wir uns mit den Grundlagen der Divergenz, den Schritten zu ihrer Integration in MQL5 Expert Advisors, den Verbesserungen des Trend Constraint Expert Advisors mit neuen Handelsausführungsbedingungen und den Erkenntnissen aus Backtests, um ihre praktische Anwendung zu demonstrieren.
Hauptinhalt:
- Die Grundlagen der Divergenz
- Schritte zur Integration der Divergenzerkennung
- Erweiterungen des Trend Constraint Expert Advisor: Implementierung neuer Bedingungen für die Handelsausführung zur Nutzung von Divergenzen.
- Backtest-Ergebnisse und praktische Anwendung
- Schlussfolgerung
Die Grundlagen der Divergenz
Divergenz ist ein Schlüsselkonzept in der technischen Analyse, das Händlern durch den Vergleich von Kursbewegungen mit der Richtung eines Indikators Einblicke in potenzielle Kursumkehrungen oder -fortsetzungen gewährt.
Bedeutung der Divergenz:
Eine Divergenz liegt vor, wenn sich der Kurs eines Vermögenswerts entgegengesetzt zu einem technischen Indikator bewegt, was häufig auf eine Abschwächung des Trends oder eine bevorstehende Umkehrung hinweist. Dieses Konzept ist besonders nützlich, wenn es darum geht, zu erkennen, wann ein Trend für eine Korrektur oder eine vollständige Trendwende fällig ist.
Arten von Divergenzen:
- Eine Aufwärts-Divergenz wird festgestellt, wenn der Kurs des Vermögenswerts niedrigere Tiefststände erreicht, der Indikator, wie der RSI, jedoch höhere Tiefststände anzeigt, was auf eine nachlassende Abwärtsdynamik hindeutet. Dies könnte bedeuten, dass der Verkaufsdruck nachlässt und eine Aufwärtsbewegung des Preises in Gang kommen könnte.
- Eine Abwärts-Divergenz wird beobachtet, wenn der Kurs höhere Höchststände erreicht, der Indikator jedoch niedrigere Höchststände anzeigt, was darauf hindeutet, dass die Aufwärtsdynamik abnimmt. Dies könnte ein Vorbote für einen Preisrückgang sein.
Hintergrund-Check:
Divergenz ist ein zentrales Konzept in der technischen Analyse, das das Marktverhalten und die Strategien der Händler beeinflusst. Bart und Masse (1981) betonen in „Divergence of Opinion and Risk", wie Diskrepanzen in der Marktmeinung das Risiko und die Preisvolatilität erhöhen können, was die Rolle der Divergenz in der technischen Analyse widerspiegelt.
Empirische Belege von Tilehnouei and Shivaraj (2013) deuten darauf hin, dass Instrumente wie der MACD den RSI in bestimmten Kontexten übertreffen können und durch Divergenzsignale wertvolle Einblicke in die Marktdynamik bieten. Aus dieser Untersuchung können wir schließen, dass die Integration der Divergenz mit anderen Indikatoren, wie z.B. dem Zusammenspiel von RSI, MACD und Kursbewegung, ihren Nutzen in einem umfassenden Handelsansatz verstärkt, was von verschiedenen Branchenquellen bestätigt wird.
Im nächsten Abschnitt werden wir einen praktischen Schritt unternehmen, um die Idee der Divergenz in unserer EA-Entwicklung umzusetzen.
Schritte zur Integration der Divergenzerkennung
Um die Erkennung von Divergenzen in einen MQL5 Expert Advisor (EA) zu integrieren, berechnen wir zunächst die Werte des Relative Strength Index (RSI) mit Funktionen wie iRSI() und vergleichen sie mit der Preisentwicklung. Signifikante Preisextreme werden mit iHigh() und iLow() über einen bestimmten Zeitraum ermittelt. Für dieses Projekt werde ich zwei Arten von Divergenzen unterscheiden: reguläre (Umkehrung) und versteckte.
Reguläre Divergenz:
Reguläre Divergenzen signalisieren potenzielle Trendumkehrungen, wobei ein Aufwärts-Setup entsteht, wenn der Kurs ein niedrigeres Tief erreicht, während der Indikator ein höheres Tief bildet, und ein Abwärts-Setup entsteht, wenn der Kurs ein höheres Hoch erreicht, der Indikator aber ein niedrigeres Hoch anzeigt.
// Regular divergence conditions in code bool CheckRegularBearishDivergence(int period = 14, ENUM_TIMEFRAMES timeframe = PERIOD_H1) { double priceHigh1 = iHigh(_Symbol, timeframe, 2); double priceHigh2 = iHigh(_Symbol, timeframe, 8); double rsiHigh1 = iRSI(_Symbol, timeframe, period, PRICE_CLOSE, 2); double rsiHigh2 = iRSI(_Symbol, timeframe, period, PRICE_CLOSE, 8); if(priceHigh1 > priceHigh2 && rsiHigh1 < rsiHigh2) return true; return false; }
Zur Veranschaulichung dieser regelmäßigen Divergenzen sind hier zwei Bilder zu sehen, die eine Aufwärts- und eine Abwärts-Divergenz darstellen:
Boom 300 IndexH4 - Aufwärts-Divergenz (Ein tieferes Tief, B, und ein höheres Tief des RSI, D)
Boom 300 IndexH4 - Abwärts-Divergenz: (Ein höheres Hoch, B, und ein niedrigeres Hoch des RSI, D)
Versteckte Divergenz:
Versteckte Divergenzen hingegen deuten auf eine Trendfortsetzung hin. Eine versteckte Aufwärts-Divergenz tritt in einem Aufwärtstrend auf, wenn der Kurs ein höheres Tief erreicht, während der Indikator ein niedrigeres Tief bildet, während eine versteckte Abwärts-Divergenz in einem Abwärtstrend auftritt, wenn der Kurs ein niedrigeres Hoch erreicht und der Indikator ein höheres Hoch bildet.
//RSI and Price Levels declaration and hidden divergence condition bool CheckHiddenBullishDivergence(int period = 14, ENUM_TIMEFRAMES timeframe = PERIOD_H1) { double priceLow1 = iLow(_Symbol, timeframe, 2); double priceLow2 = iLow(_Symbol, timeframe, 8); double rsiLow1 = iRSI(_Symbol, timeframe, period, PRICE_CLOSE, 2); double rsiLow2 = iRSI(_Symbol, timeframe, period, PRICE_CLOSE, 8); if(priceLow1 > priceLow2 && rsiLow1 < rsiLow2) return true; return false; }
Die folgenden Abbildungen zeigen die versteckte Aufwärts-Divergenz und die versteckte Abwärts-Divergenz. Vergleichen Sie diese mit den Beschreibungen, die Sie zuvor erhalten haben, und üben Sie, ähnliche Muster in Ihren eigenen Charts zu erkennen.
Boom 300 IndexH4: Versteckte Aufwärts-Divergenz
Boom 300 IndexH4: Versteckte Abwärts-Divergenz
Die Integration dieser Divergenztypen in den EA erfordert die Codierung von Bedingungen, um sie bei jedem Tick oder Balkenschluss zu erkennen, wobei Tools wie iRSI() oder iMACD() für die Indikatorberechnung verwendet werden. Sobald die Divergenzsignale erkannt sind, werden sie mit den Trendbegrenzungen abgeglichen, die anhand der täglichen Marktstimmung ermittelt werden.
Erweiterungen des Trend Constraint Expert Advisor: Einführung neuer Handelsausführungsbedingungen zur Nutzung von Divergenzen
Zum obigen Abschnitt: Wenn eine Divergenz festgestellt wird, benötigen wir einen zusätzlichen Indikator, um die Auftragsausführung zu bestätigen und zu signalisieren. Hierfür gibt es viele Möglichkeiten, aber wir werden den Einsatz von MACD und RSI in Betracht ziehen. Hier finden Sie eine Liste mit weiteren optionalen Bestätigungsindikatoren:
- Bollinger-Bänder
- Stochastik Oszillator
- On Balance Volume (OBV) und volumengewichteter Durchschnittspreis (VWAP)
- Durchschnittlicher dynamischer Index (ADX)
Moving Average Convergence Divergence (MACD):
Warum er? Der MACD kann Momentumveränderungen bestätigen. Wenn eine Divergenz zum RSI festgestellt wird, kann der MACD eine sekundäre Bestätigung der Trendstärke oder -schwäche liefern.
So funktioniert es:
Der EA sucht nach MACD-Linienüberkreuzungen oder Histogrammänderungen, die mit den Divergenzergebnissen übereinstimmen. Eine Abwärts-Divergenz könnte beispielsweise bestätigt werden, wenn die MACD-Linie unter die Signallinie kreuzt oder das Histogramm zu sinken beginnt.
Die wichtigsten Merkmale des MACD-Indikators:
Um eine Vorschau auf den eingebauten Indikator wie den MACD zu erhalten, können wir auf den Ordner "Examples" unter dem Ordner "Indicators" in der MetaEditor 5 Software zugreifen. Schauen Sie sich das folgende Bild an.
MetaEditor 5: Zugriff auf die MACD-Quelldatei
Der Grund für den Zugriff auf den Code ist, dass wir leicht herausfinden können, wie die Puffer aufgebaut sind, sodass wir sie in unserem Expert Advisor leicht anpassen können. Nachfolgend finden Sie einen Codeabschnitt für die gepufferten Deklarationen innerhalb des Indikators, an dem wir interessiert sind.
//--- indicator buffers double ExtMacdBuffer[]; double ExtSignalBuffer[]; double ExtFastMaBuffer[]; double ExtSlowMaBuffer[]; int ExtFastMaHandle; int ExtSlowMaHandle;
Mit unseren Puffern im Hinterkopf gehen wir nun Schritt für Schritt durch den Entwicklungsprozess, der im Folgenden beschrieben wird.
Entwicklung der Strategie der Divergenz:
Schritt 1: Deklarationen und Eingabeparameter
Wir beginnen mit der Deklaration von Eingabeparametern für die Divergenzstrategie, MACD-Puffern und der Initialisierung der Klasse CTrade.
#include <Trade\Trade.mqh> CTrade trade; input bool UseDivergenceStrategy = true; // Enable/Disable Divergence Strategy input int DivergenceMACDPeriod = 12; // MACD Fast EMA period input int DivergenceSignalPeriod = 9; // MACD Signal period input double DivergenceLots = 1.0; // Lot size for Divergence trades input double DivergenceStopLoss = 300; // Stop Loss in points for Divergence input double DivergenceTakeProfit = 500; // Take Profit in points for Divergence input int DivergenceMagicNumber = 87654321; // Magic number for Divergence Strategy input int DivergenceLookBack = 8; // Number of periods to look back for divergence double ExtMacdBuffer[]; // MACD values double ExtSignalBuffer[]; // Signal line values int macd_handle; // MACD indicator handle
Schritt 2: MACD-Indikator initialisieren
Initialisierung des MACD-Handles und Zuweisung von Pufferspeicher in OnInit().
int OnInit() { macd_handle = iMACD(_Symbol, PERIOD_CURRENT, DivergenceMACDPeriod, 26, DivergenceSignalPeriod, PRICE_CLOSE); if (macd_handle == INVALID_HANDLE) { Print("Failed to initialize MACD. Error: ", GetLastError()); return INIT_FAILED; } ArrayResize(ExtMacdBuffer, DivergenceLookBack); ArrayResize(ExtSignalBuffer, DivergenceLookBack); return INIT_SUCCEEDED; }
Schritt 3: Erkennung von Divergenzen
Eine Divergenz tritt auf, wenn die Kursentwicklung eines Vermögenswerts nicht mit einem Indikator übereinstimmt, in diesem Fall mit dem MACD. Diese Strategie erkennt vier Arten von Divergenzen: „bullish regular“, „bullish hidden“, „bearish regular“ und „bearish hidden“ (reguläre und versteckte Auf- und Abwärts-Divergenzen). Jeder Typ hat spezifische Bedingungen, wobei die Höchst- oder Tiefstwerte der Kurse mit den entsprechenden Höchst- oder Tiefstwerten des MACD verglichen werden, um das Vorhandensein einer Divergenz festzustellen.
bool CheckBullishRegularDivergence() { double priceLow1 = iLow(_Symbol, PERIOD_CURRENT, 2); double priceLow2 = iLow(_Symbol, PERIOD_CURRENT, DivergenceLookBack); double macdLow1 = ExtMacdBuffer[2]; double macdLow2 = ExtMacdBuffer[DivergenceLookBack - 1]; return (priceLow1 < priceLow2 && macdLow1 > macdLow2); } bool CheckBearishHiddenDivergence() { double priceHigh1 = iHigh(_Symbol, PERIOD_CURRENT, 2); double priceHigh2 = iHigh(_Symbol, PERIOD_CURRENT, DivergenceLookBack); double macdHigh1 = ExtMacdBuffer[2]; double macdHigh2 = ExtMacdBuffer[DivergenceLookBack - 1]; return (priceHigh1 < priceHigh2 && macdHigh1 > macdHigh2); }
Schritt 4: Handelslogik
Erstens stellt die Strategie sicher, dass der Divergenzhandel aktiviert ist und nicht mehr als 3 auf Divergenz basierende Positionen offen sind. Er ruft MACD-Pufferdaten ab, versucht es bei Fehlschlägen erneut und führt nur Handelsgeschäfte auf vollständigen Bars aus. Darüber hinaus richtet es den Handel an den täglichen Kerzen-Trends aus und sorgt dafür, dass nur an Aufwärtstagen gekauft und an Abwärtstagen verkauft wird.
void CheckDivergenceTrading() { if (!UseDivergenceStrategy) return; int openDivergencePositions = CountOrdersByMagic(DivergenceMagicNumber); if (openDivergencePositions == 0 || openDivergencePositions < 3) { if (CopyBuffer(macd_handle, 0, 0, DivergenceLookBack, ExtMacdBuffer) > 0 && CopyBuffer(macd_handle, 1, 0, DivergenceLookBack, ExtSignalBuffer) > 0) { double dailyClose = iClose(_Symbol, PERIOD_D1, 0); double dailyOpen = iOpen(_Symbol, PERIOD_D1, 0); bool isDailyBullish = dailyClose > dailyOpen; bool isDailyBearish = dailyClose < dailyOpen; if (isDailyBullish && (CheckBullishRegularDivergence() && ExtMacdBuffer[0] > ExtSignalBuffer[0]) || CheckBullishHiddenDivergence()) { ExecuteDivergenceOrder(true); } if (isDailyBearish && (CheckBearishRegularDivergence() && ExtMacdBuffer[0] < ExtSignalBuffer[0]) || CheckBearishHiddenDivergence()) { ExecuteDivergenceOrder(false); } } } }
Schritt 5: Auftragsausführung
Sobald eine Divergenz erkannt wird, führt die Strategie Trades mit vordefinierten Parametern wie Lotgröße, Stop Loss und Take Profit aus. Die Funktion ExecuteDivergenceOrder berechnet auf der Grundlage der Handelsrichtung die entsprechenden Niveaus und verwendet das Handelsobjekt, um Kauf- oder Verkaufsaufträge zu erteilen.
void ExecuteDivergenceOrder(bool isBuy) { trade.SetExpertMagicNumber(DivergenceMagicNumber); double currentPrice = isBuy ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) : SymbolInfoDouble(_Symbol, SYMBOL_BID); double stopLossPrice = isBuy ? currentPrice - DivergenceStopLoss * _Point : currentPrice + DivergenceStopLoss * _Point; double takeProfitPrice = isBuy ? currentPrice + DivergenceTakeProfit * _Point : currentPrice - DivergenceTakeProfit * _Point; if (isBuy) { if (trade.Buy(DivergenceLots, _Symbol, 0, stopLossPrice, takeProfitPrice, "Divergence Buy")) Print("Divergence Buy order placed."); } else { if (trade.Sell(DivergenceLots, _Symbol, 0, stopLossPrice, takeProfitPrice, "Divergence Sell")) Print("Divergence Sell order placed."); } }
Schritt 6: Auftragsverwaltung
Um Overtrading zu vermeiden, verwendet die Strategie die Funktion CountOrdersByMagic, um alle offenen Positionen mit der angegebenen magischen Zahl zu zählen. Dies gewährleistet die Einhaltung des maximalen Positionslimits für divergenzbasierte Trades.
int CountOrdersByMagic(int magic) { int count = 0; for (int i = 0; i < PositionsTotal(); i++) { ulong ticket = PositionGetTicket(i); if (PositionSelectByTicket(ticket)) { if (PositionGetInteger(POSITION_MAGIC) == magic) { count++; } } } return count; }
Magische Zahl:
Ein weiterer wichtiger Aspekt ist, dass wir unseren Positionen eine Identität geben. In diesem Fall haben wir den durch die Divergenzstrategie gesteuerten Geschäften eine eindeutige magische Zahl zugewiesen.
// Ensure the magic number is set for the trade trade.SetExpertMagicNumber(DivergenceMagicNumber);
Schritt 7: Schutz des Gewinns
Wir haben eine Gewinnsicherungsfunktion eingeführt, die eine Gewinnsicherungslogik für unseren Trend Constraint Expert Advisor enthält, um Gewinne aus offenen Geschäften dynamisch zu sichern. Die Funktion LockProfits scannt alle aktiven Positionen und identifiziert diejenigen, deren Gewinne einen Schwellenwert von 100 Punkten überschreiten. Für jede qualifizierte Position wird auf der Grundlage des Parameters profitLockerPoints ein neues Stop-Loss-Niveau berechnet (z. B. 20 Punkte vom Einstiegskurs).
Durch diese Anpassung wird sichergestellt, dass der Stop-Loss näher an den aktuellen Kurs heranrückt, wodurch Gewinne effektiv gesichert werden. Bei Kaufpositionen wird der Stop-Loss über den Einstiegskurs verschoben, während er bei Verkaufspositionen nach unten verschoben wird. Die Funktion aktualisiert den Stop-Loss nur dann, wenn das neue Niveau einen besseren Schutz bietet, um ein optimales Risikomanagement zu gewährleisten. Erfolgreiche Änderungen werden mit einer Meldung zur Nachverfolgung protokolliert. Diese Funktion trägt dazu bei, die Gewinne zu sichern und gleichzeitig dem Handel das Potenzial für weiteres Wachstum zu geben.
Hier ist die Funktion LockProfits():
//+------------------------------------------------------------------+ //| Profit Locking Logic | //+------------------------------------------------------------------+ void LockProfits() { for (int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if (PositionSelectByTicket(ticket)) { double entryPrice = PositionGetDouble(POSITION_PRICE_OPEN); double currentProfit = PositionGetDouble(POSITION_PROFIT); double currentPrice = PositionGetDouble(POSITION_PRICE_CURRENT); // Convert profit to points double profitPoints = MathAbs(currentProfit / _Point); // Check if profit has exceeded 100 points if (profitPoints >= 100) { double newStopLoss; if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { newStopLoss = entryPrice + profitLockerPoints * _Point; // 20 points above entry for buys } else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) { newStopLoss = entryPrice - profitLockerPoints * _Point; // 20 points below entry for sells } else { continue; // Skip if not a buy or sell position } // Modify stop loss only if the new stop loss is more protective double currentStopLoss = PositionGetDouble(POSITION_SL); if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { if (currentStopLoss < newStopLoss || currentStopLoss == 0) { if (trade.PositionModify(ticket, newStopLoss, PositionGetDouble(POSITION_TP))) { Print("Profit locking for buy position: Stop Loss moved to ", newStopLoss); } } } else // POSITION_TYPE_SELL { if (currentStopLoss > newStopLoss || currentStopLoss == 0) { if (trade.PositionModify(ticket, newStopLoss, PositionGetDouble(POSITION_TP))) { Print("Profit locking for sell position: Stop Loss moved to ", newStopLoss); } } } } } } }
Schritt 8: Integrieren in OnTick()
Wir rufen die Handelslogik der Divergenz innerhalb der EA-Hauptschleife auf.
void OnTick() { CheckDivergenceTrading(); }
Schritt 9: Beenden
void OnDeinit(const int reason) { IndicatorRelease(macd_handle); }
Integration der Strategie in den Haupttrend Constrant Expert.
Im letzten Artikel dieser Serie haben wir einen auf dem Donchian-Kanal basierenden Expert Advisor entwickelt, der zwei Strategien in einem einzigen Experten markiert. Heute beziehen wir die 3. Strategie mit ein und verwenden boolesche Daten, um die Strategien ein- und auszuschalten.
// Input parameters for controlling strategies input bool UseTrendFollowingStrategy = false; // Enable/Disable Trend Constraint Strategy input bool UseBreakoutStrategy = false; // Enable/Disable Breakout Strategy input bool UseDivergenceStrategy = true; // Enable/Disable Divergence Strategy
Wir setzen die Strategie Divergence auf true, damit wir beim Strategy Tester nicht durcheinander kommen.
Schließlich integrieren wir unsere Strategie sorgfältig in den Hauptcode:
//+------------------------------------------------------------------+ //| Trend Constraint Expert.mq5 | //| Copyright 2024, Clemence Benjamin | //| https://www.mql5.com/en/users/billionaire2024/seller | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, Clemence Benjamin" #property link "https://www.mql5.com/en/users/billionaire2024/seller" #property version "1.02" #include <Trade\Trade.mqh> CTrade trade; // Input parameters for controlling strategies input bool UseTrendFollowingStrategy = false; // Enable/Disable Trend Following Strategy input bool UseBreakoutStrategy = false; // Enable/Disable Breakout Strategy input bool UseDivergenceStrategy = true; // Enable/Disable Divergence Strategy // Input parameters for Trend Constraint Strategy input int RSI_Period = 14; // RSI period input double RSI_Overbought = 70.0; // RSI overbought level input double RSI_Oversold = 30.0; // RSI oversold level input double Lots = 0.1; // Lot size input double StopLoss = 100; // Stop Loss in points input double TakeProfit = 200; // Take Profit in points input double TrailingStop = 50; // Trailing Stop in points input int MagicNumber = 12345678; // Magic number for the Trend Constraint EA input int OrderLifetime = 43200; // Order lifetime in seconds (12 hours) // Input parameters for Breakout Strategy input int InpDonchianPeriod = 20; // Period for Donchian Channel input double RiskRewardRatio = 1.5; // Risk-to-reward ratio input double LotSize = 0.1; // Default lot size for trading input double pipsToStopLoss = 15; // Stop loss in pips for Breakout input double pipsToTakeProfit = 30; // Take profit in pips for Breakout // Input parameters for Divergence Strategy input int DivergenceMACDPeriod = 12; // MACD Fast EMA period input int DivergenceSignalPeriod = 9; // MACD Signal period input double DivergenceLots = 1.0; // Lot size for Divergence trades input double DivergenceStopLoss = 300; // Stop Loss in points for Divergence input double DivergenceTakeProfit = 500; // Take Profit in points for Divergence input int DivergenceMagicNumber = 87654321; // Magic number for Divergence Strategy input int DivergenceLookBack = 8; // Number of periods to look back for divergence input double profitLockerPoints = 20; // Number of profit points to lock // Indicator handle storage int rsi_handle; int handle; // Handle for Donchian Channel int macd_handle; double ExtUpBuffer[]; // Upper Donchian buffer double ExtDnBuffer[]; // Lower Donchian buffer double ExtMacdBuffer[]; // MACD buffer double ExtSignalBuffer[]; // Signal buffer int globalMagicNumber; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { // Initialize RSI handle rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, RSI_Period, PRICE_CLOSE); if (rsi_handle == INVALID_HANDLE) { Print("Failed to create RSI indicator handle. Error: ", GetLastError()); return INIT_FAILED; } // Create a handle for the Donchian Channel handle = iCustom(_Symbol, PERIOD_CURRENT, "Free Indicators\\Donchian Channel", InpDonchianPeriod); if (handle == INVALID_HANDLE) { Print("Failed to load the Donchian Channel indicator. Error: ", GetLastError()); return INIT_FAILED; } // Initialize MACD handle for divergence globalMagicNumber = DivergenceMagicNumber; macd_handle = iMACD(_Symbol, PERIOD_CURRENT, DivergenceMACDPeriod, 26, DivergenceSignalPeriod, PRICE_CLOSE); if (macd_handle == INVALID_HANDLE) { Print("Failed to create MACD indicator handle for divergence strategy. Error: ", GetLastError()); return INIT_FAILED; } // Resize arrays for MACD buffers ArrayResize(ExtMacdBuffer, DivergenceLookBack); ArrayResize(ExtSignalBuffer, DivergenceLookBack); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { IndicatorRelease(rsi_handle); IndicatorRelease(handle); IndicatorRelease(macd_handle); } //+------------------------------------------------------------------+ //| Check and execute Trend Following EA trading logic | //+------------------------------------------------------------------+ void CheckTrendFollowing() { if (PositionsTotal() >= 2) return; // Ensure no more than 2 orders from this strategy double rsi_value; double rsi_values[]; if (CopyBuffer(rsi_handle, 0, 0, 1, rsi_values) <= 0) { Print("Failed to get RSI value. Error: ", GetLastError()); return; } rsi_value = rsi_values[0]; double ma_short = iMA(_Symbol, PERIOD_CURRENT, 50, 0, MODE_EMA, PRICE_CLOSE); double ma_long = iMA(_Symbol, PERIOD_CURRENT, 200, 0, MODE_EMA, PRICE_CLOSE); bool is_uptrend = ma_short > ma_long; bool is_downtrend = ma_short < ma_long; if (is_uptrend && rsi_value < RSI_Oversold) { double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID); double stopLossPrice = currentPrice - StopLoss * _Point; double takeProfitPrice = currentPrice + TakeProfit * _Point; // Corrected Buy method call with 6 parameters if (trade.Buy(Lots, _Symbol, 0, stopLossPrice, takeProfitPrice, "Trend Following Buy")) { Print("Trend Following Buy order placed."); } } else if (is_downtrend && rsi_value > RSI_Overbought) { double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double stopLossPrice = currentPrice + StopLoss * _Point; double takeProfitPrice = currentPrice - TakeProfit * _Point; // Corrected Sell method call with 6 parameters if (trade.Sell(Lots, _Symbol, 0, stopLossPrice, takeProfitPrice, "Trend Following Sell")) { Print("Trend Following Sell order placed."); } } } //+------------------------------------------------------------------+ //| Check and execute Breakout EA trading logic | //+------------------------------------------------------------------+ void CheckBreakoutTrading() { if (PositionsTotal() >= 2) return; // Ensure no more than 2 orders from this strategy ArrayResize(ExtUpBuffer, 2); ArrayResize(ExtDnBuffer, 2); if (CopyBuffer(handle, 0, 0, 2, ExtUpBuffer) <= 0 || CopyBuffer(handle, 2, 0, 2, ExtDnBuffer) <= 0) { Print("Error reading Donchian Channel buffer. Error: ", GetLastError()); return; } double closePrice = iClose(_Symbol, PERIOD_CURRENT, 0); double lastOpen = iOpen(_Symbol, PERIOD_D1, 1); double lastClose = iClose(_Symbol, PERIOD_D1, 1); bool isBullishDay = lastClose > lastOpen; bool isBearishDay = lastClose < lastOpen; if (isBullishDay && closePrice > ExtUpBuffer[1]) { double stopLoss = closePrice - pipsToStopLoss * _Point; double takeProfit = closePrice + pipsToTakeProfit * _Point; if (trade.Buy(LotSize, _Symbol, 0, stopLoss, takeProfit, "Breakout Buy") > 0) { Print("Breakout Buy order placed."); } } else if (isBearishDay && closePrice < ExtDnBuffer[1]) { double stopLoss = closePrice + pipsToStopLoss * _Point; double takeProfit = closePrice - pipsToTakeProfit * _Point; if (trade.Sell(LotSize, _Symbol, 0, stopLoss, takeProfit, "Breakout Sell") > 0) { Print("Breakout Sell order placed."); } } } //+------------------------------------------------------------------+ //| DIVERGENCE TRADING STRATEGY | //+------------------------------------------------------------------+ bool CheckBullishRegularDivergence() { double priceLow1 = iLow(_Symbol, PERIOD_CURRENT, 2); double priceLow2 = iLow(_Symbol, PERIOD_CURRENT, DivergenceLookBack); double macdLow1 = ExtMacdBuffer[2]; double macdLow2 = ExtMacdBuffer[DivergenceLookBack - 1]; return (priceLow1 < priceLow2 && macdLow1 > macdLow2); } bool CheckBullishHiddenDivergence() { double priceLow1 = iLow(_Symbol, PERIOD_CURRENT, 2); double priceLow2 = iLow(_Symbol, PERIOD_CURRENT, DivergenceLookBack); double macdLow1 = ExtMacdBuffer[2]; double macdLow2 = ExtMacdBuffer[DivergenceLookBack - 1]; return (priceLow1 > priceLow2 && macdLow1 < macdLow2); } bool CheckBearishRegularDivergence() { double priceHigh1 = iHigh(_Symbol, PERIOD_CURRENT, 2); double priceHigh2 = iHigh(_Symbol, PERIOD_CURRENT, DivergenceLookBack); double macdHigh1 = ExtMacdBuffer[2]; double macdHigh2 = ExtMacdBuffer[DivergenceLookBack - 1]; return (priceHigh1 > priceHigh2 && macdHigh1 < macdHigh2); } bool CheckBearishHiddenDivergence() { double priceHigh1 = iHigh(_Symbol, PERIOD_CURRENT, 2); double priceHigh2 = iHigh(_Symbol, PERIOD_CURRENT, DivergenceLookBack); double macdHigh1 = ExtMacdBuffer[2]; double macdHigh2 = ExtMacdBuffer[DivergenceLookBack - 1]; return (priceHigh1 < priceHigh2 && macdHigh1 > macdHigh2); } void CheckDivergenceTrading() { if (!UseDivergenceStrategy) return; // Check if no position is open or if less than 3 positions are open int openDivergencePositions = CountOrdersByMagic(DivergenceMagicNumber); if (openDivergencePositions == 0 || openDivergencePositions < 3) { int barsAvailable = Bars(_Symbol, PERIOD_CURRENT); if (barsAvailable < DivergenceLookBack * 2) { Print("Not enough data bars for MACD calculation."); return; } int attempt = 0; while(attempt < 6) { if (CopyBuffer(macd_handle, 0, 0, DivergenceLookBack, ExtMacdBuffer) > 0 && CopyBuffer(macd_handle, 1, 0, DivergenceLookBack, ExtSignalBuffer) > 0) break; Print("Failed to copy MACD buffer, retrying..."); Sleep(1000); attempt++; } if(attempt == 6) { Print("Failed to copy MACD buffers after ", attempt, " attempts."); return; } if(TimeCurrent() == iTime(_Symbol, PERIOD_CURRENT, 0)) { Print("Skipping trade due to incomplete bar data."); return; } double currentClose = iClose(_Symbol, PERIOD_CURRENT, 0); double dailyClose = iClose(_Symbol, PERIOD_D1, 0); double dailyOpen = iOpen(_Symbol, PERIOD_D1, 0); bool isDailyBullish = dailyClose > dailyOpen; bool isDailyBearish = dailyClose < dailyOpen; // Only proceed with buy orders if D1 is bullish if (isDailyBullish) { if ((CheckBullishRegularDivergence() && ExtMacdBuffer[0] > ExtSignalBuffer[0]) || CheckBullishHiddenDivergence()) { ExecuteDivergenceOrder(true); } } // Only proceed with sell orders if D1 is bearish if (isDailyBearish) { if ((CheckBearishRegularDivergence() && ExtMacdBuffer[0] < ExtSignalBuffer[0]) || CheckBearishHiddenDivergence()) { ExecuteDivergenceOrder(false); } } } else { Print("Divergence strategy: Maximum number of positions reached."); } } void ExecuteDivergenceOrder(bool isBuy) { // Ensure the magic number is set for the trade trade.SetExpertMagicNumber(DivergenceMagicNumber); double currentPrice = isBuy ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) : SymbolInfoDouble(_Symbol, SYMBOL_BID); double stopLossPrice = isBuy ? currentPrice - DivergenceStopLoss * _Point : currentPrice + DivergenceStopLoss * _Point; double takeProfitPrice = isBuy ? currentPrice + DivergenceTakeProfit * _Point : currentPrice - DivergenceTakeProfit * _Point; if (isBuy) { if (trade.Buy(DivergenceLots, _Symbol, 0, stopLossPrice, takeProfitPrice, "Divergence Buy")) { Print("Divergence Buy order placed."); } } else { if (trade.Sell(DivergenceLots, _Symbol, 0, stopLossPrice, takeProfitPrice, "Divergence Sell")) { Print("Divergence Sell order placed."); } } } int CountOrdersByMagic(int magic) { int count = 0; for (int i = 0; i < PositionsTotal(); i++) { ulong ticket = PositionGetTicket(i); if (PositionSelectByTicket(ticket)) { if (PositionGetInteger(POSITION_MAGIC) == magic) { count++; } } } return count; } //+------------------------------------------------------------------+ //| Profit Locking Logic | //+------------------------------------------------------------------+ void LockProfits() { for (int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if (PositionSelectByTicket(ticket)) { double entryPrice = PositionGetDouble(POSITION_PRICE_OPEN); double currentProfit = PositionGetDouble(POSITION_PROFIT); double currentPrice = PositionGetDouble(POSITION_PRICE_CURRENT); // Convert profit to points double profitPoints = MathAbs(currentProfit / _Point); // Check if profit has exceeded 100 points if (profitPoints >= 100) { double newStopLoss; if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { newStopLoss = entryPrice + profitLockerPoints * _Point; // 20 points above entry for buys } else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) { newStopLoss = entryPrice - profitLockerPoints * _Point; // 20 points below entry for sells } else { continue; // Skip if not a buy or sell position } // Modify stop loss only if the new stop loss is more protective double currentStopLoss = PositionGetDouble(POSITION_SL); if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { if (currentStopLoss < newStopLoss || currentStopLoss == 0) { if (trade.PositionModify(ticket, newStopLoss, PositionGetDouble(POSITION_TP))) { Print("Profit locking for buy position: Stop Loss moved to ", newStopLoss); } } } else // POSITION_TYPE_SELL { if (currentStopLoss > newStopLoss || currentStopLoss == 0) { if (trade.PositionModify(ticket, newStopLoss, PositionGetDouble(POSITION_TP))) { Print("Profit locking for sell position: Stop Loss moved to ", newStopLoss); } } } } } } } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { if (UseTrendFollowingStrategy) CheckTrendFollowing(); if (UseBreakoutStrategy) CheckBreakoutTrading(); if (UseDivergenceStrategy) CheckDivergenceTrading(); LockProfits(); // Call this function to check and lock profits }
Backtest-Ergebnisse und praktische Anwendung
Um unseren Test durchzuführen, müssen wir den Trend Constraint Expert unter den Experten auf dem Terminal suchen. Stellen Sie sicher, dass Sie mit einem Demokonto arbeiten. Es öffnet sich ein Strategietester-Fenster, in dem die Eingabeeinstellungen für verschiedene Optimierungen angepasst werden können. Siehe die Bilder unten mit Standardeinstellungen:
Der Trend Constraint Experte: Demo-Einstellungen
Wir haben den Strategy Tester ausgeführt, und die Trades wurden erfolgreich ausgeführt. Das System beschränkte die maximale Anzahl von Positionen auf drei pro Sitzung, wodurch eine mehrfache unkontrollierte Auftragsausführung verhindert wurde. Das folgende Bild zeigt einen Ausschnitt aus dem Backtesting-Prozess in Aktion:
Der Trend Constraint Experte: Prüfung auf EURUSD M15
Die folgende Abbildung zeigt, dass unsere Positionsmanagementfunktionen wie erwartet funktionieren. Gemäß der implementierten Logik sind maximal drei Orders aktiv, die jeweils mit dem Kommentar Divergence Sell gekennzeichnet sind, wodurch sie leicht identifizierbar und auf die Strategie abgestimmt sind.
Der Trend Constraint Experte: Maximal 3 Positionen pro
Schlussfolgerung
Wir haben verschiedene Arten von Divergenzen untersucht und sie im Rahmen einer Confluence-Strategie in Code umgesetzt, die Indikatoren wie RSI und MACD kombiniert, um präzise Handelssignale zu generieren. Diese Signale wurden weiter verfeinert, indem tägliche Kerzen-Trendeinschränkungen einbezogen wurden, um sicherzustellen, dass sie mit breiteren Markttrends übereinstimmen und somit zuverlässiger sind. Unser Trend Constraint Expert Advisor (EA) verfügt jetzt über unterschiedliche, konfigurierbare Strategien, die es den Nutzern ermöglichen, den EA auf ihre Handelsvorlieben zuzuschneiden und an verschiedene Marktbedingungen anzupassen.
Um das Handelsmanagement zu verbessern, haben wir Funktionen wie eindeutige MAGIC-Nummern für jede Position eingeführt, die eine präzise Kontrolle der offenen Geschäfte und eine Begrenzung der Anzahl der Positionen pro Strategie ermöglichen. Darüber hinaus wurde eine nutzerdefinierte Gewinnsicherungsfunktion entwickelt, um Gewinne zu sichern, indem die Stop-Loss dynamisch angepasst werden, falls der Markt vor Erreichen des Take-Profit-Ziels umschlägt. Diese Funktionalität gewährleistet sowohl Risikomanagement als auch Flexibilität und macht den EA robust und anpassungsfähig. Im Anhang finden Sie die Quelldateien für das EA-Programm. Wir ermutigen Sie, sie zu erforschen, verschiedene Konfigurationen zu testen und Ihr Feedback im Kommentarbereich zu hinterlassen. Bitte beachten: Diese Beispiele sind nur für Lehrzwecke gedacht, und alle Tests sollten auf Demo-Konten durchgeführt werden.
Viel Spaß beim Entwickeln, liebe Händler!
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/16549





- 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.