English Русский 中文 Español 日本語 Português
LifeHack für Händler: Fast-Food aus Indikatoren

LifeHack für Händler: Fast-Food aus Indikatoren

MetaTrader 5Integration | 12 März 2018, 10:01
635 0
Vladimir Karputov
Vladimir Karputov

Wenn etwas unmöglich ist, Sie es aber unbedingt wollen, dann geht es doch. Russisches Sprichwort


Einfachheit vs. Zuverlässigkeit

Bereits 2005, im neu veröffentlichten MetaTrader 4, wurde die einfache MQL-II-Skriptsprache durch MQL4 ersetzt. So skurril es heute auch erscheinen mag, viele Händler begegneten der neuen C-ähnlichen Sprache mit Vorbehalten. Es gab viele, heftige Debatten und Anschuldigungen, die sich gegen MetaQuotes Software Corp. richteten. Kritiker behaupteten, dass die Sprache sehr kompliziert sei und es unmöglich sei, sie zu beherrschen.

Jetzt, nach 12 Jahren, erscheinen solche Behauptungen seltsam, aber die Geschichte wiederholt sich. Genau wie im Jahr 2005 erklären einige Händler, dass MQL5 im Vergleich zu MQL4 zu kompliziert ist, wenn es darum geht, Strategien zu lernen und zu entwickeln. Dies bedeutet, dass das Gesamtniveau der Entwicklung von Handelsrobotern im Laufe der Jahre beträchtlich zugenommen hat, da der Entwickler keine Angst davor hatte, algorithmische Händler mit noch leistungsfähigeren Werkzeugen der Sprache C++ umzusetzen. Die neue MQL5 erlaubt es Programmierern, die Ergebnisse aller Operationen bis ins kleinste Detail zu überprüfen (dies ist besonders wichtig für die Abwicklung von Positionen) und den Speicherbedarf (RAM) zu kontrollieren. Das alte MQL4 bot viel weniger Möglichkeiten dieser Art, bevor es auf das Niveau von MQL5 verbessert wurde. Außerdem war die Syntax selbst weniger streng.

Ich glaube, dass Debatten über die Komplexität von MQL5 nach kurzer Zeit auch in Vergessenheit geraten werden. Aber da viele Händler immer noch nostalgisch am "good old MQL4" hängen, werden wir versuchen zu zeigen, wie die vertrauten MQL4-Funktionen aussehen können, wenn sie in MQL5 implementiert sind.

Wenn Sie gerade erst auf MQL5 umgestiegen sind, dann wird Ihnen dieser Artikel helfen. Erstens erfolgt der Zugriff auf die Indikatorendaten und -serien im üblichen MQL4-Stil. Zweitens ist diese ganze Einfachheit in MQL5 implementiert. Alle Funktionen sind so übersichtlich wie möglich und eignen sich perfekt für ein schrittweise Debugging.


1. Ist es möglich, in MQL5 mit Indikatoren im Stile von MQL4 zu arbeiten?

Der Hauptunterschied bei der Arbeit mit Indikatoren besteht darin, dass in MQL4 der Indikator-Befehl in einem Programm (iMACD(NULL,0,12,26,9,PRICE_CLOSE) das Anfordern der Indikatordaten eines Puffers - zB. ("MODE_MAIN") und dem Index (1) - gleichzeitig auch der Befehl für das Erstellen des Indikators ist.

//+------------------------------------------------------------------+
//|                                                        iMACd.mq4 |
//|                              Copyright © 2018, Vladimir Karputov |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2018, Vladimir Karputov"
#property link      "http://wmua.ru/slesar/"
#property version   "1.00"
#property strict
//+------------------------------------------------------------------+
//| Initialisierungsfunktion des Experten                            |
//+------------------------------------------------------------------+
int OnInit()
  {
//---

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Deinitialisierungsfunktion des Experten                          |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Experten Funktion OnTick                                         |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   double macd_main_1=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,1);
  }
//+------------------------------------------------------------------+

Folglich steht eine einzelne Zeichenkette in der Programmzeile nur für einen einzigen Schritt.

In MQL5 benötigt das Äquivalent dieses Codes mehrere Schritte:

  • Deklarieren der Variablen, in der der Indikator-Handle gespeichert werden soll;
  • Anlegen und Prüfen des Indikator-Handle;
  • Eigenständige Funktion, die den Indikatorwert liefert.
//+------------------------------------------------------------------+
//|                                                        iMACD.mq5 |
//|                              Copyright © 2018, Vladimir Karputov |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2018, Vladimir Karputov"
#property link      "http://wmua.ru/slesar/"
#property version   "1.000"

int    handle_iMACD;                         // Variable des Handles für den Indikator des MACD
//+------------------------------------------------------------------+
//| Initialisierungsfunktion des Experten                            |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Erstellen des Handles für den Indikator iMACD
   handle_iMACD=iMACD(Symbol(),Period(),12,26,9,PRICE_CLOSE);
//--- wenn die Erstellung fehlschlug 
   if(handle_iMACD==INVALID_HANDLE)
     {
      //--- Grund des Fehlers und die Ausgabe des Fehler-Nummer 
      PrintFormat("Failed to create handle of the iMACD indicator for the symbol %s/%s, error code %d",
                  Symbol(),
                  EnumToString(Period()),
                  GetLastError());
      //--- Der Indikator wurde zu früh beendet 
      return(INIT_FAILED);
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Deinitialisierungsfunktion des Experten                          |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Experten Funktion OnTick                                         |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   double macd_main_1=iMACDGet(MAIN_LINE,1);
  }
//+------------------------------------------------------------------+
//| Get value of buffers for the iMACD                               |
//|  the buffer numbers are the following:                           |
//|   0 - MAIN_LINE, 1 - SIGNAL_LINE                                 |
//+------------------------------------------------------------------+
double iMACDGet(const int buffer,const int index)
  {
   double MACD[1];
//--- Fehlernummer zurücksetzen 
   ResetLastError();
//--- Füllen eine Teils des iMACDBuffer-Arrays mit Werten aus dem Indikatorpuffer mit dem Index 0. 
   if(CopyBuffer(handle_iMACD,buffer,index,1,MACD)<0)
     {
      //--- Im Fehlerfall von CopyBuffer, drucke die Fehlernummer 
      PrintFormat("Failed to copy data from the iMACD indicator, error code %d",GetLastError());
      //--- Beenden mit Ergebnis Null - das heißt, anscheinend hat der Indikator nicht berechnet 
      return(0.0);
     }
   return(MACD[0]);
  }
