MQL4: How to Close All Trades?

Closing all open trades is a common requirement in automated trading systems implemented in MQL4. Whether it’s due to a specific event, risk management rules, or strategy changes, programmatically closing positions is a fundamental task for any serious MQL4 developer.

Why Close All Trades? Use Cases

Several scenarios necessitate the ability to close all trades:

  • End of Day/Session: Winding down all positions before market close to avoid overnight risk.
  • Stop-Loss/Take-Profit Triggers: Closing all trades as a form of portfolio-level risk management when a critical threshold is breached.
  • Strategy Switching: Transitioning from one trading strategy to another, requiring a clean slate.
  • Manual Intervention: Providing a ‘panic button’ to exit all positions immediately.

Brief Overview of Trade Management Functions in MQL4

MQL4 provides a set of functions specifically designed for trade management. These include:

  • OrdersTotal(): Returns the total number of open and pending orders.
  • OrderSelect(): Selects a specific order from the order pool for subsequent operations.
  • OrderClose(): Closes an existing market order.
  • OrderSymbol(): Returns the symbol for a selected order.
  • OrderType(): Returns the order type (e.g., OPBUY, OPSELL).
  • OrderMagicNumber(): Returns the magic number assigned to an order.

Understanding MQL4 Trade Iteration and Selection

Before closing trades, you need to understand how to iterate through all open orders and select the ones you want to close.

Using OrdersTotal() to Determine the Number of Open Trades

OrdersTotal() is the starting point. It returns an integer representing the total number of open and pending orders in the market. This value is crucial for setting up your loop.

The OrderSelect() Function: Selecting Trades for Processing

OrderSelect() is the workhorse for accessing individual order properties. It takes two parameters:

  • index: The index of the order you want to select (starting from 0).
  • select: A flag indicating the order pool to select from. Use SELECT_BY_POS if you’re iterating through orders, and SELECT_BY_TICKET if you know the specific order ticket number. However, for closing all trades, SELECT_BY_POS is almost always what you need.

Understanding MODE_TRADES

While technically related to older MQL4 versions, it’s important to note that MODE_TRADES is not directly used when iterating through and closing orders. MODE_TRADES was related to account information retrieval and is largely irrelevant in modern MQL4 trade management. The OrderSelect() function with SELECT_BY_POS handles the selection of trades.

Implementing the ‘Close All Trades’ Function

Here’s how to put these functions together to create a ‘close all trades’ function.

Basic Implementation: Looping Through and Closing Trades

The most straightforward approach involves a loop that iterates through all open orders and closes them one by one.

void CloseAllTrades()
{
   int total = OrdersTotal();
   for(int i = total - 1; i >= 0; i--)
   {
      if(OrderSelect(i, SELECT_BY_POS))
      {
         if(OrderType() == OP_BUY)
         {
            OrderClose(OrderTicket(), OrderLots(), Bid, Slippage, Blue);          
         }
         else if (OrderType() == OP_SELL)
         {
            OrderClose(OrderTicket(), OrderLots(), Ask, Slippage, Blue);
         }
      }
   }
}

Note the reverse iteration (from total - 1 to 0). This is crucial. Closing an order shifts the indices of the remaining orders. Iterating backwards prevents skipping orders during the process.

Error Handling and Trade Closure Verification

Trade closure can fail for various reasons (e.g., requotes, insufficient funds). Robust code must include error handling.

void CloseAllTrades()
{
   int total = OrdersTotal();
   for(int i = total - 1; i >= 0; i--)
   {
      if(OrderSelect(i, SELECT_BY_POS))
      {
         double closePrice = (OrderType() == OP_BUY) ? Bid : Ask;
         int ticket = OrderTicket();
         double lots = OrderLots();
         int slippage = 3; // Adjust slippage as needed
         int color = Blue;

         bool closed = OrderClose(ticket, lots, closePrice, slippage, color);

         if(!closed)
         {
            Print("OrderClose failed for ticket: ", ticket, ", Error: ", GetLastError());
         }
      }
   }
}

The GetLastError() function provides a numeric code explaining the failure. Refer to the MQL4 documentation for a complete list of error codes.

Considering Trade Types (Buy/Sell) and Symbols

The basic example closes all trades regardless of type. You might want to close only buy or sell orders, or orders on specific symbols. This requires adding conditional checks.

Advanced Techniques and Considerations

Closing Trades Based on Magic Number

Expert Advisors often use ‘magic numbers’ to identify trades they’ve opened. To close only trades belonging to a specific EA:

void CloseTradesByMagicNumber(int magic)
{
   int total = OrdersTotal();
   for(int i = total - 1; i >= 0; i--)
   {
      if(OrderSelect(i, SELECT_BY_POS) && OrderMagicNumber() == magic)
      {
         OrderClose(OrderTicket(), OrderLots(), (OrderType() == OP_BUY) ? Bid : Ask, Slippage, Blue);
      }
   }
}

Closing Trades Based on Symbol

To close trades only on a particular symbol:

void CloseTradesBySymbol(string symbol)
{
   int total = OrdersTotal();
   for(int i = total - 1; i >= 0; i--)
   {
      if(OrderSelect(i, SELECT_BY_POS) && OrderSymbol() == symbol)
      {
         OrderClose(OrderTicket(), OrderLots(), (OrderType() == OP_BUY) ? Bid : Ask, Slippage, Blue);
      }
   }
}

Asynchronous Trade Closure and Order Send Limits

MetaTrader imposes limits on the frequency of order sending. Rapidly closing many trades can trigger these limits, leading to closure failures. While MQL4 doesn’t have built-in asynchronous order execution, strategies need to be designed to account for this limitation. Introducing small delays (using Sleep()) within the loop can help, but it’s not a perfect solution. Proper risk and money management greatly reduces risk of reaching those limits.

Complete Code Example and Explanation

Here’s a complete example incorporating error handling, magic number filtering, and comments.

//+------------------------------------------------------------------+
//| Script program start function                                     |
//+------------------------------------------------------------------+
void OnStart()
  {
   //---
   CloseAllTradesWithMagic(12345); // Example: Close trades with magic number 12345
  }

//+------------------------------------------------------------------+
//| Function to close all trades with a specific magic number        |
//+------------------------------------------------------------------+
void CloseAllTradesWithMagic(int magicNumber)
{
   int totalTrades = OrdersTotal();
   Print("Total trades open: ", totalTrades);

   // Iterate through trades in reverse order
   for (int i = totalTrades - 1; i >= 0; i--)
   {
      // Select the trade
      if (OrderSelect(i, SELECT_BY_POS))
      {
         // Check if the trade's magic number matches the specified magic number
         if (OrderMagicNumber() == magicNumber)
         {
            // Determine the order type (buy or sell) to determine the close price
            double closePrice = (OrderType() == OP_BUY) ? SymbolInfoDouble(OrderSymbol(),SYMBOL_BID) : SymbolInfoDouble(OrderSymbol(),SYMBOL_ASK);

            // Close the order
            bool result = OrderClose(OrderTicket(), OrderLots(), closePrice, 3, Red);

            // Check if the order was closed successfully
            if (result)
            {
               Print("Order with ticket #", OrderTicket(), " closed successfully.");
            }
            else
            {
               Print("Failed to close order with ticket #", OrderTicket(), ". Error code: ", GetLastError());
            }
         }
      }
      else
      {
         Print("Failed to select order at position ", i, ". Error code: ", GetLastError());
      }

   }

   Print("Finished attempting to close all trades with magic number ", magicNumber);
}
//+------------------------------------------------------------------+

Step-by-Step Code Walkthrough

  1. The OnStart() function is the entry point for the script.
  2. The CloseAllTradesWithMagic() function iterates through all open orders using OrdersTotal() and OrderSelect(). The trades are processed from the end of the order pool to the beginning to avoid issues caused by order indices changing after closing a trade.
  3. For each order, it checks if its magic number matches the specified magicNumber.
  4. If the magic numbers match, the order is closed using OrderClose(). The close price is determined based on the order type (buy or sell).
  5. The result of the OrderClose() function is checked, and a message is printed to the Experts tab indicating whether the order was closed successfully or if an error occurred.

Customization Options and Parameters

  • Slippage: The Slippage variable (set to 3 in this example) controls the maximum acceptable price slippage during order closure. Adjust this value based on market volatility and your risk tolerance. High volatility might require a higher slippage value.
  • Magic Number: This example uses hardcoded magic number 12345. You can modify this to suit specific trading strategies.

Testing and Debugging the Function

  • Print Statements: The code includes Print() statements to provide detailed information about the closure process, including order tickets, error codes, and success/failure messages. These statements are invaluable for debugging.
  • Backtesting: Before deploying the code in a live trading environment, thoroughly test it using the MetaTrader strategy tester. This allows you to evaluate its performance under different market conditions and identify potential issues.

This article provides a comprehensive guide to closing all trades in MQL4. By understanding the underlying principles and implementing robust error handling, you can create reliable automated trading systems that effectively manage your positions.


Leave a Reply