Summary: Step-by-step technical guide for converting MQL4 EAs to MQL5. Covers OrderSend to PositionOpen mapping, tick handling, time series reversal, and backtest compatibility adjustments.




Migrating an Expert Advisor from MQL4 to MQL5 is not a simple syntax replacement. The two languages have fundamental differences in trade execution, history access, and event handling. Direct copy-paste will fail because MQL5 uses a position-centric model while MQL4 uses an order-centric model.

Critical Difference: Trade Execution Model

MQL4 uses individual orders where each partial close creates a new order. MQL5 uses positions (netting or hedging) with separate trade history records. The function mapping:

| MQL4 | MQL5 |
|------|------|
| OrderSend() | PositionOpen() / OrderSend() (CTrade) |
| OrderClose() | PositionClose() |
| OrderModify() | PositionModify() |
| OrdersTotal() | PositionsTotal() |
| OrderSelect() | PositionSelect() |

Code: Converting OrderSend to MQL5 Position Open
``cpp
// MQL4 version
int ticket = OrderSend(Symbol(), OP_BUY, 0.1, Ask, 3, stopLoss, takeProfit, "EA", magic, 0, clrNONE);

// MQL5 equivalent using CTrade
#include
CTrade trade;
double sl = 0, tp = 0;
if(stopLoss > 0) sl = Ask - stopLoss _Point;
if(takeProfit > 0) tp = Ask + takeProfit
_Point;
bool success = trade.PositionOpen(Symbol(), ORDER_TYPE_BUY, 0.1, Ask, sl, tp, "EA");
`

Time Series Index Reversal

MQL4 uses time series where index 0 is the current bar. MQL5 uses array-like series where index 0 is the oldest bar unless
ArraySetAsSeries() is called.

`cpp
// MQL4 - current bar close
double currentClose = Close[0];

// MQL5 - must set series or use copying
double closeArray[];
ArraySetAsSeries(closeArray, true);
CopyClose(Symbol(), Period(), 0, 10, closeArray);
double currentClose = closeArray[0];
`

Event Handler Mapping

| MQL4 | MQL5 |
|------|------|
|
init() | OnInit() |
|
deinit() | OnDeinit() |
|
start() | OnTick() |
|
OnTimer() | OnTimer() (same but requires EventSetTimer()) |

Backtest Compatibility Fix

MQL5 backtest does NOT guarantee
_LastError reset on every tick. Always check return values explicitly:

`cpp
// MQL4 style (unsafe in MQL5)
OrderSend(...);
if(GetLastError() == 0) { ... }

// MQL5 safe pattern
bool result = trade.PositionOpen(...);
if(result && trade.ResultRetcode() == TRADE_RETCODE_DONE) {
Print("Position opened successfully");
} else {
Print("Error: ", trade.ResultRetcode());
}
`

Tick Structure Differences

MQL4
bid/ask are global variables. MQL5 uses SymbolInfoTick() to fetch both bid and ask simultaneously, preventing cross-tick misalignment:

`cpp
// MQL5 - atomic tick fetch
MqlTick currentTick;
SymbolInfoTick(Symbol(), currentTick);
double currentBid = currentTick.bid;
double currentAsk = currentTick.ask;
`

Order of Operations for Migration
  • Replace all trade functions with CTrade class methods

  • Convert time series indexing (add ArraySetAsSeries where needed)

  • Update event handlers to MQL5 naming

  • Replace _Point with SymbolInfoDouble(Symbol(), SYMBOL_POINT)`

  • Add explicit error handling after every trade operation


  • Reference: MQL5 Documentation - Migration from MQL4 (https://www.mql5.com/en/docs/migration), "MQL5 Programming for Traders" by Andrew R. Young, 2021.