//+------------------------------------------------------------------+

Lassen Sie uns den Code im MQL4-Stil umschreiben.

Das Erstellen des Indikator-Handles und das Anfordern der Indikatorendaten werden in einer einzigen Funktion realisiert:

//+------------------------------------------------------------------+
//| iMACD function in MQL4 notation                                  |
//+------------------------------------------------------------------+
double iMACD(
             string              symbol,              // Symbolname 
             ENUM_TIMEFRAMES     period,              // Zeitrahmen 
             int                 fast_ema_period,     // Periodenlänge der schnellen Glättung
             int                 slow_ema_period,     // Periodenlänge der langsamen Glättung
             int                 signal_period,       // Periodenlänge der Glättung der Differenz
             ENUM_APPLIED_PRICE  applied_price,       // Preistyp
             int                 buffer,              // Puffer
             int                 shift                // Verschub
             )
  {
   double result=NULL;
//---
   int handle=iMACD(symbol,period,fast_ema_period,slow_ema_period,signal_period,
                    applied_price);
   double val[1];
   int copied=CopyBuffer(handle,buffer,shift,1,val);
   if(copied>0)
      result=val[0];
   return(result);
  }

Hinweis! Nach dem Schreiben der Funktion erstellen wir das Indikator-Handle BEI JEDEM Tick. Man kann sagen, dass eine solche "Kreativität" in der Dokumentation nicht empfohlen wird. Werfen wir einen Blick auf den Abschnitt Funktionen für die Arbeit mit technischen Indikatoren:

Man kann nicht Daten des Indikators sofort nah seiner Erzeugung verwenden, denn man braucht einige Zeit für Berechnung der Indikatorwerte. Darum ist es am besten Handles der Indikatoren in OnInit() zu erzeugen..

Warum funktioniert dieser Code ohne Speicherbedarf? Die Antwort ist im selben Abschnitt:

Hinweis. Wiederholter Aufruf der Funktion des Indikators mit denselben Parametern führt nicht zu vielfachen Steigerung des Counters der Verweise, Counter wird nur einmal um 1 vergrößert. Es wird jedoch empfohlen, die Indikator-Handles in der Funktion OnInit() oder im Klassenkonstruktor zu erstellen und diese Handles in anderen Funktionen weiter zu verwenden. Der Referenzzähler reduziert sich, wenn ein mql5-Programm deinitialisiert wird.

Mit anderen Worten, MQL5 ist optimal konzipiert: Es steuert die Erstellung der Handles und erlaubt nicht, den gleichen Indikator mit denselben Parametern mehrmals zu erstellen. Bei wiederholten Versuchen, ein Handle zu erzeugen, das nur eine Kopie des Indikators ist, erhalten Sie einfach das Handle des zuvor angelegten Indikators mit den entsprechenden Einstellungen. Trotzdem ist es immer noch empfehlenswert, die Handles einmalig in OnInit() zu erstellen und zu sichern. Die Gründe werden später bekannt gegeben.

Hinweis: Es findet keine Überprüfung der Gültigkeit des erzeugten Handles statt.

Nun sieht der Code, der die iMACD-Indikatorwerte ​​anfordert, so aus:

//+------------------------------------------------------------------+
//|                                           MACD MQL4 style EA.mq5 |
//|                              Copyright © 2018, Vladimir Karputov |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2018, Vladimir Karputov"
#property link      "http://wmua.ru/slesar/"
#property version   "1.000"

#define MODE_MAIN 0
#define MODE_SIGNAL 1
//+------------------------------------------------------------------+
//| Initialisierungsfunktion des Experten                            |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- 

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Deinitialisierungsfunktion des Experten                          |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Experten Funktion OnTick                                         |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   double macd_main_1=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,1);
  }
//+------------------------------------------------------------------+
//| iMACD function in MQL4 notation                                  |
//+------------------------------------------------------------------+
double iMACD(
             string              symbol,              // Symbolname 
             ENUM_TIMEFRAMES     period,              // Zeitrahmen 
             int                 fast_ema_period,     // Periodenlänge der schnellen Glättung
             int                 slow_ema_period,     // Periodenlänge der langsamen Glättung
             int                 signal_period,       // Periodenlänge der Glättung der Differenz
             ENUM_APPLIED_PRICE  applied_price,       // Preistyp
             int                 buffer,              // Puffer
             int                 shift                // Verschub
             )
  {
   double result=NULL;
//---
   int handle=iMACD(symbol,period,fast_ema_period,slow_ema_period,signal_period,
                    applied_price);
   double val[1];
   int copied=CopyBuffer(handle,buffer,shift,1,val);
   if(copied>0)
      result=val[0];
   return(result);
  }
//+------------------------------------------------------------------+

HINWEIS: Der Wunsch, auf Indikatoren im MQL4-Stil zuzugreifen, beraubt uns der Möglichkeit, den Rückgabewert zu überprüfen, da alle Funktionen im MQL4-Stil NUR Werte des Formats 'double' zurückgeben. Eine mögliche Lösung wird im Abschnitt 1.1 beschrieben.

Es sieht bisher ziemlich umständlich aus, deshalb implementierten wir den Block 'define' und die Funktion iMACD(), die einen 'double'-Wert zurückgibt, in einer separaten Include-Datei IndicatorsMQL5.mqh, die sich im eigenen Ordner "[Datenordner]\MQL5\Include\SimpleCall". befindet. In diesem Fall wird der Code ziemlich kurz. Bitte beachten Sie, dass wir die Datei IndicatorsMQL5.mqh mit 'include' laden müssen. Das bedeutet, dass die Namen der Indikatorlinien beim Zugriff auf den MACD in Form von MQL5 MAIN_LINE und nicht MQL4 MODE_MAIN übergeben werden sollten:

//+------------------------------------------------------------------+
//|                                     MACD MQL4 style EA short.mq5 |
//|                              Copyright © 2018, Vladimir Karputov |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2018, Vladimir Karputov"
#property link      "http://wmua.ru/slesar/"
#property version   "1.000"
#include <SimpleCall\IndicatorsMQL5.mqh>
//+------------------------------------------------------------------+
//| Initialisierungsfunktion des Experten                            |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- 

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Deinitialisierungsfunktion des Experten                          |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Experten Funktion OnTick                                         |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   double macd_main_1=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MAIN_LINE,1);
   Comment("MACD, main buffer, index 1: ",DoubleToString(macd_main_1,Digits()+1));
  }
