Discussion of article "Migrating from MQL4 to MQL5"

 

New article Migrating from MQL4 to MQL5 is published:

Many developers have accumulated a lot of indicators and trading strategies written in MQL4. To use them in Metatrader 5, they should be converted to MQL5. It's not so easy to rewrite all programs in MQL5. It would be much easier to convert them, if there were a translation-reference, and better with examples.

This article is a quick guide to MQL4 language functions, it will help you to migrate your programs from MQL4 to MQL5. For each MQL4 function (except trading functions) the description and MQL5 implementation are presented, it allows you to reduce the conversion time significantly. For convenience, the MQL4 functions are divided into groups, similar to MQL4 Reference.

Author: Sergey

 

are you sure it works????

A simple compilation already raises the question

and secondly what will this function return!

     CopyClose(symbol,timeframe,start,count,Close);
      return(ArrayMaximum(Close,start,count));

copy the closing prices into the Klose array, copy from the position "start" and the number of "Counts" correctly.

and returns the index of the maximum element of the Klose array starting from the position "start" and looking only at the "count" elements......

what is your heresy sorry for the frankness.....

 
 
In those cells of the tables where it says "No analogue" you should give a brief description of how these things are solved in mql5 with references to a specific section of the documentation (something like, for example, this: "does not make sense, because in mql5 this and that").
 
CoreWinTT:

are you sure it works????

Yes, it does.

//+------------------------------------------------------------------+
//|test.mq5 |
//|Copyright DC2008 |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "DC2008"
//--- Time series arrays
double            Close[];
double            Open[];
double            High[];
double            Low[];
long              Volume[];
datetime          Time[];
//+------------------------------------------------------------------+
//| Expert initialisation function|
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   ArraySetAsSeries(Close,true);
   ArraySetAsSeries(Open,true);
   ArraySetAsSeries(High,true);
   ArraySetAsSeries(Low,true);
   ArraySetAsSeries(Volume,true);
   ArraySetAsSeries(Time,true);
   ArraySetAsSeries(Low,true);

//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialisation function|
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function|
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   Comment(
           "\niHighest",iHighest("EURUSD",PERIOD_M2,0,10,0),
           " iLowest ",iLowest("EURUSD",PERIOD_M2,0,10,0),"   Open",
           "\niHighest",iHighest("EURUSD",PERIOD_M2,1,10,0),
           " iLowest ",iLowest("EURUSD",PERIOD_M2,1,10,0),"   Low",
           "\niHighest",iHighest("EURUSD",PERIOD_M2,2,10,0),
           " iLowest ",iLowest("EURUSD",PERIOD_M2,2,10,0),"   High",
           "\niHighest",iHighest("EURUSD",PERIOD_M2,3,10,0),
           " iLowest ",iLowest("EURUSD",PERIOD_M2,3,10,0),"   Close",
           "\niHighest",iHighest("EURUSD",PERIOD_M2,4,10,0),
           " iLowest ",iLowest("EURUSD",PERIOD_M2,4,10,0),"   Volume",
           "\niHighest",iHighest("EURUSD",PERIOD_M2,5,10,0),
           " iLowest ",iLowest("EURUSD",PERIOD_M2,5,10,0),"   Time",
           "\n",""
           );

  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
