PINE SCRIPT · PROP FIRM DAILY LOSS LIMIT

A daily loss limit in Pine Script that holds like a prop firm's

A limit checked in an if acts a candle late. On two years of MNQ with a $1,000 limit, 61 days still ended more than $50 past it, 101 on closed trades. Placed in the trade's stop, as the code below does, it held on every day but one: a hole in the data.

Run this script free

Opens on MNQ 5-minute with the backtest done. Free account, no card.

Days that ended more than $50 past a $1,000 limitMNQ1! · 5-minute · 514 days traded
No limitworst day −$2,018101
Closed trades onlyworst day −$1,497101
Pine's built-inworst day −$1,48997
Open trade, checked each candleworst day −$1,43061
In the stop: the code belowworst day −$1,1981

The same strategy every time, $500 a trade and up to three trades a day, costs charged; only the limit's code changes. The one day in the last row is 6 March 2026: the minute data has no prices from 10:01 to 10:56 New York, and the stop filled at the first price after it, as a stop does on a gap.

How the code keeps the limit

Three parts, each a few lines.

  1. 1

    The day's own books

    The day's P&L is strategy.equity minus the equity when the day began, the open trade included. The day starts at CME's 18:00 New York reopen, on session.isfirstbar.

  2. 2

    The limit as a price

    Before each entry: what the day may still lose, divided by the contracts and the dollars a point, from the entry. That price goes in the trade's stop when it is nearer than the strategy's own, so the trade closes where the day reaches the limit.

  3. 3

    A backstop, then no more entries

    Each candle's worst point is checked for a gap past the stop. Once the day reaches the limit the trade closes and no entry is taken until the next session.

The code

Tested on CME's MNQ data and passed by TradingView's compiler. Change the limit to your plan's, and put your entries where the example's are.

A $1,000 daily loss limit on an MNQ pullback strategy, two years of MNQ

The limit keeps the day's own books from the 18:00 New York reopen, the open trade included. Before each trade it works out what the day may still lose and the price where this trade, at this size, would lose it, and puts that price in the trade's stop when it is nearer than the strategy's own. A check of each candle's worst point stays as the backstop. The entries are an example, the pullback to the 9 EMA from our prop firm page at $500 a trade and up to three trades a day; your own go in their place.

Trades
1,397
Won
33.6%
Profit factor
0.99
Net
−6.2%
Worst drawdown
−36.4%
Worst trade
−$1,198, a hole in the data