//+------------------------------------------------------------------+

Ich habe "Comment" nur zur Verifizierung implementiert. Sie können die Arbeit im Tester überprüfen, wenn Sie "MACD MQL4 style EA short.mq5" im visuellen Modus starten und den Cursor auf dei Bar mit dem Index #1 stellen:

"MACD MQL4 style EA short.mh5" im Tester

Abb. 1. "MACD MQL4 style EA short.mh5" im Tester

1.1. Einige Feinheiten bei der Arbeit mit "IndicatorsXXXXXX.mqh".


Fehlerbehandlung in einem Rückgabewert

Alle Indikatoren geben ihre Daten 'double'-Werte zurück. Hier geht es darum, eine Nachricht an einen Benutzer zu senden, wenn es plötzlich nicht mehr möglich ist, Daten vom Indikator zu erhalten. Dies kann passieren, wenn das Indikatorhandle nicht erzeugt wird (z.B. wenn ein nicht vorhandenes Symbol angegeben ist) oder wenn beim Aufruf von CopyBuffer ein Kopierfehler aufgetreten ist.

Die einfache Übergabe von "0.0" im Fehlerfall ist keine Option, da für die meisten Indikatoren "0.0" ein ganz normaler Wert ist (z.B. für MACD). Die Rückgabe der Konstante EMPTY_VALUE (mit dem Wert von DBL_MAX) ist ebenfalls keine Option, da der Indikator Fractals seine Puffer mit dem Wert EMPTY_VALUE indiziert, was bedeutet, dass dies kein Fehler ist.

Die einzige verbleibende Option ist, "Nicht-Zahl" - NaN - zu übergeben. Um dies zu erreichen, wird die Variable NaN auf globaler Ebene angelegt. Die Variable wird als "Nicht-Zahl" initialisiert:

double NaN=double("nan");
//+------------------------------------------------------------------+
//| iAC function in MQL4 notation                                    |
//+------------------------------------------------------------------+
double   iAC(
             string                       symbol,              // Symbolname 
             ENUM_TIMEFRAMES              timeframe,           // Zeitrahmen 
             int                          shift                // Verschub
             )
  {
   double result=NaN;
//---
   int handle=iAC(symbol,timeframe);
   if(handle==INVALID_HANDLE)
     {
      Print(__FUNCTION__,": INVALID_HANDLE error=",GetLastError());
      return(result);
     }
   double val[1];
   int copied=CopyBuffer(handle,0,shift,1,val);
   if(copied>0)
      result=val[0];
   else
      Print(__FUNCTION__,": CopyBuffer error=",GetLastError());
   return(result);
  }

Der Vorteil dieses Ansatzes besteht auch darin, dass NaN im Fehlerfall zurückgegeben wird und das Ergebnis des Vergleichs mit jeder beliebigen Zahl 'falsch' ist.

//+------------------------------------------------------------------+
//| Script Programm Start Funktion                                   |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- Beispiel eines NaN-Vergleiches
   double NaN=double("nan");
   double a=10.3;
   double b=-5;
   double otherNaN=double("nan");
   Print("NaN>10.3=",NaN>a);
   Print("NaN<-5=",NaN<b);
   Print("(NaN==0)=",NaN==0);
   Print("(NaN==NaN)=",NaN==otherNaN);
//--- Ergebnis
   NaN>10.3=false
   NaN<-5=false
   (NaN==0)=false
   (NaN==NaN)=false
//---
  }

Wenn wir also diese Funktionen im MQL4-Stil verwenden wollen, dann ist es notwendig, Handelsoperationen (wie auch alle anderen wichtigen Aktionen) nur dann durchzuführen, wenn das Ergebnis des Vergleichs true ist. Obwohl ich in diesem Fall darauf bestehe, den Rückgabewert mit der Funktion MathIsValidNumber zu überprüfen. 

Bezeichner der Indikatorzeilen in MQL4 und MQL5

Es gibt ein Kompatibilitätsproblem im Teil der Werte von Konstanten, die die Indikatorzeilen beschreiben. Nehmen wir zum Beispiel den iAlligator:

  • MQL4: 1 - MODE_GATORJAW, 2 - MODE_GATORTEETH, 3 - MODE_GATORLIPS
  • MQL5: 0 - GATORJAW_LINE,   1 - GATORTEETH_LINE,   2 - GATORLIPS_LINE 

Das Problem ist, dass die Indikatorzeile in der Funktion "IndicatorsXXXXXX.mqh" eine Zahl ist. Wenn diese Zahl z.B. 1 ist, dann kann niemand sagen, was der Benutzer meinte: Entweder sie arbeiteten im MQL4-Stil (und hatten im Kopf 1 - MODE_GATORJAW), oder sie arbeiteten im MQL5-Stil (und hatten im Kopf eine ganz andere Indikatorzeile 1 - GATORTEETH_LINE).

In diesem Zusammenhang habe ich beschlossen, zwei Include-Dateien zu erstellen - praktisch Zwillinge: "IndicatorsMQL4.mqh" und "IndicatorsMQL5.mqh". Ihr Unterschied besteht darin, dass die Datei "IndicatorsMQL4.mqh" Indikatorzeilen NUR im MQL4-Stil versteht, während die Datei "IndicatorsMQL5.mqh" Indikatorzeilen NUR im MQL5-Stil versteht. In "IndicatorsMQL4.mqh" erfolgt die Transformation der Indikatorzeile im Eingabeparameter direkt innerhalb der Funktionen iADX, iAlligator... - diese Transformationen können nicht mittels einem #define erreicht werden.

Lassen Sie mich den Grund dafür am Beispiel von iBands und iEnvelopes erläutern:

//+------------------------------------------------------------------+
//| iBands function in MQL4 notation                                 |
//|   The buffer numbers are the following:                          |
//|      MQL4 0 - MODE_MAIN, 1 - MODE_UPPER, 2 - MODE_LOWER          |
//|      MQL5 0 - BASE_LINE, 1 - UPPER_BAND, 2 - LOWER_BAND          |
//+------------------------------------------------------------------+
double   iBands(
...
//+------------------------------------------------------------------+
//| iEnvelopes function in MQL4 notation                             |
//|   The buffer numbers are the following:                          |
//|      MQL4 0 - MODE_MAIN,  1 - MODE_UPPER, 2 - MODE_LOWER         | ???
//|      MQL5 0 - UPPER_LINE, 1 - LOWER_LINE,        -/-             |
//+------------------------------------------------------------------+
double   iEnvelopes(

In MQL4 wird, für den Indikator iBands, MODE_UPPER in 1 transformiert, während für den den Indikator iEnvelopes es in 0 transformiert wird.

2. Was ist der Speicherbedarf, wenn wir Indikatoren im MQL4-Stil bei jedem Tick anwenden?

Vergleichen wir den Speicherbedarf der beiden EAs: "iMACD.mq5" - der EA mit korrektem Zugriff auf die Indikatoren und der "MACD MQL4 style EA short.mq5" - mit Zugriff auf MQL4 style Indikatoren. Die maximale Anzahl der Bars im Fenster ist in den Terminaleinstellungen auf "100 000" eingestellt. Erstellen Sie zwei Profile von 14 Charts:

  • Das Profil "iMACd" - der EA "iMACd.mq5" ist auf 13 Charts gestartet worden, alle Charts haben den Zeitrahmen M30;
  • Das Profil "MACD MQL4 style EA short" - der EA "MACD MQL4 style EA short.mq5" wird auch auf 13 Charts gestartet.

Der Indikator "Terminal Memory used.mq5" wird auf dem vierzehnten gestartet. Sein Ziel ist es, den Wert von TERMINAL_MEMORY_USED alle 10 Sekunden zu drucken.

Wir werden zwei Werte vergleichen: die Menge des vom Terminal benötigten RAMs (Task-Manager-Daten) und die angezeigten Werte von TERMINAL_MEMORY_USED. Die Beobachtung wird für 10 Minuten durchgeführt - wir werden sehen, ob zu viel Speicher verwendet wird. Die wichtigste Bedingung: Nach dem Starten des Terminals nichts tun - keine neuen Registerkarten öffnen oder den Chat lesen.

Profil Task-Manager TERMINAL_MEMORY_USED Task-Manager (in 10 Minuten) TERMINAL_MEMORY_USED (in 10 Minuten)
iMACd 279.7 MB 745 MB 279.7 MB 745 MB
MACD MQL4 style EA short 279.9 MB 745 MB 280.0 MB 745 MB

Ändern wir nun den Test: Nach einer Laufzeit von 10 Minuten stellen wir die Zeitrahmen aller Charts auf H1 um.

Profil Task-Manager TERMINAL_MEMORY_USED Task-Manager (in 10 Minuten) TERMINAL_MEMORY_USED (in 10 Minuten)
iMACd 398.0 MB 869 MB 398.3 MB 869 MB
MACD MQL4 style EA short 319.2 MB 874 MB 330.5 MB 874 MB

Übersichtstabelle zur besseren Übersichtlichkeit des Speicherbedarfs:

Profil Task Manager
(M30), MB
TERMINAL_MEMORY_USED
(M30), MB
Task Manager
(H1), MB
TERMINAL_MEMORY_USED
(H1), MB

Start nach 10 Minuten Start nach 10 Minuten Start nach 10 Minuten Start nach 10 Minuten
iMACd 279.7 279.7 745 745 398.0 869 398.3 869
MACD MQL4 style EA short 279.9 280.0 745 745 319.2 874 330.5 874

3. Das neue Leben des EAs MACD Sample.mq4

Lassen Sie uns die Ausführungsgeschwindigkeit, den Speicherbedarf und den EA [Datenordner]\MQL4\Experts\MACD Sample.mq4 (entwickelt in MQL5, aber im MQL4-Stil wie "MACD MQL4 style EA short.mq5") überprüfen.

3.1. Ändern wir den EA "MACD Sample.mq5", so dass er einen Wert nach dem anderen erhält.

Der standardmäßige "MACD Sample.mq5" erhält zwei Indikatorwerte auf einmal:

//+------------------------------------------------------------------+
//| main function returns true if any position processed             |
//+------------------------------------------------------------------+
bool CSampleExpert::Processing(void)
  {
//--- neue Kurse abfragen
   if(!m_symbol.RefreshRates())
      return(false);
//--- Indikatorwerte neu berechnen
   if(BarsCalculated(m_handle_macd)<2 || BarsCalculated(m_handle_ema)<2)
      return(false);
   if(CopyBuffer(m_handle_macd,0,0,2,m_buff_MACD_main)  !=2 ||
      CopyBuffer(m_handle_macd,1,0,2,m_buff_MACD_signal)!=2 ||
      CopyBuffer(m_handle_ema,0,0,2,m_buff_EMA)         !=2)
      return(false);
//   m_indicators.Refresh();
//--- um den Code zu vereinfachen und den Zugriff zu beschleunigen
//--- Datenspeicherung in internen Variablen
   m_macd_current   =m_buff_MACD_main[0];
   m_macd_previous  =m_buff_MACD_main[1];
   m_signal_current =m_buff_MACD_signal[0];
   m_signal_previous=m_buff_MACD_signal[1];
   m_ema_current    =m_buff_EMA[0];
   m_ema_previous   =m_buff_EMA[1];

Danach werden den Variablen die Daten der Arrays mit der Dimension "2" zugewiesen. Warum wird das so gemacht? Unabhängig davon, ob wir mit einem oder zwei Werten pro Zeit kopieren, verwenden wir immer noch CopyBuffer. Wenn wir jedoch zwei Werte auf einmal kopieren, sparen wir uns eine Operation, wenn wir die Werte dem Array zuweisen.

Aber "MACD Sample.mq4" EA erhält jedes Mal nur einen Indikatorwert:

//--- um den Coe zu vereinfachen und die Ausführung zu beschleunigen, werden die Daten internen Variablen zugewiesen
   MacdCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,0);
   MacdPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,1);
   SignalCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,0);
   SignalPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,1);
   MaCurrent=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,0);
   MaPrevious=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,1);