int iLowest(string symbol,
            int tf,
            int type,
            int count=WHOLE_ARRAY,
            int start=0)
  {
   ENUM_TIMEFRAMES timeframe=TFMigrate(tf);
   if(type<=0)
     {
      CopyOpen(symbol,timeframe,start,count,Open);
      return(ArrayMinimum(Open,start,count));
     }
   if(type==1)
     {
      CopyLow(symbol,timeframe,start,count,Low);
      return(ArrayMinimum(Low,start,count));
     }
   if(type==2)
     {
      CopyHigh(symbol,timeframe,start,count,High);
      return(ArrayMinimum(High,start,count));
     }
   if(type==3)
     {
      CopyClose(symbol,timeframe,start,count,Close);
      return(ArrayMinimum(Close,start,count));
     }
   if(type==4)
     {
      CopyTickVolume(symbol,timeframe,start,count,Volume);
      return(ArrayMinimum(Volume,start,count));
     }
   if(type>=5)
     {
      CopyTime(symbol,timeframe,start,count,Time);
      return(ArrayMinimum(Time,start,count));
     }
//---
   return(0);
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
int iHighest(string symbol,
             int tf,
             int type,
             int count=WHOLE_ARRAY,
             int start=0)
  {
   ENUM_TIMEFRAMES timeframe=TFMigrate(tf);
   if(type<=0)
     {
      CopyOpen(symbol,timeframe,start,count,Open);
      return(ArrayMaximum(Open,start,count));
     }
   if(type==1)
     {
      CopyLow(symbol,timeframe,start,count,Low);
      return(ArrayMaximum(Low,start,count));
     }
   if(type==2)
     {
      CopyHigh(symbol,timeframe,start,count,High);
      return(ArrayMaximum(High,start,count));
     }
   if(type==3)
     {
      CopyClose(symbol,timeframe,start,count,Close);
      return(ArrayMaximum(Close,start,count));
     }
   if(type==4)
     {
      CopyTickVolume(symbol,timeframe,start,count,Volume);
      return(ArrayMaximum(Volume,start,count));
     }
   if(type>=5)
     {
      CopyTime(symbol,timeframe,start,count,Time);
      return(ArrayMaximum(Time,start,count));
     }
//---
   return(0);
  }
//+------------------------------------------------------------------+
ENUM_TIMEFRAMES TFMigrate(int tf)
{
   switch(tf)
   {
      case 0: return(PERIOD_CURRENT);
      case 1: return(PERIOD_M1);
      case 5: return(PERIOD_M5);
      case 15: return(PERIOD_M15);
      case 30: return(PERIOD_M30);
      case 60: return(PERIOD_H1);
      case 240: return(PERIOD_H4);
      case 1440: return(PERIOD_D1);
      case 10080: return(PERIOD_W1);
      case 43200: return(PERIOD_MN1);      
      default: return(PERIOD_CURRENT);
   }
}
 
marketeer:
In those cells of the tables where it says "No analogue" you should give a brief description of how these things are solved in mql5 with references to a specific section of the documentation (something like, for example, this: "does not make sense, because in mql5 this and that").

It should be understood as follows: the implementation is too complicated and is not justified. After all, the goal is to completely abandon MQL4 functions.

But I will try to take it into account if I could provide links to those MQL5 functions that can be used to do something similar.

 

We're taking this one from the TF m2. Right, I understand.

but it's just a kind of throwing dust in our eyes. The TF migrate is giving us

  default: return(PERIOD_CURRENT);

from 0 bar. That's weird.

But if we try from 20, for example.

You're trying to confuse us again.

and such nonsense in every function.

And why make TF migrate???

if mql5 has all TFs that mql4 has even more......

complete heresy =))))

How did your moderators miss such a thing?

Dear Eugene! I hope you were not the one who checked this article.

 
CoreWinTT:

complete heresy =))))

How did your moderators miss this?

Dear Eugene! I hope you did not check this article.

Dear Vasily!

Thank you for your comments, the functions of section 18 have been updated. Please check the current version.

The author has done a lot of work, there may be errors, we will fix them together.

The TFMigrate(int tf) function is needed to substitute correct values of MQL5 timeframes. For example, in MQL4 the numerical value of the PERIOD_H1 constant is 60, and in MQL5 the numerical value of PERIOD_H1=16385, i.e. TFMigrate(60)=16385.

 

I think there are many more mistakes.

because they occur even in such simple moments. I would even say the simplest ones.


In some sections, functions are compared with each other.

in others, an analogue is written.


there is not a single successful example of how to implement the article,

as far as I understand, this article is an attempt to transfer something from µl4.....


Your attitude towards verification is always admirable.

I think it's the author's unbridled desire to throw dust in your eyes.

which he has certainly succeeded in doing.

as I know your sensitivity to the material being checked.

 
CoreWinTT:


What if you try with 20, for example.

You're trying to confuse me again.

and such nonsense in every function.

And why make TF migrate????

if mql5 has all TFs that mql4 has even more......

complete heresy =)))))


Thanks for finding the error. I had overlooked that the search can be started from other than the zero bar. Here are the corrected functions:

//+------------------------------------------------------------------+
//|test.mq5 |
//|Copyright DC2008 |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "DC2008"
//--- Time series arrays
double            Close[];
double            Open[];
double            High[];
double            Low[];
long              Volume[];
datetime          Time[];
//+------------------------------------------------------------------+
//| Expert initialisation function|
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   ArraySetAsSeries(Close,true);
   ArraySetAsSeries(Open,true);
   ArraySetAsSeries(High,true);
   ArraySetAsSeries(Low,true);
   ArraySetAsSeries(Volume,true);
   ArraySetAsSeries(Time,true);
   ArraySetAsSeries(Low,true);

//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialisation function|
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function|
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   Comment(Open[0],Close[0],Open[1],Close[1],
           "\niHighest",iHighest("EURUSD",PERIOD_M2,0,10,20),
           " iLowest ",iLowest("EURUSD",PERIOD_M2,0,10,20),"   Open",
           "\niHighest",iHighest("EURUSD",PERIOD_M2,1,10,20),
           " iLowest ",iLowest("EURUSD",PERIOD_M2,1,10,20),"   Low",
           "\niHighest",iHighest("EURUSD",PERIOD_M2,2,10,20),
           " iLowest ",iLowest("EURUSD",PERIOD_M2,2,10,20),"   High",
           "\niHighest",iHighest("EURUSD",PERIOD_M2,3,10,20),
           " iLowest ",iLowest("EURUSD",PERIOD_M2,3,10,20),"   Close",
           "\niHighest",iHighest("EURUSD",PERIOD_M2,4,10,20),
           " iLowest ",iLowest("EURUSD",PERIOD_M2,4,10,20),"   Volume",
           "\niHighest",iHighest("EURUSD",PERIOD_M2,5,10,20),
           " iLowest ",iLowest("EURUSD",PERIOD_M2,5,10,20),"   Time",
           "\n",""
           );

  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
