English 日本語
preview
Selbstoptimierende Expert Advisors in MQL5 (Teil 8): Analyse mehrerer Strategien (3) – Gewichtetes Abstimmungsverhalten

Selbstoptimierende Expert Advisors in MQL5 (Teil 8): Analyse mehrerer Strategien (3) – Gewichtetes Abstimmungsverhalten

MetaTrader 5Beispiele |
165 0
Gamuchirai Zororo Ndawana
Gamuchirai Zororo Ndawana

Wir werden nun die letzte Komponente zu unserem Multiple Strategy Expert Advisor hinzufügen: die Strategie Williams Percentage Reversal. Wie bereits in den vorangegangenen Artikeln haben wir zunächst eine manuelle Implementierung der Strategie hart kodiert, um ihre Leistung mit der Klasse zu vergleichen, die wir für unsere Handelsanwendung erstellen werden. Um jedoch die Leser, die die Serie verfolgt haben, nicht zu langweilen, werden wir die Testergebnisse, die wir zur Validierung der Klasse verwendet haben, weglassen. Für den Moment sollte es genügen zu sagen, dass die Leser darauf vertrauen können, dass angemessene Tests durchgeführt wurden, um die Integrität der Klasse zu überprüfen, die wir heute vorstellen.

Bei der Zusammenstellung eines Ensembles von Strategien stellt sich natürlich die Frage, wie wir beweisen können, dass alle von uns ausgewählten Strategien notwendig sind. Wie können wir einigermaßen sicher sein, dass wir mit einigen wenigen von ihnen nicht besser abschneiden würden? Wie können wir uns selbst etwas davon beweisen?

Glücklicherweise kann der genetische Optimierer bei der Beantwortung solch schwieriger Fragen helfen, vorausgesetzt, wir formulieren die Frage sorgfältig für ihn. 

Um dies zu erreichen, werden wir unseren Strategien erlauben, durch eine Demokratie zusammenzuarbeiten, wobei jede Strategie nur eine Stimme haben darf. Das Gewicht der Stimme, die jede Strategie abgibt, kann ein Tuning-Parameter sein, der vom genetischen Optimierer angepasst wird. Wenn der Optimierer feststellt, dass eine unserer Strategien keinen positiven Beitrag zur Gesamtleistung leistet, setzt er die Gewichtung der Stimme dieser Strategie auf nahezu Null. Ebenso werden die Strategien, die rentabel sind, mehr Gewicht erhalten.

Daher stellen wir diesen Rahmen als eine gewichtete Abstimmungspolitik vor, bei der wir zunächst ein Benchmark-Leistungsniveau festlegen, indem wir jeder unserer Strategien gleichmäßig verteilte Stimmgewichte zuweisen. In unserem Beispiel beginnt jede Strategie mit einer Stimmgewichtung von 0,5 auf einer Skala von 0 bis 1. 

Von dort aus erlauben wir dem genetischen Optimierer, diese Gewichte anzupassen, um die Rentabilität zu maximieren und zu bestimmen, ob alle drei Strategien wirklich hilfreich sind.

Es stellt sich heraus, dass dieses Verfahren eine breite Palette verschiedener Konfigurationen liefert, die jeweils zeigen, wie sich die Nützlichkeit einer Strategie je nach den jeweiligen Strategieeinstellungen ändern kann. In jeder einzelnen Konfiguration verschiebt sich das Gewicht der einzelnen Strategien. So kann es eine Konstellation geben, in der sich nur eine Strategie als nützlich erweist, während in einer anderen Konfiguration alle drei einen positiven Beitrag leisten. 

Das macht die Frage „Sind alle drei Strategien notwendig?“ zu einer echten Herausforderung, die es zu beantworten gilt. Unsere Ergebnisse deuten darauf hin, dass die Antwort von der Konfiguration abhängt, die die Anwendung in erster Linie verwendet. Lassen Sie uns beginnen.


Erste Schritte in MQL5

Am Ende unserer Diskussion kann unser Vererbungsbaum für Handelsstrategien wie in Abbildung 1 unten dargestellt werden. Wir werden 3 individuelle Handelsstrategien verwenden:

  1. Relative Strength Index Momentum Strategie
  2. Strategie des Kreuzens von gleitenden Durchschnitten
  3. Williams Percent Range Reversal Strategie

