Summary: 面向进阶用户的MQL4与MQL5跨平台开发指南。使用条件编译实现统一交易函数,涵盖Buy、Sell、Close操作及多条件仓位筛选,一套代码双平台运行。
跨平台EA开发已变得至关重要,因为交易者和经纪商正逐步从MT4过渡到MT5。维护两套独立的代码库不仅效率低下,而且容易出错。本指南将展示如何使用条件编译,构建一套在双平台上无缝运行的统一交易函数系统。
1. 跨平台检测基础
统一代码的基础是编译器宏`__MQL4__`和`__MQL5__`。这些宏使得同一份源码能够在任一平台上正确编译。
```cpp
// 平台检测宏
#ifdef __MQL4__
#define IS_MQL4 true
#define PLATFORM "MT4"
#else
#define IS_MQL4 false
#define PLATFORM "MT5"
#endif
// 统一的仓位遍历宏
#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. 统一的OrderSend替代方案
MQL4与MQL5之间最显著的差异在于交易执行方式。MQL4直接使用`OrderSend()`函数,而MQL5则使用`CTrade`类或`MqlTradeRequest`结构体。
```cpp
// 跨平台Buy函数
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
}
// 跨平台Sell函数
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. 统一的仓位平仓
平仓操作需要处理相反的方向:多单在Bid价格平仓,空单在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. 多条件批量平仓
专业EA通常需要基于多个条件筛选平仓:魔术号、品种或注释。以下跨平台实现支持基于数组的多条件筛选。
```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. 实际使用示例
```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;
// 在此处编写入场信号逻辑
bool buySignal = CheckBuySignal();
bool sellSignal = CheckSellSignal();
if(buySignal) {
ulong ticket = Buy(LotSize, StopLoss * _Point, TakeProfit * _Point, MagicNumber, _Symbol, "CrossPlatformEA");
if(ticket > 0) Print("买单已发送: ", ticket);
}
if(sellSignal && CloseAllBuyPositions()) {
Print("所有多单已平仓");
}
}
}
bool CloseAllBuyPositions() {
ulong magicArray[1] = {MagicNumber};
string symbolArray[1] = {_Symbol};
string emptyArray[];
return BuyClose(magicArray, symbolArray, emptyArray);
}
```
参考来源:MQL5社区《MQL4与MQL5跨平台开发》(mql5.com);微信公众号《MT4/MT5统一交易函数》(2026)。