int iLowest(string symbol,
            int tf,
            int type,
            int count=WHOLE_ARRAY,
            int start=0)
  {
   ENUM_TIMEFRAMES timeframe=TFMigrate(tf);
   if(type<=0)
     {
      CopyOpen(symbol,timeframe,start,count,Open);
      return(ArrayMinimum(Open,0,count));
     }
   if(type==1)
     {
      CopyLow(symbol,timeframe,start,count,Low);
      return(ArrayMinimum(Low,0,count));
     }
   if(type==2)
     {
      CopyHigh(symbol,timeframe,start,count,High);
      return(ArrayMinimum(High,0,count));
     }
   if(type==3)
     {
      CopyClose(symbol,timeframe,start,count,Close);
      return(ArrayMinimum(Close,0,count));
     }
   if(type==4)
     {
      CopyTickVolume(symbol,timeframe,start,count,Volume);
      return(ArrayMinimum(Volume,0,count));
     }
   if(type>=5)
     {
      CopyTime(symbol,timeframe,start,count,Time);
      return(ArrayMinimum(Time,0,count));
     }
//---
   return(0);
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
int iHighest(string symbol,
             int tf,
             int type,
             int count=WHOLE_ARRAY,
             int start=0)
  {
   ENUM_TIMEFRAMES timeframe=TFMigrate(tf);
   if(type<=0)
     {
      CopyOpen(symbol,timeframe,start,count,Open);
      return(ArrayMaximum(Open,0,count));
     }
   if(type==1)
     {
      CopyLow(symbol,timeframe,start,count,Low);
      return(ArrayMaximum(Low,0,count));
     }
   if(type==2)
     {
      CopyHigh(symbol,timeframe,start,count,High);
      return(ArrayMaximum(High,0,count));
     }
   if(type==3)
     {
      CopyClose(symbol,timeframe,start,count,Close);
      return(ArrayMaximum(Close,0,count));
     }
   if(type==4)
     {
      CopyTickVolume(symbol,timeframe,start,count,Volume);
      return(ArrayMaximum(Volume,0,count));
     }
   if(type>=5)
     {
      CopyTime(symbol,timeframe,start,count,Time);
      return(ArrayMaximum(Time,0,count));
     }
//---
   return(0);
  }
//+------------------------------------------------------------------+
ENUM_TIMEFRAMES TFMigrate(int tf)
{
   switch(tf)
   {
      case 0: return(PERIOD_CURRENT);
      case 1: return(PERIOD_M1);
      case 5: return(PERIOD_M5);
      case 15: return(PERIOD_M15);
      case 30: return(PERIOD_M30);
      case 60: return(PERIOD_H1);
      case 240: return(PERIOD_H4);
      case 1440: return(PERIOD_D1);
      case 10080: return(PERIOD_W1);
      case 43200: return(PERIOD_MN1);      
      default: return(PERIOD_CURRENT);
   }
}
 
CoreWinTT:

I think there are many more mistakes.

because they occur even in such simple moments. I would even say the simplest ones.


In some sections, functions are compared with each other.

in others, an analogue is written.


there is not a single successful example of how to implement the article,

as far as I understand, this article is an attempt to transfer something from µl4.....


Your attitude towards verification is always admirable.

I think it's the author's unbridled desire to throw dust in your eyes.

which he has certainly succeeded in doing.

as I know your sensitivity to the material being checked.


There may be mistakes, the material is quite large.

The topic of porting (more precisely, the topic of writing an emulator class with MQL4 methods) was undertaken in another article (we hope it will be finished). In the process of reading the material, we asked the author to write an article in the form of a reference book to cover all the functions of MQL4 (except for trading - you will see one of the solutions for them soon), to provide an analogue for each of them in MQL5, in general, to put everything together so that those who rewrite MQL4 programs could quickly find an analogue. About the unrestrained desire, if we are talking about the number of sections considered - we insisted on covering all the functions (they turned out to be more than 250).

As for the comparison of functions in some sections - it was not exactly a comparison. It was necessary to give an analogue, even if it is the same. For all functions. So it seems that there is a comparison, but you can tell from the comparison that, for example, the maths functions are the same. By the way, as a recommendation, it would probably be useful to mention this at the beginning of each section, which is something to look out for.

For this reason (architecture of emulator functions) the author had some non-obvious things in the implementation (for example, for iLowest/iHighest global Open[]...High[]..., which were previously declared globally and made AsSeries in OnInit), which were implied as in the emulator, naturally for universality in functions it is better to use local arrays.

As for working with technical indicators, there can be many questions, working with them should not be like in MQL4 - it is better to create them manually in OnInit and refer to descriptors, instead of creating them each time in local functions. But the approach suggested by the author also works, because the terminal does not immediately destroy indicators. So there are a lot of subtleties.

The important thing is that now there is something to discuss, if you find errors (including those caused by the proposed structure of functions) - offer your variants.