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
1. Replace all trade functions with CTrade class methods
2. Convert time series indexing (add `ArraySetAsSeries` where needed)
3. Update event handlers to MQL5 naming
4. Replace `_Point` with `SymbolInfoDouble(Symbol(), SYMBOL_POINT)`
5. 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.