Jede mit gemeinsamer Funktionalität, z. B. der Möglichkeit, einen Kauf- oder Verkaufs-Einstieg zu signalisieren. Unsere drei Strategien haben alle einen gemeinsamen Vorfahren. Dies ist wichtig, um sicherzustellen, dass wir in allen unseren Klassen einen einheitlichen Nutzen haben.

In der heutigen Diskussion werden wir uns auf die Umsetzung der letzten der drei in Abbildung 1 dargestellten Strategien konzentrieren: die Williams Percent Range Strategie. Von dort aus passt unser genetischer Optimierer die den einzelnen Strategien zugewiesenen Gewichte an, um sicherzustellen, dass die am wenigsten rentable Strategie die Leistung unserer Anwendung nicht beeinträchtigt.

Abbildung 1: Der aktuelle Stand unseres Vererbungsbaums, der von unseren Handelsstrategien gemeinsam genutzt wird

Zusätzlich haben wir in Abbildung 2 visuelle Hilfen bereitgestellt, um die Kernideologie hinter unserer Strategie zu veranschaulichen. Beachten Sie, dass sich in der Abbildung 2 die Gesamtgewichte aller Stimmen nicht zu eins addieren. Obwohl es üblich ist, eine solche Einschränkung vorzunehmen, haben wir uns entschieden, dies hier nicht zu tun. Möglicherweise werden wir diese Variante in Zukunft erforschen, da sie einen etwas anderen Algorithmus als den heute implementierten erfordern würde.

Im Moment erlauben wir dem genetischen Optimierer einfach, für jede der drei Strategien einen Wert von und einschließlich 0 und 1 zuzuweisen. Für unseren genetischen Optimierer ist es einfacher, profitable Strategien zu entwickeln, wenn er die am wenigsten profitable Strategie nicht berücksichtigen muss. Dies ist der Grund für unsere Diskussion: Wir wollen zeigen, dass der genetische Optimierer auch unseren Baum von Handelsstrategien beschneiden kann, während er andere wichtige Parameter unserer Strategie abstimmt. 

Abbildung 2: Visualisierung der Gewichtung der einzelnen Strategien durch den genetischen Optimierer

Der erste Schritt bei der Umsetzung unserer Strategie besteht darin, die Abhängigkeiten zu laden. Die erste Abhängigkeit ist, wie schon bei unserer Williams Percent Range (WPR) Strategie, das Laden der zuvor erstellten Single-Buffer Williams Percentage Indicator Klasse. Danach laden wir die übergeordnete Strategieklasse, die wir ebenfalls in einer separaten Diskussion entwickelt haben.

//+------------------------------------------------------------------+
//|                                                  WPRReversal.mqh |
//|                                               Gamuchirai Ndawana |
//|                    https://www.mql5.com/en/users/gamuchiraindawa |
//+------------------------------------------------------------------+
#property copyright "Gamuchirai Ndawana"
#property link      "https://www.mql5.com/en/users/gamuchiraindawa"
#property version   "1.00"

//+------------------------------------------------------------------+
//| Dependencies                                                     |
//+------------------------------------------------------------------+
#include <VolatilityDoctor\Indicators\WPR.mqh>
#include <VolatilityDoctor\Strategies\Parent\Strategy.mqh>

Sobald unsere Abhängigkeiten geladen sind, können wir mit der Definition der Mitglieder unserer Klasse beginnen. Das erste Element verweist auf den Williams Percent Range Indikator, den wir verwenden werden. Dies wird ein privates Mitglied sein – das einzige private Mitglied unserer Klasse. Die übrigen Mitglieder sind öffentliche Klassenmitglieder. Dazu gehören insbesondere der Konstruktor, der Destruktor und die vom Elternteil geerbten virtuellen Methoden.

class WPRReversal : public Strategy
  {
private:
                     //--- The instance of the RSI used in this strategy
                     WPR *my_wpr;

public:
                     //--- Class constructor 
                     WPRReversal(string user_symbol,ENUM_TIMEFRAMES user_timeframe,int user_period);
                     
                     //--- Class destructor
                    ~WPRReversal();
                    
                    //--- Class overrides
                    virtual bool Update(void);
                    virtual bool BuySignal(void);
                    virtual bool SellSignal(void);
  };

Wir beginnen damit, die Aktualisierungsmethode zu überschreiben. Die Aktualisierungsmethode ruft einfach die Methode set_indicator_values auf, eine Funktion, die in allen unseren Indikatorklassen vorhanden ist. Mit dieser Funktion werden die WPR-Messwerte vom Terminal in unseren Indikatorpuffer eingefügt. Bevor die Kontrolle an den aufrufenden Kontext zurückgegeben wird, wird vorsorglich geprüft, ob der Zählerstand nicht Null ist.

