English 日本語
preview
Erstellen von selbstoptimierenden Expert Advisor in MQL5 (Teil 5): Selbstanpassende Handelsregeln

Erstellen von selbstoptimierenden Expert Advisor in MQL5 (Teil 5): Selbstanpassende Handelsregeln

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

Technische Indikatoren sind zu einem unverzichtbaren Instrument in den meisten algorithmischen Handelsanwendungen geworden, da sie genau definierte Handelssignale liefern und eine schnelle Entwicklung von Anwendungen ermöglichen. Leider kommt es häufig vor, dass Händler mit widrigen Marktbedingungen konfrontiert werden, die von den standardisierten Regeln für die Verwendung eines technischen Indikators abweichen. 

Der Relative-Stärke-Indikator wird beispielsweise verwendet, um die Stärke von Kursveränderungen auf einem bestimmten Markt zu messen. Es ist weithin als beste Praxis für Händler anerkannt, ihre Käufe zu tätigen, wenn der RSI Werte unter 30 angibt, und zu verkaufen, wenn RSI Werte über 70 zu beobachten sind. 

In der nachstehenden Abbildung 1 haben wir einen RSI mit 20 Perioden auf den Tagespreis von Gold in US-Dollar angewandt. Der Leser kann feststellen, dass keiner der erwarteten Messwerte über einen längeren Zeitraum von 3 Monaten beobachtet wurde. Anhand der im Chart eingezeichneten Trendlinie können wir erkennen, dass sich der Goldpreis von September 2019 bis Dezember 2019 in einem starken Abwärtstrend befand.

Wenn der Leser jedoch genauer hinschaut, wird er feststellen, dass unser RSI-Indikator während dieses Abwärtstrends nicht die erwarteten Signale für den Einstieg in eine Verkaufsposition geliefert hat.

Bildschirmfoto 1

Abb. 1: Es ist möglich, dass die Marktbedingungen nicht den erwarteten Wert eines technischen Indikators ergeben, was zu unbeabsichtigtem Verhalten führt.

Manche Leser mögen sich denken: „Man kann versuchen, seine Periode entsprechend anzupassen, und wird das standardisierte Ergebnis erhalten“. Die Anpassung des Zeitraums ist jedoch nicht immer eine gute Lösung. Mitglieder unserer Gemeinschaft, die an der Analyse mehrerer Symbole interessiert sind, haben beispielsweise bestimmte Zeiträume, die das gesuchte marktübergreifende Muster am besten aufzeigen, und müssen daher ihre Zeiträume festhalten.

Darüber hinaus müssen Leser, die jeweils nur einen einzigen Markt handeln, bedenken, dass eine Erhöhung des RSI-Zeitraums das Problem verschlimmert. Ebenso nimmt eine Verkürzung der RSI-Periode mehr Rauschen aus dem Markt auf und verringert die Gesamtqualität der Handelssignale.

Kurz gesagt, ein leichtfertiges Herangehen an dieses Problem kann zu unbeabsichtigtem Verhalten von Handelsanwendungen führen, was zu entgangenen Gewinnen aufgrund nicht genutzter Gelegenheiten oder zu einem höheren als dem erwarteten Marktengagement führt, da die Ausstiegsbedingungen nicht vollständig erfüllt sind.


Überblick über die Methodik

Es liegt auf der Hand, dass wir die Anwendungen so gestalten müssen, dass sie ihre Handelsregeln an die vorliegenden historischen Daten anpassen können. Wir werden die von uns vorgeschlagene Lösung in den folgenden Abschnitten dieses Artikels im Detail diskutieren. Die von uns vorgeschlagene Lösung lässt sich am besten so zusammenfassen: Um zu wissen, was eine starke Bewegung ist, muss man zunächst wissen, wie eine durchschnittliche Bewegung in diesem bestimmten Markt aussieht. Auf diese Weise kann der Leser seine Anwendungen so einstellen, dass sie nur Einstiegssignale annehmen, die über dem Durchschnitt liegen, oder noch besser, dass sie spezifischer sind und Bewegungen auswählen, die 2 oder 3 Mal über dem Durchschnitt liegen. 

