English Русский 中文 Español 日本語 Português
Universeller Expert Advisor: Traden mit Gruppen von Strategien und deren Verwaltung (Part 4)

Universeller Expert Advisor: Traden mit Gruppen von Strategien und deren Verwaltung (Part 4)

MetaTrader 5Beispiele | 19 Mai 2016, 09:56
1 011 0
Vasiliy Sokolov
Vasiliy Sokolov

Inhaltsverzeichniss

 

Einleitung

Es ist häufig nötig, mehr als nur einen Algorithmus innerhalb eines Expert Advisors zur gleichen Zeit laufen zu lassen, welche sich aber gegenseitig nicht beeinflussen sollen. Diese Situation entsteht, wenn mehrere Algorithmen in einem ausführbaren Modul vereint werden müssen. Trotz seiner scheinbaren Einfachheit, verbergen diese Aufgaben einige bedeutende "Fallen" - z.B. algorithmische Funktion, die berücksichtigt werden müssen, wenn die Trading Engine entwickelt wird.

Die CStrategy Trading Engine enthält eine Ansammlung von Algorithmen, welche die parallele Ausführung von ein oder mehreren Strategien ermöglicht. Die werden dieses im Detail in dem vierten Abschnitt dieser Serie besprechen. Zudem werden wir ein Handelsprofil erstellen — Eine Gruppe von Expert Advisor-Strategien, welche gleichzeitig handeln, um das Risiko diversifizieren zu können. Die CStrategyList Klasse — Ein Container für Strategien vom Type CStrategy — gehört zu den Algorithmen, welche die gleichzeitige Operation von Strategien erlauben. Die Klasse erlaubt das Laden von Strategien, welche in XML geschrieben worden sind, sowie die dynamische Erzeugung mit einer entsprechenden Methode — eine Fabrik für Strategien.

Das angefügte Video demonstriert den Vorgang für das Testen von mehrfachen Strategien in dem MetaTrader 5 Strategietester. Alle Strategien, die mit der hier beschriebenen Trading Engine zusammenarbeiten, besitzen im Chart ein Bedienfeld, mit welchem Sie ganz einfach die Kontrolle über die verschiedenen Strategien haben.

 

CStrategyList Strategie Manager

Der zweite Artikel der "Universellen Expert Advisors" Serie beschreibt die CStrategy Klasse Und deren wichtigsten Module. Durch die Verwendung dieser Klasse und ihrer Funktionalität in den implementierten Modulen, erhält jede ererbte Strategie eine einheitliche Handels-Logik. Aber das Ausführen und Organisieren von Transaktionen mit Robotern ist mehr als nur eine Reihenfolge von Handelsanfragen. Es ist wichtig, dass ihre Zusammenarbeit einwandfrei funktioniert, einschließlich des Betriebs von mehreren Algorithmen in einer ausführbaren ex5 Datei.

Die spezielle CStrategyList Klasse findet für diesen Fall Verwendung. Wie sie aus dem Namen erraten können, bietet diese Klasse eine Liste von Strategien vom Typ CStrategy, aber die Verwendung ist etwas komplizierter als der einfache Zugriff auf einen Daten-Container. Das Modul löst die folgenden Aufgaben:

  • Sie stellt sicher, dass mehrere Handelsstrategien gleichzeitig laufen können;
  • Sie liefert die Handels-Events an jede Instanz einer Strategie;
  • Wie erzeugt Strategie Objekte aus einer XML Datei die mehrere Strategien enthalten kann (Data Deserializierung);
  • Sie interagiert mit dem Bedienfeld für die EA Konfiguration.

Hier ist der Header der CStrategyList Klasse:

//+----------------------------------------------------------------------------+
//| Container Klasse für die Verwaltung von Strategien des Typs CStrategy      |
//+----------------------------------------------------------------------------+
class CStrategyList
  {
private:
   CLog*       Log;                 // Logging
   CArrayObj   m_strategies;        // Strategien des Typs CStrategy type
   CLimits*    m_limits;
   void        ParseStrategies(CXmlElement* xmlStrategies, bool load_curr_symbol);
   void        ParseLimits(CXmlElement* xmlLimits);
   CStrBtn     StrButton;   
public:
   CStrategyList(void);
   ~CStrategyList(void);
   void LoadStrategiesFromXML(string xml_name, bool load_curr_symbol);
   bool AddStrategy(CStrategy* strategy);
   int  Total();
   CStrategy* At(int index);
   void OnTick();
   void OnTimer();
   void OnBookEvent(string symbol);
   void OnDeinit(const int reason);
   void OnChartEvent(const int id,
                     const long &lparam,
                     const double &dparam,
                     const string &sparam);
                     

  };

Wie Sie sehen können sind die meisten Methoden Eventhandler von Handels-Events Sie haben Inhalte des gleichen Typs Lassen Sie uns eine analysieren, OnBookEvent:

//+----------------------------------------------------------------+
//| Sendet OnBookEvent zu allen aufgelisteten Strategien           |
//+----------------------------------------------------------------+
void CStrategyList::OnBookEvent(string symbol)
  {
   for(int i=0; i<m_strategies.Total(); i++)
     {
      CStrategy *strategy=m_strategies.At(i);
      strategy.OnBookEvent(symbol);
     }
  }

Wie Sie sehen können, wird die Liste von Strategien des Typs CStrategy durchlaufen und die entsprechende Methode innerhalb der Strategie aufgerufen. Dieser Vorgang ist bei den anderen Event-Methoden gleich.

Zu der Weiterleitung von Events führt die CStrategyList Klasse auch noch spezielle Prozeduren für das Laden von Strategien aus XML Dateien durch. Mehr Informationen dazu finden Sie in dem nächsten Abschnitt.

 

Laden von Strategien über eine XML-Datei. Ein Portfolio von Strategien in einer XML-Datei

Wenn eine ausführbare ex5 Datei mehrere Handels-Algorithmen enthält, dann benötigen wir ein Werkzeug um ein Portfolio von Strategien erzeugen zu können. Nehmen wir nun an, dass zwei Algorithmen mit unterschiedlichen Parametern in einem ausführbaren Module ausgeführt werden sollen. Wie konfigurieren wir diese Parameter? Die einfachste Möglichkeit wäre, dieses über das Eigenschaftenfenster des Expert-Advisors zu machen. Aber was sollen wir machen, wenn es viele Strategien gibt und jede dieser Strategien auch noch viele Parameter besitzt? In diesem Fall wird die Parameterliste extrem groß werden. Wenn wir zum Beispiel einen Expert Advisor haben, der drei Strategien besitzt, dann würde die Parameterliste so aussehen:

Abbildung 1. Die Parameterliste des Expert Advisors mit drei Strategien

Ein Expert Advisor könnte auch noch mehr Strategien besitzen. In so einem Fall könnte die Liste von Parametern eine unüberschaubare Größe erreichen. Ein zweiter wichtiger Aspekt bei der Verwendung von Portfolios ist das Erstellen von Strategien "on-the-fly" Nehmen wir an, dass wir ein und dieselbe Strategie mit unterschiedlichen Parametern laufen lassen wollen. Was sollen wir jetzt tun? Obviously, despite the different sets of parameters, these two strategies are one and the same strategy, although with different settings. Anstelle diese Strategien manuell zu erzeugen, können wir diese Aufgabe einer separaten Klasse überlassen. Diese Klasse kann ganz automatisch ein Strategie-Objekt erzeugen und dieses auch perfekt konfigurieren.

Bevor wir jedoch eine Strategie on-the-fly erstellen können, ist es notwendig eine vollständige Beschreibung zu formulieren. Diese muss folgende Details beinhalten:

  • Den Namen der Strategie;
  • Eine eindeutige Strategie ID oder ihre Magic number;
  • Das Symbol, welches für die Strategie verwendet werden soll;
  • Die Timeframe, die für diese Strategie verwendet werden soll;
  • Eine Liste von eindeutigen Parametern für die Strategie (Dieses ist eine individuelle Liste für jede Strategie).

Strategien können auch noch weitere Eigenschaften enthalten. Der beste Weg für die Erstellung dieser Beschreibung, ist die Verwendung von XML Dateien. Diese Sprache wurde speziell für solche Beschreibungen entwickelt. Sie erlaubt es uns, ein komplexes Objekt - wie zum Beispiel ein Objekt für unsere Handelsstrategie - als XML zu erzeugen (Als Datei) und dieses Dokument/die Datei kann dann später wieder zurück in eine Strategie übersetzt werden. Somit kann unsere Trading Engine über eine solche XML-Datei eine Strategie erstellen und diese auch mit allen ihren Parametern konfigurieren. Um mit dieser speziellen Art von Dokumenten direkt in mql5 arbeiten zu können, verwenden wir einen speziellen XML-Parser. Diese Bibliothek steht in der Codebase zu Verfügung.

Hier ist ein Beispiel einer XML-Datei, welche eine Beschreibung für drei Strategien mit gleitenden Durchschnitten und unterschiedlichen Parametern enthält:

