Erweiterung der MQL5-Standardbibliothek und Wiederverwendung von Code

laplacianlab | 27 Juni, 2016

Einleitung

Die MQL5-Standardbibliothek ist ein objektorientiertes Framework aus gebrauchsfertigen Klassen, die Ihnen das Leben als Entwickler erleichtern. Dennoch geht sie nicht auf die Bedürfnisse aller Entwickler auf der Welt ein. Wenn Sie also das Gefühl haben, dass Sie mehr benutzerdefinierte Funktionen brauchen, können Sie einen Schritt weitergehen und die Bibliothek erweitern. Dieser Beitrag begleitet Sie durch die Integration des technischen Indikators ZigZag von MetaQuotes in die Standardbibliothek. Wir lassen uns durch die Designphilosophie von MetaQuotes inspirieren, um unser Ziel zu erreichen.

Kurz gesagt, ist die MQL5-API dafür vorgesehen, Sie in den Genuss von wiederverwendbaren Codes, Zuverlässigkeit, Flexibilität und einfacher Wartung kommen zu lassen. Soweit die Theorie. Doch darüber hinaus müssen Sie dazu in der Lage sein, Codes auf die Art der Standardbibliothek zu schreiben, sodass der Erfolg Ihrer Anwendungen garantiert werden kann, wenn Sie Ihre MQL5-Kenntnisse erweitern und ausgeklügeltere Anwendungen entwickeln möchten, beispielsweise mehrwährungsfähige Expert Advisors.

Mit der steigenden Komplexität Ihrer EAs und Indikatoren wird es immer wichtiger, die Konzepte hinter der Entwicklung eines Frameworks vollständig zu begreifen. Ein konkretes Beispiel ist mein persönliches Bestreben, einen komplexen, mehrwährungsfähigen EA zu entwickeln, das mich dazu zwingt, die Grundlagen meines Projekts von Grund auf durchzudenken.

Abbildung 1. Regelmäßige Polyeder sind perfekte Objekte und veranschaulichen die Idee hinter der Ausarbeitung von Anwendungen auf Basis eines soliden Konzepts.

Abbildung 1. Regelmäßige Polyeder sind perfekte Objekte und veranschaulichen die Idee hinter der Ausarbeitung von Anwendungen auf Basis eines soliden Konzepts

1. Download von ZigZag

Wir fangen mit dem Download des ZigZag-Indikators von MetaQuotes an, der über das MetaTrader 5 Terminal in der Code Base zur Verfügung steht. Dabei werden die Dateien Indicators\zigzag.mq5 und Indicators\zigzag.ex5 erstellt.

Abbildung 2. Download von ZigZag von MetaQuotes

Abbildung 2. Download von ZigZag über das MetaTrader 5 Terminal

Ich führe an dieser Stelle jene Zeilen von Indicators\zigzag.mq5 auf, die die Eingabeparameter des Indikators, globale Variablen und den Handler OnInit() beinhalten. Ich beschränke mich deshalb auf diesen Teil, weil die vollständige Datei aus 298 Zeilen Code besteht. Dies dient nur der Bequemlichkeit und dem Verständnis des großen Ganzen, das wir im weiteren Verlauf besprechen werden.

//+------------------------------------------------------------------+
//|                                                       ZigZag.mq5 |
//|                        Copyright 2009, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2009, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 3
#property indicator_plots   1
//---- plot Zigzag
#property indicator_label1  "Zigzag"
#property indicator_type1   DRAW_SECTION
#property indicator_color1  Red
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- input parameters
input int      ExtDepth=12;
input int      ExtDeviation=5;
input int      ExtBackstep=3;
//--- indicator buffers
double         ZigzagBuffer[];      // main buffer
double         HighMapBuffer[];     // highs
double         LowMapBuffer[];      // lows
int            level=3;             // recounting depth
double         deviation;           // deviation in points
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,ZigzagBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,HighMapBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(2,LowMapBuffer,INDICATOR_CALCULATIONS);

//--- set short name and digits   
   PlotIndexSetString(0,PLOT_LABEL,"ZigZag("+(string)ExtDepth+","+(string)ExtDeviation+","+(string)ExtBackstep+")");
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
//--- set empty value
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
//--- to use in cycle
   deviation=ExtDeviation*_Point;
//---
   return(INIT_SUCCEEDED);
  }


2. Kurzübersicht – von oben nach unten

Wenden wir nun einen Top-down-Ansatz an, um über unseren neuen objektorientierten Indikator ZigZag nachzudenken, den wir in die MQL5-Standardbibliothek integrieren wollen. Das bedeutet, dass wir erst das Gesamtsystem betrachten und anschließend seine Bestandteile analysieren müssen. Schreiben wir also ein paar Dummy-EAs, um das Gesamtbild zu erkennen. Lassen Sie uns einen verfahrensorientierten Expert Advisor zusammen mit einer objektorientierten Version davon schreiben.


2,1. Standardindikator ZigZag

Der durchschnittliche MQL5-Entwickler nutzt den ZigZag-Indikator vermutlich etwa so in seinen EAs:

//+----------------------------------------------------------------------+
//|                                            ExpertOriginalZigZag.mq5  |
//|                   Copyright © 2013, Laplacianlab - Jordi Bassagañas  | 
//+----------------------------------------------------------------------+
//--- EA properties
#property copyright     "Copyright © 2013, Laplacianlab - Jordi Bassagañas"
#property link          "https://www.mql5.com/de/articles"
#property version       "1.00"
#property description   "This dummy Expert Advisor is just for showing how to use the original MetaQuotes' ZigZag indicator."
//--- EA inputs
input ENUM_TIMEFRAMES   EAPeriod=PERIOD_H1;
input string            CurrencyPair="EURUSD";
//--- global variables
int      zigZagHandle;
double   zigZagBuffer[];
double   zigZagHigh[];
double   zigZagLow[];
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   zigZagHandle=iCustom(CurrencyPair,EAPeriod,"zigzag",12,5,3);
   ArraySetAsSeries(zigZagBuffer,true);
   ArraySetAsSeries(zigZagHigh,true);
   ArraySetAsSeries(zigZagLow,true);  
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   IndicatorRelease(zigZagHandle);
   ArrayFree(zigZagBuffer);
   ArrayFree(zigZagHigh);
   ArrayFree(zigZagLow);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   //--- refresh data   
   if(CopyBuffer(zigZagHandle,0,0,2,zigZagBuffer)<0)
   {
      Print("Can't copy ZigZag buffer 0!");
      return;
   }
   if(CopyBuffer(zigZagHandle,1,0,2,zigZagHigh)<0)
   {
      Print("Can't copy ZigZag buffer 1!");
      return;
   }
   if(CopyBuffer(zigZagHandle,2,0,2,zigZagLow)<0)
   {
      Print("Can't copy ZigZag buffer 2!");
      return;
   }
   //--- print values
   if(zigZagBuffer[0]!=0) Print("zigZagBuffer[0]: ", zigZagBuffer[0]);
   if(zigZagHigh[0]!=0) Print("zigZagHigh[0]: ", zigZagHigh[0]);
   if(zigZagLow[0]!=0) Print("zigZagLow[0]: ", zigZagLow[0]);
  }
//+------------------------------------------------------------------+


2,2. ZigZag in der Standardbibliothek

Andererseits arbeiten erfahrene MQL5-Entwickler mit dem ZigZag-Indikator wahrscheinlich genauso wie sie es bereits mit den Indikatoren aus der Standardbibliothek tun:

//+----------------------------------------------------------------------+
//|                                                  ExpertOOZigZag.mq5  |
//|                   Copyright © 2013, Laplacianlab - Jordi Bassagañas  | 
//+----------------------------------------------------------------------+
#include <..\Include\Indicators\Custom\Trend.mqh>
//--- EA properties
#property copyright     "Copyright © 2013, Laplacianlab - Jordi Bassagañas"
#property link          "https://www.mql5.com/de/articles"
#property version       "1.00"
#property description   "This dummy Expert Advisor is just for showing how to use the object-oriented version of MetaQuotes' ZigZag indicator."
//--- EA inputs
input ENUM_TIMEFRAMES   EAPeriod=PERIOD_H1;
input string            CurrencyPair="EURUSD";
//--- global variables
CiZigZag *ciZigZag;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   ciZigZag=new CiZigZag;
   ciZigZag.Create(CurrencyPair,EAPeriod,12,5,3);
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   delete(ciZigZag);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {   
   //--- refresh data
   ciZigZag.Refresh();
   //--- print values
   if(ciZigZag.ZigZag(0)!=0) Print("OO ZigZag buffer: ", ciZigZag.ZigZag(0));
   if(ciZigZag.High(0)!=0) Print("OO ZigZag high: ", ciZigZag.High(0));
   if(ciZigZag.Low(0)!=0) Print("OO ZigZag low: ",ciZigZag.Low(0));
  }