Indem wir unsere Handelssignale so einstellen, dass sie sich an der Größe einer durchschnittlichen Bewegung orientieren, eliminieren wir effektiv die Möglichkeit, längere Zeiträume ohne ein Handelssignal zu durchlaufen, und machen hoffentlich Schluss mit der Notwendigkeit, den Zeitraum der RSI-Berechnung endlos zu optimieren. 


Erste Schritte in MQL5

Unsere Untersuchung beginnt damit, dass wir mit dem MetaTrader 5 Strategy Tester ein Basis-Leistungsniveau festlegen. Unsere Strategie wird als Gerüst verwendet, das der Leser durch seine eigenen Handelsstrategien ersetzen soll. Wir werden eine Strategie in MQL5 entwickeln, die die Durchbrüche der wichtigen Unterstützungs- oder Widerstandsniveaus handelt. Unser RSI wird uns bestätigen, dass das Niveau erfolgreich überwunden wurde. Wir werden die Größe unserer Stop-Loss und Take-Profits in allen Versionen der Anwendung festlegen, um sicherzustellen, dass Änderungen der Rentabilität direkt auf unsere besseren Entscheidungen zurückzuführen sind. 

Es gibt verschiedene Definitionen dafür, was ein gültiges Unterstützungs- oder Widerstandsniveau ist. Aber für unsere Diskussionen reicht es aus, wenn wir wissen, dass ein Unterstützungsniveau ein niedriges Preisniveau ist, das eine Preisrallye ausgelöst hat. Umgekehrt sind Widerstandsniveaus interessante Kursniveaus, die auf unseren Charts einen starken Abwärtstrend erkennen lassen. Die genaue Dauer, für die diese Niveaus gelten werden, ist zu Beginn einer Handelssitzung nicht bekannt. 

Wenn eines dieser Niveaus erfolgreich durchbrochen wird, folgt in der Regel eine volatile Kursentwicklung. Unser RSI wird uns als Richtschnur dienen, um zu entscheiden, ob wir einen Handel platzieren sollten, wenn der beobachtete Ausbruch in Aktion ist. Wir suchen nach Möglichkeiten, Kaufpositionen einzugehen, wenn die Kurse unter wichtige Unterstützungsniveaus gefallen sind, und nur dann Verkaufspositionen einzugehen, wenn das Gegenteil auf dem Widerstandsniveau der Fall ist.

Unsere Unterstützungs- und Widerstandsniveaus finden wir, indem wir die aktuellen Kursniveaus mit den entsprechenden Niveaus von vor 5 Tagen vergleichen. 

Bildschirmfoto 2

Abb. 2: Visualisierung von Unterstützungs- und Widerstandsniveaus beim XAGUSD

Einige Parameter unserer Diskussion werden fest bleiben. Um eine unnötige Wiederholung derselben Informationen zu vermeiden, werden diese festen Parameter hier besprochen. Unsere Diskussion wird darauf abzielen, Ausbrüche in Unterstützungs- und Widerstandsniveaus zu handeln, und zwar auf dem Tageskurs von Silber in US-Dollar (XAGUSD). Wir werden unsere Strategie mit historischen M15-Daten vom 1. Januar 2017 bis zum 28. Januar 2025 testen.

Bildschirmfoto 3

Abb. 3: Der Zeitraum, den wir für unsere Backtest verwenden werden

Zusätzlich werden wir während unseres Backtests die Einstellung „Zufällige Verzögerung“ verwenden, da dies der Erfahrung des realen Handels ähnelt. Und wir haben „Jeder Tick anhand realer Ticks“ gewählt, um unsere Tests mit tatsächlichen Marktdaten durchzuführen, die wir von unserem Broker erhalten.

Bildschirmfoto 4

Abb. 4: Die zweite Gruppe von festen Einstellungen in unserem heutigen Backtest

Nachdem dies erledigt ist, können wir uns nun auf die Erstellung unserer Basisanwendung mit MQL5 konzentrieren. Wir beginnen mit der Definition kritischer Systemkonstanten, die während unseres Gesprächs nicht verändert werden sollen. Diese Systemkonstanten definieren Parameter, die das Verhalten unserer Handelsanwendung steuern, wie z. B. die Höhe des Stop-Loss und des Take-Profits, die zu verwendenden Zeitrahmen und die Größe der einzelnen Positionen, die wir eingehen, um nur einige Aufgaben zu nennen.

