How we migrated from MQL4 to MQL5?

Why?

In 2018 MetaTrader has announced they stopped selling MT4 new server licenses to brokers. This means if the broker already has licenses he can continue to use MT4 without extending its server capacity. On the other hand, if the broker has never had an MT4 server license it is not able to buy it and it can only use MT5.

So today there are some new brokers that only have MT5 and some old brokers that are pushing their clients to switch to MT5 since the MT4 server capacity is limited.

Not only this, MT5 has built a modern architecture that allows easily working on different markets (not only forex), has more features (such as more timeframes) and lots more.

These are some of the main reasons why we have chosen to create also the MT5 version of MT4Professional, keeping our MT4 version so having both versions, and why you should start thinking about it for your indicator or expert advisor.

If we take a look at Google trend, MT4 has a bigger market share but MT5 trend (red line) is rising more than MT4 trend (blue line). This means that in the next years having MT5 version will be a must.

Google Trend MT4 vs MT5 for the last 5 years

We have seen why an MT5 version today is a must, now we see how to make a migration and how to maintain both versions with the minimum effort.

How to migrate MQL4 to MQL5

Before telling how we have achieved this, we give 2 facts.

Fact #1: OOP is not required

MQL5 has OOP (object-oriented programming) support, but this doesn't mean you have to use it, you can still use your structured programming approach.

Fact #2: Now a lot of functions are in common between MQL4 and MQL5

Now there are some functions that can be used both on MQL4 and MQL5, this kind of function replaces some functions available only on MQL4.
For example, instead of using AccountBalance() you can use AccountInfoDouble(ACCOUNT_BALANCE), the second version works both on MQL4 and on MQL5. Also, a lot of constants are the same on MQL4 and on MQL5.
You can find more details on MQL5 migration dedicated article from MetaTrader.

Pay attention: some functions have different behavior for example StringTrimLeft on MQL4 returns a modified copy of the string, on MQL5 it changes the original string returning the number of cut chars. Analogous things for other functions.

Fact #3: Indicators calling has changed

MQL5 has a newer and more efficient way to call indicators, however this is totally different from MQL4. Moreover, the signature of some standard indicators has changed, the good news is that MQL5 has introduced some new standard indicators. In fact, in MQL5 indicators return a handle not the value like MQL4.

How to achieve the migration efficiently maintaining both versions?

We have to do this efficiently reducing also the maintenance effort and error possibility, so to manage situations where we introduce a new change/feature to both versions of the code. To do this we proceeded with the following steps:

1
We analyzed the code looking for functions identified on Fact #2, replacing them with the common function where possible.

2
For functions that are different from MQL4 to MQL5 or have a different behavior we created a dedicated include file where we have created custom functions that have the same signatures between MQL4 and MQL5 but different implementations.

For example, for StringTrimLeft we created the following two versions

on MQL4:

void StringTrimLeftCustom(string &str){
	str = StringTrimLeft(str);
}

on MQL5:

void StringTrimLeftCustom(string &str){
	StringTrimLeft(str);
}

The idea is to create this include file with these functions and do not touch it but just calling these custom functions

3
Analogous approach for indicators, for indicators we created a dedicated include file with common indicators signatures. However, there is a little bit more difficulty: the way the value is returned. To have an analogous way to accomplish this you can return values in MQL5 in the same way they are returned in MQL4. Of course, this introduces inefficiency.

To accomplish this we created a support function

double GetIndicatorValue(
    int handle,
    int index,
    int shift){
    double mas[1];
    if(CopyBuffer(handle,index,shift,1,mas)!=-1)
       return mas[0];
    return 0;
}

To return the value we pass the handle to this function, so using an include file like the one in the previous point we would have the following two versions to call iMA

on MQL4:

double iMaCustom(
    string symbol,
    int period,
    int ma_period,
    int ma_shift,
    int ma_method,
    int applied_price){
	return iMA(symbol,
    	period,
        ma_period,
        ma_shift,
        ma_method,
        applied_price,
        shift);
}

on MQL5:

double iMaCustom(
    string symbol,
    int period,
    int ma_period,
    int ma_shift,
    int ma_method,
    int applied_price){
	return GetIndicatorValue(
    	iMA(symbol, TFMigrate(period),
    	ma_period,
    	ma_shift,
    	(ENUM_MA_METHOD)ma_method,
    	(ENUM_APPLIED_PRICE )applied_price),
    	0,
    	shift);
}

Note: TFMigrate is a support function suggested by the official MQL5 migration article

Conclusion

We have seen why today thinking about an MT5 version of your indicator or expert advisor is a must.

We described how we performed efficient migration to MQL5, maintaining both versions, creating dedicated include files to create common signatures. In this way when we introduce a change we can use the same code, since we modify common parts that use the same code (not specific MQL version parts), this reduces to the minimum the risk of errors.

Of course, during migrations, there are some other things to manage, for example, a different orders management, but you can use an analogous approach to the one we previously described.