Summary: This technical guide covers MQL4 to MQL5 migration essentials: trade structure changes, position vs order model, and practical code conversion patterns for advanced EA developers.
Migrating an Expert Advisor from MQL4 to MQL5 is not a simple recompilation. The two platforms differ fundamentally in order handling, time series access, and pre-defined variables. This guide focuses on core migration patterns for advanced developers.
1. Order vs Position Model
MQL4 uses `OrderSelect()`, `OrderSend()`, and a flat order pool. MQL5 separates pending orders (`COrder`) and market positions (`CPositionInfo`). A direct mapping is impossible; logic must be restructured.
Example: Open a buy market order
MQL4:
```cpp
int ticket = OrderSend(Symbol(), OP_BUY, lot, Ask, 3, stopLoss, takeProfit, "EA", magic, 0, clrNONE);
if(ticket < 0) Print("Error: ", GetLastError());
```
MQL5:
```cpp
CTrade trade;
trade.SetExpertMagicNumber(magic);
trade.SetDeviationInPoints(3);
if(!trade.Buy(lot, Symbol(), 0, stopLoss, takeProfit))
Print("Error: ", trade.ResultRetcode());
```
The `CTrade` class handles slippage and order filling modes. For market orders, avoid using `SymbolInfoDouble(Symbol(), SYMBOL_ASK)` directly – the `Buy()` method automatically uses current Ask.
2. Time and Tick Functions
`TimeCurrent()` returns `datetime` in both, but MQL5 requires `TimeTradeServer()` for server time. `iTime()` for historical bars: MQL4 uses shift from current, MQL5 uses series index. Use `CopyTime()` for flexibility.
3. Pre-defined Variables Removal
`Bid`, `Ask`, `Point`, `Digits` are not available in MQL5. Replace with:
```cpp
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
```
4. OrderSend Replacement Pattern
For complex orders, use `COrderSend` with `CRequest`. Example sending a limit order:
```cpp
CRequest request;
request.action = TRADE_ACTION_PENDING;
request.type = ORDER_TYPE_BUY_LIMIT;
request.volume = lot;
request.price = limitPrice;
request.sl = stopLoss;
request.tp = takeProfit;
request.deviation = 5;
COrderSend sender;
if(!sender.Send(request))
Print("Send failed: ", sender.ResultRetcode());
```
5. Backtest Migration Tips
MT4 backtest `MODEL_EVERY_TICK` corresponds to `EVERY_TICK` (based on real ticks) in MT5. Use `OnTester()` for optimization pass processing. The `TesterStatistics()` function differs: e.g., `TRADE_PROFIT` instead of `GROSS_PROFIT`.
Reference: MQL5 Documentation – "Migration from MQL4 to MQL5" (mql5.com)