//+------------------------------------------------------------------+
//| Our strategy update method                                       |
//+------------------------------------------------------------------+
bool WPRReversal::Update(void)
   {
      //--- Set the indicator value
      my_wpr.SetIndicatorValues(Strategy::GetIndicatorBufferSize(),true);
      
      //--- Check readings are valid
      if(my_wpr.GetCurrentReading() != 0) return(true);
      
      //--- Something went wrong
      return(false);
   }  

Von dort aus definieren wir zwei Methoden, um unsere Kauf- und Verkaufseinträge zu signalisieren. Diese Methoden geben einfach ein Ergebnis von true zurück, wenn die jeweiligen Bedingungen erfüllt sind.

//+------------------------------------------------------------------+
//| Check for our buy signal                                         |
//+------------------------------------------------------------------+
bool WPRReversal::BuySignal(void)
   {
      //--- Buy signals when the RSI is above 50
      return(my_wpr.GetCurrentReading()>50);
   }

//+------------------------------------------------------------------+
//| Check for our sell signal                                        |
//+------------------------------------------------------------------+
bool WPRReversal::SellSignal(void)
   {
      //--- Sell signals when the RSI is below 50
      return(my_wpr.GetCurrentReading()<50);
   }

Schließlich definieren wir unseren parametrischen Konstruktor, der das Symbol, den Zeitrahmen und die Periode aufnimmt, mit denen der WPR-Indikator initialisiert werden soll. Der Destruktor löscht dann einfach den Zeiger, den wir auf die neue Instanz unseres WPR-Klassenobjekts erstellt haben

//+------------------------------------------------------------------+
//| Our class constructor                                            |
//+------------------------------------------------------------------+
WPRReversal::WPRReversal(string user_symbol,ENUM_TIMEFRAMES user_timeframe,int user_period)
  {
   my_wpr = new WPR(user_symbol,user_timeframe,user_period);
   Print("WPRReversal Strategy Loaded.");
  }
  
//+------------------------------------------------------------------+
//| Our class destructor                                             |
//+------------------------------------------------------------------+
WPRReversal::~WPRReversal()
  {
   delete my_wpr;
  }
//+------------------------------------------------------------------+


Aufbau des Expertenberaters

Wir beginnen nun mit der Definition des Expertenberaters, den wir in unserem aktuellen Setup verwenden werden. Der erste Teil unseres Expertenberaters sind die Systemkonstanten, die wir aus Gründen der Reproduzierbarkeit in unseren Tests beibehalten werden. Einfache Parameter – wie die Verschiebung des gleitenden Durchschnitts und die Art des gleitenden Durchschnitts, den wir verwenden wollen – müssen festgelegt werden. Diese werden auf Werte gesetzt, die leicht zu merken sind, z. B. eine Verschiebung von Null.

//+------------------------------------------------------------------+
//|                                                   MSA Test 1.mq5 |
//|                                               Gamuchirai Ndawana |
//|                    https://www.mql5.com/en/users/gamuchiraindawa |
//+------------------------------------------------------------------+
#property copyright "Gamuchirai Ndawana"
#property link      "https://www.mql5.com/en/users/gamuchiraindawa"
#property version   "1.00"

//+------------------------------------------------------------------+
//| System constants                                                 |
//+------------------------------------------------------------------+
//--- Fix any parameters that can afford to remain fixed
#define MA_SHIFT         0
#define MA_TYPE          MODE_EMA
#define RSI_PRICE        PRICE_CLOSE

Außerdem müssen wir bestimmte Nutzereingaben akzeptieren. Erinnern Sie sich an unsere Analogie: Wir beabsichtigen, diese Eingabevorschläge des genetischen Optimierers zu akzeptieren. Die ersten drei Eingabegruppen dürften dem Leser recht vertraut sein. Dies sind einfach die Zeiträume, die wir mit unseren technischen Indikatoren verwenden werden.