//+------------------------------------------------------------------+
//|                                  Self Adapting Trading Rules.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                                                 |
//+------------------------------------------------------------------+
#define RSI_PERIOD 10              //The period for our RSI indicator
#define RSI_PRICE  PRICE_CLOSE     //The price level our RSI should be applied to
#define ATR_SIZE   1.5             //How wide should our Stop loss be?
#define ATR_PERIOD 14              //The period of calculation for our ATR indicator
#define TF_1       PERIOD_D1       //The primary time frame for our trading application
#define TF_2       PERIOD_M15      //The secondary time frame for our trading application
#define VOL        0.1             //Our trading volume   

Nun werden wir die Handelsbibliothek importieren, die uns bei der Verwaltung unserer Positionen hilft.

//+------------------------------------------------------------------+
//| Libraries we need                                                |
//+------------------------------------------------------------------+
#include <Trade/Trade.mqh>
CTrade Trade;

Als Nächstes müssen wir ein paar wichtige globale Variablen definieren.

//+------------------------------------------------------------------+
//| Global variables                                                 |
//+------------------------------------------------------------------+
int rsi_handler,atr_handler;
double rsi[],atr[];
double support,resistance;

Unsere MetaTrader 5-Anwendungen werden hauptsächlich durch Ereignisse gesteuert, die in unserem Terminal stattfinden. Wir haben nutzerdefinierte Methoden entwickelt, die nacheinander aufgerufen werden, wenn die einzelnen Terminal-Ereignisse ausgelöst werden.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   setup();
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   release();
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   update();
  }
//+------------------------------------------------------------------+

Wenn unser Indikator zum ersten Mal geladen wird, richten wir unsere technischen Indikatoren ein und setzen dann unsere Unterstützungs- und Widerstandsniveaus auf die höchsten und niedrigsten Kursniveaus, die wir in der Vorwoche beobachtet haben.

//+------------------------------------------------------------------+
//| User defined methods                                             |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Initialize our system variables                                  |
//+------------------------------------------------------------------+
void setup(void)
  {
//Load our technical indicators
   atr_handler = iATR(Symbol(),TF_1,ATR_PERIOD);
   rsi_handler = iRSI(Symbol(),TF_2,RSI_PERIOD,RSI_PRICE);
   resistance  = iHigh(Symbol(),TF_1,5);
   support     = iLow(Symbol(),TF_1,5);
  }

Wenn unsere Handelsanwendung nicht mehr genutzt wird, müssen wir die technischen Indikatoren, die wir nicht mehr verwenden, freigeben.

//+------------------------------------------------------------------+
//| Let go of resources we are no longer consuming                   |
//+------------------------------------------------------------------+
void release(void)
  {
//Free up resources we are not using
   IndicatorRelease(atr_handler);
   IndicatorRelease(rsi_handler);
  }

Unsere Aktualisierungsfunktion ist in 2 Teile unterteilt. Die erste Hälfte ist für Routineaufgaben zuständig, die einmal am Tag erledigt werden müssen, während die zweite Hälfte für Aufgaben zuständig ist, die häufig und in einem geringeren Zeitrahmen erledigt werden müssen. So können wir sicher sein, dass wir von einem abrupten oder abnormalen Marktverhalten nicht überrascht werden. 

