Summary: Advanced cross-platform development guide for MQL4 and MQL5. Unified trade function implementation with conditional compilation, covering Buy, Sell, Close operations and multi-condition position filtering.
Cross-platform EA development has become essential as traders and brokers gradually transition from MT4 to MT5. Maintaining two separate code bases is inefficient and error-prone. This guide presents a unified trade function system that works seamlessly on both platforms using conditional compilation.
1. Core Cross-Platform Detection
The foundation of unified code is the compiler macros `__MQL4__` and `__MQL5__`. These allow the same source file to compile correctly on either platform.
```cpp
// Platform detection macros
#ifdef __MQL4__
#define IS_MQL4 true
#define PLATFORM "MT4"
#else
#define IS_MQL4 false
#define PLATFORM "MT5"
#endif
// Unified loop macro for positions
#ifdef __MQL4__
#define ForEachPositionDown(i) for(int i=OrdersTotal()-1; i>=0; i--)
#define SelectPositionByIndex(i) OrderSelect(i, SELECT_BY_POS, MODE_TRADES)
#else
#define ForEachPositionDown(i) for(int i=PositionsTotal()-1; i>=0; i--)
#define SelectPositionByIndex(i) PositionSelectByIndex(i)
#endif
```
2. Unified OrderSend Replacement
The most significant difference between MQL4 and MQL5 is trade execution. MQL4 uses `OrderSend()` directly, while MQL5 uses the `CTrade` class or `MqlTradeRequest` structure.
```cpp
// Cross-platform Buy function
ulong Buy(double volume, double sl, double tp, ulong magic, string symbol, string comment) {
#ifdef __MQL4__
double ask = MarketInfo(symbol, MODE_ASK);
double sl_price = (sl > 0) ? ask - sl * Point : 0;
double tp_price = (tp > 0) ? ask + tp * Point : 0;
int ticket = OrderSend(symbol, OP_BUY, volume, ask, 3, sl_price, tp_price, comment, (int)magic, 0, clrNONE);
return (ticket > 0) ? (ulong)ticket : 0;
#else
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_DEAL;
request.symbol = symbol;
request.volume = volume;
request.type = ORDER_TYPE_BUY;
request.price = SymbolInfoDouble(symbol, SYMBOL_ASK);
request.sl = sl;
request.tp = tp;
request.deviation = 10;
request.magic = (ulong)magic;
request.comment = comment;
request.type_filling = ORDER_FILLING_FOK;
return OrderSend(request, result) ? result.order : 0;
#endif
}
// Cross-platform Sell function
ulong Sell(double volume, double sl, double tp, ulong magic, string symbol, string comment) {
#ifdef __MQL4__
double bid = MarketInfo(symbol, MODE_BID);
double sl_price = (sl > 0) ? bid + sl * Point : 0;
double tp_price = (tp > 0) ? bid - tp * Point : 0;
int ticket = OrderSend(symbol, OP_SELL, volume, bid, 3, sl_price, tp_price, comment, (int)magic, 0, clrNONE);
return (ticket > 0) ? (ulong)ticket : 0;
#else
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_DEAL;
request.symbol = symbol;
request.volume = volume;
request.type = ORDER_TYPE_SELL;
request.price = SymbolInfoDouble(symbol, SYMBOL_BID);
request.sl = sl;
request.tp = tp;
request.deviation = 10;
request.magic = (ulong)magic;
request.comment = comment;
request.type_filling = ORDER_FILLING_FOK;
return OrderSend(request, result) ? result.order : 0;
#endif
}
```
3. Unified Position Closing
Closing positions requires handling the opposite direction: buy positions close at Bid, sell positions close at Ask.
```cpp
bool ClosePosition(ulong ticket, string symbol) {
#ifdef __MQL4__
if(!OrderSelect((int)ticket, SELECT_BY_TICKET)) return false;
double close_price = (OrderType() == OP_BUY) ? MarketInfo(symbol, MODE_BID) : MarketInfo(symbol, MODE_ASK);
return OrderClose((int)ticket, OrderLots(), close_price, 3, clrNONE);
#else
if(!PositionSelectByTicket(ticket)) return false;
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_DEAL;
request.position = ticket;
request.symbol = symbol;
request.volume = PositionGetDouble(POSITION_VOLUME);
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) {
request.price = SymbolInfoDouble(symbol, SYMBOL_BID);
request.type = ORDER_TYPE_SELL;
} else {
request.price = SymbolInfoDouble(symbol, SYMBOL_ASK);
request.type = ORDER_TYPE_BUY;
}
request.deviation = 10;
request.type_filling = ORDER_FILLING_FOK;
return OrderSend(request, result);
#endif
}
```
4. Multi-Condition Batch Closing
Professional EAs often need to close positions based on multiple criteria: magic numbers, symbols, or comments. This cross-platform implementation supports array-based filtering.
```cpp
bool BuyClose(ulong &magic[], string &symbol[], string &comment[]) {
bool ret = true;
ForEachPositionDown(i) {
if(!SelectPositionByIndex(i)) continue;
#ifdef __MQL4__
if(OrderType() != OP_BUY) continue;
if(!MatchMagic(magic, OrderMagicNumber())) continue;
if(!MatchSymbol(symbol, OrderSymbol())) continue;
if(!MatchComment(comment, OrderComment())) continue;
ret = ret && ClosePosition(OrderTicket(), OrderSymbol());
#else
if(PositionGetInteger(POSITION_TYPE) != POSITION_TYPE_BUY) continue;
if(!MatchMagic(magic, (ulong)PositionGetInteger(POSITION_MAGIC))) continue;
if(!MatchSymbol(symbol, PositionGetString(POSITION_SYMBOL))) continue;
ret = ret && ClosePosition(PositionGetInteger(POSITION_TICKET), PositionGetString(POSITION_SYMBOL));
#endif
}
return ret;
}
bool MatchMagic(ulong &magic[], ulong value) {
int size = ArraySize(magic);
if(size == 0) return true;
for(int i = 0; i < size; i++)
if(magic[i] == value) return true;
return false;
}
bool MatchSymbol(string &symbols[], string value) {
int size = ArraySize(symbols);
if(size == 0) return true;
for(int i = 0; i < size; i++)
if(symbols[i] == value || symbols[i] == "") return true;
return false;
}
```
5. Practical Usage Example
```cpp
input ulong MagicNumber = 12345;
input double LotSize = 0.1;
input int StopLoss = 50;
input int TakeProfit = 100;
void OnTick() {
static datetime lastBarTime = 0;
datetime currentBarTime = iTime(_Symbol, PERIOD_CURRENT, 1);
if(currentBarTime != lastBarTime) {
lastBarTime = currentBarTime;
// Entry signal logic here
bool buySignal = CheckBuySignal();
bool sellSignal = CheckSellSignal();
if(buySignal) {
ulong ticket = Buy(LotSize, StopLoss * _Point, TakeProfit * _Point, MagicNumber, _Symbol, "CrossPlatformEA");
if(ticket > 0) Print("Buy order placed: ", ticket);
}
if(sellSignal && CloseAllBuyPositions()) {
Print("All buy positions closed");
}
}
}
bool CloseAllBuyPositions() {
ulong magicArray[1] = {MagicNumber};
string symbolArray[1] = {_Symbol};
string emptyArray[];
return BuyClose(magicArray, symbolArray, emptyArray);
}
```
Reference: MQL5 Community, “Cross-Platform Development with MQL4 and MQL5” (mql5.com); WeChat Public Account, “Unified Trade Functions for MT4/MT5” (2026).