There is no warning shot before a daily loss limit. It is not a margin call — nothing gets liquidated at eighty percent of it, nobody emails you at ninety. You cross the line by one dollar, on one tick, and the evaluation is over. Often the position that did it is still open when the notification arrives.

That is a strange thing to leave manual. Your expert advisor already owns entry logic, exit logic, session filters, spread filters — and then the one rule that can end the account in a second is enforced by you, watching a number in the terminal while the robot works.

This page closes that gap. Not the rule itself (you know what a daily line is) but the control flow: what the EA measures, when it decides a new day started, at what level it pulls the plug, and how it sizes every trade so the plug rarely has to be pulled. Every number below is worked on a hypothetical $100,000 account against a 5% daily line, because the arithmetic is the lesson — your own limit, buffer and reset hour belong in EA inputs, read from your firm's rulebook, never hardcoded from an article.

Key Takeaways
  • The daily line is a floor built from two values — a reference captured at the reset and a measured value compared against it — and an EA that fills either slot wrong enforces the wrong number perfectly.
  • The reset moment belongs to the firm's clock, not your terminal's, and the day reference plus the trip latch must survive a restart; an EA that re-snapshots after a bad morning hands itself a second full budget.
  • Sizing and the kill-switch only work as a pair: risk each trade against the equity left above your trip level minus what open stops still commit, and let the switch cover what a stop cannot — a gap, a slip, a fill that never held.
  • The buffer between your trip level and the firm's floor is a budget for closing costs, so measure it from forced trips on demo rather than copying a percentage.
Table of Contents (26 min read)Contents

What the 5% Daily Line Actually Measures

A daily limit is a floor, and a floor is two things: a reference value captured at the day's reset, and a measured value compared against it on every evaluation. Get either wrong and every mechanism downstream is watching the wrong number with perfect discipline.

The floor itself is trivial arithmetic — reference minus the limit percentage. What varies between firms is which quantity fills each slot. Four shapes cover almost everything you will meet, and a serious guard implements all of them as a mode switch rather than betting on one:

Rule shapes an EA must handle
Rule shapeWhat the EA snapshots at resetWhat it compares each evaluationWhat breaks if you guess wrong
Static balance floor Account balance at the reset moment Closed-trade balance only Guarding on equity halts days the firm would have allowed
Static equity floor Account equity at the reset moment Live equity, floating positions included Guarding on balance misses the breach entirely — the firm counts a float you ignore
Intraday-trailing equity floor Equity at reset, then the running intraday peak Live equity against peak minus the limit A static floor lets a profitable morning handed back become a breach you never modelled
Rolling 24-hour window A reference that moves with the window, not a fixed hour Live equity against the value the window has aged out Day-boundary logic never fires, so the EA believes it has a fresh budget it does not have
The floor is always reference minus limit — the disagreement between firms is entirely about which two numbers fill those slots.

The reader-facing consequence is small; the code consequence is not. A balance-based guard is a one-line read of a value that only changes when a trade closes. An equity-based guard has to run continuously, because the number it watches moves on every tick whether or not your EA did anything.

Balance-Based vs Equity-Based Daily Drawdown

This is the single most expensive detail in the whole system, so it is worth seeing rather than reading. Balance and equity are the same number only when you are flat. The moment a position is open, equity carries the floating profit or loss and balance does not.

Same day, two rulebooks
Identical trades on an illustrative $100,000 account. Measured on equity, the account is already gone at 13:30. Measured on balance, the same day closes down 3.3% and survives.

One position, held through a drawdown and recovered before the close, is the whole story. If your firm measures equity, that trade ended the account hours before it became profitable again. If your firm measures balance, the intraday excursion was invisible and only the closing result counted.

Two rules follow for the build. First, if the rulebook is ambiguous, implement the equity model — it is the stricter of the two, so a guard built on it never under-protects, it only occasionally halts a day the firm would have forgiven. Second, whichever model you implement, keep the other value logged. When your numbers and the firm's dashboard disagree by exactly a floating loss, you will know within a minute instead of a weekend.

Static Floor vs Intraday-Trailing Floor