//+------------------------------------------------------------------+
//| Update our system variables and look for trading setups          |
//+------------------------------------------------------------------+
void update(void)
  {
//Update our system variables
//Some duties must be performed periodically on the higher time frame
     {
      static datetime time_stamp;
      datetime current_time = iTime(Symbol(),TF_1,0);

      //Update the time
      if(time_stamp != current_time)
        {
         time_stamp = current_time;

         //Update indicator readings
         CopyBuffer(rsi_handler,0,0,1,rsi);
         CopyBuffer(atr_handler,0,0,1,atr);

         //Update our support and resistance levels
         support    = iLow(Symbol(),TF_1,5);
         resistance = iHigh(Symbol(),TF_1,5);
         ObjectDelete(0,"Support");
         ObjectDelete(0,"Resistance");
         ObjectCreate(0,"Suppoprt",OBJ_HLINE,0,0,support);
         ObjectCreate(0,"Resistance",OBJ_HLINE,0,0,resistance);
        }
     }

//While other duties need more attention, and must be handled on lower time frames.
     {
      static datetime time_stamp;
      datetime current_time = iTime(Symbol(),TF_2,0);
      double bid,ask;   
                  
      //Update the time
      if(time_stamp != current_time)
        {
         time_stamp = current_time;
         bid=SymbolInfoDouble(Symbol(),SYMBOL_BID);
         ask=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
         
         //Check if we have broken either extreme
         if(PositionsTotal() == 0)
            {
               //We are looking for opportunities to sell
               if(iLow(Symbol(),TF_2,0) > resistance)
                  {
                     if(rsi[0] > 70) Trade.Sell(VOL,Symbol(),bid,(ask + (ATR_SIZE * atr[0])),(ask - (ATR_SIZE * atr[0])));
                  }
              
              //We are looking for opportunities to buy
              if(iHigh(Symbol(),TF_2,0) < support)
                  {
                     if(rsi[0] < 30) Trade.Buy(VOL,Symbol(),ask,(bid - (ATR_SIZE * atr[0])),(bid + (ATR_SIZE * atr[0])));
                  }
            }
         }      
        }
     }

Schließlich müssen wir die Systemkonstanten, die wir zu Beginn der Anwendung definiert haben, zurücksetzen.

//+------------------------------------------------------------------+
//| Undefine the system constants                                    |
//+------------------------------------------------------------------+
#undef RSI_PERIOD
#undef RSI_PRICE
#undef ATR_PERIOD
#undef ATR_SIZE
#undef TF_1
#undef TF_2
#undef VOL
//+------------------------------------------------------------------+

Alles in allem sieht unsere aktuelle Codebasis so aus.

//+------------------------------------------------------------------+
//|                                  Self Adapting Trading Rules.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                                                 |
//+------------------------------------------------------------------+
#define RSI_PERIOD 10            //The period for our RSI indicator
#define RSI_PRICE  PRICE_CLOSE   //The price level our RSI should be applied to
#define ATR_SIZE   1.5             //How wide should our Stop loss be?
#define ATR_PERIOD 14            //The period of calculation for our ATR indicator
#define TF_1       PERIOD_D1     //The primary time frame for our trading application
#define TF_2       PERIOD_M15    //The secondary time frame for our trading application
#define VOL        0.1           //Our trading volume   

//+------------------------------------------------------------------+
//| Libraries we need                                                |
//+------------------------------------------------------------------+
#include <Trade/Trade.mqh>
CTrade Trade;

//+------------------------------------------------------------------+
//| Global variables                                                 |
//+------------------------------------------------------------------+
int rsi_handler,atr_handler;
double rsi[],atr[];
double support,resistance;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   setup();
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   release();
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   update();
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| User defined methods                                             |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Initialize our system variables                                  |
//+------------------------------------------------------------------+
void setup(void)
  {
//Load our technical indicators
   atr_handler = iATR(Symbol(),TF_1,ATR_PERIOD);
   rsi_handler = iRSI(Symbol(),TF_2,RSI_PERIOD,RSI_PRICE);
   resistance  = iHigh(Symbol(),TF_1,5);
   support     = iLow(Symbol(),TF_1,5);
  }

//+------------------------------------------------------------------+
//| Let go of resources we are no longer consuming                   |
//+------------------------------------------------------------------+
void release(void)
  {
//Free up resources we are not using
   IndicatorRelease(atr_handler);
   IndicatorRelease(rsi_handler);
  }