//+------------------------------------------------------------------+


2,3. Fazit

Die zweite Lösung ist besser, weil sie objektorientiert ist. Nach der Ausarbeitung der objektorientierten Klassen lässt sich beobachten, dass es viel einfacher ist, mit der objektorientierten Funktionalität von ZigZag zu interagieren, als mit seinem verfahrensorientierten Gegenstück zu arbeiten. Rufen wir uns allerdings kurz die Vorteile der Arbeit mit einer objektorientierten Bibliothek ins Gedächtnis:

  • OOP ermöglicht eine einfache Modellierung von Aufgaben.
  • OOP macht es einfach, Codes wiederzuverwenden, was sich wiederum positiv auf Kosten, Zuverlässigkeit, Flexibilität und Wartungsfreundlichkeit auswirkt.
  • Dieses Paradigma ermöglicht die Erschaffung von ADTs (abstrakten Datentypen). Ein ADT ist eine Abstraktion des herkömmlichen Konzepts von Datentypen, die in allen Programmiersprachen vorkommen.

Abbildung 3. Regulärer Ikosaeder. Der Aufbau unserer Anwendungen auf Basis solider Konzepte ist eine Qualitätsgarantie, die sicherstellt, dass unsere Konzepte die Zeit überdauern.

Abbildung 3. Regulärer Ikosaeder. Der Aufbau unserer Anwendungen auf Basis solider Konzepte ist eine Qualitätsgarantie, die sicherstellt, dass unsere Konzepte die Zeit überdauern


3. Integration des neuen objektorientierten ZigZag in die MQL5-Standardbibliothek

Wie ich in der Einleitung dieses Beitrags erwähnt habe, lassen wir uns beim Aufbau unseres neuen Satzes von Klassen zum Verpacken des ZigZag vom objektorientierten Stil von MetaQuotes inspirieren. Das ist einfach – wir müssen uns nur die Dateien in Include\Indicators ansehen und einige Ideen hinter der MQL5-Standardbibliothek studieren und verstehen. Wenn Sie sich ansehen, was sich innerhalb von Trend.mqh von MetaQuotes befindet, werden Sie schnell feststellen, dass die Datei voller Klassen ist, die eine Reihe von technischen Indikatoren darstellen: ADX, Bollinger Bands, SAR, gleitende Mittelwerte usw. All diese Klassen sind Erben von CIndicator. Wenden wir also dieses Schema an. Übrigens, eine Erweiterung des neuen objektorientierten Indikators aus der MQL5-Klasse CiCustom wäre eine weitere Alternative für diese Übung.

Fangen wir an, indem wir den neuen Ordner Include\Indicators\Custom und gleich danach die neue Datei Include\Indicators\Custom\Trend.mqh erstellen, sodass wir dort unsere eigenen technischen Indikatoren schreiben können, genauso, wie MetaQuotes es in seiner Datei Include\Indicators\Trend.mqh tut. Hier ist unsere erweiterte Datei Include\Indicators\Custom\Trend.mqh bereits implementiert. Nachfolgend werde ich auf einige technische Aspekte für ihre Ausarbeitung eingehen.

