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.
- The limit is an input in dollars.
- 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.
- 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.
- 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.
- 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.
- The tally is in the Data Window and a table on the chart: the days the limit ended trading.
//@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)