MNQ1! · 5-minute · 23 Oct 2024 → 22 Oct 2026 · 2 years · 517 sessions · $0.75 a contract each side (about a micro's all-in rate), one tick of slippage, $50,000 account, $500 risk a trade, up to three trades a day, flat by 15:55 New York

The example entries lost 6.2% over two years; they are there to show the limit, not to make money. The limit ended trading early on 146 of the 514 days the strategy traded, and on every one but one the day ended no more than $27 past −$1,000: the commission and a tick of slippage. The one is 6 March 2026: the minute data has no prices from 10:01 to 10:56 New York, and the stop filled at the first price after the hole, $1,198 down, as a stop does on a gap.

  1. The limit is an input in dollars.
  2. The books: the day's P&L is the strategy's equity minus its equity when the day began, the open trade included, so a trade counts while it moves, not only once it has closed.
  3. The day is CME's, from the 18:00 New York reopen, marked by session.isfirstbar; a calendar day would count the evening's trades against the day before.
  4. Before each entry: what the day may still lose, and the price where this trade at this size would lose it. That price goes in the trade's stop when it is nearer than the strategy's own, so the limit acts at its price, as a firm's does, not when a candle closes.
  5. The backstop for a gap: each candle's worst point is checked, and once the day reaches the limit the trade closes and no entry is taken until the next session.
  6. The tally is in the Data Window and a table on the chart: the days the limit ended trading.
Pine Script v6 · 90 linesRun this script
//@version=6
// Suggested timeframe: 5-minute
strategy("MNQ pullback with a prop firm daily loss limit", overlay=true, initial_capital=50000, default_qty_type=strategy.fixed, default_qty_value=1,
     commission_type=strategy.commission.cash_per_contract, commission_value=0.75, slippage=1, margin_long=0, margin_short=0)

// ── The daily loss limit ──────────────────────────────────────────────────────────────────────────
// An example number, not any firm's: take yours from your plan's own page.
dlLimit = input.float(1000, "Daily loss limit ($)", minval=1, group="Daily loss limit")

// The day's books: dollars since the day began, the open trade included
var float dlStart = strategy.initial_capital  // the strategy's equity when the day began
var bool  dlHit   = false                     // the limit was reached: no more trades today
var int   dlDays  = 0                         // days the limit ended

// A CME day starts at the 18:00 New York reopen, not at midnight
if session.isfirstbar
    dlStart := strategy.equity
    dlHit   := false

dlPnl  = strategy.equity - dlStart
// what the day may still lose
dlRoom = dlLimit + dlPnl

// The limit as a price: where a trade of this size takes the day to the limit. Put it in the
// trade's stop when it is nearer than your own, so the limit acts at its price, as a firm's does.
// A check in an if only runs when a bar closes, after the bar has moved.
dlStopLong(entry, qty) =>
    entry - dlRoom / (qty * syminfo.pointvalue)
dlStopShort(entry, qty) =>
    entry + dlRoom / (qty * syminfo.pointvalue)

// The backstop, for a gap past the stop: the open trade's worst point in this bar
dlPos   = strategy.position_size
dlWorst = dlPnl - (dlPos > 0 ? (close - low) * dlPos : dlPos < 0 ? (high - close) * -dlPos : 0.0) * syminfo.pointvalue
if not dlHit and dlWorst <= -dlLimit
    strategy.close_all(comment="Daily loss limit", immediately=true)
    dlHit  := true
    dlDays += 1

// ── The example strategy: a pullback to the 9 EMA with the trend, as on our prop firm page ─────────
// Your own entries go here, behind `dlRoom > 0 and not dlHit`, with the limit's stop in the exit.
riskUsd = input.float(500, "Risk per trade ($)", minval=10, group="Strategy")
atrMult = input.float(1.5, "Stop (ATR)", minval=0.5, step=0.25, group="Strategy")
rMult   = input.float(2.0, "Target (R)", minval=0.5, step=0.5, group="Strategy")
maxDay  = input.int(3, "Trades per day", minval=1, group="Strategy")
maxQty  = input.int(5, "Most contracts", minval=1, group="Strategy")

nyH = hour(time, "America/New_York")
nyM = minute(time, "America/New_York")
inWindow = (nyH == 9 and nyM >= 45) or (nyH >= 10 and nyH < 15) or (nyH == 15 and nyM < 30)
cutoff   = nyH == 15 and nyM >= 55

var int today = 0
if session.isfirstbar
    today := 0

fast = ta.ema(close, 9)
slow = ta.ema(close, 21)
vw   = ta.vwap(hlc3)
atr  = ta.atr(14)
longSig  = fast > slow and close > vw and low <= fast and close > fast
shortSig = fast < slow and close < vw and high >= fast and close < fast

// contracts: the risk over what one contract loses at the stop, two ticks of slippage counted
stopDist = atrMult * atr
qty = math.min(maxQty, math.floor(riskUsd / ((stopDist + 2 * syminfo.mintick) * syminfo.pointvalue)))
canTrade = dlRoom > 0 and not dlHit and inWindow and today < maxDay and strategy.position_size == 0 and qty >= 1

if canTrade and longSig
    strategy.entry("Long", strategy.long, qty=qty)
    strategy.exit("Long exit", "Long", stop=math.max(close - stopDist, dlStopLong(close, qty)), limit=close + rMult * stopDist)
    today += 1
else if canTrade and shortSig
    strategy.entry("Short", strategy.short, qty=qty)
    strategy.exit("Short exit", "Short", stop=math.min(close + stopDist, dlStopShort(close, qty)), limit=close - rMult * stopDist)
    today += 1

// flat before the close, and on the session's last bar: on a short day CME closes early
if (cutoff or session.islastbar) and strategy.position_size != 0
    strategy.close_all(comment="Cut-off", immediately=true)

// the tally, in the Data Window and a table on the last bar
plot(dlPnl, "Today's P&L", display=display.data_window)
plot(dlRoom, "What today may still lose", display=display.data_window)
plot(dlDays, "Days the limit ended", display=display.data_window)

var table book = table.new(position.top_right, 2, 1, bgcolor=color.new(color.black, 15), border_width=1)
if barstate.islast
    table.cell(book, 0, 0, "Days the limit ended", text_color=color.white)
    table.cell(book, 1, 0, str.tostring(dlDays), text_color=color.white)
The limit on its own · 33 lines
// ── The daily loss limit ──────────────────────────────────────────────────────────────────────────
// An example number, not any firm's: take yours from your plan's own page.
dlLimit = input.float(1000, "Daily loss limit ($)", minval=1, group="Daily loss limit")

// The day's books: dollars since the day began, the open trade included
var float dlStart = strategy.initial_capital  // the strategy's equity when the day began
var bool  dlHit   = false                     // the limit was reached: no more trades today
var int   dlDays  = 0                         // days the limit ended

// A CME day starts at the 18:00 New York reopen, not at midnight
if session.isfirstbar
    dlStart := strategy.equity
    dlHit   := false

dlPnl  = strategy.equity - dlStart
// what the day may still lose
dlRoom = dlLimit + dlPnl

// The limit as a price: where a trade of this size takes the day to the limit. Put it in the
// trade's stop when it is nearer than your own, so the limit acts at its price, as a firm's does.
// A check in an if only runs when a bar closes, after the bar has moved.
dlStopLong(entry, qty) =>
    entry - dlRoom / (qty * syminfo.pointvalue)
dlStopShort(entry, qty) =>
    entry + dlRoom / (qty * syminfo.pointvalue)

// The backstop, for a gap past the stop: the open trade's worst point in this bar
dlPos   = strategy.position_size
dlWorst = dlPnl - (dlPos > 0 ? (close - low) * dlPos : dlPos < 0 ? (high - close) * -dlPos : 0.0) * syminfo.pointvalue
if not dlHit and dlWorst <= -dlLimit
    strategy.close_all(comment="Daily loss limit", immediately=true)
    dlHit  := true
    dlDays += 1

Paste it under your strategy() line. Then put dlRoom > 0 and not dlHit in front of each entry's condition, and the limit's price in each exit: stop=math.max(yourStop, dlStopLong(close, qty)) for a long, math.min with dlStopShort for a short.

What Run opens

The script above in the Alpha Charts terminal on MNQ 5-minute: its own screens, taken on 4 November 2026.

The terminal's chat with the daily loss limit script read, put on MNQ1! and backtested, and its reply
It lands on MNQ 5-minute and runs. The Copilot reads the script, puts it on the chart and runs the backtest. Give it your plan's limit, or ask which days it ended: it edits the script and runs it again.
MNQ 5-minute on 20 October 2026: three losing trades, the third closed early where the day reached the limit, and the script's table: 146 days the limit ended
The limit at work. 20 October 2026: two losers, −$476 and −$339, then a third whose stop sat where the day reached the limit: out at −$195, the day at −$1,010, and no more trades. The table counts the days the limit ended: 146.
The terminal's results for the daily loss limit script: −6.2% after costs over 1,397 trades, the last 6 months held back
The results, with the months it never saw. −6.2% after costs over 1,397 trades: the example entries are there for the limit, not the money. The terminal holds back the last 6 months, and says the strategy did not survive them.

Run your version free

The code is free to copy. Running it takes a free account, no card.

Free account

No card, no time limit.

$0
  • Unlimited backtests, costs charged, with the out-of-sample check
  • The Pine script audit and the full trade list
  • The Pine Copilot writes and edits your script
  • 50 AI credits a day

Paid plans add more AI, the optimiser and the rest of the desk, each with 30 days money back. See the plans

The same trades, five ways to keep the limit

Each run changes only how the $1,000 limit is kept. The entries, the data and the costs stay.

The limitDays past itWorst dayDays it ended
No limitThe strategy alone101−$2,018—
Closed trades onlyThe day's loss from strategy.netprofit, checked when a candle closes101−$1,497107
Pine's built-instrategy.risk.max_intraday_loss(1000, strategy.cash)97−$1,489—
Open trade, checked each candleThe day's loss from strategy.equity at each candle's worst point, the trade closed at the candle's close61−$1,430148
In the stop: the code aboveThe script's way: the limit's price in each trade's stop, the candle check as a backstop1−$1,198the hole in the data on 6 March 2026146

Closed trades only did nothing. Sized from $500 in whole contracts, a loser lost a little under $500, so two of them never quite reached the limit: on 190 days a third trade started with less room than its stop needed and ran to it. 101 days ended more than $50 past the limit, as many as with no limit at all.

The open trade, checked in an if, still came late. The check runs when a candle closes. On a fast candle the trade's own stop was hit first, past the limit, before the script could act: 61 days.

The built-in rule counts the open trade, then closes at the worst price. In our tester strategy.risk.max_intraday_loss acts once a candle's worst point is past the limit and closes the trade at that point: 97 days. It ends the day; it cannot fail an account.

In the stop, the limit is a price. The trade closes where the day reaches the limit, with the commission and a tick of slippage on top: every limit day but one ended no more than $27 past −$1,000. The one is the 57-minute hole in the data on 6 March 2026, where the stop filled at the first price after it.

When the built-in rule is enough

strategy.risk.max_intraday_loss(1000, strategy.cash) is one line, and it does the main job: no more trades that day once the loss is reached. It is enough when your plan's day matches the platform's, the limit only ends the day, and a close past the limit on a fast candle is a cost you accept.

Use the books on this page when the limit fails the account, when your plan's day starts at the 18:00 reopen and you trade the evening, or when you want the backtest to close where the firm would. Use strategy.cash for a dollar limit: strategy.percent_of_equity takes a share of the day's highest equity, which moves.

Questions

How do I add a daily loss limit to a Pine Script strategy?

Keep the day's books from the session's first candle, the 18:00 New York reopen on CME futures, with the open trade included: strategy.equity minus the equity at the day's start. Take no new entries once the loss reaches the limit, and put the limit's price in each trade's stop, so the trade closes where the day reaches the limit instead of a candle later. The script on this page does both, in a block that goes on top of your own strategy.

Does strategy.risk.max_intraday_loss work like a prop firm's daily loss limit?

Partly. It stops trading for the rest of the day and counts the open trade. In our tester it acts once a candle's worst point is past the limit and closes the trade there, so on two years of MNQ it let 97 days end more than $50 past a $1,000 limit. It cannot fail an account, and with strategy.percent_of_equity the limit moves with the day's highest equity: use strategy.cash for a dollar limit.

Why does my daily loss limit go past the limit in the backtest?

Because a check in an if runs once a candle has closed. When a candle runs from inside the limit to the trade's own stop, the loss is booked before the check runs. Counted on closed trades it is worse: the next trade starts with less room than its stop needs. In this test, 61 days went more than $50 past with the open trade checked each candle, and 101 with closed trades only. With the limit in the stop, 1.

Should the limit count the open trade?

Yes. A firm counts the open trade as it moves. strategy.netprofit leaves it out, so a limit built on it is checked only after the losing trade has closed; strategy.equity includes it.

When does the day start for the limit?

When your plan says it does. CME's futures session opens at 18:00 New York, which session.isfirstbar marks; dayofmonth changes at midnight and would count the evening's trades against the day before. In our tester the built-in rule's day also turns at midnight New York. Take the reset time from your plan's own page.

Does a daily loss limit make a strategy better?

It caps the day; it adds no edge. The example strategy here lost 6.2% over two years with the limit in its stop and 4.7% with no limit at all: the limit ended 146 days early, and some of them would have come back.

Can I use my firm's limit?

Yes, the limit is an input. The script stores no firm's rules, and firms change them, so take the number from your plan's current page. Alpha Charts is not a prop firm and is not connected with any.

Do I need TradingView to run it?

No. It is Pine v6 and runs in TradingView, and Run this script opens it in the Alpha Charts terminal on MNQ 5-minute with the backtest done. A free account runs as many tests as you like, no card.

Test the whole challenge

The daily limit is one rule of a challenge. To test a strategy against all of them at once, the target, the daily loss limit, the drawdown and the cut-off, paste it into the prop firm challenge backtester. The drawdown on its own is on a trailing drawdown in Pine Script, and which contract fits a 50K plan on MNQ or NQ for a 50K challenge.

Alpha Charts is software for writing and testing trading scripts. It is not a prop firm: it offers no challenges, evaluations or funded accounts, does not trade for you, holds no money and gives no investment advice. Backtests are past results with costs charged and do not predict passing a challenge or making money. The limit on this page is an example number, not any firm's. MNQ is a CME Group contract.

The daily loss limit scriptFree account, no cardRun it free