A static floor is set once at reset and does not move for the rest of the day. A trailing floor rises with your intraday high-water mark: make $2,000 in the morning and the line follows you up, so the same $5,000 loss that was survivable at the open now breaches while you are still green on the day.

For the EA this means one extra piece of state and one rule about it. Track the highest equity seen since the reset, recompute the floor from that peak whenever it makes a new high, and never let the floor move down. A guard that recomputes the floor from current equity instead of the peak silently converts a trailing rule back into a static one — the most polite bug in this entire article, because it does nothing wrong until the day you are up and give it back.

When Does the Trading Day Actually Reset?

Two frosted glass clock faces side by side on a pale surface, their hands set an hour apart.
The firm's day and your terminal's day are two different clocks — the EA has to run on the firm's.

The reset moment is not midnight anywhere in particular. It is a wall-clock hour in a timezone the firm chose, and your terminal's idea of "today" is almost certainly a different one. Three patterns cover the field: a broker/server midnight, a fixed hour in a stated timezone, and a rolling window with no reset at all.

The code consequence is that TimeLocal() is never the right answer, and TimeCurrent() — the server's time, derived from the last quote — is only right if your firm reset is server midnight and your broker's server sits in the firm's timezone. Anything else needs the boundary derived from GMT plus a configured offset. Getting this wrong is not a rounding error: an hour of clock drift between your day and the firm's day means one hour of trades is billed to the wrong budget, in both directions.

Then there is what happens at the boundary:

  • The snapshot must be taken at the boundary, not at EA initialisation. An EA that snapshots on OnInit() and then restarts after three losing trades will re-snapshot from the depressed equity and hand itself a brand-new full-size budget on a day it has already half-spent. This is the single most dangerous bug in the whole system, and it only ever shows up in production, because in the tester nothing restarts.
  • The reference has to survive a restart, a recompile and a terminal crash. Terminal global variables (or a small file) keyed by the day identifier do this; anything in memory does not. Global variables are also purged after a long idle period, which is fine — the key tells you whether the value you found belongs to today.
  • Rollover interest posts at the boundary too. A swap credit or debit lands on the balance without any trade happening. Snapshot before it posts and the first minutes of the new day already show a phantom loss you never traded.
  • Positions carried through the reset are a policy question, not a code question. Read whether yesterday's open float is counted against today. If it is, and you snapshot equity while a position floats at -$2,000, today's entire budget is measured from an already-depressed number.
Reset handling
mql5 day_reference.mqh
input int    InpResetHour   = 0;    // the firm's reset hour, in ITS timezone
input int    InpFirmGmtOffs = 2;    // that timezone's offset from GMT, in hours
input string InpGvPrefix    = "DDG_";

datetime g_dayId    = 0;   // identifier of the current *firm* day
double   g_refValue = 0;   // the value today's floor is computed from
double   g_dayPeak  = 0;   // intraday high-water, for a trailing floor

datetime FirmDayId()
{
   // shift GMT into the firm's clock, then floor it to that clock's midnight
   datetime shifted = TimeGMT() + (InpFirmGmtOffs - InpResetHour) * 3600;
   MqlDateTime t;
   TimeToStruct(shifted, t);
   t.hour = 0; t.min = 0; t.sec = 0;
   return StructToTime(t);
}

void SyncDayReference()
{
   datetime id = FirmDayId();
   if(id == g_dayId)
      return;                                  // same firm day: leave everything alone

   string key = InpGvPrefix + (string)id;
   if(GlobalVariableCheck(key))
      g_refValue = GlobalVariableGet(key);     // restart inside a day: RECOVER
   else
   {
      g_refValue = AccountInfoDouble(ACCOUNT_EQUITY);
      GlobalVariableSet(key, g_refValue);      // genuinely a new day: snapshot
   }

   g_dayId   = id;
   g_dayPeak = MathMax(g_refValue, AccountInfoDouble(ACCOUNT_EQUITY));
}
The entire reset problem in one function: derive the day from GMT and a configured offset, recover an existing snapshot, and only take a new one when the day genuinely changed.

Note what that function does not do: it never re-reads the reference within a day, and it never trusts memory. Those two properties are what make it safe to restart the terminal at 14:00 on a bad day.

Building the Equity Kill-Switch

