Übertragung von MQL4-Indikatoren nach MQL5

Vasily | 7 März, 2016

Einleitung

Liebe Leserinnen und Leser,

In diesem Beitrag möchte ich Ihnen einen Algorithmus zur Übertragung elementarer Kursberechnungen aus MQL4 nach MQL5 vorstellen. In Anbetracht der Unterschiede zwischen MQL5 und MQL4 wurde die Funktionsbibliothek mql4_2_mql5.mqh hinzugefügt, deren Verwendung wir in diesem Beitrag kennenlernen werden.

1. Vorbereiten des Indikators für die Übertragung

In diesem Artikel befassen wir uns ausschließlich mit der Übertragung der Indikatorberechnungen. Wenn uns in einem Indikator grafische Elemente oder komplexere Kursberechnungen begegnen, kann es schwierig werden.

Zunächst muss der MQL4-Code für die Übertragung vorbereitet werden. Sehen wir uns an, was dazu zu tun ist.

Wir öffnen das Bearbeitungsprogramm MetaEditor 4 mit dem benötigten Indikator, zum Beispiel MACD, und fangen mit der Bearbeitung der Eingangsparameter an:

//---- indicator parameters
extern int FastEMA=12;
extern int SlowEMA=26;
extern int SignalSMA=9;
//---- indicator buffers
double     MacdBuffer[];
double     SignalBuffer[];

Wir müssen das alles in folgende Form bringen:

double &MacdBuffer[],double &SignalBuffer[],int FastEMA,int SlowEMA,int SignalSMA

Am Anfang der Zeile stehen die Indikatorpuffer mit dem ergänzten „&“ vor der Pufferbezeichnung, da wir die Verknüpfungen in das Datenfeld übertragen müssen, in dem alle Änderungen vor sich gehen, jedoch nicht das Datenfeld selbst.

Es folgen die Eingangsparameter. In unserem MQL4-Indikator ersetzen wir die folgende Zeile:

int start()

durch

int start(int rates_total,
         int prev_calculated,
         double &MacdBuffer[],
         double &SignalBuffer[],
         int FastEMA,
         int SlowEMA,
         int SignalSMA)

Wie wir sehen, wurden 2 weitere Pflichtelemente ergänzt:

int rates_total, int prev_calculated,

Der nächste Teil ist die unsere zuvor formulierte Zeile.

Jetzt kopieren wir den gesamten Block bis zum letzten Zeichen.

//+------------------------------------------------------------------+
//| Moving Averages Convergence/Divergence                           |
//+------------------------------------------------------------------+
int start(int rates_total
         ,int prev_calculated
         ,double &MacdBuffer[]
         ,double &SignalBuffer[]
         ,int FastEMA
         ,int SlowEMA
         ,int SignalSMA)
  {
   int limit;
   int counted_bars=IndicatorCounted();
//---- last counted bar will be recounted
   if(counted_bars>0) counted_bars--;
   limit=Bars-counted_bars;
//---- macd counted in the 1-st buffer
   for(int i=0; i<limit; i++)
      MacdBuffer[i]=iMA(NULL,0,FastEMA,0,MODE_EMA,PRICE_CLOSE,i)
                     -iMA(NULL,0,SlowEMA,0,MODE_EMA,PRICE_CLOSE,i);
//---- signal line counted in the 2-nd buffer
   for(i=0; i<limit; i++)
      SignalBuffer[i]=iMAOnArray(MacdBuffer,Bars,SignalSMA,0,MODE_SMA,i);
//---- done
   return(0);
  }
//+------------------------------------------------------------------

2. Erstellen einer MQL5-Schablone für MQL4-Programme

Jetzt muss die Umgebung für unseren Block vorbereitet werden.

Dazu wählen wir in dem Bearbeitungsprogramm MetaEditor 5 den Menüpunkt „Erstellen“ und anschließend „Benutzerdefinierter Indikator“.

Die Eingangsparameter (Abb. 1) werden analog zu denjenigen des MQL4-Indikators angelegt:

//---- indicator parameters
extern int FastEMA=12;
extern int SlowEMA=26;
extern int SignalSMA=9;

Eingangsparameter des Indikators MACD

Abbildung 1. Eingangsparameter des Indikators MACD

Danach legen wir die Indikatorpuffer (Abb. 2) entsprechend den Aufzeichnungen zu ihnen in dem MQL4-Programm:

//---- indicator buffers
double     MacdBuffer[];
double     SignalBuffer[];

Die Puffer des Indikators MACD

Abbildung 2. Die Puffer des Indikators MACD

Damit haben wir eine Schablone, ein Template, für unseren neuen Indikator angelegt.

Wir müssen daran einige Änderungen vornehmen: die Zeilen mit den Eingangsparametern von oben ergänzen

#include <mql4_2_mql5.mqh>
//--- input parameters

in die Funktion:

int OnInit()

die Zeile

    InitMql4();
einfügen und den Hauptteil des Programms um eine Zeile ergänzen, die auf den Start der Umgebung für das MQL4-Programm reagiert.
int bars=MQL4Run(rates_total,prev_calculated);
// bars - number of bars available to MQL4 programs

Wie wir sehen, gibt diese Funktion die Anzahl der der MQL4-Umgebung zugänglichen Balken aus, und es zeigt sich eine neue Variable: 

int CountedMQL4;

sie entspricht der MQL5-Variablen

 prev_calculated,

Die Variable CountedMQL4 wird in der eingebetteten Include-Datei deklariert und überträgt die Anzahl der berechneten Daten.

Anschließend fügen wir den von uns bearbeiteten MQL4-Block hinter dem letzten Zeichen in die angelegte MQL5-Schablone ein.

Jetzt müssen wir unseren Indikator aufrufen.

Dazu muss der Hauptteil des Programms um folgende Zeile erweitert werden:

Start(bars,
      CountedMQL4,
      MacdBuffer,
      SignalBuffer,
      FastEMA,
      SlowEMA,
      SignalSMA);

Wie zu sehen überträgt diese Zeile die für unser MQL4-Programm erforderlichen Daten sowie Verknüpfungen zu den resultierenden Puffern, deren Bezeichnungen wir unserer in MQL5 erstellten Schablone entnehmen.

Dabei müsste Folgendes herauskommen:

//+------------------------------------------------------------------+
//|                                                     MACD_MQ4.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_plots   2
//--- plot MacdBuffer
#property indicator_label1  "MacdBuffer"
#property indicator_type1   DRAW_LINE
#property indicator_color1  Red
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- plot SignalBuffer
#property indicator_label2  "SignalBuffer"
#property indicator_type2   DRAW_LINE
#property indicator_color2  Red
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1
//--- input parameters
#include <mql4_2_mql5.mqh>
input int      FastEMA=12;
input int      SlowEMA=26;
input int      SignalSMA=9;
//--- indicator buffers
double         MacdBuffer[];
double         SignalBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,MacdBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,SignalBuffer,INDICATOR_DATA);
//---
   InitMql4();
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime& time[],
                const double& open[],
                const double& high[],
                const double& low[],
                const double& close[],
                const long& tick_volume[],
                const long& volume[],
                const int& spread[])
  {
//---
int bars=MQL4Run(rates_total,prev_calculated);
// bars - number of bars available to MQL4 programs

   Start(bars,
         CountedMQL4,
         MacdBuffer,
         SignalBuffer,
         FastEMA,
         SlowEMA,
         SignalSMA);//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Moving Averages Convergence/Divergence                           |
//+------------------------------------------------------------------+
int Start(int rates_total,
         int prev_calculated,
         double &MacdBuffer[],
         double &SignalBuffer[],
         int FastEMA,
         int SlowEMA,
         int SignalSMA)
  {
   int limit;
   int counted_bars=IndicatorCounted();
//---- last counted bar will be recounted
   if(counted_bars>0) counted_bars--;
   limit=Bars-counted_bars;
//---- macd counted in the 1-st buffer
   for(int i=0; i<limit; i++)
      MacdBuffer[i]=iMA(NULL,0,FastEMA,0,MODE_EMA,PRICE_CLOSE,i)
                       -iMA(NULL,0,SlowEMA,0,MODE_EMA,PRICE_CLOSE,i);
//---- signal line counted in the 2-nd buffer
   for(i=0; i<limit; i++)
      SignalBuffer[i]=iMAOnArray(MacdBuffer,Bars,SignalSMA,0,MODE_SMA,i);
//---- done
   return(0);
  }

Dabei handelt es sich erst um den ersten Teil der Übertragung, es folgt die Überprüfung des Indikators.

3. Besonderheiten der Arbeit mit Indikatorpuffern in MQL5

Da zahlreiche der voreingestellten Variablen in MQL4 mit den Bezeichnungen der voreingestellten MQL5-Variablen übereinstimmen, müssen an dem zu übertragenden MQL4-Block folgende Änderungen vorgenommen werden:

MQL4
MQL5
IndicatorCounted()
prev_calculated
 Bars rates_total
 iMA( iMAMql4(
 iMAOnArray( iMAOnArrayMql4(

//+--------------------+------------------+
//|              MQL4  | MQL5             |
//+--------------------+------------------+
//|IndicatorCounted()  | prev_calculated  |
//|              Bars  | rates_total      |
//|              iMA(  | iMAMql4(         |
//|       iMAOnArray(  | iMAOnArrayMql4(  |
//+--------------------+------------------+ 

Bezüglich der Besonderheiten der Organisation der Datenspeicherung in MQL5 heißt es in der Hilfe zu dem SetIndexBuffer():

Hinweis

Nach der Einbindung weist das dynamische Datenfeld buffer[] dieselbe Kennziffernfolge auf wie gewöhnliche Datenfelder, selbst wenn für das einzubindende Datenfeld im Vorfeld eine Kennziffernfolge wie bei Zeitreihen eingerichtet worden ist. Wenn die Reihenfolge des Zugriffs auf die Elemente des Indikatordatenfeldes geändert werden muss, ist nach mithilfe der Funktion SetIndexBuffer() erfolgter Einbindung die Funktion ArraySetAsSeries() zu verwenden.

Das heißt, die ursprüngliche Strategie für den Zugriff auf die Indikatorpuffer entspricht jetzt der Arbeit mit gewöhnlichen Datenfeldern, weswegen stets folgendes Codebündel angelegt werden muss:

   ArraySetAsSeries(MacdBuffer,true);
   ArraySetAsSeries(SignalBuffer,true);

Als Ergebnis erhalten wir folgenden Code:

//+------------------------------------------------------------------+
//|                                                    MACD_MQL4.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_plots   2
//--- plot MacdBuffer
#property indicator_label1  "MacdBuffer"
#property indicator_type1   DRAW_LINE
#property indicator_color1  Red
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- plot SignalBuffer
#property indicator_label2  "SignalBuffer"
#property indicator_type2   DRAW_LINE
#property indicator_color2  Red
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

#include <mql4_2_mql5.mqh>
//--- input parameters
input int      FastEMA=12;
input int      SlowEMA=26;
input int      SignalSMA=9;
//--- indicator buffers
double         MacdBuffer[];
double         SignalBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,MacdBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,SignalBuffer,INDICATOR_DATA);
//---   
   InitMql4();
//---
   ArraySetAsSeries(MacdBuffer,true);
   ArraySetAsSeries(SignalBuffer,true);
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---
   int bars=MQL4Run(rates_total,prev_calculated);
// bars - number of bars available for MQL4 programs   
   Start(bars,
         CountedMQL4,
         MacdBuffer,
         SignalBuffer,
         FastEMA,
         SlowEMA,
         SignalSMA);
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Moving Averages Convergence/Divergence                           |
//+------------------------------------------------------------------+
//+--------------------+------------------+
//|              MQL4  | MQL5             |
//+--------------------+------------------+
//|IndicatorCounted()  | prev_calculated  |
//|              Bars  | rates_total      |
//|              iMA(  | iMAMql4(         |
//|       iMAOnArray(  | iMAOnArrayMql4(  |
//+--------------------+------------------+ 
int Start(int rates_total,
         int prev_calculated,
         double &MacdBuffer[],
         double &SignalBuffer[],
         int FastEMA,
         int SlowEMA,
         int SignalSMA)
  {
   int limit;
   int counted_bars=prev_calculated;
//---- last counted bar will be recounted
   if(counted_bars>0) counted_bars--;
   limit=rates_total-counted_bars;
//---- macd counted in the 1-st buffer
   for(int i=0; i<limit; i++)
      MacdBuffer[i]=iMAMql4(NULL,0,FastEMA,0,MODE_EMA,PRICE_CLOSE,i)
                    -iMAMql4(NULL,0,SlowEMA,0,MODE_EMA,PRICE_CLOSE,i);
//---- signal line counted in the 2-nd buffer
   for(int i=0; i<limit; i++)
      SignalBuffer[i]=iMAOnArrayMql4(MacdBuffer,rates_total,SignalSMA,0,MODE_SMA,i);
//---- done
   return(0);
  }
//+------------------------------------------------------------------+

Das Ergebnis seiner Ausführung zeigt Abbildung 3:

Abbildung 3. Vergleich des umgeschriebenen MQL4-Indikators MACD mit dem Standardindikator MACD in MQL5.


4. Beispiel für die Übertragung des Indikators Stochastik

Wir legen in MetaEditor 5 (Abb. 4 - 5) eine neue Schablone für unseren Indikator an:

Eingangsparameter

Abbildung 4. Eingangsparameter

Puffer

Abbildung 5. Puffer

Während der Überprüfung hat sich gezeigt, dass einige Berechnungen aus der MQL4-Funktion „OnInit“ durch schlichtes Kopieren in die Funktion „start“ übertragen werden müssen:

int draw_begin1=KPeriod+Slowing;
int draw_begin2=draw_begin1+DPeriod;
Des Weiteren muss die Anzahl der Puffer für die grafische Darstellung geändert werden, da in unserem MQL4-Programm 2 Puffer für interne Berechnungen und 2 für die grafische Darstellung verwendet werden.
#property indicator_plots   2

Sowie der Status der von unserem MQL4-Programm für interne Berechnungen verwendeten Puffer.

   SetIndexBuffer(2,HighesBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(3,LowesBuffer,INDICATOR_CALCULATIONS);
Wir nehmen die erforderlichen Änderungen vor:
//+------------------------------------------------------------------+
//|                                              Stochastic_MQL4.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_minimum 0
#property indicator_maximum 100
#property indicator_buffers 4
#property indicator_plots   2
//--- plot MainBuffer
#property indicator_label1  "MainBuffer"
#property indicator_type1   DRAW_LINE
#property indicator_color1  Red
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- plot SignalBuffer
#property indicator_label2  "SignalBuffer"
#property indicator_type2   DRAW_LINE
#property indicator_color2  Red
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

#include <mql4_2_mql5.mqh>
//--- input parameters
input int      Kperiod=14;
input int      Dperiod=5;
input int      Slowing=5;
//--- indicator buffers
double         MainBuffer[];
double         SignalBuffer[];
double         HighesBuffer[];
double         LowesBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,MainBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,SignalBuffer,INDICATOR_DATA);
   SetIndexBuffer(2,HighesBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(3,LowesBuffer,INDICATOR_CALCULATIONS);
//---
    InitMql4();
//---
   ArraySetAsSeries(MainBuffer,true);
   ArraySetAsSeries(SignalBuffer,true);
   ArraySetAsSeries(HighesBuffer,true);
   ArraySetAsSeries(LowesBuffer,true);
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---
   int bars=MQL4Run(rates_total,prev_calculated);
// bars - количество баров, доступных mql4-программам
   start(bars,
         CountedMQL4,
         MainBuffer,
         SignalBuffer,
         HighesBuffer,
         LowesBuffer,
         Kperiod,
         Dperiod,
         Slowing);
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+--------------------+------------------+
//|              MQL4  | MQL5             |
//+--------------------+------------------+
//|IndicatorCounted()  | prev_calculated  |
//|              Bars  | rates_total      |
//|              iMA(  | iMAMql4(         |
//|       iMAOnArray(  | iMAOnArrayMql4(  |
//+--------------------+------------------+ 
int start(int rates_total,
          int prev_calculated,
          double &MainBuffer[],
          double &SignalBuffer[],
          double &HighesBuffer[],
          double &LowesBuffer[],
          int KPeriod,
          int DPeriod,
          int Slowing)
  {
   int draw_begin1=KPeriod+Slowing;
   int draw_begin2=draw_begin1+DPeriod;
   int    i,k;
   int    counted_bars=prev_calculated;
   double price;
//----
   if(rates_total<=draw_begin2) return(0);
//---- initial zero
   if(counted_bars<1)
     {
      for(i=1;i<=draw_begin1;i++) MainBuffer[rates_total-i]=0;
      for(i=1;i<=draw_begin2;i++) SignalBuffer[rates_total-i]=0;
     }
//---- minimums counting
   i=rates_total-KPeriod;
   if(counted_bars>KPeriod) i=rates_total-counted_bars-1;
   while(i>=0)
     {
      double min=1000000;
      k=i+KPeriod-1;
      while(k>=i)
        {
         price=Low[k];
         if(min>price) min=price;
         k--;
        }
      LowesBuffer[i]=min;
      i--;
     }
//---- maximums counting
   i=rates_total-KPeriod;
   if(counted_bars>KPeriod) i=rates_total-counted_bars-1;
   while(i>=0)
     {
      double max=-1000000;
      k=i+KPeriod-1;
      while(k>=i)
        {
         price=High[k];
         if(max<price) max=price;
         k--;
        }
      HighesBuffer[i]=max;
      i--;
     }
//---- %K line
   i=rates_total-draw_begin1;
   if(counted_bars>draw_begin1) i=rates_total-counted_bars-1;
   while(i>=0)
     {
      double sumlow=0.0;
      double sumhigh=0.0;
      for(k=(i+Slowing-1);k>=i;k--)
        {
         sumlow+=Close[k]-LowesBuffer[k];
         sumhigh+=HighesBuffer[k]-LowesBuffer[k];
        }
      if(sumhigh==0.0) MainBuffer[i]=100.0;
      else MainBuffer[i]=sumlow/sumhigh*100;
      i--;
     }
//---- last counted bar will be recounted
   if(counted_bars>0) counted_bars--;
   int limit=rates_total-counted_bars;
//---- signal line is simple moving average
   for(i=0; i<limit; i++)
      SignalBuffer[i]=iMAOnArrayMql4(MainBuffer,rates_total,DPeriod,0,MODE_SMA,i);
//----
   return(0);
  }
//+------------------------------------------------------------------+

Als Ergebnis erhalten wir einen vollwertigen „Stochastik“ in MQL5 mit MQL4-Kursgerüst.

Das Ergebnis seiner Arbeit zeigt Abbildung 6:

Vergleich des umgeschriebenen MQL4-Indikators Stochastik mit dem Standardindikator Stochastik in MQL5.

Abbildung 6. Vergleich des umgeschriebenen MQL4-Indikators Stochastik mit dem Standardindikator Stochastik in MQL5.

5. Beispiel für die Übertragung des Indikators RSI

Wir stellen zunächst die Informationen zu unserem Indikator zusammen:
//---- input parameters
extern int RSIPeriod=14;
//---- buffers
double RSIBuffer[];
double PosBuffer[];
double NegBuffer[];

Anschließend legen wir in MetaEditor 5 (Abb. 7 - 8) eine Schablone für ihn an:

Eingangsparameter des Indikators RSI

Abbildung 7. Eingangsparameter des Indikators RSI

Puffer des Indikators RSI

Abbildung 8. Puffer des Indikators RSI

Die Gesamtzahl der Puffer beträgt 3:

#property indicator_buffers 3

Die Anzahl der abzubildenden Puffer ist 1:

#property indicator_plots   1

Wir stellen den Status der Puffer für die Berechnungen ein:

   SetIndexBuffer(1,PosBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(2,NegBuffer,INDICATOR_CALCULATIONS)

dann stellen wir ihn zusammen und nehmen die erforderlichen Änderungen vor:

//+------------------------------------------------------------------+
//|                                                     RSI_MQL4.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 3
#property indicator_plots   1
//--- plot RSIBuffer
#property indicator_label1  "RSIBuffer"
#property indicator_type1   DRAW_LINE
#property indicator_color1  Green
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- plot PosBuffer
#property indicator_label2  "PosBuffer"
#property indicator_type2   DRAW_LINE
#property indicator_color2  Red
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1
//--- plot NegBuffer
#property indicator_label3  "NegBuffer"
#property indicator_type3   DRAW_LINE
#property indicator_color3  Red
#property indicator_style3  STYLE_SOLID
#property indicator_width3  1

#include <mql4_2_mql5.mqh>
//--- input parameters
input int      RSIPeriod=14;
//--- indicator buffers
double         RSIBuffer[];
double         PosBuffer[];
double         NegBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,RSIBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,PosBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(2,NegBuffer,INDICATOR_CALCULATIONS);
//---
   InitMql4(3);

   ArraySetAsSeries(RSIBuffer,true);
   ArraySetAsSeries(PosBuffer,true);
   ArraySetAsSeries(NegBuffer,true);

   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   int bars=MQL4Run(rates_total,prev_calculated);
// bars - number of bars available for MQL4 programs
   RSImql4(bars,
           CountedMQL4,
           RSIBuffer,
           PosBuffer,
           NegBuffer,
           RSIPeriod);
   return(rates_total);
  }
//+--------------------+------------------+
//|              MQL4  | MQL5             |
//+--------------------+------------------+
//|IndicatorCounted()  | prev_calculated  |
//|              Bars  | rates_total      |
//|              iMA(  | iMAMql4(         |
//|       iMAOnArray(  | iMAOnArrayMql4(  |
//+--------------------+------------------+ 
int RSImql4(int rates_total,
            int prev_calculated,
            double &RSIBuffer[],
            double &PosBuffer[],
            double &NegBuffer[],
            int RSIPeriod)
  {
   int    i,counted_bars=prev_calculated;
   double rel,negative,positive;
//----fd
   if(rates_total<=RSIPeriod) return(0);
//---- initial zero
   if(counted_bars<1)
      for(i=1;i<=RSIPeriod;i++) RSIBuffer[rates_total-i]=0.0;
//----
   i=rates_total-RSIPeriod-1;
   if(counted_bars>=RSIPeriod) i=rates_total-counted_bars-1;
   while(i>=0)
     {
      double sumn=0.0,sump=0.0;
      if(i==rates_total-RSIPeriod-1)
        {
         int k=rates_total-2;
         //---- initial accumulation
         while(k>=i)
           {
            rel=Close[k]-Close[k+1];
            if(rel>0) sump+=rel;
            else      sumn-=rel;
            k--;
           }
         positive=sump/RSIPeriod;
         negative=sumn/RSIPeriod;
        }
      else
        {
         //---- smoothed moving average
         rel=Close[i]-Close[i+1];
         if(rel>0) sump=rel;
         else      sumn=-rel;
         positive=(PosBuffer[i+1]*(RSIPeriod-1)+sump)/RSIPeriod;
         negative=(NegBuffer[i+1]*(RSIPeriod-1)+sumn)/RSIPeriod;
        }
      PosBuffer[i]=positive;
      NegBuffer[i]=negative;
      if(negative==0.0) RSIBuffer[i]=0.0;
      else RSIBuffer[i]=100.0-100.0/(1+positive/negative);
      i--;
     }
//----
   return(0);
  }
//+------------------------------------------------------------------+

Hier wurde anders als bei dem vorhergehenden Indikator die Bezeichnung geändert: anstelle der in MQL4 üblichen Funktion „int Start()“:

int start()
  {

wird in MQL5

int RSImql4(

verwendet. Umbenannt wurden im Hauptteil des MQL5-Programms sowohl die Funktion selbst als auch die Zeile, mittels derer sie aufgerufen wird.

Das Ergebnis er Arbeit der Bibliothek ist in Abbildung 9 dargestellt:

Vergleich des umgeschriebenen MQL4-Indikators RSIc mit dem Standardindikator RSI in MQL5.

Abbildung 9. Vergleich des umgeschriebenen MQL4-Indikators RSIc mit dem Standardindikator RSI in MQL5.

6. Einrichtung

Zur Einrichtung dieses Moduls muss die Datei mql4_2_mql5.mqh in den Ordner MQL5\Include\ verschoben oder kopiert werden.

Die Testdateien gehören in den Ordner MQL5\Indicators.

7. Erweiterung

Auf Wunsch kann der Funktionsumfang des Moduls durch Einbindung der Bibliothek aus dem Beitrag Der Übergang von MQL4 zu MQL5 erweitert werden. Fügen Sie die Datei InitMQL4.mqh aus dem Beitrag in das Verzeichnis MQL5\Include ein und setzen sie folgende Zeilen vor die Eingangsparameter:

#include <InitMQL4.mqh>

Eine Aufstellung der erforderlichen Änderungen liefert der Beitrag Der Übergang von MQL4 zu MQL5.

Fazit

In diesem Beitrag wurde ein Algorithmus für die Übertragung elementaren Kursgerüste aus MQL4 in eine MQL5-Umgebung mithilfe der besonderen Bibliothek mql4_2_mql5.mqh vorgestellt.

Bei der Prüfung kann es zu geringfügigen Schwierigkeiten kommen, aber für jemanden, der sich mit MQL4 auskennt, bedeutet deren Behebung keine besondere Anstrengung.

In Anbetracht der Besonderheit des Datenzugriffs in MQL5-Umgebungen kann die Neuberechnung der Indikatoren einige Zeit in Anspruch nehmen, da die für die Programme erforderlichen Daten angelegt oder aus der MQL4-Umgebung neu berechnet werden müssen. Zur vollständigen Übertragung eines Indikators in eine MQL5-Umgebung muss er unter Berücksichtigung der Besonderheiten der Speicherung der Daten sowie des Zugriffs auf sie in dieser Umgebung umgeschrieben werden.

Nachtrag

Richten Sie Ihre Aufmerksamkeit bitte auf folgende Aussage: „In Anbetracht der Besonderheit des Datenzugriffs in MQL5-Umgebungen kann die Neuberechnung der Indikatoren einige Zeit in Anspruch nehmen, da die für die Programme erforderlichen Daten angelegt oder aus der MQL4-Umgebung neu berechnet werden müssen.“ Manchmal kann diese Wartezeit mehrere Sekunden betragen (siehe Abb. 10 - 11):

  

Abbildung 10. Keine Daten berechnet                                                                                                  Abbildung 11. Daten verfügbar

Das ist mit einer Besonderheit der Anwendungsinstanz von MetaTrader 5 auf dem Ausgabegerät (Terminal) verbunden, die darin besteht, dass bei der Erstellung des Handles für den Indikator im Zwischenspeicher des Ausgabegerätes der Berechnungsteil nur einmal angelegt wird. Wenn dieser Indikator (mit diesen Eingangsparametern) im Zwischenspeicher des Ausgabegerätes noch nicht vorhanden ist, erstellt der Aufruf der Funktion 

iMA(Symb,TimFram,iMAPeriod,ma_shift,ma_method,applied_price);

einen MA-Indikator für gleitende Durchschnittswerte, ebenfalls nur einmal.

Beim nächsten Mal gibt das Ausgabegerät bei dem Versuch, den bereits vorhandenen Indikator anzulegen, einfach dessen Handle.

Entsprechend erfolgt die Berechnung des Indikators nur ein einziges Mal und zwar kurz nach der Erstellung seines Handles.