January 13, 20267 min read

How to Auto-Close All MT5 Positions When Daily Loss Threshold Is Hit (Beginner-Friendly EA Guide)

How to auto-close all MT5 positions when daily loss threshold is hit: this guide shows a safe, EA-friendly approach to calculate daily loss, trigger a kill switch, and close positions reliably.

mt5 auto close positions

On this page

Why a daily-loss kill switch matters

If you trade with rules (especially in prop firm challenges), you’ll eventually need a hard safety mechanism: when daily loss reaches a threshold, trading stops and exposure is removed. This is not about “being scared of losses.” It’s about preventing the two most common account killers:

  • A bad day turning into a catastrophic day (revenge trading, overtrading, tilt).
  • A technical failure (EA bug, news spike, platform freeze) causing uncontrolled drawdown.

In this guide you’ll learn how to auto-close all MT5 positions when daily loss threshold is hit in a way that is realistic for MetaTrader 5 and MQL5: clear definitions, reliable calculations, and practical closing logic.

Important: This is educational content, not financial advice. Always confirm the exact “daily loss” rule definition your broker/prop firm uses (balance vs equity, server day, floating P/L included or not).

Step 1: Define “daily loss” correctly (equity vs balance)

Before you write code, pick which metric you protect:

Equity-based daily loss (recommended for safety)

Equity includes floating P/L. It’s stricter and helps prevent breaches during fast moves:

  • DailyLoss = DayStartEquity - CurrentEquity

If the threshold is hit, you close all positions to stop further equity erosion.

Balance-based daily loss (common in some rule sets)

Balance counts closed trades only:

  • DailyLoss = DayStartBalance - CurrentBalance

This can be “friendlier” but less safe if you carry losing floating positions.

Most traders who want a robust kill switch choose equity-based checks, because it protects against floating losses and platform disconnects.

Step 2: Decide what “day” means (server time, rollover hour)

“Daily” usually means the broker’s server day, not your local timezone. In MT5, you can base day changes on:

  • TimeTradeServer() (preferred), or
  • TimeCurrent() (often acceptable, but can differ)

Some prop firms use a “trading day” that resets at a specific hour (e.g., 17:00 New York). If you must match that, you need a configurable rollover hour and to compute a “session date” based on server time.

Step 3: Store day-start equity reliably

You need a stable reference point: day-start equity (or balance). That value must persist even if MT5 restarts.

Practical approaches:

  • Store in a GlobalVariable (persists on the terminal).
  • Store in a file (more control, more complexity).
  • Store on a backend (best for enterprise, beyond this post).

For a beginner-friendly EA, GlobalVariable*() is a reasonable choice.

Step 4: When threshold is hit, do 3 things (in order)

  1. Trigger a kill switch flag (so the EA stops opening new trades).
  2. Close all open positions (reduce exposure).
  3. Optionally: Delete pending orders (stop new entries from triggering).

This “risk firewall” approach is a standard pattern in risk management automation and is compatible with most strategies.

LSI keywords that naturally apply here: daily loss limit, max daily drawdown, equity protection, trading kill switch, risk control EA, MT5 Expert Advisor, MQL5 close all positions, prop firm compliance.

A practical MQL5 example: daily loss kill switch + close-all routine

The snippet below focuses on the core mechanics: day start equity tracking, daily loss calculation, and a close-all routine using CTrade.

EA inputs (configure once)

input bool   UseEquityForDailyLoss = true;
input double DailyLossLimitMoney   = 250.0;  // example: $250 daily loss limit
input int    RolloverHourServer    = 0;      // 0 = midnight server time; change if needed
input bool   ClosePositionsOnHit   = true;
input bool   DeletePendingsOnHit   = true;

Utility: compute “session date” based on rollover hour

datetime SessionStart(datetime serverTime, int rolloverHour)
{
   MqlDateTime t; TimeToStruct(serverTime, t);
   if(t.hour < rolloverHour)
      t.day -= 1;
   t.hour = rolloverHour; t.min = 0; t.sec = 0;
   return StructToTime(t);
}

Store and load day-start reference (Global Variables)

string GVKey(const string suffix)
{
   return StringFormat("PRM_%s_%s_%d", _Symbol, suffix, (int)AccountInfoInteger(ACCOUNT_LOGIN));
}

double LoadOrInitDayStartValue(const string key, double currentValue)
{
   if(GlobalVariableCheck(key))
      return GlobalVariableGet(key);
   GlobalVariableSet(key, currentValue);
   return currentValue;
}

Close all positions (netting + hedging-safe loop)

#include <Trade/Trade.mqh>
CTrade trade;

bool CloseAllPositions()
{
   bool allClosed = true;

   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
      if(!PositionSelectByIndex(i))
         continue;

      const string symbol = PositionGetString(POSITION_SYMBOL);
      const ulong  ticket = (ulong)PositionGetInteger(POSITION_TICKET);

      if(!trade.PositionClose(ticket))
         allClosed = false;
   }

   return allClosed;
}