<Global>
        <Strategies>
                <Strategy Name="MovingAverage" Magic="100" Timeframe="PERIOD_M1" Symbol="Si">
                        <TradeStateStart>Stop</TradeStateStart>
                        <Params>
                                <FastMA>1</FastMA>
                                <SlowMA>3</SlowMA>
                                <Shift>0</Shift>
                                <Method>MODE_SMA</Method>
                                <AppliedPrice>PRICE_CLOSE</AppliedPrice>
                        </Params>
                </Strategy>
                <Strategy Name="MovingAverage" Magic="101" Timeframe="PERIOD_M5" Symbol="SBRF">
                        <TradeStateStart>BuyOnly</TradeStateStart>
                        <Params>
                                <FastMA>15</FastMA>
                                <SlowMA>21</SlowMA>
                                <Shift>0</Shift>
                                <Method>MODE_SMA</Method>
                                <AppliedPrice>PRICE_CLOSE</AppliedPrice>
                        </Params>
                </Strategy>
                <Strategy Name="MovingAverage" Magic="102" Timeframe="PERIOD_M15" Symbol="GAZR">
                        <TradeStateStart>BuyAndSell</TradeStateStart>
                        <Params>
                                <FastMA>12</FastMA>
                                <SlowMA>45</SlowMA>
                                <Shift>1</Shift>
                                <Method>MODE_EMA</Method>
                                <AppliedPrice>PRICE_CLOSE</AppliedPrice>
                        </Params>
                </Strategy>
        </Strategies>
</Global>

Jede Strategie erzeugt einen <Strategy>-Abschnitt. Darin sind die folgenden Angaben enthalten: Symbol, Timeframe, Magic und StrategyName. In dem oben gezeigten Beispiel können wir sehen, dass jedes Strategie ihr eigenes Symbol, die eigene Magic number und eine eigene Timeframe besitzt. Zu diesen benötigen Parametern, werden noch weitere Eigenschaften in der XML Liste angegeben. Die Sektion <TradeStateStart> Spezifiziert den Handels-Modus, der während des Ladens der Strategie eingestellt wird. Die Sektion <Params> beinhaltet die Parameter der Strategie.

Somit werden beim Start der Trading Engine die oben aufgeführten Strategien der XML Liste in die entsprechenden Strategieobjekte umgewandelt. Es wird also eine Strategie mit LoadStrategiesFromXML, basierend auf dem XML-Dokument, erzeugt und dann in die CStrategyList Klasse eingefügt. Hier sehen Sie nun den Inhalt dieser Methode, sowie alle damit in Zusammenhang stehenden Methoden:

//+-----------------------------------------------------------------------------+
//| Daten von Strategien aus der XML-Datei "xml_name"                           |
//| Falls das load_curr_symbol flag true ist, werden mit nur Strategien geladen |
//| deren Symbol zu dem aktuellen Symbol passt                                  |
//| symbol CurrentSymbol()                                                      |
//+-----------------------------------------------------------------------------+
void CStrategyList::LoadStrategiesFromXML(string xml_name,bool load_curr_symbol)
  {
   CXmlDocument doc;
   string err;
   bool res=doc.CreateFromFile(xml_name,err);
   if(!res)
      printf(err);
   CXmlElement *global=GetPointer(doc.FDocumentElement);
   for(int i=0; i<global.GetChildCount(); i++)
     {
      CXmlElement* child = global.GetChild(i);
      if(child.GetName() == "Strategies")
         ParseStrategies(child,load_curr_symbol);
     }
  }
//+----------------------------------------------------------------+
//| Übersetzen der XML Strategien                                  |
//+----------------------------------------------------------------+
void CStrategyList::ParseStrategies(CXmlElement *xmlStrategies,bool load_curr_symbol)
  {
   CParamsBase *params=NULL;
   for(int i=0; i<xmlStrategies.GetChildCount(); i++)
     {
      CXmlElement *xStrategy=xmlStrategies.GetChild(i);
      if(CheckPointer(params)!=POINTER_INVALID)
         delete params;
      params=new CParamsBase(xStrategy);
      if(!params.IsValid() || (params.Symbol()!=Symbol() && load_curr_symbol))
         continue;
      CStrategy *str=CStrategy::GetStrategy(params.Name());
      if(str==NULL)
         continue;
      str.ExpertMagic(params.Magic());
      str.ExpertSymbol(params.Symbol());
      str.Timeframe(params.Timeframe());
      str.ExpertName(params.Name());
      string name=str.ExpertName();
      CXmlElement *xml_params=xStrategy.GetChild("Params");
      if(xml_params!=NULL)
         str.ParseXmlParams(xml_params);
      CXmlElement *xml_mm=xStrategy.GetChild("MoneyManagment");
      if(xml_mm!=NULL)
        {
         if(!str.MM.ParseByXml(xml_mm))
           {
            string text="Strategy "+str.ExpertName()+" (Magic: "+(string)str.ExpertMagic()+") load MM from XML failed";
            CMessage *msg=new CMessage(MESSAGE_WARNING,__FUNCTION__,text);
            Log.AddMessage(msg);
           }
        }
      CXmlElement *xml_regim=xStrategy.GetChild("TradeStateStart");
      if(xml_regim!=NULL)
        {
         string regim=xml_regim.GetText();
         if(regim=="BuyAndSell")
            str.TradeState(TRADE_BUY_AND_SELL);
         else if(regim=="BuyOnly")
            str.TradeState(TRADE_BUY_ONLY);
         else if(regim=="SellOnly")
            str.TradeState(TRADE_SELL_ONLY);
         else if(regim=="Stop")
            str.TradeState(TRADE_STOP);
         else if(regim=="Wait")
            str.TradeState(TRADE_WAIT);
         else if(regim=="NoNewEntry")
            str.TradeState(TRADE_NO_NEW_ENTRY);
         else
           {
            string text="For strategy "+str.ExpertName()+" (Magic: "+(string)str.ExpertMagic()+
                        ") set not correctly trade state: "+regim;
            CMessage *msg=new CMessage(MESSAGE_WARNING,__FUNCTION__,text);
            Log.AddMessage(msg);
           }
        }
      AddStrategy(str);
     }
   if(CheckPointer(params)!=POINTER_INVALID)
      delete params;
  }