Die Hauptlinie, die Signallinie und der gleitende Durchschnitt des MACD werden jeweils zweimal abgefragt. Daher sollte "MACD Sample.mq5" in die gleiche Form gebracht werden. Nennen wir diese EA-Version "MACD Sample One value at a time.mq5". Hier ist er jetzt so verändert, dass wir einen Wert nach dem anderen erhalten:

//--- Indikatorwerte neu berechnen
   if(BarsCalculated(m_handle_macd)<2 || BarsCalculated(m_handle_ema)<2)
      return(false);
//   if(CopyBuffer(m_handle_macd,0,0,2,m_buff_MACD_main)  !=2 ||
//      CopyBuffer(m_handle_macd,1,0,2,m_buff_MACD_signal)!=2 ||
//      CopyBuffer(m_handle_ema,0,0,2,m_buff_EMA)         !=2)
//      return(false);
//   m_indicators.Refresh();
//--- um den Code zu vereinfachen und den Zugriff zu beschleunigen
//--- Datenspeicherung in internen Variablen
   CopyBuffer(m_handle_macd,0,0,1,m_buff_MACD_main);
   m_macd_current=m_buff_MACD_main[0];
   CopyBuffer(m_handle_macd,0,1,1,m_buff_MACD_main);
   m_macd_previous=m_buff_MACD_main[0];
   CopyBuffer(m_handle_macd,1,0,1,m_buff_MACD_signal);
   m_signal_current=m_buff_MACD_signal[0];
   CopyBuffer(m_handle_macd,1,1,1,m_buff_MACD_signal);
   m_signal_previous=m_buff_MACD_signal[0];
   CopyBuffer(m_handle_ema,0,0,1,m_buff_EMA);
   m_ema_current=m_buff_EMA[0];
   CopyBuffer(m_handle_ema,0,1,1,m_buff_EMA);
   m_ema_previous=m_buff_EMA[0];

Dieser Code wird in der datei "MACD Sample One value at a time.mq5" gespeichert, die am Ende des Artikels angehängt ist.

3.2. Konvertieren von "MACD Sample.mq4" nach MQL5

Um auf die Indikatoren im MQL4-Stil zugreifen zu können, sowie mit Positionen und Handel arbeiten zu können, sollten wir die Datei "IndicatorsMQL4.mqh" (wie Sie sich erinnern, versteht diese Datei nur die MQL4-Namen der Indikatorlinien) und die Handelsklassen CPositionInfo, CTrade, CSymbolInfo und CAccountInfo einbinden. Außerdem sollte der Block von 'define' - Namen der Zeilen im Indikator - dem EA hinzugefügt werden, um einen korrekten Zugriff auf die Indikatoren in "IndicatorsMQL4.mqh" zu ermöglichen:

#property description " and the indicators are accessed in the style of MQL4"
#define MODE_MAIN    0
#define MODE_SIGNAL  1 
#include <SimpleCall\IndicatorsMQL4.mqh>
//---
#include <Trade\PositionInfo.mqh>
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>  
#include <Trade\AccountInfo.mqh>
CPositionInfo  m_position;                   // Objekt der Position
CTrade         m_trade;                      // Handelsobjekt
CSymbolInfo    m_symbol;                     // Objekt der Symbolinfo.
CAccountInfo   m_account;                    // Kontoobjekt
//---
input double TakeProfit    =50;

Darüber hinaus wird ein spezieller Faktor für die Anpassung an drei- und fünfstellige Kurse benötigt:

input double MACDCloseLevel=2;
input int    MATrendPeriod =26;
//---
double       m_adjusted_point;               // Wert eines Points für 3 und 5 Stellen
//+------------------------------------------------------------------+
//| Initialisierungsfunktion des Experten                            |
//+------------------------------------------------------------------+

Um aktuelle Preise zu erhalten, verwende ich das Objekt m_symbol der Handelsklasse CSymbolInfo:

//+------------------------------------------------------------------+
//| Initialisierungsfunktion des Experten                            |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   if(!m_symbol.Name(Symbol())) // Festlegen des Symbolnamens
      return(INIT_FAILED);
   RefreshRates();

Die Methode RefreshRates() aktualisiert die Preise und stellt sicher, dass keine Preise mit dem Wert "0.0" existieren:

//+------------------------------------------------------------------+
//| Refreshes the symbol quotes data                                 |
//+------------------------------------------------------------------+
bool RefreshRates(void)
  {
//--- neue Kurse abfragen
   if(!m_symbol.RefreshRates())
     {
      Print("RefreshRates error");
      return(false);
     }
//--- Schutz vor der Rückgabe von "Null"
   if(m_symbol.Ask()==0 || m_symbol.Bid()==0)
      return(false);
//---
   return(true);
  }

Der Faktor m_adjusted_point wird in OnInit () initialisiert, nachdem das Objekt m_symbol initialisiert wurde:

//+------------------------------------------------------------------+
//| Initialisierungsfunktion des Experten                            |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   if(!m_symbol.Name(Symbol())) // Festlegen des Symbolnamens
      return(INIT_FAILED);
   RefreshRates();
   //--- Bestimmen von 3 oder 5 Stellen
   int digits_adjust=1;
   if(m_symbol.Digits()==3 || m_symbol.Digits()==5)
      digits_adjust=10;
   m_adjusted_point=m_symbol.Point()*digits_adjust;
//---
   return(INIT_SUCCEEDED);
  }

In OnTick(), dank der angehängten Datei "IndicatorsMQL4Style.mqh", greifen wir auf die Indikatoren im MQL4-Stil zu:

   if(!RefreshRates())
      return;
//--- um den Coe zu vereinfachen und die Ausführung zu beschleunigen, werden die Daten internen Variablen zugewiesen
   MacdCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MAIN_LINE,0);
   MacdPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MAIN_LINE,1);
   SignalCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,SIGNAL_LINE,0);
   SignalPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,SIGNAL_LINE,1);
   MaCurrent=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,0);
   MaPrevious=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,1);

3.2.1. Die Arbeit mit Positionen

