Most MT5 “daily loss guard” implementations look like this:
double today_pnl = 0.0; // module-level variable
bool daily_blocked = false;
Enter fullscreen mode Exit fullscreen mode
It works fine — until the terminal restarts, the EA is recompiled, the chart is switched, or the config is reloaded. Every one of those calls OnInit() again and zeroes the variable. Your hard daily cap cheerfully hands you back the full day’s risk budget.
If you trade a prop-firm account (5% daily drawdown rule), this is not a small bug: crashes and restarts cluster on bad trading days, exactly when you need that guard most.
What “persistence” actually has to survive
Event Memory var Terminal globals File (common folder) New tick / new bar yes yes yes EA recompile / re-attach no yes yes Terminal restart no yes yes Reinstall / another machine / several terminals no no yesGlobalVariableSet() covers the common cases. The file wins the last row.
The three fields you must persist
struct GuardState
{
long day_stamp; // which trading day this state belongs to
double day_start_balance; // anchor for the daily drawdown
bool blocked; // has the day already tripped
};
Enter fullscreen mode Exit fullscreen mode
day_stamp is the field people forget. Without it the restored state is either ignored forever or applied forever. Both are wrong.
Pitfall 1: the trading day must come from the broker clock
long TradingDayStamp()
{
MqlDateTime t;
TimeToStruct(TimeTradeServer(), t); // NOT TimeLocal()
return((long)t.year * 10000 + t.mon * 100 + t.day);
}
Enter fullscreen mode Exit fullscreen mode
TimeLocal() resets your cap in the middle of the session. TimeCurrent() is the last quote time and lags badly in quiet markets.
Pitfall 2: persist first, then act
if(blocked) return; // cheap, and catches externally triggered blocks
if(!risk_ok) { blocked = true; SaveState(); return; }
SendOrder();
Enter fullscreen mode Exit fullscreen mode
Wrong order + one crash between the two lines = one order that should never have been sent.
Pitfall 3: one EA cannot police another EA
MQL5 has no cross-program order hook. Your “guard EA” cannot stop an order another EA (or a Python strategy on the same account) is about to send. Three options: close positions when the cap trips, publish a terminal global your own strategies respect, or move risk control outside the terminal.
The only test worth running
- Set a cap that trips within minutes.
- Let it trip.
- Kill the terminal process (not just the EA) with positions open.
- Reopen it and try to send another order.
If the new process happily sends the order, your state was in memory and the guard was decoration.
Conclusion
Three lines of discipline: state on disk, broker trading day, write before send. That is the difference between a risk limit and a wish.
I packaged this as a free, open MT5 tool (pure MQL5, no DLL, no network calls, percentages only):
https://xuks124.github.io/vigildesk/free.html
No profit promises — it only handles risk control.