Der wichtigste Teil dieser Methode ist die Erzeugung einer Strategie unter Verwendung der speziellen statischen Methode CStrategy::GetStrategy. Der Name der Strategie sollte als Parameter übergeben werden. Die Methode gibt dann eine Instanz dieser Strategie mit diesem Namen zurück. Diese Methode wurde statisch gemacht, um einen Zugriff, bevor ein Strategie-Objekt erstellt worden ist, zu ermöglichen. GetStrategy wurde in einem separaten Header-File geschrieben, da sie entgegen den anderen Teilen der Trading Engine ab und zu editiert werden muss, wenn eine neue Strategie hinzugefügt wird. Wenn sie ihre Strategie über XML laden wollen, dann muss die Prozedur der Erstellung direkt dieser Methode hinzugefügt werden. Der Quellcode dieses Header-Files sieht wie folgt aus:

//+------------------------------------------------------------------+
//|                                              StrategyFactory.mqh |
//|                                 Copyright 2015, Vasiliy Sokolov. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Vasiliy Sokolov."
#property link      "http://www.mql5.com"
/*
   GetStrategy ist die Strategiefabrik. Sie erstellt ein Strategie Objekt entsprechend dem Namen
   Für die Automatisierung wurde diese Methode als ein eigenständiges File beigefügt
*/
#include <Strategy\Strategy.mqh>
#include <Strategy\Samples\MovingAverage.mqh>
#include <Strategy\Samples\ChannelSample.mqh>

CStrategy *CStrategy::GetStrategy(string name)
  {
   if(name=="MovingAverage")
      return new CMovingAverage();
   if(name=="BollingerBands")
      return new CChannel();
   CLog *mlog=CLog::GetLog();
   string text="Strategy with name "+name+" not defined in GetStrategy method. Please define strategy in 'StrategyFactory.mqh'";
   CMessage *msg=new CMessage(MESSAGE_ERROR,__FUNCTION__,text);
   mlog.AddMessage(msg);
   return NULL;
  }

Sobald die Strategie erzeugt worden ist, muss sie mit den Parametern aus der <Params> Sektion initialisiert werden. Da die Parameter der einzelnen Strategien eindeutig sind, ist es nicht möglich, diese Parameter auf der Ebene der Trading Engine zu initialisieren. Anstelle dessen ruft die Basisklasse der Strategie die virtuelle MethodeParseXmlParams auf. Wenn die Strategie diese Methode überschreibt und die Liste der Parameter richtig analysiert, dann ist es ihr möglich die benötigten Parameter selbst zu spezifizieren. Als Beispiel können Sie sich die ParseXmlParams Methode der CMovingAverage Strategie ansehen, Welche Transaktionen auf der Basis von zwei gleitenden Durchschnitten durchführt (Dieser Algorithmus wurde in dem ersten Kapitel dieses Artikels beschrieben).

//+-----------------------------------------------------------------------------------------------+
//| Ein Beispiel für die klassische Strategie, welche auf zwei gleitenden Durchschnitten basiert. |
//| Wenn der schnelle MA den langsamen MA von oben nach unten schneidet                           |
//| dann kaufen wir, wenn er von oben nach unten geschnitten wird, dann verkaufen wir.            |
//+-----------------------------------------------------------------------------------------------+
class CMovingAverage : public CStrategy
  {
   ...
public:
   virtual bool      ParseXmlParams(CXmlElement *params);
  };
