
Wie man die automatische Optimierung in MQL5 Expert Advisors implementiert
Machen Sie sich bereit, in die wunderbare Welt der automatisch optimierenden Forex-Handelsalgorithmen eingeführt zu werden. Sie kann es Ihrem Expert Advisor (EA) ermöglichen, sich für die nächste Iteration des Handels auf der Grundlage der Marktbedingungen nach einem abgeschlossenen Handel anzupassen.
Betrachten Sie Ihren EA als einen versierten Händler, der die Trends anhand von gleitenden Durchschnitten beobachtet. Es hat funktioniert, aber was wäre, wenn es eine marktbewusste Blackbox wäre, die mit der Zeit noch lernen könnte, ihre Strategie zu optimieren? Dies ist der Prozess der automatischen Optimierung.
Einer der Hauptvorteile eines Expert Advisors (EA) besteht darin, dass er sich an die Marktbedingungen anpassen kann, wenn diese sich weiter verändern. Der EA passt sich automatisch an das aktuelle Marktumfeld an und reduziert so die ständige manuelle Überwachung und Änderung der Parameter. Dies ermöglicht es den Händlern, kurzfristige, sekundengenaue Chancen konsequent zu nutzen und ihre Handelsstrategie ohne Unterbrechungen auszuführen. Außerdem ist der EA in der Lage, Handelsstrategien jeden Tag und die ganze Zeit über zu optimieren.
Allerdings gibt es einige Fallstricke, die man beachten sollte. Eine Herausforderung ist das Risiko der Überanpassung an aktuelle Daten, was zu einer schlechten Leistung unter verschiedenen Marktbedingungen führen kann. Eine effiziente Verwaltung der Rechenressourcen ist ebenfalls von entscheidender Bedeutung, da die Komplexität des Codes bei der Automatisierung von Strategien zunehmen kann. Es kann schwierig sein, die Stabilität bei Parameteränderungen aufrechtzuerhalten, und die Zuordnung der Leistung kann manchmal zu einem Problem werden.
In diesem Leitfaden werden wir den Prozess der Erstellung eines automatisch optimierenden EA erkunden, einschließlich der Automatisierung von Strategien mit nutzerdefinierten Indikatoren. Wir werden eine robuste Optimierungslogik, bewährte Verfahren für die Parameterauswahl und die Rekonstruktion von Strategien mit Backtesting behandeln. Darüber hinaus werden übergeordnete Methoden wie die Walk-Forward-Optimierung erörtert, um Ihren Handelsansatz zu verbessern.
Wie Sie Ihre Ziele erreichen und produktiv sein können (und wie Sie nicht in Fallen tappen!)
Wir werden unseren Handelsplan auf eine Crossover-Strategie mit gleitendem Durchschnitt stützen, die die grundlegendste aller Strategien ist, aber in trendorientierten Märkten nie versagt.
1. Einrichten von Bibliotheken, Eingabeparametern und Optimierungsbereichen für die Auto-Optimierung von EA
1.1 Importieren der erforderlicher Bibliotheken
In der ersten Zeile durch Einbindung der notwendigen MQL5-Bibliotheken:
#include <Trade\Trade.mqh> #include <Arrays\ArrayObj.mqh>
Die Trade-Bibliothek bietet Funktionen zur Ausführung von Trades, während die ArrayObj-Bibliothek die Arbeit mit dynamischen Arrays von Objekten ermöglicht, die wir zum Speichern von Optimierungsergebnissen verwenden werden.
1.2 Definition der Eingabeparameter
Als Nächstes definieren wir die Eingabeparameter für unseren EA:
input int MA_Fast_Period = 10; // Fast Moving Average Period input int MA_Slow_Period = 20; // Slow Moving Average Period input ENUM_MA_METHOD MA_Method = MODE_SMA; // Moving Average Method input ENUM_APPLIED_PRICE Applied_Price = PRICE_CLOSE; // Applied Price input double LotSize = 0.1; // Lot Size input int StopLoss = 50; // Stop Loss in points input int TakeProfit = 100; // Take Profit in points // Optimization parameters input bool AutoOptimize = false; // Enable Auto Optimization input int OptimizationPeriod = 5000; // Number of ticks between optimizations input int MinDataPoints = 1000; // Minimum number of data points for optimization
Diese Eingabeparameter ermöglichen es dem Nutzer, das Verhalten und die Optimierungseinstellungen des EA direkt über die MetaTrader-Oberfläche zu konfigurieren.
1.3 Globale Variablen und Handles
Anschließend deklarieren wir globale Variablen und Handles, die im gesamten EA verwendet werden:
CTrade trade; int fastMA_Handle, slowMA_Handle; double fastMA[], slowMA[]; int tickCount = 0; CArrayObj* optimizationResults; // Optimization ranges const int MA_Fast_Min = 5, MA_Fast_Max = 50, MA_Fast_Step = 1; const int MA_Slow_Min = 10, MA_Slow_Max = 100, MA_Slow_Step = 1;
Das Objekt „CTrade“ verwaltet die Handelsoperationen, während „fastMA_Handle“ und „slowMA_Handle“ für die Verwaltung der Indikatoren des gleitenden Durchschnitts verwendet werden. Das Array „optimizationResults“ speichert die Ergebnisse unserer Optimierungstests.
1.4 Optimierungseinstellungen
Die Optimierungseinstellungen legen den Wertebereich fest, den wir für jeden Parameter testen:
- Schnelle MA-Periodenlänge: Von 5 bis 50, gestaffelt nach 1- Slow MA Period: Von 10 bis 100, schrittweise um 1
2. Implementierung der zentralen Handelslogik
Nachdem wir unsere EA-Struktur eingerichtet haben, können wir nun die Kernfunktionen implementieren, die die Initialisierung, Deinitialisierung und Tick-Verarbeitung übernehmen.
2.1 Die Funktion OnInit()
Die Funktion „OnInit()“ wird aufgerufen, wenn der EA zum ersten Mal in einen Chart geladen wird. So setzen wir es um:
int OnInit() { // Initialize MA handles fastMA_Handle = iMA(_Symbol, PERIOD_CURRENT, MA_Fast_Period, 0, MA_Method, Applied_Price); slowMA_Handle = iMA(_Symbol, PERIOD_CURRENT, MA_Slow_Period, 0, MA_Method, Applied_Price); if(fastMA_Handle == INVALID_HANDLE || slowMA_Handle == INVALID_HANDLE) { Print("Failed to create MA indicators"); return INIT_FAILED; } // Initialize optimization results array optimizationResults = new CArrayObj(); return INIT_SUCCEEDED; }
Diese Funktion erstellt die Indikatoren des gleitenden Durchschnitts und initialisiert das Array der Optimierungsergebnisse. Wenn die Indikatoren nicht initialisiert werden können, wird der EA nicht gestartet.
2.2 Die Funktion OnDeinit()
Die Funktion „OnDeinit()“ wird aufgerufen, wenn der EA aus dem Chart entfernt oder das Terminal geschlossen wird:void OnDeinit(const int reason) { // Release MA handles IndicatorRelease(fastMA_Handle); IndicatorRelease(slowMA_Handle); // Clean up optimization results if(optimizationResults != NULL) { delete optimizationResults; optimizationResults = NULL; } }
Diese Funktion stellt sicher, dass die Indikator-Handles ordnungsgemäß freigegeben werden und der vom Array der Optimierungsergebnisse belegte Speicher freigegeben wird.
2.3 Die Funktion OnTick()
Die Funktion „OnTick()“ ist das Herzstück unseres EA und wird bei jedem Tick des ausgewählten Symbols aufgerufen:
void OnTick() { // Check if we have enough bars to calculate MAs if(Bars(_Symbol, PERIOD_CURRENT) < MA_Slow_Period) return; // Copy MA values if(CopyBuffer(fastMA_Handle, 0, 0, 2, fastMA) != 2) return; if(CopyBuffer(slowMA_Handle, 0, 0, 2, slowMA) != 2) return; // Auto Optimization if(AutoOptimize && ++tickCount >= OptimizationPeriod) { Optimize(); tickCount = 0; } // Trading logic if(fastMA[1] <= slowMA[1] && fastMA[0] > slowMA[0]) { // Open buy position double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); trade.Buy(LotSize, _Symbol, ask, ask - StopLoss * _Point, ask + TakeProfit * _Point); } else if(fastMA[1] >= slowMA[1] && fastMA[0] < slowMA[0]) { // Open sell position double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); trade.Sell(LotSize, _Symbol, bid, bid + StopLoss * _Point, bid - TakeProfit * _Point); } }
Diese Funktion erfüllt mehrere wichtige Aufgaben:
- Es wird geprüft, ob genügend historische Daten für die Berechnung der gleitenden Durchschnitte vorhanden sind.
- Sie ruft die aktuellen Werte der gleitenden Durchschnitte ab.
- Wenn die automatische Optimierung aktiviert ist und es an der Zeit ist, zu optimieren (basierend auf „tickCount“), wird die Funktion „Optimize()“ aufgerufen.
- Es implementiert die Handelslogik und eröffnet Kauf- oder Verkaufspositionen auf der Grundlage von Überkreuzungen gleitender Durchschnitte.
3. Implementierung der Optimierungslogik
Der Kern unserer automatischen Optimierungsfunktion liegt in der Funktion „Optimize()“. Schauen wir uns die einzelnen Bestandteile an.
3.1 Die Funktion Optimieren()
Hier ist die allgemeine Struktur der Funktion „Optimize()“:
void Optimize() { Print("Starting optimization..."); optimizationResults.Clear(); // Loop through all combinations of MA periods for(int fastPeriod = MA_Fast_Min; fastPeriod <= MA_Fast_Max; fastPeriod += MA_Fast_Step) { for(int slowPeriod = MA_Slow_Min; slowPeriod <= MA_Slow_Max; slowPeriod += MA_Slow_Step) { if(slowPeriod <= fastPeriod) continue; // Slow period should be greater than fast period double profit = TestParameters(fastPeriod, slowPeriod); OptimizationResult* result = new OptimizationResult; result.fastPeriod = fastPeriod; result.slowPeriod = slowPeriod; result.profit = profit; optimizationResults.Add(result); } } // Find the best result OptimizationResult* bestResult = NULL; for(int i = 0; i < optimizationResults.Total(); i++) { OptimizationResult* currentResult = optimizationResults.At(i); if(bestResult == NULL || currentResult.profit > bestResult.profit) { bestResult = currentResult; } } if(bestResult != NULL) { // Update the EA parameters MA_Fast_Period = bestResult.fastPeriod; MA_Slow_Period = bestResult.slowPeriod; // Update indicator handles IndicatorRelease(fastMA_Handle); IndicatorRelease(slowMA_Handle); fastMA_Handle = iMA(_Symbol, PERIOD_CURRENT, MA_Fast_Period, 0, MA_Method, Applied_Price); slowMA_Handle = iMA(_Symbol, PERIOD_CURRENT, MA_Slow_Period, 0, MA_Method, Applied_Price); Print("Optimization complete. New parameters: Fast MA = ", MA_Fast_Period, ", Slow MA = ", MA_Slow_Period); } else { Print("Optimization failed to find better parameters."); } }
3.2 Schleife durch Parameterkombinationen
Die verschachtelten for-Schleifen in der Funktion „Optimize()“ ermöglichen es uns, alle Kombinationen von schnellen und langsamen gleitenden Durchschnittsperioden innerhalb der von uns festgelegten Bereiche zu testen. Dies ist ein sogenannter „Brute-Force“-Ansatz zur Optimierung.
for(int fastPeriod = MA_Fast_Min; fastPeriod <= MA_Fast_Max; fastPeriod += MA_Fast_Step) { for(int slowPeriod = MA_Slow_Min; slowPeriod <= MA_Slow_Max; slowPeriod += MA_Slow_Step) { if(slowPeriod <= fastPeriod) continue; // Slow period should be greater than fast period double profit = TestParameters(fastPeriod, slowPeriod); // Store results... } }
Wir lassen Kombinationen aus, bei denen die langsame Periodenlänge kleiner oder gleich der schnellen Periodenlänge ist, da dies für unsere Strategie keinen Sinn machen würde.
3.3 Speichern und Vergleichen von Ergebnissen
Für jede gültige Kombination rufen wir „TestParameter()“ auf, um ihre Leistung zu bewerten. Die Ergebnisse werden in dem Objekt „OptimizationResult“ gespeichert und zu unserem Array „OptimizationResults“ hinzugefügt.
Nachdem wir alle Kombinationen getestet haben, gehen wir die Ergebnisse in einer Schleife durch, um den besten Parametersatz zu finden:
OptimizationResult* bestResult = NULL; for(int i = 0; i < optimizationResults.Total(); i++) { OptimizationResult* currentResult = optimizationResults.At(i); if(bestResult == NULL || currentResult.profit > bestResult.profit) { bestResult = currentResult; } }
Wenn ein optimales Ergebnis gefunden wird, aktualisieren wir die Parameter des EA und erstellen die Handles der Indikatoren mit den neuen Perioden neu.
4. Testen der Parameter
Die Funktion „TestParameters()“ ist entscheidend für die Auswertung der einzelnen Parametersätze. Schauen wir uns das im Detail an.
4.1 Die Funktion TestParameter()
double TestParameters(int fastPeriod, int slowPeriod) { int maFast = iMA(_Symbol, PERIOD_CURRENT, fastPeriod, 0, MA_Method, Applied_Price); int maSlow = iMA(_Symbol, PERIOD_CURRENT, slowPeriod, 0, MA_Method, Applied_Price); if(maFast == INVALID_HANDLE || maSlow == INVALID_HANDLE) { Print("Failed to create MA indicators for testing"); return -DBL_MAX; } double fastBuffer[], slowBuffer[]; ArraySetAsSeries(fastBuffer, true); ArraySetAsSeries(slowBuffer, true); int copied = CopyBuffer(maFast, 0, 0, MinDataPoints, fastBuffer); copied = MathMin(copied, CopyBuffer(maSlow, 0, 0, MinDataPoints, slowBuffer)); if(copied < MinDataPoints) { Print("Not enough data for testing"); return -DBL_MAX; } double profit = 0; for(int i = 1; i < copied; i++) { if(fastBuffer[i] > slowBuffer[i] && fastBuffer[i-1] <= slowBuffer[i-1]) { // Buy signal profit += Close[i-1] - Open[i]; } else if(fastBuffer[i] < slowBuffer[i] && fastBuffer[i-1] >= slowBuffer[i-1]) { // Sell signal profit += Open[i] - Close[i-1]; } } IndicatorRelease(maFast); IndicatorRelease(maSlow); return profit; }
4.2 Temporäre Indikatoren erstellen
Für jeden getesteten Parametersatz werden temporäre Indikatoren des gleitenden Durchschnitts erstellt:
int maFast = iMA(_Symbol, PERIOD_CURRENT, fastPeriod, 0, MA_Method, Applied_Price); int maSlow = iMA(_Symbol, PERIOD_CURRENT, slowPeriod, 0, MA_Method, Applied_Price);
Diese temporären Indikatoren ermöglichen es uns, gleitende Durchschnitte mit unterschiedlichen Zeiträumen zu berechnen, ohne unsere Haupt-Handelslogik zu beeinträchtigen.
4.3 Simulieren von Handelsgeschäften
Anschließend durchlaufen wir die historischen Daten und simulieren den Handel auf der Grundlage unserer Crossover-Logik der gleitenden Durchschnitte:
for(int i = 1; i < copied; i++) { if(fastBuffer[i] > slowBuffer[i] && fastBuffer[i-1] <= slowBuffer[i-1]) { // Buy signal profit += Close[i-1] - Open[i]; } else if(fastBuffer[i] < slowBuffer[i] && fastBuffer[i-1] >= slowBuffer[i-1]) { // Sell signal profit += Open[i] - Close[i-1]; } }
Diese vereinfachte Simulation geht davon aus, dass wir einen Handel zum Eröffnungskurs des auf einen Crossover folgenden Balkens eröffnen und zum Schlusskurs desselben Balkens schließen können.
4.4 Berechnung des Gewinns
Die Funktion gibt den Gesamtgewinn aus den simulierten Handelsgeschäfte zurück. Bei einer anspruchsvolleren Umsetzung könnten Sie andere Faktoren wie den maximalen Drawdown, die Sharpe Ratio oder die Gewinnrate berücksichtigen.
5. Optimierte Parameter anwenden
Sobald wir die leistungsfähigsten Parameter gefunden haben, soll sie unser EA verwenden.
5.1 EA-Parameter aktualisieren
Wir aktualisieren unsere globalen Variablen mit den neuen optimalen Werten:
MA_Fast_Period = bestResult.fastPeriod; MA_Slow_Period = bestResult.slowPeriod;
5.2 Wiederherstellen von Indikator-Handles
Nachdem wir die Parameter aktualisiert haben, müssen wir unsere Indikator-Handles neu erstellen:
IndicatorRelease(fastMA_Handle); IndicatorRelease(slowMA_Handle); fastMA_Handle = iMA(_Symbol, PERIOD_CURRENT, MA_Fast_Period, 0, MA_Method, Applied_Price); slowMA_Handle = iMA(_Symbol, PERIOD_CURRENT, MA_Slow_Period, 0, MA_Method, Applied_Price);
Dadurch wird sichergestellt, dass unsere Haupthandelslogik in Zukunft die neu optimierten Parameter verwenden wird.
6. Fortgeschrittene Optimierungstechniken
Während unsere aktuelle Implementierung eine solide Grundlage für die automatische Optimierung bietet, gibt es mehrere fortgeschrittene Techniken, die Sie in Betracht ziehen können, um die Leistung Ihres EA weiter zu verbessern.
6.1 Optimierung mehrerer Kriterien
Anstatt nur auf den Gewinn zu optimieren, können Sie mehrere Kriterien in Ihren Optimierungsprozess einbeziehen. Zum Beispiel:
struct OptimizationResult { int fastPeriod; int slowPeriod; double profit; double drawdown; double sharpeRatio; }; double CalculateScore(const OptimizationResult &result) { return result.profit * 0.5 + result.sharpeRatio * 0.3 - result.drawdown * 0.2; }
Mit diesem Ansatz können Sie mehrere Leistungsaspekte abwägen, was zu robusteren Parametersätzen führen kann.
6.2 Walk-Forward-Optimierung
Bei der Walk-Forward-Optimierung werden Ihre historischen Daten in mehrere Segmente unterteilt, die Optimierung wird für ein Segment durchgeführt und dann für das nächste getestet.
Dies kann dazu beitragen, eine Überanpassung zu verhindern:
void WalkForwardOptimization() { int totalBars = Bars(_Symbol, PERIOD_CURRENT); int segmentSize = 1000; // Adjust as needed for(int i = 0; i < totalBars - 2*segmentSize; i += segmentSize) { // Optimize on segment i to i+segmentSize OptimizeSegment(i, i+segmentSize); // Test on segment i+segmentSize to i+2*segmentSize TestSegment(i+segmentSize, i+2*segmentSize); } }
6.3 Adaptive Parameteranpassung
Anstatt die Parameter während der Optimierung vollständig zu ersetzen, können Sie ein System implementieren, das die Parameter schrittweise auf der Grundlage der jüngsten Leistung anpasst:
void AdaptParameters() { double recentPerformance = CalculateRecentPerformance(); double adaptationRate = 0.1; // Adjust as needed MA_Fast_Period += (int)((bestResult.fastPeriod - MA_Fast_Period) * adaptationRate * recentPerformance); MA_Slow_Period += (int)((bestResult.slowPeriod - MA_Slow_Period) * adaptationRate * recentPerformance); }
Dieser Ansatz kann einen sanfteren Übergang zwischen Parametersätzen ermöglichen und die Auswirkungen kurzfristiger Marktstörungen auf Ihren Optimierungsprozess verringern.
7. Bewährte Praktiken und Überlegungen
Beachten Sie bei der Implementierung und Verfeinerung Ihres EA mit automatischer Optimierung diese bewährten Verfahren:
7.1 Auswahl der Optimierungsfrequenz
Die Häufigkeit der Optimierung kann die Leistung Ihres EAs erheblich beeinflussen. Eine zu häufige Optimierung kann zu einer Überreaktion auf kurzfristige Marktschwankungen führen, während eine zu seltene Optimierung zu verpassten Chancen führen kann.
Ziehen Sie die Implementierung einer dynamischen Optimierungsfrequenz in Betracht, die auf der Marktvolatilität oder der jüngsten Performance des EAs basiert:
bool ShouldOptimize() { double recentVolatility = CalculateRecentVolatility(); int dynamicPeriod = (int)(OptimizationPeriod * (1 + recentVolatility)); return tickCount >= dynamicPeriod; }
7.2 Ausgleich zwischen Anpassungsfähigkeit und Stabilität
Obwohl die Anpassungsfähigkeit ein entscheidender Vorteil von automatisch optimierten EAs ist, ist es wichtig, ein gewisses Maß an Stabilität zu wahren. Drastische Parameteränderungen können zu inkonsistentem Handelsverhalten führen.
Ziehen Sie in Erwägung, die Anzahl der Parameter, die bei einer einzelnen Optimierung geändert werden können, zu begrenzen:
void LimitParameterChange(int ¶meter, int newValue, int maxChange) { int change = newValue - parameter; change = MathMax(-maxChange, MathMin(change, maxChange)); parameter += change; }
7.3 Eine Überanpassung ist ein großes Risiko in jedem Optimierungsprozess. Ein überangepasster EA kann bei historischen Daten außergewöhnlich gut abschneiden, aber versagen, wenn er mit neuen Marktbedingungen konfrontiert wird. Um dieses Risiko zu mindern, ist es wichtig, eine ausreichende Menge an historischen Daten für die Optimierung zu verwenden. Darüber hinaus kann die Durchführung von Out-of-Sample-Tests oder Walk-Forward-Optimierung dazu beitragen, die Robustheit sicherzustellen. Die Komplexität Ihrer Strategie sollte auch im Verhältnis zur Menge der verfügbaren Daten betrachtet werden. Eine genaue Überwachung der Live-Performance ist von entscheidender Bedeutung, und Sie müssen darauf vorbereitet sein, einzugreifen, wenn das Verhalten des EA erheblich von den Backtest-Ergebnissen abweicht.
7.4 Die automatische Optimierung kann sehr rechenintensiv sein, weshalb die Gewährleistung der Recheneffizienz von entscheidender Bedeutung ist. Um Ihren EA reaktionsfähig zu halten, ist es ratsam, Optimierungen außerhalb der Geschäftszeiten oder in einem separaten Thread durchzuführen. Effiziente Datenstrukturen und Algorithmen können die Verarbeitungszeit erheblich verkürzen. Für intensivere Optimierungsaufgaben sind Cloud-basierte Lösungen möglicherweise eine gute Option.
8. Die Entwicklung eines automatisch optimierenden EA bringt neue Herausforderungen bei der Fehlersuche und -behebung mit sich
8.1 Während der Entwicklung können einige allgemeine Probleme auftreten. Wenn Ihr EA beispielsweise bei jedem Durchlauf inkonsistente Ergebnisse liefert, sollten Sie sicherstellen, dass Sie konsistente Daten verwenden und Ihren Code auf Zufallselemente überprüfen. Eine schlechte Live-Performance trotz guter Backtest-Ergebnisse könnte auf Faktoren wie Slippage, Spread oder veränderte Marktbedingungen zurückzuführen sein. Wenn die Optimierung fehlschlägt oder unerwartete Ergebnisse liefert, ist es wichtig, Ihre Optimierungskriterien zu überprüfen und sicherzustellen, dass Ihre Funktion TestParameters() wie erwartet funktioniert.
8.2 Um die Fehlersuche zu erleichtern, wird dringend empfohlen, eine umfassende Protokollierung zu implementieren. Auf diese Weise können Sie das Verhalten des EA und den Optimierungsprozess im Detail verfolgen und so Probleme besser erkennen und beheben.
Implementieren Sie eine umfassende Protokollierung, um das Verhalten des EA und den Optimierungsprozess zu verfolgen:void Log(string message) { Print(TimeToString(TimeCurrent()) + ": " + message); int handle = FileOpen("EA_Log.txt", FILE_WRITE|FILE_READ|FILE_TXT); if(handle != INVALID_HANDLE) { FileSeek(handle, 0, SEEK_END); FileWriteString(handle, TimeToString(TimeCurrent()) + ": " + message + "\n"); FileClose(handle); } }
Verwenden Sie diese Funktion, um wichtige Ereignisse, Parameteränderungen und alle Fehler, die während des Betriebs oder der Optimierung auftreten, zu protokollieren.
8.3 Der MetaTrader Strategy Tester ist ein unschätzbares Werkzeug für die Fehlersuche in Ihrem EA. Sie können den visuellen Modus verwenden, um das Verhalten Ihres EA Takt für Takt durchzugehen, was einen detaillierten Einblick in die Funktionsweise des EA in Echtzeit bietet. Darüber hinaus kann ein Vergleich der Optimierungsergebnisse im Strategy Tester mit denen der automatischen Optimierung Ihres EAs helfen, etwaige Diskrepanzen zu erkennen. Die Optimierungsfunktion des Strategy Testers ist auch eine nützliche Methode, um die Funktionalität Ihrer TestParameters()-Funktion zu überprüfen.
9. Leistung und Herausforderungen des automatisch optimierenden Moving Average EA
9.1 Um die potenziellen Vorteile und Herausforderungen der automatischen Optimierung zu veranschaulichen, betrachten wir eine hypothetische Fallstudie.
Wir haben unseren automatisch optimierenden Moving Average Crossover EA auf EURUSD H1-Daten von 2010 bis 2020 getestet. Der EA wurde so konfiguriert, dass er seine Parameter alle 5000 Ticks optimiert. Die Ergebnisse waren vielversprechend und zeigten einen Gesamtnettogewinn von 15.420 $, einen Gewinnfaktor von 1,65 und einen maximalen Drawdown von 2.105 $ bei insgesamt 1.247 Trades.
Anschließend haben wir diese Ergebnisse mit demselben EA mit statischen Parametern (MA_Fast_Period = 10, MA_Slow_Period = 20) verglichen. Die statische Version ergab einen Gesamtnettogewinn von 8.750 $, einen Gewinnfaktor von 1,38 und einen höheren maximalen Drawdown von 3.210 $ bei 1.562 Gesamtgeschäften. Dieser Vergleich zeigte, dass die Version mit automatischer Optimierung sowohl die Gesamtrentabilität als auch die risikobereinigten Renditen deutlich verbesserte.
9.2 Die Ergebnisse der Backtests sind zwar vielversprechend, doch sind bei der Bewertung der realen Leistung mehrere wichtige Faktoren zu berücksichtigen. Änderungen des Marktregimes, wie die Finanzkrise 2008 oder die COVID-19-Pandemie 2020, könnten die Anpassungsfähigkeit des EA beeinträchtigen, und dies muss sorgfältig bewertet werden. Darüber hinaus sollten die Transaktionskosten berücksichtigt werden, um sicherzustellen, dass die verbesserte Performance eine erhöhte Handelstätigkeit rechtfertigt. Die für eine kontinuierliche Optimierung in einer Live-Umgebung erforderlichen Rechenressourcen sind ein weiterer Aspekt, ebenso wie die psychologische Belastbarkeit, die erforderlich ist, um mit Perioden geringer Leistung fertig zu werden, während sich der EA an neue Bedingungen anpasst.
10. Zukünftige Trends bei der Auto-Optimierung von EAs: Maschinelles Lernen, externe Daten und Cloud-Lösungen
10.1 Mit der Weiterentwicklung der Handelstechnologie zeichnen sich spannende Entwicklungen für die automatische Optimierung von EAs ab. Eine solche Entwicklung ist die Integration von Algorithmen des maschinellen Lernens in den Devisenhandel, die den Optimierungsprozess durch die Erkennung komplexer Muster in den Marktdaten verbessern könnten. Dies eröffnet Möglichkeiten für noch anpassungsfähigere und effizientere Handelsstrategien in der Zukunft.
Algorithmen des maschinellen Lernens können den Optimierungsprozess potenziell verbessern, indem sie komplexe Muster in Marktdaten erkennen:
from sklearn.ensemble import RandomForestRegressor def ml_optimize(data, labels): model = RandomForestRegressor(n_estimators=100) model.fit(data, labels) return model.feature_importances_
Während in diesem Beispiel Python verwendet wird, können ähnliche maschinelle Lerntechniken in MQL5 implementiert oder über externe Bibliotheken integriert werden.
10.2 Integration mit externen Datenquellen
Die Einbeziehung externer Daten (Wirtschaftsindikatoren, Stimmungsanalysen usw.) in Ihren Optimierungsprozess kann einen umfassenderen Blick auf die Marktbedingungen ermöglichen:
string GetExternalData() { string cookie=NULL,headers; char post[],result[]; int res; string url="https://api.example.com/economic-data"; res=WebRequest("GET",url,cookie,NULL,500,post,0,result,headers); if(res==-1) { Print("Error in WebRequest. Error code =",GetLastError()); return ""; } string resultString=CharArrayToString(result); return resultString; }
Durch die Integration externer Daten kann Ihr EA potenziell fundiertere Entscheidungen darüber treffen, wann und wie er seine Parameter optimieren soll.
10.3 Cloud-basierte Optimierung
Da die Optimierungsaufgaben immer komplexer werden, bieten cloudbasierte Lösungen das Potenzial für leistungsfähigere und flexiblere Optimierungsprozesse:
void CloudOptimize() { string optimizationData = PrepareOptimizationData(); string url = "https://your-cloud-service.com/optimize"; string headers = "Content-Type: application/json\r\n"; char post[], result[]; string resultHeaders; StringToCharArray(optimizationData, post); int res = WebRequest("POST", url, headers, 30000, post, result, resultHeaders); if(res == -1) { Print("Error in WebRequest. Error code =", GetLastError()); return; } string optimizationResult = CharArrayToString(result); ApplyCloudOptimizationResult(optimizationResult); }
Mit diesem Ansatz können Sie mehr Rechenleistung und potenziell anspruchsvollere Optimierungsalgorithmen nutzen, als dies auf einem lokalen Rechner möglich wäre.
Die Entwicklung eines effektiven, selbstoptimierenden EA ist ein fortlaufender Prozess, der kontinuierliche Verbesserung und Lernen erfordert. Eine Strategie zur Verbesserung ist die regelmäßige Überprüfung der Leistung der EA. Diese Praxis wird dazu beitragen, Bereiche mit Verbesserungsbedarf zu ermitteln und sicherzustellen, dass der EA auch unter veränderten Marktbedingungen optimal funktioniert.
void WeeklyPerformanceReview() { datetime startOfWeek = iTime(_Symbol, PERIOD_W1, 0); double weeklyProfit = 0; int totalTrades = 0; for(int i = 0; i < HistoryDealsTotal(); i++) { ulong ticket = HistoryDealGetTicket(i); if(HistoryDealGetInteger(ticket, DEAL_TIME) >= startOfWeek) { weeklyProfit += HistoryDealGetDouble(ticket, DEAL_PROFIT); totalTrades++; } } Print("Weekly Performance: Profit = ", weeklyProfit, ", Trades = ", totalTrades); }
Nutzen Sie diese Überprüfungen, um verbesserungswürdige Bereiche und potenzielle Probleme in Ihrem Optimierungsprozess zu ermitteln.
Es ist wichtig, über Handelstechnologie, Marktdynamik und Vorschriften auf dem Laufenden zu bleiben. Gründliche Tests, einschließlich Out-of-Sample- und Forward-Tests, sind von entscheidender Bedeutung. Kontinuierliches Lernen und Überwachung sind der Schlüssel zum langfristigen Erfolg. Die automatische Optimierung ist zwar leistungsstark, sollte aber solide Handelsgrundsätze und Risikomanagement ergänzen. Bleiben Sie neugierig und vorsichtig und achten Sie auf den Schutz Ihres Kapitals.
Viel Spaß beim Handeln!
Für diejenigen, die ihr Verständnis von automatischer Optimierung und algorithmischem Handel vertiefen möchten, gibt es hier einige zusätzliche Ressourcen:
- Building Reliable Trading Systems von Keith Fitschen
- Algorithmic Trading: Winning Strategies and Their Rationale von Ernie Chan
- Machine Learning for Algorithmic Trading von Stefan Jansen
- MQL5-Dokumentation: MQL5-Dokumentation
- Forex Factory Forum - Forum für Kodierer Forex Factory Forum
- Quantopian Lectures: Kurse zum Thema von Quantopian
11. Beispiel EA-Code
Nachfolgend finden Sie den vollständigen Code für den EA mit automatischer Optimierung. Kopieren Sie diesen Code in Ihren MetaEditor und kompilieren Sie ihn zur Verwendung in MetaTrader 5.
//+------------------------------------------------------------------+ //| Auto-Optimizing Moving Average Crossover EA | //| Copyright 2024, Javier Santiago Gaston de Iriarte Cabrera | //| https://www.mql5.com/en/users/jsgaston/news | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, Javier Santiago Gaston de Iriarte Cabrera" #property link "https://www.mql5.com/en/users/jsgaston/news" #property version "1.00" #property strict // Include necessary libraries #include <Trade\Trade.mqh> #include <Arrays\ArrayObj.mqh> // Input parameters input ENUM_MA_METHOD MA_Method = MODE_SMA; // Moving Average Method input ENUM_APPLIED_PRICE Applied_Price = PRICE_CLOSE; // Applied Price input double LotSize = 0.01; // Lot Size input int StopLoss = 100; // Stop Loss in points input int TakeProfit = 200; // Take Profit in points input int Initial_MA_Fast_Period = 10; // Initial Fast Moving Average Period input int Initial_MA_Slow_Period = 20; // Initial Slow Moving Average Period // Optimization parameters input bool AutoOptimize = true; // Enable Auto Optimization input int OptimizationPeriod = 5000; // Number of ticks between optimizations input int MinDataPoints = 1000; // Minimum number of data points for optimization // Global variables CTrade trade; int fastMA_Handle, slowMA_Handle; double fastMA[], slowMA[]; int tickCount = 0; CArrayObj optimizationResults; int MA_Fast_Period, MA_Slow_Period; // Optimization ranges const int MA_Fast_Min = 5, MA_Fast_Max = 50, MA_Fast_Step = 1; const int MA_Slow_Min = 10, MA_Slow_Max = 100, MA_Slow_Step = 1; // Class to hold optimization results class OptimizationResult : public CObject { public: int fastPeriod; int slowPeriod; double profit; }; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { MA_Fast_Period = Initial_MA_Fast_Period; MA_Slow_Period = Initial_MA_Slow_Period; // Initialize MA handles fastMA_Handle = iMA(_Symbol, PERIOD_CURRENT, MA_Fast_Period, 0, MA_Method, Applied_Price); slowMA_Handle = iMA(_Symbol, PERIOD_CURRENT, MA_Slow_Period, 0, MA_Method, Applied_Price); if(fastMA_Handle == INVALID_HANDLE || slowMA_Handle == INVALID_HANDLE) { Print("Failed to create MA indicators"); return INIT_FAILED; } return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { // Release MA handles IndicatorRelease(fastMA_Handle); IndicatorRelease(slowMA_Handle); // Clean up optimization results optimizationResults.Clear(); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // Check if we have enough bars to calculate MAs if(Bars(_Symbol, PERIOD_CURRENT) < MA_Slow_Period) return; // Copy MA values if(CopyBuffer(fastMA_Handle, 0, 0, 2, fastMA) != 2) return; if(CopyBuffer(slowMA_Handle, 0, 0, 2, slowMA) != 2) return; // Auto Optimization if(AutoOptimize && ++tickCount >= OptimizationPeriod) { Optimize(); tickCount = 0; } // Trading logic if(fastMA[1] <= slowMA[1] && fastMA[0] > slowMA[0]) { // Open buy position double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); trade.Buy(LotSize, _Symbol, ask, ask - StopLoss * _Point, ask + TakeProfit * _Point); } else if(fastMA[1] >= slowMA[1] && fastMA[0] < slowMA[0]) { // Open sell position double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); trade.Sell(LotSize, _Symbol, bid, bid + StopLoss * _Point, bid - TakeProfit * _Point); } } //+------------------------------------------------------------------+ //| Optimization function | //+------------------------------------------------------------------+ void Optimize() { Print("Starting optimization..."); optimizationResults.Clear(); // Loop through all combinations of MA periods for(int fastPeriod = MA_Fast_Min; fastPeriod <= MA_Fast_Max; fastPeriod += MA_Fast_Step) { for(int slowPeriod = MA_Slow_Min; slowPeriod <= MA_Slow_Max; slowPeriod += MA_Slow_Step) { if(slowPeriod <= fastPeriod) continue; // Slow period should be greater than fast period double profit = TestParameters(fastPeriod, slowPeriod); OptimizationResult* result = new OptimizationResult(); result.fastPeriod = fastPeriod; result.slowPeriod = slowPeriod; result.profit = profit; optimizationResults.Add(result); } } // Find the best result OptimizationResult* bestResult = NULL; for(int i = 0; i < optimizationResults.Total(); i++) { OptimizationResult* currentResult = optimizationResults.At(i); if(bestResult == NULL || currentResult.profit > bestResult.profit) { bestResult = currentResult; } } if(bestResult != NULL) { // Update the EA parameters MA_Fast_Period = bestResult.fastPeriod; MA_Slow_Period = bestResult.slowPeriod; // Update indicator handles IndicatorRelease(fastMA_Handle); IndicatorRelease(slowMA_Handle); fastMA_Handle = iMA(_Symbol, PERIOD_CURRENT, MA_Fast_Period, 0, MA_Method, Applied_Price); slowMA_Handle = iMA(_Symbol, PERIOD_CURRENT, MA_Slow_Period, 0, MA_Method, Applied_Price); Print("Optimization complete. New parameters: Fast MA = ", MA_Fast_Period, ", Slow MA = ", MA_Slow_Period); } else { Print("Optimization failed to find better parameters."); } } //+------------------------------------------------------------------+ //| Test a set of parameters | //+------------------------------------------------------------------+ double TestParameters(int fastPeriod, int slowPeriod) { int maFast = iMA(_Symbol, PERIOD_CURRENT, fastPeriod, 0, MA_Method, Applied_Price); int maSlow = iMA(_Symbol, PERIOD_CURRENT, slowPeriod, 0, MA_Method, Applied_Price); if(maFast == INVALID_HANDLE || maSlow == INVALID_HANDLE) { Print("Failed to create MA indicators for testing"); return -DBL_MAX; } double fastBuffer[], slowBuffer[]; ArraySetAsSeries(fastBuffer, true); ArraySetAsSeries(slowBuffer, true); int copied = CopyBuffer(maFast, 0, 0, MinDataPoints, fastBuffer); copied = MathMin(copied, CopyBuffer(maSlow, 0, 0, MinDataPoints, slowBuffer)); if(copied < MinDataPoints) { Print("Not enough data for testing"); return -DBL_MAX; } double Close[], Open[]; ArraySetAsSeries(Close, true); ArraySetAsSeries(Open, true); copied = CopyClose(_Symbol, PERIOD_CURRENT, 0, copied, Close); copied = MathMin(copied, CopyOpen(_Symbol, PERIOD_CURRENT, 0, copied, Open)); double profit = 0; for(int i = 1; i < copied; i++) { if(fastBuffer[i] > slowBuffer[i] && fastBuffer[i-1] <= slowBuffer[i-1]) { // Buy signal profit += Close[i-1] - Open[i]; } else if(fastBuffer[i] < slowBuffer[i] && fastBuffer[i-1] >= slowBuffer[i-1]) { // Sell signal profit += Open[i] - Close[i-1]; } } IndicatorRelease(maFast); IndicatorRelease(maSlow); return profit; } //+------------------------------------------------------------------+ //| Custom function to log important events | //+------------------------------------------------------------------+ void Log(string message) { Print(TimeToString(TimeCurrent()) + ": " + message); int handle = FileOpen("EA_Log.txt", FILE_WRITE|FILE_READ|FILE_TXT); if(handle != INVALID_HANDLE) { FileSeek(handle, 0, SEEK_END); FileWriteString(handle, TimeToString(TimeCurrent()) + ": " + message + "\n"); FileClose(handle); } }
Wie Sie diesen Expert Advisor verwenden
- Kopieren Sie den gesamten Code in eine neue Datei in MetaEditor.
- Speichern Sie die Datei mit der Erweiterung .mq5 (z. B. „AutoOptimizingMA.mq5“).
- Kompilieren Sie den EA, indem Sie auf die Schaltfläche „Kompilieren“ klicken oder F7 drücken.
- Ziehen Sie in MetaTrader 5 den kompilierten EA auf einen Chart.
- Passen Sie die Eingabeparameter nach Bedarf im Einstellungsfenster des EA an.
- Aktivieren Sie AutoTrading und lassen Sie den EA laufen.
Hauptmerkmale dieses EA
- Crossover-Strategie mit gleitendem Durchschnitt: Der EA verwendet eine grundlegende gleitende Durchschnitts-Crossover-Strategie für Handelsentscheidungen.
- Auto-Optimierung: Der EA kann seine Parameter (schnelle und langsame MA-Periodenlängen) auf der Grundlage der jüngsten Marktdaten automatisch optimieren.
- Anpassbare Eingaben: Die Nutzer können verschiedene Parameter wie Losgröße, Stop Loss, Take Profit und Optimierungseinstellungen anpassen.
- Leistungsprotokollierung: Der EA enthält eine Protokollierungsfunktion, um wichtige Ereignisse und Parameteränderungen zu verfolgen.
Wichtige Hinweise
- Dieser EA wird als Lehrbeispiel zur Verfügung gestellt und sollte nicht ohne gründliche Tests und Anpassungen für den Live-Handel verwendet werden. Achten Sie auf die Systemressourcen, insbesondere wenn Sie auf einem VPS oder einem lokalen Rechner arbeiten.
- Testen Sie den EA immer ausgiebig in einer Demo-Umgebung, bevor Sie den Live-Handel in Betracht ziehen.
- Die in der Vergangenheit erzielten Ergebnisse sind keine Garantie für zukünftige Ergebnisse. Die Marktbedingungen können sich ändern, was die Leistung des EA beeinträchtigen kann.
Mit diesem EA können Sie erforschen, wie die Auto-Optimierung in der Praxis funktioniert und die Anpassungsfähigkeit Ihrer Handelsstrategie an sich ändernde Marktbedingungen verbessern. Denken Sie daran, die Leistung des Systems ständig zu überwachen und gegebenenfalls Anpassungen vorzunehmen.
Sie können wahrscheinlich bessere Ergebnisse erzielen, indem Sie weitere Bedingungen zu den Aufträgen hinzufügen, wie z. B. Deep Learning oder einen RSI oder was auch immer Sie sich vorstellen können.
Denken Sie daran, dass die Welt des algorithmischen Handels riesig ist und sich ständig weiterentwickelt. Dieser Leitfaden dient als Ausgangspunkt für Ihre Reise zur automatischen Optimierung von Expert Advisors. Wenn Sie Erfahrung sammeln und Ihr Wissen vertiefen, werden Sie zweifellos neue Techniken und Ansätze entdecken, um Ihre Handelssysteme zu verfeinern und zu verbessern.
Viel Glück, und möge Ihr Handel gewinnbringend sein!
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/15837





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