A glass toggle switch caught mid-throw on a pale surface, glowing green, a short distance from a thin engraved line.
The guard's job is to act on the tick before the breach, not to report it afterwards.

Everything so far was measurement. The kill switch is the part that acts — and the reason it exists is that a floor you merely observe is a rule you are still enforcing by hand.

It is a guard routine with three states: armed (normal trading), tripped (flattening in progress), and latched (no entries until the next reset). Latching matters more than it sounds. A guard that recomputes its state from scratch on every tick will happily un-trip itself the moment a favourable tick lifts equity back above the trip level — and re-enter, into the exact market that just cost you the day. The latch is a cooldown that only the reset clears.

Guard control flow
flowchart TD
  A["Tick or 1-second timer"] --> B{"New firm day?"}
  B -- Yes --> C["Snapshot the reference, clear the daily latch"]
  B -- No --> D["Load the stored reference"]
  C --> E["Floor = reference minus the daily limit"]
  D --> E
  E --> F["If the rule trails, raise the floor to any new equity peak"]
  F --> G{"Equity at or below floor plus buffer?"}
  G -- No --> H["✅ Trading allowed"]
  G -- Yes --> I["❌ Block entries, cancel pendings, close all positions"]
  I --> J{"Account flat?"}
  J -- No --> I
  J -- Yes --> K["Latch until the next reset"]
    
The guard runs the same path on every evaluation. The retry loop on 'account flat?' is not decoration — a first pass at closing often does not finish.

Four implementation details decide whether this works in production:

  1. Set the no-entry flag before you do anything slow. Cancelling and closing takes time; a signal can fire in the middle of it. The flag costs nothing and closes that window.
  2. Cancel pending orders before closing positions. A resting stop order that fills while you are busy flattening re-opens exposure behind your back — and the guard will not see it until its next pass.
  3. Assume closing fails. A trade context busy state, a requote, a partial fill, or a symbol with trading disabled will all leave you not-flat after one pass. Re-check on every subsequent tick and timer until the account is genuinely empty, rather than assuming the first loop worked.
  4. Guard the account, not your EA. The firm measures the account. If manual trades or a second robot share it, filtering by magic number protects your EA's positions but not your evaluation. Read account equity, close everything, or run one guard that owns the account and let the strategy EAs ask it for permission.

Do not rely on OnTick() alone, either. Ticks arrive per symbol, and a symbol that stops quoting — a holiday, a feed hiccup, a session close — stops calling your guard exactly when you would most like it awake. A one-second OnTimer() running the same routine costs nothing and removes the dependency.

The switch itself
mql5 guard.mqh
input double InpDailyLimitPct = 5.0;   // the firm's published daily limit
input double InpBufferPct     = 0.5;   // your margin below it
input bool   InpTrailingFloor = false; // true if the firm's floor trails the peak

bool g_tripped = false;

void GuardEvaluate()
{
   SyncDayReference();

   double eq = AccountInfoDouble(ACCOUNT_EQUITY);
   if(eq > g_dayPeak) g_dayPeak = eq;

   double base = InpTrailingFloor ? g_dayPeak : g_refValue;
   double trip = base * (1.0 - (InpDailyLimitPct - InpBufferPct) / 100.0);

   if(!g_tripped && eq <= trip)
   {
      g_tripped = true;                       // block entries FIRST
      GlobalVariableSet(InpGvPrefix + "TRIP_" + (string)g_dayId, 1);
      PrintFormat("Guard tripped: equity %.2f <= trip %.2f", eq, trip);
   }

   if(g_tripped)
      FlattenAccount();                        // retried every pass until flat
}

void FlattenAccount()
{
   CTrade trade;
   for(int i = OrdersTotal() - 1; i >= 0; i--)      // pendings first
      trade.OrderDelete(OrderGetTicket(i));
   for(int i = PositionsTotal() - 1; i >= 0; i--)   // then live exposure
      trade.PositionClose(PositionGetTicket(i));
}
The trip is one comparison; everything around it exists so the trip cannot be undone by a restart, a lucky tick, or a close that did not go through.