//+------------------------------------------------------------------+
//| Die Parameter der Strategie werden hier                          |
//| in der von CStrategy überschriebenen Methode übersetzt (parsing) |
//+------------------------------------------------------------------+
bool CMovingAverage::ParseXmlParams(CXmlElement *params)
  {
   bool res=true;
   for(int i=0; i<params.GetChildCount(); i++)
     {
      CXmlElement *param=params.GetChild(i);
      string name=param.GetName();
      if(name=="FastMA")
        {
         int fastMA=(int)param.GetText();
         if(fastMA == 0)
           {
            string text="Parameter 'FastMA' must be a number";
            CMessage *msg=new CMessage(MESSAGE_WARNING,SOURCE,text);
            Log.AddMessage(msg);
            res=false;
           }
         else
            FastMA.MaPeriod(fastMA);
        }
      else if(name=="SlowMA")
        {
         int slowMA=(int)param.GetText();
         if(slowMA == 0)
           {
            string text="Parameter 'SlowMA' must be a number";
            CMessage *msg=new CMessage(MESSAGE_WARNING,SOURCE,text);
            Log.AddMessage(msg);
            res=false;
           }
         else
            SlowMA.MaPeriod(slowMA);
        }
      else if(name=="Shift")
        {
         FastMA.MaShift((int)param.GetText());
         SlowMA.MaShift((int)param.GetText());
        }
      else if(name=="Method")
        {
         string smethod=param.GetText();
         ENUM_MA_METHOD method=MODE_SMA;
         if(smethod== "MODE_SMA")
            method = MODE_SMA;
         else if(smethod=="MODE_EMA")
            method=MODE_EMA;
         else if(smethod=="MODE_SMMA")
            method=MODE_SMMA;
         else if(smethod=="MODE_LWMA")
            method=MODE_LWMA;
         else
           {
            string text="Parameter 'Method' must be type of ENUM_MA_METHOD";
            CMessage *msg=new CMessage(MESSAGE_WARNING,SOURCE,text);
            Log.AddMessage(msg);
            res=false;
           }
         FastMA.MaMethod(method);
         SlowMA.MaMethod(method);
        }
      else if(name=="AppliedPrice")
        {
         string price=param.GetText();
         ENUM_APPLIED_PRICE a_price=PRICE_CLOSE;
         if(price=="PRICE_CLOSE")
            a_price=PRICE_CLOSE;
         else if(price=="PRICE_OPEN")
            a_price=PRICE_OPEN;
         else if(price=="PRICE_HIGH")
            a_price=PRICE_HIGH;
         else if(price=="PRICE_LOW")
            a_price=PRICE_LOW;
         else if(price=="PRICE_MEDIAN")
            a_price=PRICE_MEDIAN;
         else if(price=="PRICE_TYPICAL")
            a_price=PRICE_TYPICAL;
         else if(price=="PRICE_WEIGHTED")
            a_price=PRICE_WEIGHTED;
         else
           {
            string text="Parameter 'AppliedPrice' must be type of ENUM_APPLIED_PRICE";
            CMessage *msg=new CMessage(MESSAGE_WARNING,SOURCE,text);
            Log.AddMessage(msg);
            res=false;
           }
         FastMA.AppliedPrice(a_price);
         SlowMA.AppliedPrice(a_price);
        }
     }
   return res;
  }

Die Details dieser Strategie wurden in dem dritten Artikel dieser Serie beschrieben, Welches die Entwicklung von benutzerdefinierten Strategien umfasst.

Die Verwendung dieses Mechanismus, eine Strategie aus einer Datei zu laden, macht es möglich die Strategie einmal zu konfigurieren und sie dann immer wieder aus einer Datei laden zu können. Sie können das noch weiter verfeinern, indem sie einen selbstoptimierenden Algorithmus schreiben, der immer die besten Parameter der Testläufe als ein XML-File abspeichert. Beim Start der Trading Engine liest diese dann diese Datei und bildet daraus eine Gruppe von Strategien.

 

Das Verwalten von Strategien mit einem Bedienfeld

Aus dem Blickwinkel des Anwenders, sollten Strategien über ein spezielles Bedienfeld ganz einfach kontrolliert werden können. Dieses Bedienfeld sollte nach dem Start des Expert Advisors auf dem Chart angezeigt werden und es dem Nutzer es ermöglichen, ganz einfache Operationen mit jedem Trading-Algorithmus durchführen zu können:

  • Den Modus der Strategie ändern;
  • Kaufen oder verkaufen der notwendigen Positionsgröße anstelle der Strategie.

Die letzte Option ist nützlich, wenn der Experte aus irgendeinem Grund in nicht so funktioniert wie gewünscht und die aktuellen Positionen dem Markt angepasst werden müssen.

Für die Beschreibung von Klassen welche benutzerdefinierte Bedienelemente und Dialogboxen erstellen geht über die Reichweite dieses Artikels hinaus. Wir werden hier nur die grundlegenden Aspekte betrachten.

Das Bedienfeld des expert-advisors wird in einer separaten CPanel Klasse implementiert, die verschiedene Controls, wie zum Beispiel Listen, Buttons und Text Labels enthält. Alle dafür notwendigen Klassen sind verfügbar unter <data_folder>\MQL5\Include\Panel. Für die einwandfreie Funktion dieses Bedienfelds ist es notwendig dass OnChartEvent Event direkt in dem Expert Advisor mql5-File zu behandeln. Der Handler von Chart-Events befindet sich in der CStrategyList Klasse, daher ist es ausreichend diesen in dem OnChartEvent aufzurufen:

CStrategyList Manager;
...

void OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
   Manager.OnChartEvent(id,lparam,dparam,sparam);
  }