Der Sicherheit halber überprüfen wir, ob es keine offene Positionen gibt.

   total=PositionsTotal();
   if(total<1)
     {

Obwohl dieser Ansatz nicht ganz korrekt ist, da er die Existenz offener Positionen mit anderen Symbolen und/oder mit anderen Identifikatoren (Magicnummer) nicht berücksichtigt.

3.2.2. Kaufpositionen werden mit der Methode Buy der Klasse CTrade eröffnet, während die Korrektheit der Ausführung mit der Methode ResultDeal derselben Klasse überprüft wird. ResultDeal gibt eine Ticketnummer der Position zurück, wenn es ausgeführt wird.

      //--- Prüfen, ob eine Kaufposition eröffnet werden kann
      if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious && 
         MathAbs(MacdCurrent)>(MACDOpenLevel*m_adjusted_point) && MaCurrent>MaPrevious)
        {
         m_trade.Buy(Lots,m_symbol.Name(),m_symbol.Ask(),
                     0.0,
                     m_symbol.NormalizePrice(m_symbol.Ask()+TakeProfit*m_adjusted_point),
                     "macd sample");
         if(m_trade.ResultDeal()!=0)
            Print("BUY position opened : ",m_trade.ResultPrice());
         else
            Print("Error opening BUY position : ",m_trade.ResultRetcodeDescription());
         return;
        }

Beachten Sie, dass der Preis der Handelsanfrage mit der Methode NormalizePrice der Handelsklasse CSymbolInfo normalisiert wird. Diese Methode erlaubt es, die Quantisierung zu berücksichtigen: minimale Preisänderung und die Anzahl der Dezimalstellen. 

Die gleichen Methoden werden verwendet, um Verkaufspositionen zu eröffnen.

3.2.3. Positionen Bypass-Block: Schließen oder Modifizieren.

Die Schleife selbst wird von der Anzahl aller Positionen minus eins bis einschließlich Null durchlaufen. Um mit einer Position arbeiten zu können, müssen wir sie zunächst in der allgemeinen Liste nach Index selektieren:

   for(int i=PositionsTotal()-1;i>=0;i--)
      if(m_position.SelectByIndex(i)) // wählt die Position nach Index für den weiteren Zugriff auf seine Eigenschaften aus

Die Position wird mit der Methode PositionClose geschlossen, während eine Modifikation mit PositionModify durchgeführt wird. Beachten Sie, dass die Modifikation die Verwendung der Methode NormalizePrice der Handelsklasse CSymbolInfo erlaubt.

Der gesamte Block, um die Position zu umgehen:

//--- es ist wichtig, den Markt richtig zu betreten, aber es ist wichtiger, ihn richtig zu verlassen...   
   for(int i=PositionsTotal()-1;i>=0;i--)
      if(m_position.SelectByIndex(i)) // wählt die Position nach Index für den weiteren Zugriff auf seine Eigenschaften aus.
         if(m_position.Symbol()==m_symbol.Name())
           {
            //--- Kaufposition eröffnet
            if(m_position.PositionType()==POSITION_TYPE_BUY)
              {
               //--- Schließen?
               if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious && 
                  MacdCurrent>(MACDCloseLevel*m_adjusted_point))
                 {
                  //--- Schließen und verlassen
                  if(!m_trade.PositionClose(m_position.Ticket()))
                     Print("PositionClose error ",m_trade.ResultRetcodeDescription());
                  return;
                 }
               //--- Prüfen auf einen Trailing-Stop
               if(TrailingStop>0)
                 {
                  if(m_position.PriceCurrent()-m_position.PriceOpen()>m_adjusted_point*TrailingStop)
                    {
                     if(m_position.StopLoss()<m_symbol.Bid()-m_adjusted_point*TrailingStop)
                       {
                        //--- Position ändern und verlassen
                        if(!m_trade.PositionModify(m_position.Ticket(),
                           m_symbol.NormalizePrice(m_position.PriceCurrent()-m_adjusted_point*TrailingStop),
                           m_position.TakeProfit()))
                           Print("PositionModify error ",m_trade.ResultRetcodeDescription());
                        return;
                       }
                    }
                 }
              }

            if(m_position.PositionType()==POSITION_TYPE_SELL)
              {
               //--- Schließen?
               if(MacdCurrent<0 && MacdCurrent>SignalCurrent && 
                  MacdPrevious<SignalPrevious && MathAbs(MacdCurrent)>(MACDCloseLevel*m_adjusted_point))
                 {
                  //--- Schließen und verlassen
                  if(!m_trade.PositionClose(m_position.Ticket()))
                     Print("PositionClose error ",m_trade.ResultRetcodeDescription());
                  return;
                 }
               //--- Prüfen auf einen Trailing-Stop
               if(TrailingStop>0)
                 {
                  if((m_position.PriceOpen()-m_position.PriceCurrent())>(m_adjusted_point*TrailingStop))
                    {
                     if((m_position.StopLoss()>(m_symbol.Ask()+m_adjusted_point*TrailingStop)) || (m_position.StopLoss()==0.0))
                       {
                        //--- Position ändern und verlassen
                        if(!m_trade.PositionModify(m_position.Ticket(),
                           m_symbol.NormalizePrice(m_symbol.Ask()+m_adjusted_point*TrailingStop),
                           m_position.TakeProfit()))
                           Print("PositionModify error ",m_trade.ResultRetcodeDescription());
                        return;
                       }
                    }
                 }
              }
           }

Wir sind mit allen Änderungen fertig. Die endgültige Datei "MACD Sample 4 to 5 MQL4 style.mq5" ist unten angehängt.

3.3. Vergleichen wir die Geschwindigkeit, mit die MACD-basierten EAs ausgeführt werden.

Die folgenden EAs werden zum Vergleich herangezogen:

  • "MACD Sample.mq5" - der standardmäßige EA des Terminals mit der korrekten Indikatorverwendung
  • "MACD Sample One value at a time.mq5" - das Äquivalent zu "MACD Sample.mq5", wobei wir immer nur einen Wert des Indikators abfragen.
  • "MACD Sample 4 to 5 MQL4 style.mq5" - der MQL4 EA, konvertiert nach MQL5, mit minimalen Modifikationen und Zugriff auf die Indikatoren im Stile von MQL4

Der Test wurde mit USDJPY M30 von 2017.02.01 bis 2018.01.16 auf dem MetaQuotes-Demo-Server durchgeführt. Das Terminal wurde nach jedem Test zurückgesetzt (je nachdem, ob der EAs gewechselt wurde oder die Tick-Generierung). PC-Konfiguration:

Windows 10 (build 16299) x64, IE 11, UAC, Intel Core i3-3120M  @ 2.50GHz, Memory: 4217 / 8077 Mb, Disk: 335 / 464 Gb, GMT+2