Two things to notice. The trip level is derived from the limit minus your buffer, so the switch fires above the firm's floor rather than at it — the next section prices that gap. And the latch is persisted alongside the day reference, so a terminal restart at 15:00 finds a tripped day and stays out.

Sizing Each Trade Against What's Left of Today's Budget

A kill-switch on its own is a seatbelt, not a brake. It stops you after the loss that took you to the line. If your risk per trade is a flat percentage, the trade that trips the switch was sized as though the day had not already happened — and the switch then fires with the damage done.

The fix is to size against what is left rather than against the account. Three quantities define it: current equity, the trip level, and the loss your open positions still have in front of them.

The sizing rule
Free daily budget — the ceiling on the next trade
F = ET − ∑Ropen
E = current account equity · T = the EA's trip level, i.e. the firm's floor plus your buffer · Ropen = for each open position, the equity still to be lost if its stop is hit from here, not from entry. Worked: equity 97,380, trip level 95,500, one open position sitting 461 above its stop → F = 1,419.
Committed risk is measured from current equity, not from entry — a position already down has that loss inside equity, and counting it twice starves the rest of the day.

That last clause is the detail almost every implementation gets wrong. If a position entered risking $861 is now floating at -$400, the equity you can still lose on it is $461, because the other $400 is already inside the equity you just measured. Subtracting the original $861 double-counts and shrinks the budget for no reason.

From the free budget, the next trade's risk is a fraction of it — call it the allocation factor. Something in the region of a third leaves room for several more setups and for the cost of getting flat; a factor of one means the very next trade is allowed to spend the entire remaining day. Take the smaller of that allowance and your normal position sizing rule, so the budget only ever tightens sizing, never loosens it.

Converting risk into lots is ordinary arithmetic — risk divided by (stop distance × value per point) — with two prop-specific guards:

  • Never round up to the minimum lot. When the allowed risk lands below what one minimum-lot position would risk at your stop distance, the correct behaviour is to decline the setup. Rounding up is how a disciplined budget quietly becomes a 2% trade on the day you could least afford it.
  • Cap at the firm's per-position lot ceiling where one exists, before the budget rule even runs.

All of this assumes every position carries a real stop loss on the server. A mental stop makes committed risk unknowable, and an unknowable committed risk collapses the formula to guesswork. This article uses the remaining-budget rule purely as a drawdown-control mechanism; the broader question of position sizing that keeps drawdown under control across an entire funded account — stop placement, reward-to-risk targets, correlation — is a bigger subject than the daily line.

Watching Two Limits at Once — Daily and Maximum Drawdown

An EA tuned to survive the daily line alone can still lose the account by walking down the stairs: four days at -4.5% breach nothing daily and everything overall. The maximum drawdown limit is a second, independent floor, and it needs its own state, its own persistence and its own latch.

Structurally it is the same guard with different inputs. The account floor is computed either from the initial balance (static) or from the account's all-time high-water mark (trailing), and the high-water mark persists across days, restarts and phases — it never decreases. The EA then guards against whichever floor is closer:

  • Early in an evaluation, the daily floor is almost always nearer, so it binds.
  • After a strong run under a trailing max-drawdown rule, the account floor climbs behind you and can sit above the daily floor. From that point the daily limit is decorative and the account floor is the real constraint.

Compute both, take the higher of the two as the effective floor, and apply the buffer to that. One comparison, two rules honoured.

The latches differ, though, and this is worth being explicit about. A daily trip is routine — it clears at the reset and you trade tomorrow. A maximum-drawdown trip is terminal: it must not clear at the reset, and the right behaviour is to stop the EA entirely and raise an alert a human will see, because there is nothing left to protect. Coding both as the same latch is a bug that hides for months and then costs the account exactly once.

Two other rules pull in the opposite direction and are deliberately out of scope here: the profit target, and the consistency rule alongside the daily loss limit, which constrains how much of your total profit a single day may contribute. They interact — a guard that halts every day at -4.5% will also flatten your daily profit distribution — but they are separate mechanisms.

How Much Safety Buffer Is Enough?