Der Handler dieser Events in CStrategyList sendet sie dann direkt zu dem Bedienfeld.

Bei einem Klick auf einem Button wird die zugehörige Aktion definiert und ausgeführt. Wenn wir also eine Strategie aus der Liste selektieren und der Index dieser gewählten Strategie ist gleich der aktuellen Strategie, dann können wir weitere Handelsaktionen vornehmen. Zum Beispiel können Sie den Handelsmodus der gewählten Strategie über das zugehörige Dropdown-Menü auswählen:

Abbildung  2. Die Liste der Handelsmodi der selektierten Strategie

Abbildung 2. Die Liste der Handelsmodi der selektierten Strategie

Kauf und Verkauf über die gewählte Strategie wird in der gleichen Weise ausgeführt. Ein Pointer der Strategie ruft die Kauf- und Verkauf-Methoden der CStrategy Basisklasse auf. Diese Methoden kaufen oder verkaufen dann in der übergebenen Positionsgröße. In diesem Fall ist die Magic number dieser Operation gleich mit der Magic number der Strategie. Somit ist es unmöglich zwischen manuellen ausgeführten Transaktionen und denen von dem Expert Advisor zu unterscheiden.

Es sollte beachtet werden, dass die Handelslogik des Expert Advisor so implementiert ist, dass sie alle von einem Anwender geöffneten Positionen mit in die Logik einbezieht. Der Expert Advisor, beziehungsweise die Strategie verwaltet solche manuell geöffneten Positionen wie die eigenen automatisch geöffneten Positionen.

 

Ein Expert Advisor mit einer Gruppe von Strategien

Wir können ein Portfolio von Handelsstrategien zusammenstellen. Die Strategien müssen Methoden beinhalten, welche für die Übersetzung von XML Parametern verantwortlich sind, das heißt wir müssen die ParseXmlParams Methode überschreiben. Es ist zudem notwendig der Methode CStrategy::GetStrategy den entsprechenden Typ der Strategie mitzugeben. Zum Schluss müssen wir dann eine XML-Datei erstellen, welche die Liste der Strategien und die zugehörigen Parameter enthält. Anschließend kann dann die CStrategyList Klasse Instanzen der Strategien erstellen und diese dann zu der Liste von Strategien hinzufügen. Diese Strategien sind dann in dem Bedienfeld sichtbar.

Lassen Sie uns ein Portfolio von Strategien schaffen, bestehend aus dem oben beschriebenen Expert Advisor. Beispiele für das Übersetzen von XML-Daten für die CMovingAverage und CChannel Strategien sind erhältlich in den Abschnitten 3.5 und 4.3.

Der Inhalt von CStrategy::GetStrategy für die Erstellung von diesen beiden Strategien sieht wie folgt aus:

//+------------------------------------------------------------------+
//|                                              StrategyFactory.mqh |
//|                                 Copyright 2015, Vasiliy Sokolov. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Vasiliy Sokolov."
#property link      "http://www.mql5.com"
/*
   GetStrategy ist die Strategiefabrik. Sie erstellt ein Strategie Objekt entsprechend dem Namen
   Für die Automatisierung wurde diese Methode als ein eigenständiges File beigefügt
*/
#include <Strategy\Strategy.mqh>
#include <Strategy\Samples\MovingAverage.mqh>
#include <Strategy\Samples\ChannelSample.mqh>

CStrategy *CStrategy::GetStrategy(string name)
  {
   if(name=="MovingAverage")
      return new CMovingAverage();
   if(name=="BollingerBands")
      return new CChannel();
   CLog *mlog=CLog::GetLog();
   string text="Strategy with name "+name+" not defined in GetStrategy method. Please define strategy in 'StrategyFactory.mqh'";
   CMessage *msg=new CMessage(MESSAGE_ERROR,__FUNCTION__,text);
   mlog.AddMessage(msg);
   return NULL;
  }

Der letzte Schliff ist es, die Methode die für den vollständigen Namen des EAs verantwortlich ist, zu überschreiben Überschreiben der CMovingAverage Strategie:

//+----------------------------------------------------------------+
//| Der vollständige eindeutige Name des Expert-Advisors           |
//+----------------------------------------------------------------+
string CMovingAverage::ExpertNameFull(void)
  {
   string name=ExpertName();
   name += "[" + ExpertSymbol();
   name += "-" + StringSubstr(EnumToString(Timeframe()), 7);
   name += "-" + (string)FastMA.MaPeriod();
   name += "-" + (string)SlowMA.MaPeriod();
   name += "-" + StringSubstr(EnumToString(SlowMA.MaMethod()), 5);
   name += "]";
   return name;
  }

Nun ist alles bereit für die Erstellung eines Portfolios mit Strategien. Unser Portfolio wird vier Handelssysteme beinhalten. Jedes von denen handelt mit einem eigenen Symbol. Zwei der Strategien verwenden gleitende Durchschnitte und die anderen beiden verwenden Bollinger Bands. Eine genauere Beschreibung dieser Strategien ist erhältlich in dem vorherigen Artikel: "Universeller Expert Advisor: Benutzerdefinierte Strategien und externe Handelsklassen (part 3)".