Die Eingabegruppe, die uns für diese Diskussion besonders interessiert, ist die letzte: die Gruppe der globalen Strategieparameter. Dort werden die Gewichte, die wir heute einstellen, gespeichert. Einstellungen wie die Haltedauer und der Zeitrahmen der Strategie sollten unseren wiederkehrenden Lesern bereits bekannt sein. Neue Leser sollten jedoch wissen, dass sich die Haltedauer darauf bezieht, wie lange wir warten, bevor wir davon ausgehen, dass eine Position ihre Fälligkeit erreicht hat und geschlossen werden sollte. Diese Haltedauer hängt natürlich vom Zeitrahmen der Strategie ab. Zum Beispiel bedeutet eine Haltedauer von 5 bei einem Zeitrahmen von M10, dass wir die Position 50 Minuten lang halten, bevor wir sie schließen.

//+------------------------------------------------------------------+
//| User Inputs                                                      |
//+------------------------------------------------------------------+
input   group          "Moving Average Strategy Parameters"
input   int             MA_PERIOD                       =        10;//Moving Average Period

input   group          "RSI Strategy Parameters"
input   int             RSI_PERIOD                      =         15;//RSI Period

input   group          "WPR Strategy Parameters"
input   int             WPR_PERIOD                      =         30;//WPR Period

input   group          "Global Strategy Parameters"
input   ENUM_TIMEFRAMES STRATEGY_TIME_FRAME             = PERIOD_D1;//Strategy Timeframe
input   int             HOLDING_PERIOD                  =         5;//Position Maturity Period
input   double          weight_1                        =       0.5;//Strategy 1 vote weight
input   double          weight_2                        =       0.5;//Strategy 2 vote weight
input   double          weight_3                        =       0.5;//Strategy 3 vote weight

Als Nächstes folgen die Abhängigkeiten, die unsere Handelsanwendung benötigt. Die erste Abhängigkeit ist die Handelsbibliothek, die unsere Basisabhängigkeit darstellt. Es hilft uns bei der Verwaltung von Positionen. Von dort aus gibt es weitere nutzerdefinierte Abhängigkeiten wie TimeInfo und TradeInfo, mit deren Hilfe wir wissen, wann wir auf Marktinformationen reagieren können, und die uns Zugang zu den Mindesthandelsebenen, dem Briefkurs bzw. dem handelbaren Mindestwert bieten.

Die verbleibenden drei Abhängigkeiten stammen aus den Strategieklassen, die wir im Laufe dieser Serie gemeinsam entwickelt haben. Diese sollten Ihnen bereits bekannt sein – und wenn Sie ein neuer Leser sind, dann sollte zumindest die allerletzte Abhängigkeit erkennbar sein, denn das ist es, was wir heute gemeinsam aufgebaut haben

//+------------------------------------------------------------------+
//| Dependencies                                                     |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
#include <VolatilityDoctor\Time\Time.mqh>
#include <VolatilityDoctor\Trade\TradeInfo.mqh>
#include <VolatilityDoctor\Strategies\OpenCloseMACrossover.mqh>
#include <VolatilityDoctor\Strategies\RSIMidPoint.mqh>
#include <VolatilityDoctor\Strategies\WPRReversal.mqh>

Außerdem benötigen wir einige globale Variablen, z. B. Handler für unsere nutzerdefinierten Objekte, und einen Timer, mit dem wir verfolgen können, wie nahe wir der Fälligkeit unserer Positionen sind.

//+------------------------------------------------------------------+
//| Global Variables                                                 |
//+------------------------------------------------------------------+

//--- Custom Types
CTrade               Trade;
Time                 *TradeTime;
TradeInfo            *TradeInformation;
RSIMidPoint          *RSIMid;
OpenCloseMACrossover *MACross;
WPRReversal          *WPRR;

//--- System Types
int                  position_timer;

Wenn unsere Anwendung zum ersten Mal initialisiert wird, erstellen wir neue Instanzen unserer nutzerdefinierten Klassen, wie z. B. die Strategien und die TradeInfo-Klasse. 

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Create dynamic instances of our custom types
   TradeTime        = new Time(Symbol(),STRATEGY_TIME_FRAME);
   TradeInformation = new TradeInfo(Symbol(),STRATEGY_TIME_FRAME);
   MACross          = new OpenCloseMACrossover(Symbol(),STRATEGY_TIME_FRAME,MA_PERIOD,MA_SHIFT,MA_TYPE);
   RSIMid           = new RSIMidPoint(Symbol(),STRATEGY_TIME_FRAME,RSI_PERIOD,RSI_PRICE);
   WPRR             = new WPRReversal(Symbol(),STRATEGY_TIME_FRAME,WPR_PERIOD);
//--- Everything was fine
   return(INIT_SUCCEEDED);
  }