//+------------------------------------------------------------------+
//| Update our system variables and look for trading setups          |
//+------------------------------------------------------------------+
void update(void)
  {
//Update our system variables
//Some duties must be performed periodically on the higher time frame
     {
      static datetime time_stamp;
      datetime current_time = iTime(Symbol(),TF_1,0);

      //Update the time
      if(time_stamp != current_time)
        {
         time_stamp = current_time;

         //Update indicator readings
         CopyBuffer(rsi_handler,0,0,1,rsi);
         CopyBuffer(atr_handler,0,0,1,atr);

         //Update our support and resistance levels
         support    = iLow(Symbol(),TF_1,5);
         resistance = iHigh(Symbol(),TF_1,5);
         ObjectDelete(0,"Support");
         ObjectDelete(0,"Resistance");
         ObjectCreate(0,"Suppoprt",OBJ_HLINE,0,0,support);
         ObjectCreate(0,"Resistance",OBJ_HLINE,0,0,resistance);
        }
     }

//While other duties need more attention, and must be handled on lower time frames.
     {
      static datetime time_stamp;
      datetime current_time = iTime(Symbol(),TF_2,0);
      double bid,ask;

      //Update the time
      if(time_stamp != current_time)
        {
         time_stamp = current_time;
         bid=SymbolInfoDouble(Symbol(),SYMBOL_BID);
         ask=SymbolInfoDouble(Symbol(),SYMBOL_ASK);

         //Check if we have broken either extreme
         if(PositionsTotal() == 0)
           {
            //We are looking for opportunities to sell
            if(iLow(Symbol(),TF_2,0) > resistance)
              {
               if(rsi[0] > 70)
                  Trade.Sell(VOL,Symbol(),bid,(ask + (ATR_SIZE * atr[0])),(ask - (ATR_SIZE * atr[0])));
              }

            //We are looking for opportunities to buy
            if(iHigh(Symbol(),TF_2,0) < support)
              {
               if(rsi[0] < 30)
                  Trade.Buy(VOL,Symbol(),ask,(bid - (ATR_SIZE * atr[0])),(bid + (ATR_SIZE * atr[0])));
              }
           }
        }
     }
  }

//+------------------------------------------------------------------+
//| Undefine the system constants                                    |
//+------------------------------------------------------------------+
#undef RSI_PERIOD
#undef RSI_PRICE
#undef ATR_PERIOD
#undef ATR_SIZE
#undef TF_1
#undef TF_2
#undef VOL
//+------------------------------------------------------------------+

Lassen Sie uns nun beurteilen, wie gut dieser Algorithmus bei historischen Marktdaten abschneidet. Starten Sie Ihr MetaTrader 5-Terminal und wählen Sie die Anwendung aus, die wir gerade gemeinsam entwickelt haben. Erinnern Sie sich daran, dass die Testdaten und -einstellungen am Anfang dieses Abschnitts des Artikels für Sie angegeben sind.

Bildschirmfoto 5

Abb. 5: Start unseres Backtests in MetaTrader 5

Unser Expert Advisor hat keine Eingabeparameter. Sobald Sie die Anwendung geladen und die Testdaten entsprechend eingestellt haben, starten Sie den MetaTrader 5 Strategy Tester. Die folgende Abbildung 6 zeigt die Kapitalkurve, die sich aus den klassischen Handelsregeln für den RSI ergibt. 

Bildschirmfoto 6

Abb. 6: Die Kapitalkurve, die sich aus der klassischen RSI-Handelsstrategie ergibt

Abb. 7 gibt einen detaillierten Überblick darüber, wie unsere RSI-basierte Handelsanwendung beim ersten Test abgeschnitten hat. Unser Gesamtnettogewinn betrug 588,60 $ bei einer Sharpe Ratio von 0,85. Diese Ergebnisse sind bisher sehr ermutigend und werden uns als Ziel für die nächste Iteration unserer Handelsanwendung dienen.

Bildschirmfoto 7

Abb. 7: Eine detaillierte Zusammenfassung der Ergebnisse unseres Rückentests



Die Verbesserung unserer ersten Ergebnisse

Wir sind nun bei der vorgeschlagenen Lösung angelangt, die die potenziellen Probleme angeht, die durch nicht standardisierte Ausgaben des Indikators entstehen. Um die klassischen Niveaus von 70 und 30 durch optimale Niveaus zu ersetzen, die direkt aus der historischen Performance des Marktes ausgewählt werden, müssen wir zunächst die Bandbreite der Ergebnisse beobachten, die der Indikator auf dem jeweiligen Markt erzeugt. Anschließend werden die beiden parallelen Linien halbiert, die das Maximum und das Minimum der vom Indikator erzeugten Leistung markieren. Diese Halbierungslinie wird unser neuer Mittelpunkt. Beachten Sie, dass die Mitte des RSI-Indikators ursprünglich bei 50 liegt.