# Expert Advisor Jeder Tick auf Basis von Real-Ticks Jeder Tick OHLC


Testdauer Positionen Transaktionen Testdauer Positionen Transaktionen Testdauer Positionen Transaktionen
 1  MACD Sample.mq5  0:01:19.485  122  244  0:00:53.750  122  244  0:00:03.735  119  238
 2  MACD Sample One value at a time.mq5  0:01:20.344  122  244  0:00:56.297  122  244  0:00:03.687  119  238
 3  MACD Sample 4 to 5 MQL4 style.mq5  0:02:37.422  122  244  0:01:52.171  122  244  0:00:06.312  119  238

Alle drei EAs zeigen ähnliche Diagramme im Modus "Jeder Tick":

MACD Sample

Abb. 2. MACD Sample XXXX im Strategietester


FAZIT: Der EA "MACD Sample 4 to 5 MQL4 style.mq5" EA mit Zugriff auf Indikatoren im MQL4-Stil ist doppelt so langsam wie vergleichbare EAs mit korrektem Zugriff auf Indikatoren.

3.4. Vergleichen wir den Speicherbedarf von MACD-basierten EAs.

Dazu werden die gleichen 14 Diagramme verwendet, wie in Punkt 2. Was passiert mit dem Speicherbedarf, wenn wir Indikatoren im MQL4-Stil bei jedem Tick anwenden? Der Indikator "Terminal Memory used.mq5" wird immer auf dem ersten Chart gestartet. Es erneuert alle 10 Sekunden den Wert von TERMINAL_MEMORY_USED ID, während die EAs auf den restlichen 13 Charts einzeln gestartet werden. Das Terminal wird vor jeder Messung zurückgesetzt.

# Expert Advisor Task Manager, MB TERMINAL_MEMORY_USED, Мб
 1  MACD Sample.mq5  334.6  813
 2  MACD Sample One value at a time.mq5  335.8  813
 3  MACD Sample 4 to 5 MQL4 style.mq5  342.2  818

FAZIT: Die MACD-basierten EAs mit korrektem Zugriff auf die Indikatoren und MACD-basierte EAs mit Zugriff auf die Indikatoren im MQL4-Stil sind in Bezug auf den Speicherbedarf vergleichbar. Sie verwenden etwas gleich viel Speicherplatz.


4. Das neue Leben des EAs [Datenordner]\MQL4\Experten\Moving Average.mq4

Im vorigen Abschnitt haben wir MQL4 in MQL5 konvertiert. Was Movinge Average.mq4 angeht, schlage ich vor, einfach den Moving Average.mq5 zu ändern, so dass die Datei "IndicatorsMQL5.mqh" geladen wird.

#property version   "1.00"
#include <SimpleCall\IndicatorsMQL5.mqh>

#include <Trade\Trade.mqh>

und CopyBuffer zu ersetzen

//--- Abfrage des gleitenden Durchschnitts 
   double   ma[1];
   if(CopyBuffer(ExtHandle,0,0,1,ma)!=1)
     {
      Print("CopyBuffer from iMA failed, no data");
      return;
     }

und der Zugriff auf den Indikator im Stile von MQL4:

//--- Abfragen des gleitenden Durchschnitts 
   ma=iMA(NULL,0,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE,0);

Damit bleibt uns nur noch eine Möglichkeit, das Operationsergebnis zu überprüfen - vergleichen wir die erhaltenen Daten mit Null. Vor diesem Hintergrund sah der letzte Eintrag in den Blöcken "CheckForOpen" und "CheckForClose" wie folgt aus:

//--- Abfrage des gleitenden Durchschnitts 
   double   ma[1];
   if(CopyBuffer(ExtHandle,0,0,1,ma)!=1)
     {
      Print("CopyBuffer from iMA failed, no data");
      return;
     }

und wird so ausschauen:

//--- Abfrage des gleitenden Durchschnitts 
   double   ma[1];
   ma[0]=iMA(_Symbol,_Period,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE,0);
//if(CopyBuffer(ExtHandle,0,0,1,ma)!=1)
   if(ma[0]==0.0)
     {
      //Print("CopyBuffer from iMA failed, no data");
      Print("Get iMA in MQL4 style failed, no data");
      return;
     }

Dies sind die Änderungen, die wir im EA "Moving Average MQL4 style.mq5" speichern werden. Der EA ist unten angefügt. Messen wir die Leistung und den Speicherbedarf zwischen dem standardmäßigen "Moving Average.mq5" und "Moving Average MQL4 style.mq5". 

Wie Sie sich erinnern können, wurden die Tests auf folgendem System durchgeführt

Windows 10 (build 16299) x64, IE 11, UAC, Intel Core i3-3120M  @ 2.50GHz, Memory: 4217 / 8077 Mb, Disk: 335 / 464 Gb, GMT+2

Das Terminal wurde nach jedem Test zurückgesetzt. Die Tests wurden mit EURUSD M15 vom 01.02.2017 bis zum 01.01.2018.01.16 auf dem MetaQuotes-Demo-Server durchgeführt.

# Expert Advisor Jeder Tick auf Basis von Real-Ticks Jeder Tick OHLC


Testdauer Positionen Transaktionen Testdauer Positionen Transaktionen Testdauer Positionen Transaktionen
 1  Moving Average.mq5  0:00:33.359  1135  2270  0:00:22.562  1114  2228  0:00:02.531  1114  2228
 2  Moving Average MQL4 style.mq5  0:00:34.984  1135  2270  0:00:23.750  1114  2228  0:00:02.578  1114  2228

FAZIT: Der MQL5-Kern musste wahrscheinlich zwischen zwei Handles in MACD Sample bei jedem Tick suchen, wenn er auf die Indikatoren im MQL4-Stil zugreift. Es war diese Suche, die die meiste Zeit in Anspruch nahm.

Im Falle des Moving Average EA verbringt der MQL5-Kern beim Zugriff auf den Indikator im MQL4-Stil keine Zeit mit der Suche nach einer benötigten Kerze, da sie die einzige ist. 

Vergleichen wir den Speicherbedarf des Moving Average-basierten EAs.