//--- End of OnInit Scope

Wenn die Anwendung nicht mehr verwendet wird, löschen wir diese nutzerdefinierten Objekte, um sicherzustellen, dass kein Speicherplatz verloren geht.

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the dynamic objects
   delete TradeTime;
   delete TradeInformation;
   delete MACross;
   delete RSIMid;
  }
//--- End of Deinit Scope

Immer wenn wir neue Kursdaten erhalten, prüfen wir zunächst, ob sich eine neue Kerze gebildet hat. Wenn das der Fall ist, werden wir die Parameter und Indikatorwerte in unseren Strategien aktualisieren. Wenn wir keine offenen Positionen mehr haben, setzen wir unseren Positionstimer zurück und prüfen, ob ein Signal vorliegt. Andernfalls, wenn die Positionen bereits offen sind, verfolgen wir, wie nah wir an der Fälligkeit sind, während wir uns darauf vorbereiten, die Position abzubauen.

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- Check if a new daily candle has formed
   if(TradeTime.NewCandle())
     {
      //--- Update strategy
      Update();

      //--- If we have no open positions
      if(PositionsTotal() == 0)
        {
         //--- Reset the position timer
         position_timer = 0;

         //--- Check for a trading signal
         CheckSignal();
        }
      //--- Otherwise
      else
        {
         //--- The position has reached maturity
         if(position_timer == HOLDING_PERIOD)
            Trade.PositionClose(Symbol());
         //--- Otherwise keep holding
         else
            position_timer++;
        }
     }
  }
//--- End of OnTick Scope

Die Aktualisierungsmethode wird durch den einfachen Aufruf der Aktualisierungsfunktion implementiert, die mit jeder unserer Strategien verbunden ist. 

//+------------------------------------------------------------------+
//| Update our technical indicators                                  |
//+------------------------------------------------------------------+
void Update(void)
  {
//--- Update the strategy
   RSIMid.Update();
   MACross.Update();
   WPRR.Update();
  }
//--- End of Update Scope

Die Methode check_signal ist interessant, weil sie so aufgebaut ist. Das heißt, wir beginnen mit der Initialisierung der Gesamtzahl der Stimmen auf Null. Wenn am Ende des Prozesses die Gesamtzahl der Stimmen positiv ist, kaufen wir. Andernfalls, wenn die Gesamtzahl der Stimmen negativ ist, verkaufen wir. Von dort aus überprüfen wir, welches Signal von jeder Strategie erzeugt wird. Wenn eine Strategie ein Kaufsignal erzeugt, addieren wir das Gewicht dieser Strategie zum Gesamtvotum. Wenn sie ein Verkaufssignal erzeugt, ziehen wir das Gewicht der Strategie von der Gesamtbewertung ab. Jede Strategie hat einen Zug zur Abstimmung. Am Ende werten wir die Gesamtstimmen nach den soeben beschriebenen Regeln aus.

//+------------------------------------------------------------------+
//| Check for a trading signal using our cross-over strategy         |
//+------------------------------------------------------------------+
void CheckSignal(void)
  {
   double vote = 0;

   if(MACross.BuySignal())
      vote += weight_1;
   else
      if(MACross.SellSignal())
         vote -= weight_1;

   if(RSIMid.BuySignal())
      vote += weight_2;
   else
      if(RSIMid.SellSignal())
         vote -= weight_2;

   if(WPRR.BuySignal())
      vote += weight_3;
   else
      if(WPRR.SellSignal())
         vote -= weight_3;

//--- Long positions when the close moving average is above the open
   if(vote > 0)
     {
      Trade.Buy(TradeInformation.MinVolume(),Symbol(),TradeInformation.GetAsk(),0,0,"");
      return;
     }

//--- Otherwise short
   else
      if(vote < 0)
        {
         Trade.Sell(TradeInformation.MinVolume(),Symbol(),TradeInformation.GetBid(),0,0,"");
         return;
        }
  }
//--- End of CheckSignal Scope

Wie bei jeder Anwendung müssen wir am Ende alle von uns erstellten Systemkonstanten vereinheitlichen.

//+------------------------------------------------------------------+
//| Undefine system constants                                        |
//+------------------------------------------------------------------+
#undef MA_SHIFT
#undef RSI_PRICE
#undef MA_TYPE
//+------------------------------------------------------------------+