Sobald wir unseren neuen Mittelwert berechnet haben, zeichnen wir die absolute Differenz jedes RSI-Werts zum Mittelwert des Indikators auf und bilden den Durchschnitt, um unsere Schätzung einer durchschnittlichen Bewegung in diesem bestimmten Markt zu erhalten. Anschließend weisen wir unsere Handelsanwendung an, ihre Positionen nur dann einzugehen, wenn sie eine Veränderung des RSI-Wertes beobachtet, die 2 Mal größer ist als eine durchschnittliche Bewegung in diesem Markt. Mit diesem neuen Parameter können wir steuern, wie empfindlich unsere Handelsanwendung ist, aber wenn wir zu große Werte wählen, wie z. B. 100, wird unsere Anwendung keine Handelsgeschäfte tätigen, niemals.

Um diese Änderungen in unserer Anwendung zu implementieren, müssen wir die folgenden Änderungen vornehmen:

Vorgeschlagene Änderung Verwendungszweck
Erstellen neuer Systemkonstanten Mit diesen neuen Systemkonstanten werden die meisten Parameter der ursprünglichen Version der Anwendung korrigiert, während einige neue Parameter eingeführt werden, die wir benötigen.
Modifizierung unserer nutzerdefinierten Methoden Die nutzerdefinierten Funktionen, die wir zuvor geschrieben haben, müssen erweitert werden, um die gewünschten neuen Funktionen bereitzustellen.

Lassen Sie uns zunächst die neuen Systemkonstanten erstellen, die wir benötigen. Wir müssen dynamisch entscheiden, wie viele Balken für die Berechnungen, die wir durchführen wollen, verwendet werden sollen. Dafür wird das neue System mit der konstanten Bezeichnung „BARS“ zuständig sein. Es wird eine ganze Zahl zurückgegeben, die der Hälfte der insgesamt verfügbaren Takte entspricht. Außerdem haben wir beschlossen, dass wir nur an Veränderungen des RSI interessiert sind, die 2 Mal größer als der Durchschnitt sind. Deshalb haben wir eine neue Konstante namens „BIG SIZE“ geschaffen, die die beabsichtigte Stärke aufzeichnet, die wir hinter unseren Schritten beobachten wollen.

Schließlich werden unsere Unterstützungs- und Widerstandsniveaus durch den Vergleich des aktuellen Kurses mit dem Wert vor einer Woche oder vor 5 Tagen ermittelt.

//+---------------------------------------------------------------+
//| System constants                                              |
//+---------------------------------------------------------------+
#define RSI_PERIOD     10                                          //The period for our RSI indicator
#define RSI_PRICE      PRICE_CLOSE                                 //The price level our RSI should be applied to
#define ATR_SIZE       1.5                                         //How wide should our Stop loss be?
#define ATR_PERIOD     14                                          //The period of calculation for our ATR indicator
#define TF_1           PERIOD_D1                                   //The primary time frame for our trading application
#define TF_2           PERIOD_M15                                  //The secondary time frame for our trading application
#define VOL            0.1                                         //Our trading volume   
#define BARS           (int) MathFloor((iBars(Symbol(),TF_2) / 2)) //How many bars should we use for our calculation?
#define BIG_SIZE       2                                           //How many times bigger than the average move should the observed change be?
#define SUPPORT_PERIOD 5                                           //How far back into the past should we look to find our support and resistance levels?

Jetzt werden wir die Bedingungen ändern, die festlegen, ob wir unsere Positionen öffnen. Beachten Sie, dass wir unsere Eingaben nicht mehr auf feste Indikatorstufen setzen, sondern auf berechnete Stufen, die aus dem Speicherpuffer des Indikators abgeleitet werden.