Unser XML Portfolio sieht wie folgt aus:

<Global>
        <Strategies>
                <Strategy Name="MovingAverage" Magic="100" Timeframe="PERIOD_M1" Symbol="Si">
                        <TradeStateStart>Stop</TradeStateStart>
                        <Params>
                                <FastMA>1</FastMA>
                                <SlowMA>3</SlowMA>
                                <Shift>0</Shift>
                                <Method>MODE_SMA</Method>
                                <AppliedPrice>PRICE_CLOSE</AppliedPrice>
                        </Params>
                </Strategy>
                <Strategy Name="MovingAverage" Magic="101" Timeframe="PERIOD_M5" Symbol="SBRF">
                        <TradeStateStart>BuyAndSell</TradeStateStart>
                        <Params>
                                <FastMA>15</FastMA>
                                <SlowMA>21</SlowMA>
                                <Shift>0</Shift>
                                <Method>MODE_SMA</Method>
                                <AppliedPrice>PRICE_CLOSE</AppliedPrice>
                        </Params>
                </Strategy>
                <Strategy Name="BollingerBands" Magic="102" Timeframe="PERIOD_M15" Symbol="GAZR">
                        <TradeStateStart>BuyAndSell</TradeStateStart>
                        <Params>
                                <Period>30</Period>
                                <StdDev>1.5</StdDev>
                        </Params>
                </Strategy>
                <Strategy Name="BollingerBands" Magic="103" Timeframe="PERIOD_M30" Symbol="ED">
                        <TradeStateStart>BuyAndSell</TradeStateStart>
                        <Params>
                                <Period>20</Period>
                                <StdDev>2.0</StdDev>
                        </Params>
                </Strategy>
        </Strategies>
</Global>

Diese Datei sollte als Strategies.xml in dem 'common'-Verzeichnis der Metatrader-Platform gespeicgert werden.

Hier ist der Quellcode von den mq5 Modul, welches den Expert Advisor erzeugt:

//+------------------------------------------------------------------+
//|                                                       Expert.mq5 |
//|                                 Copyright 2015, Vasiliy Sokolov. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Vasiliy Sokolov."
#property link      "http://www.mql5.com"
#property version   "1.00"
#include <Strategy\StrategiesList.mqh>

CStrategyList Manager;
//+------------------------------------------------------------------+
//| Expert Initialisierungs-Function                                 |
//+------------------------------------------------------------------+
int OnInit()
  {
   Manager.LoadStrategiesFromXML(StrategiesXMLFile,LoadOnlyCurrentSymbol);
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization Funktion                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   EventKillTimer();
  }
//+------------------------------------------------------------------+
//| Expert tick Funktion                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   Manager.OnTick();
  }
//+------------------------------------------------------------------+
//| Orderbuch Event-Funktion                                         |
//+------------------------------------------------------------------+
void OnBookEvent(const string &symbol)
  {
   Manager.OnBookEvent(symbol);
  }

void OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
   Manager.OnChartEvent(id,lparam,dparam,sparam);
  }

Die benutzerdefinierten Variablen StrategiesXMLFile und LoadOnlyCurrentSymbol werden in der CStrategyList Klasse definiert. Sie werden innerhalb der Klasse dafür verwendet, festzustellen welche Strategien geladen werden sollen und den Modus, welcher es erlaubt, nur Strategien zu laden, die mit dem gleichen Symbol arbeiten auf welchem der Expert Advisor gerade installiert wurde. Beachten Sie auch dass manche Events, wie zum Beispiel OnBookEvent und OnTimer, nicht verwendet werden. Das bedeutet, dass diese in den benutzerdefinierten Strategien keine Verwendung finden.

Die Kompilierung sollte ohne Fehler abschließen. Anschließend ist der Expert Advisor (Agent.ex5) einsatzbereit. Wenden wir diesen jetzt auf einem Chart an. Zunächst müssen wir aber sicherstellen, dass alle verwendeten Symbole auch in dem MetaTrader Market Watch verfügbar sind. Nach einem erfolgreichen Start erscheint oben rechts das Icon von dem Expert Advisor. Oben links befindet sich jetzt ein weiterer Button, welcher das Bedienfeld maximiert. Wenn wir jetzt die Liste der Expert Advisor (Agent genannt) auf dem Bedienfeld anwählen, dann erscheint eine Liste mit 4 Expert Advisorn:

Fig. 3. Die Liste der geladenen Expert Advisors


Abbildung. 3. Die Liste der geladenen Expert Advisors

Das Screenshot enthält eine Liste der expert-advisors, die durch unsere XML-Datei Strategies.xml erzeugt wurden. Nach einer Weile fangen die Strategien damit an Transaktionen auszuführen - jede Strategie mit ihrem eigenen individuellen Symbol

 

