We’ve all been there. A high-impact news event like CPI or NFP drops, the spread blows up, and price action goes completely erratic. If you need to bail out of the market instantly, manually clicking "Close" on multiple positions is a death sentence. By the time you get to your third trade, the price has moved 30 pips and your broker is spamming you with requotes.
To solve this, I wrote a lightweight, aggressive MQL4 script designed specifically to execute closes under heavy market stress.
Here is what makes this different from the standard generic "close all" scripts floating around:
Multi-Symbol Awareness: It uses MarketInfo() instead of standard Bid/Ask variables. This means you can drop this on any chart, and it will fetch the correct execution prices to close positions across all traded pairs.
Reverse Iteration: It loops through the order pool backward. If you loop forward and close an order, the terminal's indices shift, causing the script to skip trades. This prevents that.
Hardcore Retry Logic: During news spikes, brokers love throwing ERR_REQUOTE (138) or ERR_PRICE_CHANGED (139). This script intercepts execution failures and rapid-fires the close request again up to your defined limit.
Pending Order Wipe: Includes a toggle to instantly delete pending Limit/Stop orders so a widening spread doesn't drag you back into the market.
The MT4 Code
Create a new Script in MetaEditor, name it News_Panic_Close.mq4, and paste the following:
Code: Select all
//+------------------------------------------------------------------+
//| News_Panic_Close.mq4 |
//| Closes all open positions with retry logic |
//+------------------------------------------------------------------+
#property strict
#property show_inputs
//--- Input Parameters
input int MaxRetries = 5; // Number of retries on requotes/errors
input int Slippage = 50; // Allowed slippage in points (higher for news)
input bool ClosePending = true; // Delete pending limit/stop orders as well?
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
int total = OrdersTotal();
// Loop backwards to prevent index shifting when an order is removed
for(int i = total - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
bool result = false;
int retries = 0;
// Aggressive retry loop for news volatility
while(!result && retries < MaxRetries)
{
RefreshRates(); // Force update of local environment data
int type = OrderType();
double closePrice = 0.0;
string symbol = OrderSymbol();
// Calculate accurate close prices for multi-symbol scenarios
if(type == OP_BUY)
{
closePrice = MarketInfo(symbol, MODE_BID);
result = OrderClose(OrderTicket(), OrderLots(), closePrice, Slippage, clrRed);
}
else if(type == OP_SELL)
{
closePrice = MarketInfo(symbol, MODE_ASK);
result = OrderClose(OrderTicket(), OrderLots(), closePrice, Slippage, clrBlue);
}
else if (ClosePending && (type == OP_BUYLIMIT || type == OP_SELLLIMIT || type == OP_BUYSTOP || type == OP_SELLSTOP))
{
result = OrderDelete(OrderTicket(), clrOrange);
}
else
{
break; // Break loop if it's an unrecognized order type or pending is toggled off
}
// Handle broker execution errors
if(!result)
{
int err = GetLastError();
Print("Error closing order #", OrderTicket(), " on ", symbol, ". Error: ", err, ". Retrying...");
Sleep(150); // Give the server a tiny breather before hammering it again
retries++;
}
else
{
Print("Order #", OrderTicket(), " on ", symbol, " successfully closed/deleted.");
}
}
if (!result)
{
Print("CRITICAL: Failed to close order #", OrderTicket(), " after ", MaxRetries, " retries.");
}
}
}
Print("News Panic Close execution finished.");
}
//+------------------------------------------------------------------+