The buffer is not a comfort number. It is a budget for the equity you lose between the decision to stop and the moment you are flat, and it has four measurable components:

  1. The cost of closing. Spread and commission on every open position, paid in one burst at market.
  2. Slippage on the exit. Worst exactly when the guard fires, because the conditions that trip a guard — news, thin liquidity, a fast move — are the conditions that widen exits.
  3. The move you cannot see. Equity travels between evaluations. A guard on a one-second timer has a small blind spot; a guard that only wakes on the ticks of one symbol has a large one.
  4. Measurement mismatch. Your equity and the firm's dashboard will not agree to the cent — swap posting, commission accounting and their own snapshot cadence all introduce small gaps.

Notice what those four have in common: every one of them scales with your open exposure, not with your account size. A fixed half-percent buffer is a reasonable default for an EA that holds one modest position at a time. For an EA that can hold several full-size positions in correlated symbols, the honest buffer is the worst-case cost of closing all of them at once, and it is bigger.

Which suggests the method: measure it rather than copy it. On a demo account on the same server, set the buffer absurdly wide so the guard trips constantly, and log the difference between equity at the trip and equity once flat. The worst value across a few dozen trips, plus margin, is a buffer you own.

One exposure the buffer cannot cover: a weekend or news price gap straight through your stop while no code is running. No guard evaluates during a market closure. The only real controls there are not holding positions across the gap, or sizing so a plausible gap cannot reach the floor.

And be honest with yourself about the trade-off. A wider buffer means more days that end early and flat, which costs you trading opportunity on days that would have recovered. A narrower buffer keeps you trading and shrinks the margin the exit costs have to fit inside. There is no setting that gives you both.

A Worked Example: One Funded Account, One Trading Day

Numbers make the machinery obvious. Take a hypothetical $100,000 account, a 5% daily line, a 10% static maximum drawdown, a 0.5% buffer, an allocation factor of 0.35, and a normal per-trade risk cap of 1%. These are illustrative figures for the arithmetic, not a claim about results — every trading approach carries risk, and our risk warning applies to everything below.

At the reset. No positions carried. Reference equity $100,000. Firm floor $95,000. EA trip level $95,500. Free budget: $4,500.

09:12 — Trade A. Budget allowance is 0.35 × 4,500 = $1,575; the 1% cap is $1,000, so the smaller wins and A risks $1,000. Free budget while A is open: 100,000 - 95,500 - 1,000 = $3,500.

10:05 — A stops out. Realised -$1,040 with costs and a little slippage. Equity $98,960. Free budget: $3,460.

10:40 — Trade B. Allowance 0.35 × 3,460 = $1,211, still above the 1% cap, so B risks $1,000. Free budget with B open: $2,460.

11:30 — Trade C. Allowance 0.35 × 2,460 = $861 — now below the flat cap. The budget rule binds for the first time today and C is sized to $861, not $1,000. Nothing dramatic happened; the day simply got more expensive and the sizing noticed.

13:15 — B stops out on a news candle. -$1,180 rather than the planned $1,000, because the exit slipped. Equity $97,780. C is floating at -$400, so equity reads $97,380 and C's remaining risk to its stop is $461, not $861. Free budget: 97,380 - 95,500 - 461 = $1,419.

13:40 — Trade D declined. Allowance 0.35 × 1,419 = $497. At D's stop distance, one minimum-lot position would risk about $620. The EA declines the setup rather than rounding up. This is the quiet part of the system working: the sizing rule stopped trading before the kill-switch had to.

14:26 — C gaps. A second release runs price through C's stop and the fill lands far past it: -$2,400 instead of -$861. Equity prints $95,380 on that tick — below the $95,500 trip level, still above the $95,000 firm floor.

14:26:01 — the guard fires. Entries blocked, pendings cancelled, C closed. Final flat equity $95,340.

Where the day finished
End of day, illustrative $100,000 account
  • Firm daily limit 4660 / 5000 $
    93% of limit used Survived with $340 to spare
  • EA trip level 4660 / 4500 $
    Limit reached Crossed on purpose — this is the switch firing
  • Maximum drawdown 4660 / 10000 $
    47% of limit used Account floor never came close

The day ended at -4.66%. The trip level was breached and the firm's line was not — which is exactly the arrangement the buffer buys.