//+------------------------------------------------------------------+
//|                              Include\Indicators\Custom\Trend.mqh |
//|                  Copyright 2013, Laplacianlab - Jordi Bassagañas |
//|                     https://www.mql5.com/de/users/laplacianlab |
//+------------------------------------------------------------------+
#include <..\Include\Indicators\Indicator.mqh>
//+------------------------------------------------------------------+
//| Class CiZigZag.                                                  |
//| Purpose: Class of the "ZigZag" indicator.                        |
//|          Derives from class CIndicator.                          |
//+------------------------------------------------------------------+
class CiZigZag : public CIndicator
  {
protected:
   int               m_depth;
   int               m_deviation;
   int               m_backstep;

public:
                     CiZigZag(void);
                    ~CiZigZag(void);
   //--- methods of access to protected data
   int               Depth(void)          const { return(m_depth);      }
   int               Deviation(void)      const { return(m_deviation);  }
   int               Backstep(void)       const { return(m_backstep);   }
   //--- method of creation
   bool              Create(const string symbol,const ENUM_TIMEFRAMES period,
                            const int depth,const int deviation_create,const int backstep);
   //--- methods of access to indicator data
   double            ZigZag(const int index) const;
   double            High(const int index) const;
   double            Low(const int index) const;
   //--- method of identifying
   virtual int       Type(void) const { return(IND_CUSTOM); }

protected:
   //--- methods of tuning
   virtual bool      Initialize(const string symbol,const ENUM_TIMEFRAMES period,const int num_params,const MqlParam &params[]);
   bool              Initialize(const string symbol,const ENUM_TIMEFRAMES period,
                                const int depth,const int deviation_init,const int backstep);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CiZigZag::CiZigZag(void) : m_depth(-1),
                         m_deviation(-1),
                         m_backstep(-1)
  {
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CiZigZag::~CiZigZag(void)
  {
  }
//+------------------------------------------------------------------+
//| Create indicator "Zig Zag"                                       |
//+------------------------------------------------------------------+
bool CiZigZag::Create(const string symbol,const ENUM_TIMEFRAMES period,
                      const int depth,const int deviation_create,const int backstep)
  {
//--- check history
   if(!SetSymbolPeriod(symbol,period))
      return(false);
//--- create
   m_handle=iCustom(symbol,period,"zigzag",depth,deviation_create,backstep);
//--- check result
   if(m_handle==INVALID_HANDLE)
      return(false);
//--- indicator successfully created
   if(!Initialize(symbol,period,depth,deviation_create,backstep))
     {
      //--- initialization failed
      IndicatorRelease(m_handle);
      m_handle=INVALID_HANDLE;
      return(false);
     }
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialize the indicator with universal parameters               |
//+------------------------------------------------------------------+
bool CiZigZag::Initialize(const string symbol,const ENUM_TIMEFRAMES period,const int num_params,const MqlParam &params[])
  {
   return(Initialize(symbol,period,(int)params[0].integer_value,(int)params[1].integer_value,(int)params[2].integer_value));
  }
//+------------------------------------------------------------------+
//| Initialize indicator with the special parameters                 |
//+------------------------------------------------------------------+
bool CiZigZag::Initialize(const string symbol,const ENUM_TIMEFRAMES period,
                        const int depth,const int deviation_init,const int backstep)
  {
   if(CreateBuffers(symbol,period,3))
     {
      //--- string of status of drawing
      m_name  ="ZigZag";
      m_status="("+symbol+","+PeriodDescription()+","+
               IntegerToString(depth)+","+IntegerToString(deviation_init)+","+
               IntegerToString(backstep)+") H="+IntegerToString(m_handle);
      //--- save settings
      m_depth=depth;
      m_deviation=deviation_init;
      m_backstep=backstep;       
      //--- create buffers
      ((CIndicatorBuffer*)At(0)).Name("ZIGZAG");
      ((CIndicatorBuffer*)At(1)).Name("HIGH");
      ((CIndicatorBuffer*)At(2)).Name("LOW");
      //--- ok
      return(true);
     }
//--- error
   return(false);
  }
//+------------------------------------------------------------------+
//| Access to ZigZag buffer of "Zig Zag"                             |
//+------------------------------------------------------------------+
double CiZigZag::ZigZag(const int index) const
  {
   CIndicatorBuffer *buffer=At(0);
//--- check
   if(buffer==NULL)
      return(EMPTY_VALUE);
//---
   return(buffer.At(index));
  }
//+------------------------------------------------------------------+
//| Access to High buffer of "Zig Zag"                               |
//+------------------------------------------------------------------+
double CiZigZag::High(const int index) const
  {
   CIndicatorBuffer *buffer=At(1);
//--- check
   if(buffer==NULL)
      return(EMPTY_VALUE);
//---
   return(buffer.At(index));
  }
//+------------------------------------------------------------------+
//| Access to Low buffer of "Zig Zag"                                |
//+------------------------------------------------------------------+
double CiZigZag::Low(const int index) const
  {
   CIndicatorBuffer *buffer=At(2);
//--- check
   if(buffer==NULL)
      return(EMPTY_VALUE);
//---
   return(buffer.At(index));
  }
//+------------------------------------------------------------------+


3,1. Objektorientierte Kapselung

Die objektorientierte Kapselung ist eine bewährte Praxis in der Programmierung, die bedeutet, dass Datenbestandteile von Objekten nur durch Operationen modifiziert werden können, die speziell für sie definiert sind. Alle in Trend.mqh von MetaQuotes definierten Klassen setzen diese Idee um, also tun wir das Gleiche.

Auf der anderen Seite gibt es die speziellen geschützten Eigenschaften von CiZigZag:

protected:
   int               m_depth;
   int               m_deviation;
   int               m_backstep;

Somit verfügt CiZigZag über ein offenes Interface für den Zugriff auf die oben definierten geschützten Eigenschaften von außerhalb eines bestimmten Objektes des Typen CiZigZag:

public:
   //--- methods of access to protected data
   int               Depth(void)          const { return(m_depth);      }
   int               Deviation(void)      const { return(m_deviation);  }
   int               Backstep(void)       const { return(m_backstep);   }

Dabei handelt es sich um eine Sicherheitsmaßnahme zum Isolieren von Objekten. Diese Kapselung verhindert willkürliche Veränderungen durch Personen oder Faktoren, denen der Zugriff auf die Daten des Objekts nicht gestattet ist.


3,2. Zugriff auf die Daten von ZigZag

Wie es im ersten Abschnitt dieses Beitrags gezeigt wurde, erstellt der Quellcode mit dem Namen zigzag.mq5 drei Puffer:

//--- indicator buffers mapping
   SetIndexBuffer(0,ZigzagBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,HighMapBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(2,LowMapBuffer,INDICATOR_CALCULATIONS);

Durch die objektorientierte Kapselung geben die Methoden ZigZag(const int index), High(const int index) und Low(const int index) von CiZigZag die Indikatorpuffer aus, die vorher in der Initialisierungsmethode erstellt wurden. Es muss festgehalten werden, dass der objektorientierte Wrapper CIndicatorBuffer in der MQL5-Klasse Include\Indicators\Indicator.mqh definiert ist. CIndicatorBuffer ist das Herzstück dieser drei Methoden. Und schon sind wir in die MQL5-API eingetaucht!

Als Beispiel sehen Sie hier den Code für den Zugriff auf den High-Puffer von CiZigZag:

//+------------------------------------------------------------------+
//| Access to High buffer of "Zig Zag"                               |
//+------------------------------------------------------------------+
double CiZigZag::High(const int index) const
  {
   CIndicatorBuffer *buffer=At(1);
//--- check
   if(buffer==NULL)
      return(EMPTY_VALUE);
//---
   return(buffer.At(index));
  }


3,3.
Polymorphismus, Überladen von Methoden und virtuelle Funktionen

Im vorhergehenden Abschnitt sind wir kurz auf das Thema Kapselung eingegangen, die eine der wichtigsten Funktionen in der objektorientierten Programmierung darstellt. Die Klassen in Include\Indicators\Indicator.mqh und in Include\Indicators\Custom\Trend.mqh decken zwei weitere Aspekte des OOP-Paradigmas ab, Polymorphismus und das Überladen von Methoden.

Der Polymorphismus bietet eine Möglichkeit, über ein und dasselbe Interface auf eine Bandbreite verschiedener Methoden zuzugreifen. Auf diese Art kann ein bestimmter Identifikator verschiedene Formen annehmen, je nach Kontext, in dem er sich befindet. Für die Umsetzung des Polymorphismus muss ein Vererbungsmechanismus vorhanden sein. Ein weiteres Merkmal der OOP ist das Überladen von Methoden, das die Erstellung mehrerer Methoden mit dem gleichen Namen, aber mit unterschiedlichen Deklarierungen von Parametern ermöglicht.

Dies ist nur eine kurze Einführung. Dieser Beitrag bietet nicht genügend Raum, um diese Themen im Detail zu besprechen, also liegt es an Ihnen, sich mit ihnen zu befassen. Bitte lesen Sie die MQL5-Abschnitte über Polymorphismus und Überladen. In jedem Fall sehen wir, dass die Standardbibliothek alle OOP-Möglichkeiten umsetzt. Somit können wir die API besser nach unseren Bedürfnissen erweitern, je besser wir sie kennen.

Eines muss noch festgehalten werden. MQL5 setzt den Polymorphismus mithilfe virtueller Funktionen um. Bitte lesen Sie den MQL5-Abschnitt über virtuelle Funktionen, um zu verstehen, wie das funktioniert.

Deshalb setzen wir die Initialisierungsmethode von CiZigZag auf folgende Weise um:

//+------------------------------------------------------------------+
//| Initialize the indicator with universal parameters               |
//+------------------------------------------------------------------+
bool CiZigZag::Initialize(const string symbol,const ENUM_TIMEFRAMES period,const int num_params,const MqlParam &params[])
  {
   return(Initialize(symbol,period,(int)params[0].integer_value,(int)params[1].integer_value,(int)params[2].integer_value));
  }
//+------------------------------------------------------------------+
//| Initialize indicator with the special parameters                 |
//+------------------------------------------------------------------+
bool CiZigZag::Initialize(const string symbol,const ENUM_TIMEFRAMES period,
                        const int depth,const int deviation_init,const int backstep)
  {
   if(CreateBuffers(symbol,period,3))
     {
      //--- string of status of drawing
      m_name  ="ZigZag";
      m_status="("+symbol+","+PeriodDescription()+","+
               IntegerToString(depth)+","+IntegerToString(deviation_init)+","+
               IntegerToString(backstep)+") H="+IntegerToString(m_handle);
      //--- save settings
      m_depth=depth;
      m_deviation=deviation_init;
      m_backstep=backstep;       
      //--- create buffers
      ((CIndicatorBuffer*)At(0)).Name("ZIGZAG");
      ((CIndicatorBuffer*)At(1)).Name("HIGH");
      ((CIndicatorBuffer*)At(2)).Name("LOW");
      //--- ok
      return(true);
     }
//--- error
   return(false);
  }

4. Testen des neuen, in der Standardbibliothek bereits verfügbaren objektorientierten ZigZag

Bevor Sie die von Ihnen entwickelten Erweiterungen verwenden, müssen Sie natürlich zuerst gewährleisten, dass sie funktionieren, wie geplant. Es wird empfohlen, einen vollständigen Satz von Tests auf Ihren neuen benutzerdefinierten Komponenten durchzuführen. Der Einfachheit halber führen wir jetzt allerdings einen einfachen Test auf den drei Hauptmethoden von CiZigZag aus, also ZigZag(const int index), High(const int index) und Low(const int index).

Wir drucken die durch diese drei Methoden für den Tick jedes EAs berechneten Werte und vergleichen die Ergebnisse von ExpertOriginalZigZag.ex5, dem verfahrensorientierten Dummy-EA, mit dem Ergebnis von ExpertOOZigZag.ex5, dem objektorientierten Dummy-EA. Immer, wenn beide Ergebnisse gleich sind, können wir schlussfolgern, dass die neue Erweiterung in Ordnung ist und wir unseren in die MQL5-API integrierten objektorientierten ZigZag nutzen können.

Abbildung 4. Wir vergleichen das Ergebnis von ExpertOriginalZigZag.ex5 mit dem Ergebnis von ExpertOOZigZag.ex5

Abbildung 4. Wir vergleichen das Ergebnis von ExpertOriginalZigZag.ex5 mit dem Ergebnis von ExpertOOZigZag.ex5

Also führen wir ExpertOriginalZigZag.ex5 und ExpertOOZigZag.ex5, die beiden am Anfang dieses Beitrags vorgestellten EAs, mit den folgenden Parametern im Strategietester aus:

  • Symbol: EURUSD, H1
  • Datum: Benutzerdefinierte Periode, von 2013.08.01 bis 2013.08.15
  • Ausführung: Normal, 1-minütiger OHLC
  • Einlage: 10000 USD, 1:100
  • Optimierung: keiner

Da beide Roboter zu den gleichen Ergebnissen führen, schlussfolgern wir, dass unsere CiZigZag gut umgesetzt wurde und wir sie ab jetzt in unseren Programmen nutzen können.

Log von ExpertOriginalZigZag.ex5:

DE      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:50:40   zigZagBuffer[0]: 1.32657
ML      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:50:40   zigZagLow[0]: 1.32657
FL      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:50:59   zigZagBuffer[0]: 1.32657
GE      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:50:59   zigZagLow[0]: 1.32657
KS      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:51:00   zigZagBuffer[0]: 1.32657
FR      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:51:00   zigZagLow[0]: 1.32657
GK      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:51:20   zigZagBuffer[0]: 1.32653
RJ      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:51:20   zigZagLow[0]: 1.32653
OR      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:51:40   zigZagBuffer[0]: 1.32653
FS      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:51:40   zigZagLow[0]: 1.32653
QJ      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:51:59   zigZagBuffer[0]: 1.32653
PH      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:51:59   zigZagLow[0]: 1.32653
JQ      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:52:00   zigZagBuffer[0]: 1.32653
KP      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:52:00   zigZagLow[0]: 1.32653
RH      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:52:20   zigZagBuffer[0]: 1.32653
GI      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:52:20   zigZagLow[0]: 1.32653
GP      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:52:40   zigZagBuffer[0]: 1.32614
// More data here!..

Log von ExpertOOZigZag.ex5:

RP      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:50:40   OO ZigZag buffer(0): 1.32657
HQ      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:50:40   OO ZigZag low(0): 1.32657
DI      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:50:59   OO ZigZag buffer(0): 1.32657
RH      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:50:59   OO ZigZag low(0): 1.32657
QR      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:51:00   OO ZigZag buffer(0): 1.32657
GS      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:51:00   OO ZigZag low(0): 1.32657
IK      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:51:20   OO ZigZag buffer(0): 1.32653
GJ      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:51:20   OO ZigZag low(0): 1.32653
EL      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:51:40   OO ZigZag buffer(0): 1.32653
OD      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:51:40   OO ZigZag low(0): 1.32653
OE      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:51:59   OO ZigZag buffer(0): 1.32653
IO      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:51:59   OO ZigZag low(0): 1.32653
DN      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:52:00   OO ZigZag buffer(0): 1.32653
RF      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:52:00   OO ZigZag low(0): 1.32653
PP      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:52:20   OO ZigZag buffer(0): 1.32653
RQ      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:52:20   OO ZigZag low(0): 1.32653
MI      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:52:40   OO ZigZag buffer(0): 1.32614
// More data here!..

Fazit

Die MQL5-Standardbibliothek erleichtert Ihnen das Leben als Entwickler. Dennoch kann sie nicht auf die Bedürfnisse aller Entwickler auf der ganzen Welt eingehen, also wird es immer einen Punkt geben, an dem Sie benutzerdefinierte Elemente erschaffen müssen. Mit der steigenden Komplexität Ihrer EAs und Indikatoren wird es immer wichtiger, die Konzepte hinter der Entwicklung eines Frameworks vollständig zu begreifen. Die Erweiterung der MQL5-Standardbibliothek ist eine Qualitätsgarantie, die sicherstellt, dass Ihre Anwendungen erfolgreich sind.

Indem wir den ZigZag-Indikator zuerst aus der Code Base heruntergeladen haben, haben wir von der Wiederverwendung von Code profitiert. Nach dem Laden im MetaTrader 5 Terminal wandten wir einen Top-down-Ansatz an, um über unseren neuen objektorientierten ZigZag-Indikator nachzudenken. Wir haben uns einen Überblick über das Gesamtsystem verschafft und dann mit der Analyse weitergemacht. In der ersten Entwicklungsphase haben wir einen Dummy-EA unter Benutzung des verfahrensorientierten ZigZag-Indikators mit dessen objektorientiertem Gegenstück verglichen.

Wir haben den ZigZag-Indikator in einer objektorientierten Klasse verpackt, die in Übereinstimmung mit der Designphilosophie von MetaQuotes gestaltet wurde, die auch für den Aufbau der Standardbibliothek angewendet wurde. Und zu guter Letzt haben wir einige einfache Tests durchgeführt und geschlussfolgert, dass unser neuer, bereits in der MQL5-API integrierter Wrapper CiZigZag gut umgesetzt wurde.