Summary: This guide covers the critical differences between MQL4 and MQL5 for EA migration: OrderSend vs PositionOpen, ticket handling, and unified order history. Includes working conversion code.




The migration from MQL4 to MQL5 is not a simple syntax update. MQL5 fundamentally restructures how trades are managed: separate position and order concepts replace MQL4's unified order pool. Understanding this architectural shift is essential for any cross-platform EA migration.

Core Architectural Difference

MQL4 uses a single order pool where pending orders and market positions share the same ticket system and OrderSelect() mechanism. MQL5 separates:
  • Positions: Market positions (long/short) identified by ulong PositionGetTicket()

  • Orders: Pending orders identified by ulong OrderGetTicket()

  • History: Closed positions and cancelled orders unified in history


  • MQL4 OrderSend to MQL5 Replacement

    In MQL4, opening a position uses OrderSend():
    ``cpp
    // MQL4 - Original
    int ticket = OrderSend(Symbol(), OP_BUY, Lots, Ask, 3, stopLoss, takeProfit, "EA Comment", magic, 0, Green);
    `

    In MQL5, market positions and pending orders require separate functions:
    `cpp
    // MQL5 - Equivalent
    // Open market position
    MqlTradeRequest request = {};
    MqlTradeResult result = {};
    request.action = TRADE_ACTION_DEAL;
    request.symbol = Symbol();
    request.volume = Lots;
    request.type = ORDER_TYPE_BUY;
    request.price = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
    request.sl = stopLoss;
    request.tp = takeProfit;
    request.deviation = 3;
    request.magic = magic;
    request.comment = "EA Comment";
    OrderSend(request, result);
    ulong ticket = result.order;
    `

    Position Selection Pattern Migration

    MQL4 iterative selection:
    `cpp
    for(int i = 0; i < OrdersTotal(); i++) {
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
    if(OrderMagicNumber() == magic && OrderSymbol() == Symbol()) {
    // Process order
    }
    }
    }
    `

    MQL5 position iterator:
    `cpp
    for(int i = 0; i < PositionsTotal(); i++) {
    ulong ticket = PositionGetTicket(i);
    if(PositionSelectByTicket(ticket)) {
    if(PositionGetInteger(POSITION_MAGIC) == magic && PositionGetString(POSITION_SYMBOL) == Symbol()) {
    // Process position
    }
    }
    }
    `

    Mathematical Transformation for Risk Calculation

    Position sizing formula remains consistent but requires different symbol info access:

    MQL4:
    MarketInfo(Symbol(), MODE_TICKVALUE)

    MQL5:
    SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_VALUE)

    Risk-based lot calculation:
    \[
    \text{Lots} = \frac{\text{RiskPercent} \times \text{Balance}}{100 \times \text{StopLossPoints} \times \text{TickValue}}
    \]

    Where
    TickValue must be normalized to account for quote currency. For non-USD pairs, apply:
    \[
    \text{TickValue}_{\text{USD}} = \frac{\text{TickValue}_{\text{original}}}{\text{USDQuote}}
    \]

    Cross-Platform Compatible Order Send Macro

    Use preprocessor directives to maintain single codebase:
    `cpp
    #ifdef __MQL4__
    #define OPEN_BUY(Lots, Sl, Tp) OrderSend(Symbol(), OP_BUY, Lots, Ask, 3, Sl, Tp, "", magic, 0, Green)
    #else
    #define OPEN_BUY(Lots, Sl, Tp) OpenBuyMQL5(Lots, Sl, Tp)
    #endif
    `

    History Access Migration

    MQL4 selects closed orders by
    OrderSelect() with MODE_HISTORY. MQL5 uses HistorySelect(startDate, endDate) then iterates with HistoryDealGetTicket()`.

    Reference: MQL5 Documentation - Migration from MQL4 (https://www.mql5.com/en/docs/migration), "Expert Advisor Programming for MetaTrader 5" by Andrew R. Young, 2020.