//While other duties need more attention, and must be handled on lower time frames.
     {
      static datetime time_stamp;
      datetime current_time = iTime(Symbol(),TF_2,0);
      double bid,ask;

      //Update the time
      if(time_stamp != current_time)
        {
         time_stamp = current_time;
         bid=SymbolInfoDouble(Symbol(),SYMBOL_BID);
         ask=SymbolInfoDouble(Symbol(),SYMBOL_ASK);

         //Copy the rsi readings into a vector
         vector rsi_vector   = vector::Zeros(BARS);
         rsi_vector.CopyIndicatorBuffer(rsi_handler,0,1,BARS);

         //Let's see how far the RSI tends to deviate from its centre
         double rsi_midpoint = ((rsi_vector.Max() + rsi_vector.Min()) / 2);
         vector rsi_growth   = MathAbs(rsi_vector - rsi_midpoint);

         //Check if we have broken either extreme
         if(PositionsTotal() == 0)
           {
            //We are looking for opportunities to sell
            if(iLow(Symbol(),TF_2,0) > resistance)
              {
               if((rsi[0] - rsi_midpoint) > (rsi_growth.Mean() * BIG_SIZE))
                  Trade.Sell(VOL,Symbol(),bid,(ask + (ATR_SIZE * atr[0])),(ask - (ATR_SIZE * atr[0])));
              }

            //We are looking for opportunities to buy
            if(iHigh(Symbol(),TF_2,0) < support)
              {
               if((rsi[0] - rsi_midpoint) < (-(rsi_growth.Mean() * BIG_SIZE)))
                  Trade.Buy(VOL,Symbol(),ask,(bid - (ATR_SIZE * atr[0])),(bid + (ATR_SIZE * atr[0])));
              }
           }
        }
     }

Schließlich müssen wir die neuen Systemkonstanten, die wir erstellt haben, wieder zurücksetzen.

//+------------------------------------------------------------------+
//| Undefine the system constants                                    |
//+------------------------------------------------------------------+
#undef RSI_PERIOD
#undef RSI_PRICE
#undef ATR_PERIOD
#undef ATR_SIZE
#undef TF_1
#undef TF_2
#undef VOL
#undef BARS
#undef BIG_SIZE
#undef SUPPORT_PERIOD
//+------------------------------------------------------------------+

Wir sind nun bereit, unsere neuen dynamischen Handelsregeln für den RSI zu testen. Stellen Sie sicher, dass Sie die richtige Version des Expert Advisors in Ihrem Strategietester auswählen, bevor Sie den Test starten. Denken Sie daran, dass die Datumseinstellungen dieselben sind, die wir in der Einleitung des Artikels genannt haben.

Bildschirmfoto 8

Abb. 8: Wählen Sie die richtige Version der Handelsanwendung für unseren Test

Die von unserer neuen Version des RSI-Handelsalgorithmus erzeugte Kapitalkurve ähnelt den ersten Ergebnissen, die wir erhalten haben. Lassen Sie uns jedoch die detaillierte Zusammenfassung der Ergebnisse analysieren, um eine klare Vorstellung davon zu bekommen, welche Unterschiede erzielt wurden.

Bildschirmfoto 9

Abb. 9: Die von unserer Version des Algorithmus für den Handel nach dynamischen Regeln erzeugte Kapitalkurve

In unserem anfänglichen Test betrug unser Gesamtnettogewinn 588,60 $ bei insgesamt 136 Handelsgeschäften. Unsere neue Strategie erzielte einen Gewinn von 703,20 $ bei 121 Handelsgeschäften. Damit hat sich unsere Rentabilität um etwa 19,5 % erhöht, während die Gesamtzahl der von uns getätigten Handelsgeschäfte um etwa 11 % gesunken ist. Es ist offensichtlich, dass unser neues System uns einen klaren Wettbewerbsvorteil gegenüber den klassischen Regeln verschafft, die festlegen, wie wir den Indikator normalerweise verwenden sollten. 

Bildschirmfoto 10

Abb. 10: Die detaillierten Ergebnisse, die die Leistung unserer neuen Handelsstrategie zusammenfassen



Schlussfolgerung

