🚀 AI One-Click Generation of mql4 Strategy Code

Mql4 Pre-emptive Risk Management with `AccountStopoutLevel()` and `AccountStopoutMode()`

mql4 | Published on: 2025/12/10
The following content is generated by EasyQuant .

Problem Description

How can my trading robot know when a margin call or stopout is near and close some trades to prevent it?

Solution

To prevent a margin call or stopout programmatically, your Expert Advisor (EA) needs to monitor the Margin Level percentage.

The Margin Level is calculated as:
$$ \text{Margin Level} = \left( \frac{\text{Account Equity}}{\text{Used Margin}} \right) \times 100 $$

Brokers usually trigger a Margin Call at a specific level (e.g., 100%) and a Stopout (forced closure) at a lower level (e.g., 50% or 30%).

Strategy Logic

  1. Monitor: On every tick, calculate the current Margin Level.
  2. Threshold: Define a custom "Emergency Level" (e.g., 120%) that is higher than your broker's stopout level.
  3. Action: If the Margin Level drops below this threshold, the EA will identify the position with the largest floating loss and close it immediately.
  4. Repeat: The EA continues this process on subsequent ticks until the Margin Level is back above the safety threshold.

MQL4 Implementation

Here is the complete, copy-pasteable code for an EA that performs this safety check.

//+------------------------------------------------------------------+
//|                                        MarginProtectionGuard.mq4 |
//|                                     Copyright 2023, MetaQuotes   |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, Quantitative Assistant"
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict

//--- INPUT PARAMETERS
input double InpEmergencyLevel = 120.0; // Margin Level % to trigger closure (e.g., 120%)
input int    InpMagicNumber    = 0;     // 0 = Monitor ALL trades, >0 = Monitor specific Magic Number
input int    InpSlippage       = 5;     // Allowed slippage for closing

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   // Basic validation
   if(InpEmergencyLevel <= 50)
   {
      Print("WARNING: Emergency Level is set very low (", InpEmergencyLevel, "%). Ensure this is above your broker's Stopout level.");
   }
   
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
   // 1. Check if we have open trades to monitor
   if(OrdersTotal() == 0) return;

   // 2. Get current account margin data
   double equity = AccountEquity();
   double usedMargin = AccountMargin();
   
   // Avoid division by zero if no margin is used
   if(usedMargin <= 0) return;

   // 3. Calculate Margin Level
   double currentMarginLevel = (equity / usedMargin) * 100.0;

   // 4. Check against Emergency Threshold
   if(currentMarginLevel < InpEmergencyLevel)
   {
      Print("CRITICAL: Margin Level at ", DoubleToString(currentMarginLevel, 2), 
            "%. Below limit of ", DoubleToString(InpEmergencyLevel, 2), "%. Initiating protective close.");
      
      // Close the worst performing trade to free up margin and equity
      CloseWorstTrade();
   }
}

//+------------------------------------------------------------------+
//| Helper: Find and close the trade with the largest loss           |
//+------------------------------------------------------------------+
void CloseWorstTrade()
{
   int worstTicket = -1;
   double worstProfit = 1000000.0; // Start with a high number
   double lotSize = 0;
   int orderType = -1;
   string symbol = "";

   // --- Step A: Find the biggest loser ---
   for(int i = 0; i < OrdersTotal(); i++)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         // Filter by Magic Number if specified (0 means all trades)
         if(InpMagicNumber > 0 && OrderMagicNumber() != InpMagicNumber) continue;

         // We only care about market orders (OP_BUY or OP_SELL)
         if(OrderType() > OP_SELL) continue;

         // Check profit (including swap and commission for accuracy)
         double tradeProfit = OrderProfit() + OrderSwap() + OrderCommission();

         // Identify the lowest profit (largest loss)
         if(tradeProfit < worstProfit)
         {
            worstProfit = tradeProfit;
            worstTicket = OrderTicket();
            lotSize = OrderLots();
            orderType = OrderType();
            symbol = OrderSymbol();
         }
      }
   }

   // --- Step B: Close the identified trade ---
   if(worstTicket != -1)
   {
      // Refresh rates before closing to minimize errors
      RefreshRates();
      
      double closePrice = 0.0;
      color arrowColor = clrRed;

      // Get correct closing price based on order type
      if(orderType == OP_BUY)
      {
         closePrice = MarketInfo(symbol, MODE_BID);
      }
      else if(orderType == OP_SELL)
      {
         closePrice = MarketInfo(symbol, MODE_ASK);
      }

      // Attempt to close
      bool result = OrderClose(worstTicket, lotSize, closePrice, InpSlippage, arrowColor);

      if(result)
      {
         Print("PROTECTION: Closed Order #", worstTicket, " (", symbol, ") Loss: ", DoubleToString(worstProfit, 2), " to restore margin.");
      }
      else
      {
         Print("ERROR: Failed to close Order #", worstTicket, ". Error Code: ", GetLastError());
      }
   }
}
//+------------------------------------------------------------------+

Key Features of This Code

  1. AccountMargin() Check: It first checks if AccountMargin() is greater than 0. If you have no open trades (or fully hedged trades on some broker types where margin is 0), the calculation is skipped to avoid "Division by Zero" errors.
  2. Calculation: It manually calculates (Equity / Margin) * 100. While AccountInfoDouble(ACCOUNT_MARGIN_LEVEL) exists, the manual calculation is often more reliable across different broker API versions in MQL4.
  3. "Worst Trade" Logic: Instead of closing all trades at once (which might be unnecessary), this EA finds the single trade with the largest floating loss (including swaps and commissions). Closing the biggest loser is usually the most effective way to increase the Margin Level immediately because it stops the equity drain and frees up the margin attached to that trade.
  4. Magic Number Filter: If you set InpMagicNumber to 0, it protects the entire account (manual trades and other robots). If you set it to a specific ID, it will only close trades belonging to that specific strategy.

How to Use

  1. Compile the code in MetaEditor.
  2. Attach it to any one chart (it monitors the whole account, so you only need it on one chart).
  3. Set InpEmergencyLevel.
    • Check your broker's specifications. If their Stopout is 50%, set this to 100% or 120% to give yourself a safety buffer.

Q&A: Margin Protection

Q: Why calculate Margin Level manually instead of using AccountInfoDouble?
A: While AccountInfoDouble(ACCOUNT_MARGIN_LEVEL) is valid, older MQL4 compilers or specific broker bridges sometimes return 0 or inconsistent data. Calculating (AccountEquity() / AccountMargin()) * 100 is mathematically fail-safe.

Q: Will this close all my trades instantly?
A: No. It closes one trade per tick. If closing the first trade raises the Margin Level above your InpEmergencyLevel, it stops there. If the margin is still critical on the next tick, it closes the next worst trade.

Q: Does this work if the market is moving very fast?
A: Yes, but slippage may occur. The InpSlippage parameter helps ensure the order closes even if the price ticks slightly during the request.

Q: What if my broker uses "Money" stopout instead of "Percentage"?
A: Most retail brokers use Percentage. However, if your broker uses a fixed money amount (e.g., Stopout at $500 equity), you would change the logic to check if (AccountEquity() < InpEmergencyEquityAmount). The code provided above assumes the standard Percentage model.