Tailoring this strictly for the MQL4 compiler allows us to utilize MT4’s native order management functions to actively hunt and flatten inventory. This version transforms the module from a passive visual alert into an active, autonomous execution blocker.
This script includes a robust liquidation loop that handles both open positions and pending orders, utilizing the mandatory reverse-iteration method required by MT4's order indexing system.
Tier-1 Event Risk Mitigation Module (Native MQL4)
Code: Select all
//+------------------------------------------------------------------+
//| Risk Mitigation: Event Blackout Module [Tier-1] |
//| Compiler: MQL4 Strict (MetaTrader 4) |
//+------------------------------------------------------------------+
#property strict
// =====================================================================
// OPERATIONAL PARAMETERS
// =====================================================================
input string _grp1 = "--- Event Time (Broker Server Time) ---";
input int NewsHour_ServerTime = 15; // Release Hour (Match Market Watch)
input int NewsMinute = 30; // Release Minute
input string _grp2 = "--- Operational Window ---";
input int PreMins = 30; // T-Minus Moratorium (mins)
input int PostMins = 15; // Post-Release Stand-Aside (mins)
input string _grp3 = "--- Execution Risk Controls ---";
input bool FlattenOnTrigger = true; // Auto-flatten open & pending orders
input int SlippagePoints = 30; // Maximum slippage tolerance (points)
input int MagicNumberFilter = 0; // 0 = Flatten all on this symbol, >0 = specific EA
// Internal state flag to prevent server spam during the blackout
bool hasFlattenedThisCycle = false;
// =====================================================================
// CORE TEMPORAL LOGIC
// =====================================================================
bool IsBlackoutActive() {
datetime currentServerTime = TimeCurrent();
// Convert current time to absolute minutes of the current day for boundary math
int currentMinsOfDay = TimeHour(currentServerTime) * 60 + TimeMinute(currentServerTime);
int newsMinsOfDay = NewsHour_ServerTime * 60 + NewsMinute;
int blackoutStart = newsMinsOfDay - PreMins;
int blackoutEnd = newsMinsOfDay + PostMins;
if(currentMinsOfDay >= blackoutStart && currentMinsOfDay <= blackoutEnd) {
return true;
}
// Reset the flatten flag once we are completely clear of the blackout window
if(currentMinsOfDay > blackoutEnd) {
hasFlattenedThisCycle = false;
}
return false;
}
// =====================================================================
// HARD-FLATTEN PROTOCOL
// =====================================================================
void FlattenInventory() {
if(!FlattenOnTrigger || hasFlattenedThisCycle) return;
int totalOrders = OrdersTotal();
if(totalOrders == 0) {
hasFlattenedThisCycle = true;
return;
}
// MANDATORY MT4 LOGIC: Always iterate backwards when deleting/closing orders.
// Index shifting will cause missed closes if iterating forwards.
for(int i = totalOrders - 1; i >= 0; i--) {
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
// Filter for current chart symbol and magic number (if specified)
if(OrderSymbol() == Symbol() && (MagicNumberFilter == 0 || OrderMagicNumber() == MagicNumberFilter)) {
int type = OrderType();
bool result = false;
RefreshRates();
// Liquidate active market exposure
if(type == OP_BUY) {
result = OrderClose(OrderTicket(), OrderLots(), Bid, SlippagePoints, clrRed);
}
else if(type == OP_SELL) {
result = OrderClose(OrderTicket(), OrderLots(), Ask, SlippagePoints, clrRed);
}
// Purge pending limit/stop orders (critical for prop firm rules)
else if(type > OP_SELL) {
result = OrderDelete(OrderTicket(), clrOrange);
}
if(!result) {
Print("Risk Protocol Error: Failed to close ticket #", OrderTicket(), ". Error code: ", GetLastError());
}
}
}
}
// If we successfully cleared inventory, flag it so we don't spam the broker server
if(OrdersTotal() == 0 || MagicNumberFilter > 0) {
hasFlattenedThisCycle = true;
Print("Risk Protocol: Inventory successfully flattened at T-", PreMins);
}
}
// =====================================================================
// VISUAL TELEMETRY
// =====================================================================
void UpdateStatusHUD(bool isRestricted) {
string objName = "Blackout_HUD_MT4";
if(ObjectFind(0, objName) < 0) {
ObjectCreate(0, objName, OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_RIGHT_UPPER);
ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, 15);
ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, 20);
ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, 11);
ObjectSetString(0, objName, OBJPROP_FONT, "Trebuchet MS");
ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false);
}
if(isRestricted) {
ObjectSetString(0, objName, OBJPROP_TEXT, " MODULE ACTIVE: TIER-1 BLACKOUT ");
ObjectSetInteger(0, objName, OBJPROP_COLOR, clrWhite);
// Fallback for background color simulation in standard labels
ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, clrMaroon);
} else {
ObjectSetString(0, objName, OBJPROP_TEXT, " SYSTEM ARMED: CLEAR ");
ObjectSetInteger(0, objName, OBJPROP_COLOR, clrLimeGreen);
ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, clrBlack);
}
}
// =====================================================================
// EA TICK PROCESSOR
// =====================================================================
void OnTick() {
bool blackoutState = IsBlackoutActive();
UpdateStatusHUD(blackoutState);
// 1. GATEKEEPER TRIGGER
if(blackoutState) {
// Execute flatten protocol on the first tick of the T-30 window
FlattenInventory();
// Hard override: Return immediately. No EA entry logic can process below this line.
return;
}
// 2. STANDARD EXECUTION LOGIC GOES BELOW
// e.g., if(RSI < 30) OrderSend(...);
}