Wir sind nun bereit, mit der Erprobung und Optimierung unserer Ausbildungsstrategie zu beginnen. Wir beginnen mit der Auswahl des Expertenberaters, den wir gerade gemeinsam erstellt haben. Von dort aus geben wir das Symbol an, mit dem wir unsere Anwendung testen wollen. Wir haben den EURUSD während unserer gesamten Diskussion auf dem täglichen Zeitrahmen verwendet, wie bereits erwähnt. Die Testtermine werden anhand eines nutzerdefinierten Intervalls ausgewählt, und wir haben Tests von Februar 2023 bis Mai 2025 durchgeführt.

Abbildung 3: Die Einstellungen und Daten, die wir für unsere genetische Optimierung verwenden werden

Für den Vorwärtstest wählen wir die Hälfte der Daten aus, d. h. die erste Hälfte wird für den Backtest und die zweite Hälfte für den Vorwärtstest verwendet. Der Vorwärtstest soll zeigen, welche Strategien stabil sind und welche sich wahrscheinlich zu stark an den Rückentest anpassen. Für eine möglichst authentische Simulation von Marktereignissen wählen wir immer eine zufällige Verzögerung, und unsere Modellierung sollte auf realen Ticks basieren.

Abbildung 4: Anweisung an den genetischen Optimierer, auf welchen Werten und in welchen Intervallen er die Parameter unserer Strategien durchsuchen soll

Für die Optimierung schließlich wählen Sie den schnellen genetischen Algorithmus. Die Gesamtzahl der Parameter in unserer Strategie ist eine besondere Dimension, die wir nach Kräften zu kontrollieren und zu begrenzen versucht haben. Aber wie wir sehen, ist die Gesamtzahl der Schritte, die zur Optimierung der Strategie erforderlich sind, selbst bei bescheidenen Einstellungen, beträchtlich gestiegen. Sie ist in der Tat in nur einem Schritt bemerkenswert groß geworden. Daher hielt ich es für notwendig, dass wir einen Teil der Arbeit in die MQL5 Cloud verlagern. Um mitzumachen, müssen Sie sich zunächst bei Ihrem MQL5-Konto anmelden und einen positiven Kontostand haben. 

Abbildung 5: Anmeldung bei Ihrem MQL5-Nutzerkonto über das MetaTrader 5-Terminal

Starten Sie einfach das Optimierungsverfahren, klicken Sie dann mit der rechten Maustaste auf die Anzahl der auf Ihrem Rechner verfügbaren Kerne und wählen Sie MQL5 Cloud Network verwenden. All dies wird auf der Registerkarte Agenten Ihres Strategietesters durchgeführt.

Abbildung 6: Aktivierung der MQL5-Cloud, um die Backtests zu beschleunigen

Sobald Sie die MQL5 Cloud aktivieren, werden einige der Aufgaben, die auf Ihrem Rechner ausgeführt werden, in die Cloud verlagert. Dadurch wird das Optimierungsverfahren beschleunigt, und wir kommen hoffentlich schneller zu unseren Ergebnissen – vorausgesetzt, das Netz ist sicher und zuverlässig.

Abbildung 7: Anschluss an eines der verfügbaren Rechenzentren in Ihrer Nähe

Die Optimierungsergebnisse stellen die Tests dar, die mit historischen Daten durchgeführt werden, die dem genetischen Optimierer zugänglich sind. Auf diese Weise kann sie die Leistung der Strategie bewerten und die Parameter entsprechend anpassen, um die Leistung zu verbessern. Der genetische Optimierer hat jedoch keinen Zugriff auf die Ergebnisse der Vorwärtstests – diese spiegeln wider, wie die gewählten Strategieeinstellungen außerhalb der Stichprobe abschneiden.

Aus den Backtest-Ergebnissen können wir ersehen, dass die Gewinnniveaus denjenigen entsprechen, die in früheren Versionen unserer Handelsanwendung erzielt wurden. Bei der Betrachtung der leistungsstärksten Strategien fällt auf, dass die Gewichtung der einzelnen Teilstrategien zwischen 0,4 und 0,8 liegt. Diese Spitzengewichte liegen alle recht nahe beieinander, was darauf hindeutet, dass bei der besten Konfiguration im Backtest alle Strategien zum Einsatz kamen.

Abbildung 8: Die Backtest-Ergebnisse unseres genetischen Optimierungsprozesses