Delete all pending orders (optional)

bool DeleteAllPendingOrders()
{
   bool allDeleted = true;

   for(int i = OrdersTotal() - 1; i >= 0; i--)
   {
      if(!OrderSelect(i, SELECT_BY_POS))
         continue;

      const ulong ticket = (ulong)OrderGetInteger(ORDER_TICKET);
      if(!trade.OrderDelete(ticket))
         allDeleted = false;
   }

   return allDeleted;
}

Main check: detect new day, calculate daily loss, trigger kill switch

bool KillSwitch = false;
datetime LastSession = 0;
double DayStartValue = 0.0;

void CheckDailyLossKillSwitch()
{
   const datetime now = TimeTradeServer();
   const datetime session = SessionStart(now, RolloverHourServer);

   const bool newSession = (session != LastSession);
   if(newSession)
   {
      LastSession = session;
      KillSwitch = false;

      const double current = UseEquityForDailyLoss
         ? AccountInfoDouble(ACCOUNT_EQUITY)
         : AccountInfoDouble(ACCOUNT_BALANCE);

      DayStartValue = current;
      GlobalVariableSet(GVKey("DAY_START"), DayStartValue);
      GlobalVariableSet(GVKey("SESSION"), (double)LastSession);
      return;
   }

   if(LastSession == 0)
   {
      LastSession = (datetime)GlobalVariableGet(GVKey("SESSION"));
      if(LastSession == 0) LastSession = session;
      DayStartValue = LoadOrInitDayStartValue(GVKey("DAY_START"),
         UseEquityForDailyLoss ? AccountInfoDouble(ACCOUNT_EQUITY) : AccountInfoDouble(ACCOUNT_BALANCE));
   }

   const double current = UseEquityForDailyLoss
      ? AccountInfoDouble(ACCOUNT_EQUITY)
      : AccountInfoDouble(ACCOUNT_BALANCE);

   const double dailyLoss = DayStartValue - current;

   if(!KillSwitch && dailyLoss >= DailyLossLimitMoney)
   {
      KillSwitch = true;

      if(DeletePendingsOnHit)
         DeleteAllPendingOrders();

      if(ClosePositionsOnHit)
         CloseAllPositions();
   }
}

Practical tip: call CheckDailyLossKillSwitch() from OnTick() (simple) or from OnTimer() (more consistent even when the market is quiet). If you use OnTimer(), remember to call EventSetTimer(1) in OnInit() and EventKillTimer() in OnDeinit().

Common failure modes (and how to make it more reliable)

Closing can fail in fast markets

PositionClose() can fail due to:

  • Requotes / off quotes
  • Market closed
  • Volume limits
  • Trade context busy

For robustness, consider:

  • Retrying close attempts (limited retries, with small delays).
  • Logging errors (GetLastError() / trade.ResultRetcode()).
  • Closing symbol-by-symbol (and prioritizing the biggest losing positions first).

Don’t rely only on virtual logic if the terminal can be offline

If your kill switch relies on an EA being online, you should run it on a stable VPS and add monitoring. Many traders also keep a protective server-side stop-loss per position as a “last resort” (strategy-dependent).

Example: choosing the daily loss number

Suppose you have a $10,000 account and you want a strict daily loss cap of 2%:

  • DailyLossLimitMoney = $200

If day-start equity is $10,000 and current equity drops to $9,800:

  • DailyLoss = $10,000 - $9,800 = $200 → kill switch triggers, positions close, trading stops.

This makes your risk measurable and prevents emotional escalation on bad days.

Call to action

If you want daily loss limits, max drawdown rules, trade blocking, and compliance-style risk controls without reinventing everything inside each EA, check out Pro Risk Manager. It’s built to help MT5 traders apply consistent risk rules—so one bad day doesn’t define your month.

FAQ

Should I base daily loss on balance or equity?

Equity-based checks are safer because they include floating losses. If your rule set counts only closed P/L, you can still use equity for protection to avoid accidental breaches.

Will “close all positions” always close instantly at my price?

No. In fast markets you may get slippage or partial fills. That’s exactly why the daily-loss logic should be conservative and why you should test on demo in volatile conditions.

How do I stop the EA from opening new trades after the kill switch triggers?

Gate your entry logic behind a single condition:

  • If KillSwitch == true, do not place new orders (and optionally display an on-chart warning).

Do I also need to delete pending orders?

Usually yes. Pending orders can trigger new exposure even after you closed current positions, especially if price whipsaws.

What about prop firm rules with a specific “trading day” reset time?

Use a configurable RolloverHourServer and compute the session start using broker server time. Verify the broker’s server timezone and your prop firm’s rule definition before going live.

Related posts

Browse all