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.