Die Lösung, die wir heute untersucht haben, hat Ihnen ein Design-Muster geliefert, wie Sie Ihr MetaTrader 5-Terminal verwenden können, um Ihnen eine verfeinerte Kontrolle über die Empfindlichkeit Ihrer Handelsanwendungen zu geben. Händler, die mehrere Symbole analysieren, werden von einer neuen Perspektive profitieren, wie sie die Stärke von Änderungen der Preisniveaus über verschiedene Märkte hinweg auf objektive und durchdachte Weise vergleichen können und die Möglichkeit unbeabsichtigter Fehler ausschließen, die ihre Bemühungen leicht zunichte machen könnten.

Darüber hinaus kann der von uns vorgeschlagene Algorithmus zur sorgfältigen Ersetzung der klassischen 30- und 70-Niveaus durch optimale Niveaus, die direkt aus dem beobachteten Bereich des Indikators ausgewählt werden, wenn er auf einen bestimmten Markt angewandt wird, uns einen wesentlichen Vorteil gegenüber gelegentlichen Marktteilnehmern verschaffen, die darauf warten, dass das standardisierte Ergebnis beobachtet wird. 

Angehängte Datei Beschreibung
Selbstanpassende Handelsregeln Benchmark-Version unserer Handelsanwendung mit statischen und festen Regeln.
Selbstanpassende Handelsregeln V2 Verfeinerte Version unserer Handelsanwendung, die ihre Regeln auf der Grundlage der verfügbaren Marktdaten anpasst.

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

Entwicklung eines Toolkit zur Analyse von Preisaktionen (Teil 10): External Flow (II) VWAP Entwicklung eines Toolkit zur Analyse von Preisaktionen (Teil 10): External Flow (II) VWAP
Meistern Sie die Macht des VWAP mit unserem umfassenden Leitfaden! Lernen Sie, wie Sie mit MQL5 und Python die VWAP-Analyse in Ihre Handelsstrategie integrieren können. Optimieren Sie Ihre Markteinblicke und verbessern Sie Ihre Handelsentscheidungen noch heute.
Generative Adversarial Networks (GANs) für synthetische Daten in der Finanzmodellierung (Teil 2): Erstellen eines synthetischen Symbols für Tests Generative Adversarial Networks (GANs) für synthetische Daten in der Finanzmodellierung (Teil 2): Erstellen eines synthetischen Symbols für Tests
In diesem Artikel erstellen wir ein synthetisches Symbol mit Hilfe eines Generative Adversarial Network (GAN), das realistische Finanzdaten generiert, die das Verhalten tatsächlicher Marktinstrumente, wie z. B. EURUSD, nachahmen. Das GAN-Modell lernt Muster und Volatilität aus historischen Marktdaten und erstellt synthetische Preisdaten mit ähnlichen Merkmalen.
Automatisieren von Handelsstrategien in MQL5 (Teil 5): Die Entwicklung der Strategie „Adaptive Crossover RSI Trading Suite“ Automatisieren von Handelsstrategien in MQL5 (Teil 5): Die Entwicklung der Strategie „Adaptive Crossover RSI Trading Suite“
In diesem Artikel entwickeln wir ein System für die Strategie „Adaptive Crossover RSI Trading Suite“, das das Kreuzen der gleitende Durchschnitte mit Periodenlängen von 14 und 50 als Signale verwendet, die durch einen 14-periodischen RSI-Filter bestätigt werden. Das System umfasst einen Filter für den Handelstag, Signalpfeile mit Kommentaren und ein Echtzeit-Dashboard zur Überwachung. Dieser Ansatz gewährleistet Präzision und Anpassungsfähigkeit beim automatisierten Handel.
Automatisieren von Handelsstrategien in MQL5 (Teil 4): Aufbau eines mehrstufigen Zone Recovery Systems Automatisieren von Handelsstrategien in MQL5 (Teil 4): Aufbau eines mehrstufigen Zone Recovery Systems
In diesem Artikel entwickeln wir ein mehrstufiges Zone Recovery System in MQL5, das den RSI zur Erzeugung von Handelssignalen nutzt. Jede Signalinstanz wird dynamisch zu einer Array-Struktur hinzugefügt, sodass das System mehrere Signale gleichzeitig innerhalb der Zonenwiederherstellungslogik verwalten kann. Mit diesem Ansatz zeigen wir, wie man komplexe Handelsverwaltungsszenarien effektiv handhabt und gleichzeitig einen skalierbaren und robusten Codeentwurf beibehält.