For professional EA developers, migrating strategies from MT4 to MT5 is not merely a syntax translation exercise. The two platforms operate on fundamentally different architectural paradigms. This guide addresses the core compatibility challenges and provides production-ready code patterns for MQL4 to MQL5 migration.
Why Direct Conversion Is Impossible
MT4 EAs written in MQL4 cannot run on MT5 because the languages are structurally incompatible. MQL4 uses a linear, procedural execution model centered on the
start() function, while MQL5 is an object-oriented, event-driven language that supports 11 distinct event handlers.| Feature | MQL4 | MQL5 |
| :--- | :--- | :--- |
| Entry Point |
start() | OnTick(), OnTimer(), OnChartEvent() || Order Model | Single-tier (orders only) | Two-tier (positions + orders) |
| Trading Functions |
OrderSend(), OrderSelect() | CTrade class (Buy(), Sell()) || Execution Speed | Baseline | 4-20x faster |
| Backtesting | Single-threaded | Multi-threaded, multi-currency |
| OpenCL Support | No | Native |
Critical Migration Patterns
1. Order System Conversion
The most significant architectural difference is the separation of positions (open trades) from orders (pending entries) in MQL5.
MQL4 Pattern:
``
cpp
// MQL4: Single-tier order management
int ticket = OrderSend(Symbol(), OP_BUY, 0.1, Ask, 3, 0, 0);
if(ticket > 0) {
OrderSelect(ticket, SELECT_BY_TICKET);
double openPrice = OrderOpenPrice();
}
`
MQL5 Equivalent:
`cpp
// MQL5: Two-tier with CTrade class
#include
#include
#include
CTrade trade;
CPositionInfo positionInfo;
COrderInfo orderInfo;
// Opening a market buy position
double volume = 0.1;
if(trade.Buy(volume, Symbol())) {
ulong ticket = trade.ResultOrder();
// Position management is separate
if(positionInfo.SelectByTicket(ticket)) {
double openPrice = positionInfo.PriceOpen();
}
}
`
2. Event Model Migration
MQL4s monolithic start() must be decomposed into appropriate MQL5 event handlers.MQL4 Pattern:
``
cpp
// MQL4: Everything in start()
int start() {
if(NewBar()) {
CheckEntry();
CheckExit();
}
return(0);
}
`
MQL5 Equivalent:
`cpp
// MQL5: Distributed event handlers
datetime lastBarTime = 0;
void OnTick() {
// Fast response to price changes
if(IsNewBar()) {
CheckEntry();
}
}
void OnTimer() {
// Scheduled operations (set via EventSetTimer(1))
CheckExit();
}
bool IsNewBar() {
datetime currentTime = iTime(Symbol(), PERIOD_CURRENT, 0);
if(currentTime == lastBarTime) return false;
lastBarTime = currentTime;
return true;
}
`
3. Indicator Buffer Handling
MQL5 requires explicit buffer binding where MQL4 handles this implicitly.
MQL4 Pattern:
`cpp
// MQL4: Implicit buffer indexing
#property indicator_buffers 1
double Buffer[];
int init() { SetIndexBuffer(0, Buffer); }
`
MQL5 Equivalent:
`cpp
// MQL5: Explicit buffer properties and indexing
#property indicator_buffers 1
#property indicator_plots 1
double Buffer[];
int OnInit() {
SetIndexBuffer(0, Buffer, INDICATOR_DATA);
PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_LINE);
return(INIT_SUCCEEDED);
}
`
Cross-Platform Compatibility Library
The MT5Compat.mqh library provides function-level compatibility for common MQL4 operations.
`cpp
// MT5Compat.mqh - Function Mapping Table
// Save this file and include it in your MQL5 project
//+------------------------------------------------------------------+
//| Price Access Functions |
//+------------------------------------------------------------------+
double GetAsk() { return SymbolInfoDouble(_Symbol, SYMBOL_ASK); }
double GetBid() { return SymbolInfoDouble(_Symbol, SYMBOL_BID); }
double GetPoint() { return SymbolInfoDouble(_Symbol, SYMBOL_POINT); }
int GetDigits() { return (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS); }
//+------------------------------------------------------------------+
//| Market Information Functions |
//+------------------------------------------------------------------+
double GetSymbolMinLot(string symbol) {
return SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
}
double GetSymbolMaxLot(string symbol) {
return SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
}
double GetSymbolTickSize(string symbol) {
return SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE);
}
double GetSymbolTickValue(string symbol) {
return SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE);
}
int GetSymbolSpread(string symbol) {
return (int)SymbolInfoInteger(symbol, SYMBOL_SPREAD);
}
//+------------------------------------------------------------------+
//| Time Series Access - MT4 Style |
//+------------------------------------------------------------------+
double iClose(string symbol, ENUM_TIMEFRAMES tf, int index) {
double arr[];
ArraySetAsSeries(arr, true);
if(CopyClose(symbol, tf, index, 1, arr) > 0)
return arr[0];
return 0;
}
double iOpen(string symbol, ENUM_TIMEFRAMES tf, int index) {
double arr[];
ArraySetAsSeries(arr, true);
if(CopyOpen(symbol, tf, index, 1, arr) > 0)
return arr[0];
return 0;
}
double iHigh(string symbol, ENUM_TIMEFRAMES tf, int index) {
double arr[];
ArraySetAsSeries(arr, true);
if(CopyHigh(symbol, tf, index, 1, arr) > 0)
return arr[0];
return 0;
}
double iLow(string symbol, ENUM_TIMEFRAMES tf, int index) {
double arr[];
ArraySetAsSeries(arr, true);
if(CopyLow(symbol, tf, index, 1, arr) > 0)
return arr[0];
return 0;
}
`
Position and Order Querying
MQL5 requires explicit loops for position and order enumeration, unlike MQL4s selection model.``
cpp
//+------------------------------------------------------------------+
//| Position Query Helper - MQL4 Style Wrapper |
//+------------------------------------------------------------------+
class CPositionManager {
private:
CPositionInfo m_position;
int m_total;
public:
bool SelectByIndex(int index) {
if(!PositionGetTicket(index)) return false;
return m_position.SelectByTicket(PositionGetTicket(index));
}
bool SelectByTicket(ulong ticket) {
return m_position.SelectByTicket(ticket);
}
double GetOpenPrice() { return m_position.PriceOpen(); }
double GetCurrentPrice(){ return m_position.PriceCurrent(); }
double GetStopLoss() { return m_position.StopLoss(); }
double GetTakeProfit() { return m_position.TakeProfit(); }
int GetType() { return (int)m_position.PositionType(); }
double GetVolume() { return m_position.Volume(); }
string GetSymbol() { return m_position.Symbol(); }
int Total() {
return PositionsTotal();
}
};
`
Virtual Hosting Considerations
When deploying migrated EAs to virtual hosting, note these platform differences:
| Constraint | MT4 VPS | MT5 VPS |
| :--- | :--- | :--- |
| DLL Calls | Restricted | Restricted |
| File Operations | Limited | Full access |
| WebRequest | Available | Available with whitelist |
| Multi-currency | Limited | Native support |
| Timer Precision | Basic | Millisecond precision |
Testing Migration Completeness
Before deploying a migrated EA, verify these critical components:
<strong>Order handling:</strong> Confirm OrderSend replacements work in all scenarios (market, pending, modification, partial close)
<strong>Indicator dependencies:</strong> Convert all iCustom() calls and verify buffer indexing
<strong>Time series:</strong> Replace Close[0] patterns with CopyClose() implementations
<strong>Error handling:</strong> MQL5 provides more granular error codes via GetLastError() and CheckPointer()
Summary
Successful MQL4 to MQL5 migration requires understanding three fundamental paradigm shifts:
<strong>Order system:</strong> From single-tier OrderSend to two-tier CTrade + position management
<strong>Event model:</strong> From monolithic start() to distributed OnTick/OnTimer/OnChartEvent
<strong>Data access:</strong> From implicit array indexing to explicit Copy` functionsThe compatibility library provided above offers a drop-in foundation, but complex EAs still require case-by-case refactoring, particularly for custom indicators and advanced order logic.
---
References: