MQL5 Order Filling Types: What You Need to Know

As experienced algorithmic traders utilizing MetaTrader 5, understanding the nuances of order execution is paramount. MQL5 provides sophisticated control over how trading orders are handled by the brokerage’s trading server. A critical aspect of this control is defining the order filling type. This specifies the conditions under which an order can be executed, directly impacting your strategy’s performance and robustness.

Introduction to Order Filling Types in MQL5

In automated trading, simply sending an order request isn’t enough. You must define how much of the requested volume should be filled and under what circumstances the order should be considered successful or failed. MQL5’s order filling types provide this crucial control.

Understanding Order Execution in MQL5

Order execution in MQL5 involves the client terminal sending a trade request to the broker’s server. This request includes details like the symbol, order type (buy, sell, limit, stop), volume, price (for pending orders), and importantly, the desired filling policy. The server then attempts to match this order according to market conditions and the specified filling type. The result (filled, partially filled, rejected, etc.) is communicated back to the client terminal.

Importance of Filling Policies for Traders

Choosing the correct filling policy is vital because it determines:

  • Whether a partial fill is acceptable.
  • Whether the order should remain active after a partial fill.
  • How the system should react if the full volume cannot be matched immediately.

Incorrectly setting the filling type can lead to unexpected partial fills, missed trading opportunities, or excessive order rejections, all of which negatively impact strategy performance and backtesting accuracy.

Market Order Filling Types

For market orders (ORDER_TYPE_BUY, ORDER_TYPE_SELL), which are intended for immediate execution at the best available price, the filling type dictates how the requested volume is handled.

Fill or Kill (FOK)

ORDER_FILLING_FOK: This policy demands that the order must be executed entirely and immediately. If the total requested volume cannot be matched at the available market price(s) when the order reaches the server, the entire order is canceled. No partial execution is allowed under any circumstances.

  • Use Case: High-frequency strategies requiring full execution to maintain tight risk management or capture specific market conditions. Avoids the complexity of managing partial fills.

Immediate or Cancel (IOC)

ORDER_FILLING_IOC: This policy requires execution immediately at the available price(s), but it allows for partial fills. Any volume that can be filled immediately is executed, and the remaining volume is canceled. The order does not remain pending.

  • Use Case: Strategies where getting some execution is better than none, or where slippage risk on the full volume is a concern. Useful in volatile markets or for large volumes where full fills might be difficult.

Return (Available only in the exchange execution mode)

ORDER_FILLING_RETURN: This policy is specific to instruments traded in the exchange execution mode (indicated by SYMBOL_TRADE_EXECUTION_EXCHANGE). It allows for a partial fill immediately at the available price(s), and the remaining volume is not canceled. Instead, the unfilled portion becomes a pending order (specifically, a Limit order) at the price of the partial execution.

  • Use Case: Exchange-traded instruments where partial fills are common and traders wish to leave the remaining volume in the market as a passive order to potentially get filled later at the same or a better price.

Limit Order Filling Types

Limit orders (ORDER_TYPE_BUY_LIMIT, ORDER_TYPE_SELL_LIMIT) are pending orders placed to buy at or below a specific price or sell at or above a specific price. Their filling types define how they behave once the market price reaches the specified limit price.

Fill or Kill (FOK)

ORDER_FILLING_FOK: For a Limit order, this means that once the market price reaches the specified limit price, the entire order volume must be filled at that moment (or better). If the full volume cannot be filled instantly upon reaching the limit price, the order is canceled.

  • Use Case: Highly sensitive limit entries where getting the exact desired volume at the specified price (or better) is critical, and partial fills are unacceptable.

Immediate or Cancel (IOC)

ORDER_FILLING_IOC: For a Limit order, this means that once the market price reaches the limit price, any volume that can be filled immediately at that price (or better) is executed, and the remaining volume is canceled. The order does not become a regular pending limit order for the unfilled portion.

  • Use Case: Attempting to get the best possible fill up to the limit price instantly, without leaving a pending order for the remainder.

Return (Available only in the exchange execution mode)

ORDER_FILLING_RETURN: Similar to market orders in exchange mode, for a Limit order with this policy, when the price reaches the limit, any volume that can be filled immediately is executed, and the remaining volume stays in the market as a pending Limit order at the original limit price.

  • Use Case: The standard behavior for limit orders on exchanges, allowing partial fills and keeping the rest active.

Stop Order Filling Types

Stop orders (ORDER_TYPE_BUY_STOP, ORDER_TYPE_SELL_STOP, ORDER_TYPE_BUY_STOP_LIMIT, ORDER_TYPE_SELL_STOP_LIMIT) are triggered when the market price reaches a specified stop price. For Stop-Limit orders, this trigger then places a Limit order. The filling types apply to the resulting market or limit order once the stop price is hit.

Fill or Kill (FOK)

ORDER_FILLING_FOK: When a Stop order’s trigger price is hit, the resulting market or limit order must be filled entirely and immediately at the available price(s) (for market) or at the limit price or better (for limit). If the full volume cannot be filled instantly upon triggering, the order is canceled.

  • Use Case: Exiting positions with tight stop-loss or stop-gain rules where a full exit is required immediately upon trigger, even if it means potential cancellation.

Immediate or Cancel (IOC)

ORDER_FILLING_IOC: When a Stop order’s trigger price is hit, the resulting market or limit order will be filled immediately with whatever volume is available. Any unfilled volume is canceled. The order does not remain pending.

  • Use Case: Ensuring at least a partial exit or entry upon a stop trigger, prioritizing immediate execution over full volume guarantee.

Return (Available only in the exchange execution mode)

ORDER_FILLING_RETURN: When a Stop order’s trigger price is hit in exchange mode, the resulting market or limit order will fill immediately with available volume, and the remaining volume will stay as a pending order (either a Market order queue entry or a Limit order, depending on the stop type and exchange rules) at the execution or limit price.

  • Use Case: Standard stop order behavior on exchanges, allowing partial fills and leaving the remainder active.

Practical Examples and Code Snippets

Implementing these filling types in MQL5 involves setting the type_filling field in the MqlTradeRequest structure before sending the order via OrderSend().

Implementing Different Filling Types in MQL5 Code

Here’s how you might structure a trade request for a Buy Market order with different filling policies:

#include <Trade/Trade.mqh>

CTrade trade; // Ensure CTrade object is properly initialized elsewhere

void PlaceMarketOrder(string symbol, double volume, ENUM_ORDER_FILLING filling_type)
{
    MqlTradeRequest request;
    MqlTradeResult  result;
    ZeroMemory(request);

    request.action   = TRADE_ACTION_DEAL;        // Instant execution
    request.symbol   = symbol;
    request.volume   = volume;
    request.type     = ORDER_TYPE_BUY;
    request.price    = SymbolInfoDouble(symbol, SYMBOL_ASK); // Use current ask for buy
    request.deviation = 10; // Maximum deviation in points
    request.type_filling = filling_type; // <<< Setting the filling type

    // Optional: Set magic number, comment, etc.
    request.magic = ExpertMagicNumber();
    request.comment = "MyStrategy";

    // Send the order request
    if (OrderSend(request, result))
    {
        Print("OrderSend success. Deal Ticket: ", result.deal, ", Order Ticket: ", result.order);
        // Check result for partial fill, rejection etc.
        Print("Order Result Code: ", result.retcode);
    }
    else
    {
        Print("OrderSend failed. Error: ", GetLastError());
    }
}

// Example calls:
// PlaceMarketOrder(Symbol(), 0.1, ORDER_FILLING_FOK); // Buy 0.1 lot FOK
// PlaceMarketOrder(Symbol(), 0.5, ORDER_FILLING_IOC); // Buy 0.5 lot IOC
// PlaceMarketOrder(Symbol(), 1.0, ORDER_FILLING_RETURN); // Buy 1.0 lot RETURN (if symbol supports exchange mode)

Similarly, for pending orders, you set type_filling in the request struct:

void PlaceLimitOrder(string symbol, double volume, double price, ENUM_ORDER_FILLING filling_type)
{
    MqlTradeRequest request;
    MqlTradeResult  result;
    ZeroMemory(request);

    request.action   = TRADE_ACTION_PENDING; // Pending order
    request.symbol   = symbol;
    request.volume   = volume;
    request.type     = ORDER_TYPE_BUY_LIMIT;
    request.price    = price; // Your desired limit price
    request.type_filling = filling_type; // <<< Setting the filling type

    // ... other request fields ...

    if (OrderSend(request, result))
    {
        Print("Pending OrderSend success. Order Ticket: ", result.order);
        Print("Order Result Code: ", result.retcode);
    }
    else
    {
        Print("Pending OrderSend failed. Error: ", GetLastError());
    }
}

// Example calls:
// PlaceLimitOrder(Symbol(), 0.2, Ask - 50 * _Point, ORDER_FILLING_FOK); // Buy Limit FOK
// PlaceLimitOrder(Symbol(), 0.3, Ask - 50 * _Point, ORDER_FILLING_IOC); // Buy Limit IOC
// PlaceLimitOrder(Symbol(), 0.5, Ask - 50 * _Point, ORDER_FILLING_RETURN); // Buy Limit RETURN (if symbol supports exchange mode)

Handling Order Rejections Due to Filling Policies

Orders can be rejected if the filling policy cannot be met by the server. Common rejection codes (result.retcode) might include:

  • TRADE_RETCODE_NO_CHANGES: Often related to price deviation issues, but can sometimes occur if the market conditions prevent the specified filling type (e.g., insufficient liquidity for FOK).
  • TRADE_RETCODE_INVALID_FILL: Specifically indicates that the requested filling type is not supported by the server or symbol.
  • TRADE_RETCODE_LIMIT_ORDER_BAD_STATE: Could occur for pending orders if the server cannot process the filling type.

Your EA must check the result.retcode after OrderSend() and implement appropriate error handling. This could involve logging the error, retrying with a different filling type (if appropriate for your strategy), or skipping the trade. You should always verify supported filling types for a symbol using SymbolInfoInteger(symbol, SYMBOL_TRADE_MODEL) or by checking the ENUM_SYMBOL_TRADE_EXECUTION mode and consulting broker documentation.

// Inside the OrderSend check block:
if (OrderSend(request, result))
{
    Print("OrderSend success. Order/Deal Ticket: ", result.order > 0 ? result.order : result.deal, ", Result Code: ", result.retcode);
    if (result.retcode == TRADE_RETCODE_DONE)
    {
        Print("Order successfully placed/executed.");
        // Further checks for partial fills might be needed depending on filling type and strategy
    }
    else if (result.retcode == TRADE_RETCODE_NO_CHANGES || result.retcode == TRADE_RETCODE_INVALID_FILL)
    {
        Print("Order rejected due to filling policy or market conditions. Consider alternative.");
        // Implement logic: retry with IOC? Log? Alert?
    }
    else
    {
        Print("Order failed with unexpected code: ", result.retcode);
        // Handle other errors
    }
}
else
{
    Print("OrderSend failed entirely. Error: ", GetLastError());
}

Optimizing Order Execution Based on Market Conditions

The optimal filling type often depends on market volatility and liquidity. In highly liquid, stable markets, FOK might be reliable. In volatile or less liquid markets, IOC or RETURN (if applicable) might be preferable to ensure at least partial execution.

You could incorporate logic into your EA to dynamically select the filling type based on:

  1. Volatility: Measured by ATR, standard deviation, etc. Higher volatility might favor IOC.
  2. Spread: Wider spreads can increase the chance of FOK failure. Consider IOC.
  3. Time of Day/Session: Liquidity varies throughout the day. Use different types during peak vs. off-peak hours.
  4. Symbol Properties: Always check if ORDER_FILLING_RETURN is supported for the symbol using SymbolInfoInteger or SymbolInfoString related to execution mode.

Dynamic selection requires careful testing to avoid unexpected behavior, but it can significantly improve execution quality and reduce rejections in diverse market conditions.

In conclusion, mastering MQL5’s order filling types is essential for building robust and efficient trading systems. By understanding the nuances of FOK, IOC, and RETURN, and implementing appropriate error handling and potentially dynamic selection, you can gain greater control over your order execution and enhance your algorithmic trading performance.


Leave a Reply