Generate code in 3 minutes
Enter your idea and AI generates runnable code.
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%).
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());
}
}
}
//+------------------------------------------------------------------+
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.(Equity / Margin) * 100. While AccountInfoDouble(ACCOUNT_MARGIN_LEVEL) exists, the manual calculation is often more reliable across different broker API versions in MQL4.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.InpEmergencyLevel.
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.