Dazu werden die gleichen 14 Diagramme verwendet, wie in Punkt 2. Der Indikator "Terminal Memory used.mq5" wird immer auf dem ersten Chart gestartet. Es erneuert alle 10 Sekunden den Wert von TERMINAL_MEMORY_USED ID, während die EAs auf den restlichen 13 Charts einzeln gestartet werden. Das Terminal wird vor jeder Messung zurückgesetzt.

# Expert Advisor Task Manager, MB TERMINAL_MEMORY_USED, Мб
 1  Moving Average.mq5  295.6  771
 2  Moving Average MQL4 style.mq5  283.6  760

FAZIT: Der Speicherbedarf ist nahezu identisch. Kleine Unterschiede lassen sich auf das "Innenleben" des Terminals zurückführen: Newsupdates, etc.


5. Äquivalente der iXXXX Serie

Da wir die Abfrage der Indikatorwerte im MQL4-Stil durchgeführt haben, schreiben wir die Funktionen des Abschnitts "Zugriff auf Zeitreihen und Indikatorendaten". Die Implementierung erfolgt in [Datenordner]\MQL5\Include\SimpleCall\Series.mqh.

Die Liste der Funktionen in Series.mqh, die den Zugriff auf Zeitreihenwerte wie in MQL4 ermöglichen:


Für die Funktionen iHighest und iLowest stehen die vordefinierten Enumerationen MODE_OPEN, MODE_LOW, MODE_HIGH, MODE_CLOSE, MODE_VOLUME und MODE_TIME zur Verfügung.

Beispiel für die Implementierung der Funktion iClose:

//+------------------------------------------------------------------+
//| iClose function in MQL4 notation                                 |
//+------------------------------------------------------------------+
double   iClose(
                string                    symbol,              // Symbol
                ENUM_TIMEFRAMES           timeframe,           // Zeitrahmen
                int                       shift                // Verschub
                )
  {
   double result=0.0;
//---
   double val[1];
   ResetLastError();
   int copied=CopyClose(symbol,timeframe,shift,1,val);
   if(copied>0)
      result=val[0];
   else
      Print(__FUNCTION__,": CopyClose error=",GetLastError());
//---
   return(result);
  }

Der Wert für shift der Schlusskurse wird über CopyClose umgesetzt — der ersten Form des Aufrufs (Zugriff über die Ausgangsposition und die Anzahl der benötigten Elemente):

int  CopyClose( 
   string           symbol_name,       // Symbolname 
   ENUM_TIMEFRAMES  timeframe,         // Zeitrahmen 
   int              start_pos,         // Anfangsposition
   int              count,             // Anzahl der Kopien
   double           close_array[]      // Array der kopierten Preise
   );


Schlussfolgerung

Wie wir sehen können, erlaubt MQL5 MQL4-Fans, die Werte ​​von Indikatoren und Zeitreihen in ihrem bevorzugten Stil zu erhalten. Manche sagen, dass dieser Code kürzer und leichter zu lesen ist. Plattformentwickler benötigen jedoch eine sorgfältigere Arbeit mit einem Code und maximale Prüfungen beim Aufruf von Funktionen (und ich stimme ihnen voll und ganz zu). Lassen Sie uns kurz die Vor- und Nachteile der im Artikel beschriebenen Funktionen aufzählen.


Nachteile
  • Einschränkung bei der Verarbeitung des zurückgegebenen Fehlers beim Zugriff auf Indikatoren;
  • Verringerung der Testgeschwindigkeit bei gleichzeitigem Zugriff auf mehr als einen Indikator;
  • Die Notwendigkeit, die Indikatorzeilen korrekt hervorzuheben, je nachdem, ob IndicatorsMQL5.mqh oder IndicatorsMQL4.mqh geladen wurden.
Vorteile
  • Einfachheit des Code-Schreibens - eine Zeichenkette statt mehrerer;
  • Sichtbarkeit und Prägnanz - je kürzer der Code, desto leichter ist das Verständnis.
Ich bleibe jedoch dem klassischen MQL5-Ansatz beim Zugriff auf Indikatoren treu. In diesem Artikel habe ich nur eine mögliche Alternative getestet.

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

Beigefügte Dateien |
MQL5.zip (25.33 KB)
LifeHack für Händler: ForEach mit #define zubereiten LifeHack für Händler: ForEach mit #define zubereiten
Eine Zwischenstufe für diejenigen, die immer noch in MQL4 schreiben und nicht auf MQL5 umsteigen können. Wir suchen weiter nach den Möglichkeiten, Codes im MQL4-Stil zu schreiben. Diesmal betrachten wir die Makrosubstitution des Präprozessors #define.
Individuell Strategien testen basierend auf schnellen mathematischen Berechnungen Individuell Strategien testen basierend auf schnellen mathematischen Berechnungen
Der Artikel beschreibt die Art und Weise, wie man Strategien individuell testen und einen benutzerdefinierten Analysator für die Optimierungsdurchläufe erstellt. Nach dem Lesen werden Sie verstehen, wie die "Mathematische Berechnung" und der Mechanismus der sogenannten Frames funktionieren, wie Sie benutzerdefinierte Daten für Berechnungen vorbereiten und laden und effektive Algorithmen für ihre Komprimierung verwenden. Dieser Artikel wird auch für diejenigen interessant sein, die an Möglichkeiten interessiert sind, benutzerdefinierte Informationen innerhalb eines Experten zu speichern.
Kontrollierte Optimierung: Simuliertes Abkühlen Kontrollierte Optimierung: Simuliertes Abkühlen
Der Strategy Tester in der Handelsplattform MetaTrader 5 bietet nur zwei Optimierungsoptionen: Die vollständige Suche nach Parametern oder den genetischen Algorithmus. Dieser Artikel schlägt eine neue Methode zur Optimierung von Handelsstrategien vor — Simuliertes Abkühlen (simulated annealing). Dabei werden der Algorithmus der Methode, ihre Implementierung und die Integration in jeden Expert Advisor besprochen. Der entwickelte Algorithmus wird mit dem Moving Average EA getestet.
Automatisches Erstellen von Unterstützung- und Widerstandslinien Automatisches Erstellen von Unterstützung- und Widerstandslinien
Der Artikel beschäftigt sich mit der automatischen Konstruktion von Unterstützungs-/Widerstandslinien unter Verwendung aktueller Hochs und Tiefs. Zur Definition dieser Extremwerte wird der bekannte ZigZag-Indikator verwendet.