Read the sequence back and notice the division of labour. The budget rule did the routine work all day, tightening size trade by trade and finally declining a setup outright. The kill-switch never had to touch a normal outcome; it fired for the one thing sizing cannot control — a stop that did not hold. That is the correct relationship between the two, and it is why neither survives alone.

The uncomfortable detail is the last one. The gap cost $1,539 more than C's stop said it would, and only the buffer absorbed it. Had the buffer been zero, the same tick would have printed $94,840 and ended the account.

Checklist Before You Go Live

Every item below is something you can verify in an afternoon on a demo account of the same server — and every one of them corresponds to a failure that is invisible in the strategy tester, because in the tester nothing restarts, no clock drifts and nothing gaps over a weekend. Treat a forward test of the guard itself, separate from the strategy, as mandatory.

Before it touches a funded account

Drawdown-guard pre-flight

0 / 11

Checklist complete — you’re cleared to proceed.

Each line is a production failure mode that a backtest cannot reproduce.

The last item deserves its own sentence. Every mechanism on this page runs inside your terminal, which means a dropped connection, a laptop lid or a Windows update is a period with no guard at all. That is the strongest practical argument for a VPS for running EAs — not latency, but the fact that a protection routine only protects while it is executing.

Get these four pieces right — the right reference value, the right reset, a latching kill-switch above the line, and sizing that spends the day's budget instead of ignoring it — and the daily limit stops being the thing that ends accounts. It becomes a constraint your EA trades inside, the same way it trades inside a session filter. Which is only the first of several rules standing between an automated system and a payout; passing a prop firm challenge with an ICT EA also means surviving the rules that govern when you trade and how evenly you profit.

FAQ

Is blocking new entries enough, or does the kill-switch have to close open positions?

It has to close them. Blocking entries only freezes the exposure you already have, and that exposure is precisely what is still moving equity toward the floor. If your firm measures on closed balance rather than equity, closing is what realises the loss — so read the rule carefully, but on any equity-measured account, flat is the only safe state after a trip.

What happens if the terminal restarts after the switch has already fired?

Nothing, if you persisted the latch. That is the whole reason the trip flag is written to a terminal global variable keyed by the day, rather than living in a variable. On restart the guard reloads today's reference, sees today's trip flag, and stays out. Without persistence, the restart looks like a fresh day to the EA — a fresh budget and a fresh willingness to enter, on an account that has already spent both.

Should the buffer be a percentage or a fixed cash amount?

Internally it is easier to reason about as cash, because the costs it covers are cash: spread, commission and slippage on closing your actual open positions. Expressing it as a percentage of the reference is fine as an input, but size it from your measured worst-case cost of getting flat, not from a number that sounded prudent. An EA that can hold several correlated positions needs a wider buffer than one that holds a single small one, on the same account.

Can the drawdown guard be a separate EA from the strategy EA?

Yes, and on a shared account it is usually better. A dedicated guard attached to one chart reads account equity, which is what the firm measures, and can close everything regardless of which robot opened it. The coordination cost is that your strategy EAs need to see the latch — a shared terminal global variable is the simplest channel, and it means the guard can veto entries without knowing anything about the strategies.

Does hedging a losing position instead of closing it help with the daily limit?

Not on an equity-measured account. A hedge freezes floating profit and loss roughly where it stands, so it stops the bleeding, but the loss already inside equity stays inside equity — the floor does not move back up. It also adds spread, doubles your exposure to a widening spread and, on some firms, is restricted outright. Closing is simpler and its cost is known.

My firm measures on balance — can the EA ignore floating loss entirely?

It can for the limit check, but it should not for sizing. Floating loss is the loss that is about to become realised, and a budget rule that ignores it will happily authorise a new trade while $3,000 of unrealised loss sits on the books. Guard on the value your firm measures; size on the value that reflects everything you actually have at risk.

Sources & Further Reading

Want to go deeper? These independent, authoritative sources shaped this guide — each one is worth reading in full:

Signalbots Funded Desk

The Funded Desk is the SignalBots editorial team covering prop-firm challenges and funded-account trading. We research and write the guides on evaluation rules, drawdown limits, payout structures and the discipline funded trading demands.

More from this desk

Discussions 0

Leave a comment