Die Analyse der Arbeitsweise des Expert-Advisors in dem Strategietester

Nachdem wir ein Portfolio mit Strategien erzeugt haben, können wir dieses im Strategietester auf seine einwandfreie Funktion hin überprüfen. Es ist hierfür keine weitere Aktion notwendig, da die XML-Datei, welche die Strategien enthält, in dem globalen Verzeichnis der Metatrader Plattform gespeichert wurde, auf welches der Strategietester ebenfalls zugreifen kann. Nach dem Start des Agent.ex5 EA Moduls in dem Tester, werden alle benötigten Symbole automatisch geladen. Jeder Expert Advisor wird seine eigenen Handelsoperationen nach seinen speziellen Regeln ausführen und zudem die zugehörigen Indikatoren zeichnen. Das hier gezeigte Video zeigt den Test eines Portfolios mit Strategien mit vier unterschiedlichen Finanzinstrumenten:


Die Simulation von CStrategy basierten Strategien in dem Tester ist gleich dem Realtime-Trading dieser Strategien. Dieser visuelle Test erlaubt eine ganz einfache Überprüfung der Korrektheit der Ein- und Ausstiegspunkte der Strategien.

 

Schlussfolgerung

Wir haben uns Algorithmen angeschaut, welche es uns erlauben zufällige Sets von Handelsstrategien zu erzeugen. Mit diesem Set oder Portfolios von Strategien können Sie ganz flexibel und effizient den Trading-Prozess skalieren, während sie verschiedene Handels-Algorithmen in dem gleichen Modul ausführen. Diese Algorithmen sind insbesondere dann hilfreich, wenn Sie Strategien testen, die verschiedene Finanzinstrumente gleichzeitig verwenden. Der hier vorgeschlagene Ansatz für die Erstellung von ähnlichen Handels-Algorithmen, ist genauso einfach wie die Entwicklung von herkömmlichen Handelsstrategien.

Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/2179

Beigefügte Dateien |
strategyarticle.zip (97.88 KB)
Grundlagen der Programmierung in MQL5: Listen Grundlagen der Programmierung in MQL5: Listen
Die neue Version der Programmiersprache für die Entwicklung von Handelsstrategien, MQL [MQL5], liefert im Vergleich zur Vorgängerversion [MQL4] leistungsstärkere und effektivere Features. Der Vorteil besteht im Wesentlichen aus den Merkmalen der objektorientierten Programmierung. In diesem Beitrag wird die Möglichkeit betrachtet, komplexe benutzerdefinierte Datentypen wie Knoten und Listen zu verwenden. Außerdem liefert der Beitrag ein Anwendungsbeispiel für die Verwendung von Listen in der praktischen Programmierung in MQL5.
Die Verwendung von Layout und Containern für GUI Controls: Die CGrid Klasse Die Verwendung von Layout und Containern für GUI Controls: Die CGrid Klasse
Dieser Artikel präsentiert eine alternative Methode für die Erzeugung eines GUI, basierend auf Layouts und Containern und der Verwendung eines Layout-Managers — die CGrid Klasse. Die CGrid Klasse ist ein externes Control, welches wie ein Container für andere Container und Controls agiert und ein Grid-Layout verwendet.
Das MQL5-Kochbuch: Entwicklung eines Indikators mit mehreren Symbolen für die Analyse von Preisunterschieden Das MQL5-Kochbuch: Entwicklung eines Indikators mit mehreren Symbolen für die Analyse von Preisunterschieden
In diesem Beitrag betrachten wir die Entwicklung eines Indikators mit mehreren Symbolen für die Analyse von Preisunterschieden in einem bestimmten Zeitraum. Die wichtigsten Themen wurden bereits im vorhergehenden Beitrag zur Programmierung mehrwährungsfähiger Indikatoren besprochen, "Das MQL5-Kochbuch: Entwicklung eines Indikators für die Volatilität mehrerer Symbole in MQL5". Diesmal gehen wir also nur auf jene neuen Features und Funktionen ein, an denen wesentliche Änderungen vorgenommen wurden. Wenn Sie ein Neuling in der Programmierung von mehrwährungsfähigen Indikatoren sind, empfehle ich Ihnen, zuerst den vorherigen Beitrag zu lesen.
Verwendung von Layouts und Containern für GUI Controls: Die CBox Klasse Verwendung von Layouts und Containern für GUI Controls: Die CBox Klasse
Dieser Artikel präsentiert eine alternative Methode für die Erzeugung von GUI-Controls, basierend auf Layouts und Containern und der Verwendung eines Layoutmanagers, der CBox Klasse. Die CBox Klasse ist ein externes Control, welches als ein Container für besondere Controls in einem GUI-Panel agiert. Sie vereinfacht das Designen von grafischen Panels und in einigen Fällen reduziert sie auch den Programmieraufwand.