Wenn wir uns jedoch dem Vorwärtstest zuwenden, stellen wir fest, dass sich die besten Strategien meist auf nur zwei Strategien stützen. Tatsächlich hatten die Top-Strategien eine minimale Gewichtung für Strategie Drei – einige wiesen ihr sogar eine Gewichtung von Null zu.

Enttäuschend ist, dass nur wenige der Strategien, die im Vorwärtstest am besten abschnitten, auch im Backtest profitabel waren. Unter den Strategien, die in beiden Tests gut abschnitten, konnten wir jedoch erneut beobachten, dass Strategie Drei geringe Gewichte aufwies – selbst in den stabilsten Konfigurationen, die wir finden konnten.

Dies legt den Gedanken nahe, die Strategie Drei fallen zu lassen, da sie keinen nennenswerten Beitrag zu den leistungsstärksten Strategien des Vorwärtstests geleistet hat. Diese Schlussfolgerung basiert jedoch auf der profitabelsten Konfiguration, die gefunden wurde – und es ist nicht immer ratsam, auf diese Weise Schlussfolgerungen zu ziehen, da dies dazu führen kann, dass wir unsere Entscheidungen zu sehr an die vorliegenden Daten anpassen.

Betrachtet man jedoch alle Strategien, die in beiden Tests profitabel waren, so stellt man fest, dass in den meisten Fällen die Gewichte aller drei Strategien relativ nahe beieinander lagen. Nur in diesem einen herausragenden Fall hatte Strategie Drei das geringste Gewicht und die beste Leistung. Es ist eine Herausforderung, unter dieser Unsicherheit Entscheidungen zu treffen. Dies ist jedoch die Art der Herausforderung, vor der wir stehen.

In der Überzeugung, dass unser Handeln auf die bestmögliche Leistung ausgerichtet ist, werden wir daher zu dem Schluss kommen, dass Strategie Drei möglicherweise nicht so wichtig ist, und wir werden weiterhin nur die ersten beiden Strategien anwenden.

Abbildung 9: Die vorläufigen Ergebnisse unseres genetischen Optimierungsprozesses legen nahe, dass Strategie 3 für unseren Erfolg nicht so wichtig ist.


Schlussfolgerung

Wie Sie in unserer Diskussion gesehen haben, kann die Bestimmung der optimalen Anzahl von Strategien, die in einer Gesamtanwendung mit mehreren Strategien verwendet werden sollen, eine äußerst schwierige Aufgabe sein. Wir wissen nicht immer von Anfang an, ob wir eine, fünf oder zehn verschiedene Strategien benötigen.

Die wichtigste Erkenntnis ist jedoch, dass unser genetischer Optimierer uns helfen kann, solche schwierigen Fragen mit Leichtigkeit zu lösen. Es ist auch erwähnenswert, dass der genetische Optimierer als ein weitaus leistungsfähigeres Werkzeug angesehen werden kann als das populäre ChatGPT und andere LLMs, auf die sich Entwickler verlassen können, um einige der Fragen zu beantworten, mit denen sie in ihrem Bemühen, algorithmische Anwendungen zu erstellen, konfrontiert werden.

Wie wir bereits in unserer früheren Artikelserie Überwindung der Grenzen der KI behandelt haben. Wir haben festgestellt, dass Algorithmen, die auf einen bestimmten Bereich zugeschnitten sind, für uns wertvoller sind als Algorithmen, die für allgemeine Zwecke eingesetzt werden. ChatGPT und andere LLMs dieser Art sind Allzweckalgorithmen, während der genetische Optimierer, der in Ihr Exemplar von MetaTrader 5 eingebettet ist, ein bereichsspezifischer Algorithmus ist, was ihn dem Versuch, ChatGPT die gleiche Frage zu stellen, weit überlegen macht.

Wir haben auch gezeigt, wie Sie die MQL5 Cloud nutzen können, um Ihre Backtests- und Optimierungsprozesse zu beschleunigen. Dieser Artikel wäre ohne den Einsatz der MQL5 Cloud möglicherweise nicht rechtzeitig fertig geworden. Der Einstieg ist einfach, und die Preise sind sehr günstig.

Sie haben die Möglichkeit, rund um die Uhr Cloud Computing mit mehreren redundanten Rechenzentren zu nutzen. Für den Fall, dass Sie die Verbindung aufgrund von Netzwerkproblemen verlieren, bleiben Sie fast immer verbunden. Alles in allem sind die MQL5 Cloud und der Genetic Optimizer unverzichtbare Werkzeuge im Werkzeugkasten des modernen Algorithmenentwicklers.

Diese Übung wird unsere Entscheidungsprozesse bei der Entwicklung statistischer Modelle für unsere Handelsstrategie unterstützen.

In unseren weiteren Diskussionen werden wir bereits erfahren haben, dass die ersten beiden Strategien ausreichen, um eine binäre Klassifizierungsaufgabe zu entwickeln, bei der entweder Strategie Eins oder Strategie Zwei am profitabelsten ist. Anschließend werden wir die Leistung unserer statistischen Modellierungsanwendung mit der ursprünglichen Strategie vergleichen, die wir gemeinsam entwickelt haben.

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

Beigefügte Dateien |
MSA_Test_3.mq5 (6.82 KB)
WPRReversal.mqh (3.44 KB)
Automatisieren von Handelsstrategien in MQL5 (Teil 23): Zone Recovery mit Trailing- und Basket-Logik Automatisieren von Handelsstrategien in MQL5 (Teil 23): Zone Recovery mit Trailing- und Basket-Logik
In diesem Artikel erweitern wir unser Zone Recovery System durch die Einführung von Trailing-Stops und Multi-Basket-Handelsfunktionen. Wir untersuchen, wie die verbesserte Architektur dynamische Trailing-Stops verwendet, um Gewinne zu sichern, und ein Basket-Management-System, um mehrere Handelssignale effizient zu verarbeiten. Durch Implementierung und Backtests demonstrieren wir ein robusteres Handelssystem, das auf eine adaptive Marktperformance zugeschnitten ist.
Vom Neuling zum Experten: Animierte Nachrichten-Schlagzeile mit MQL5 (IV) – Markteinsichten durch lokal verfügbare KI-Modelle Vom Neuling zum Experten: Animierte Nachrichten-Schlagzeile mit MQL5 (IV) – Markteinsichten durch lokal verfügbare KI-Modelle
In der heutigen Diskussion untersuchen wir, wie man Open-Source-KI-Modelle selbst hosten und zur Gewinnung von Markteinblicken nutzen kann. Dies ist Teil unserer laufenden Bemühungen, den News Headline EA zu erweitern, indem wir einen AI Info-Streifen einführen, die ihn in ein Multi-Integrations-Assistenz-Tool verwandelt. Der aktualisierte EA zielt darauf ab, Händler durch Kalenderereignisse, aktuelle Finanznachrichten, technische Indikatoren und jetzt auch durch KI-generierte Marktperspektiven auf dem Laufenden zu halten - und bietet so zeitnahe, vielfältige und intelligente Unterstützung für Handelsentscheidungen. Seien Sie dabei, wenn wir praktische Integrationsstrategien erforschen und untersuchen, wie MQL5 mit externen Ressourcen zusammenarbeiten kann, um ein leistungsstarkes und intelligentes Arbeitsterminal für den Handel aufzubauen.
Vom Neuling zum Experten: Animierte Nachrichtenschlagzeilen mit MQL5 (V) – Ereignis-Erinnerungssystem Vom Neuling zum Experten: Animierte Nachrichtenschlagzeilen mit MQL5 (V) – Ereignis-Erinnerungssystem
In dieser Diskussion werden wir weitere Fortschritte bei der Integration einer verfeinerten Logik zur Ereigniswarnung für die vom „News Headline EA“ angezeigten wirtschaftlichen Kalenderereignisse untersuchen. Diese Verbesserung ist von entscheidender Bedeutung, da sie sicherstellt, dass die Nutzer rechtzeitig vor wichtigen Ereignissen benachrichtigt werden. Nehmen Sie an dieser Diskussion teil und erfahren Sie mehr.
Automatisieren von Handelsstrategien in MQL5 (Teil 22): Erstellen eines Zone Recovery Systems für den Trendhandel mit Envelopes Automatisieren von Handelsstrategien in MQL5 (Teil 22): Erstellen eines Zone Recovery Systems für den Trendhandel mit Envelopes
In diesem Artikel entwickeln wir ein Zone Recovery System, das mit einer Envelopes-Trend-Handelsstrategie in MQL5 integriert ist. Wir skizzieren die Architektur für die Verwendung von RSI- und Envelopes-Indikatoren, um Handelsgeschäfte auszulösen und Erholungszonen zu verwalten, um Verluste zu mindern. Durch Implementierung und Backtests zeigen wir, wie man ein effektives automatisches Handelssystem für dynamische Märkte aufbaut.