Pine Script Snippets for Prop Firm Trading
Copy-paste Pine Script code blocks for every prop firm safety mechanism. Each snippet is standalone, commented, and ready to paste into TradingView's Pine Editor.
Daily Kill Switch
Stops new entries when cumulative session losses hit a threshold. Prevents daily limit breaches.
Apex · Topstep · FTMO
View Snippet →Session Time Filter
Restricts entries to RTH (or any custom session). Prevents overnight holds and off-hours fills.
All firms
View Snippet →Daily Profit Cap
Stops entries after daily profit hits a target. Required for Apex's 30% consistency rule on PA accounts.
Apex
View Snippet →EOD Flatten
Closes all open positions at a configured time each session. Prevents overnight holds that violate firm rules.
All firms
View Snippet →Bar-Close Entry Guard
Ensures entries only fire on confirmed bar closes, preventing repainting. Matches backtest to live.
All firms
View Snippet →Daily Kill Switch
Full page with examples →Tracks cumulative session P&L and sets a boolean flag that blocks all new entries once your losses exceed the configured threshold. Set the limit to 80% of your firm's daily loss cap to give yourself a buffer before the hard floor. Resets automatically at each session open.
Works for: Apex, Topstep, FTMO, MyFundedFutures, and any firm with a daily loss limit rule.
//@version=5
strategy("Daily Kill Switch", overlay=true)
// ── Inputs ──────────────────────────────────────────────
dailyLossLimit = input.float(-800.0, "Daily Loss Limit ($)", step=50,
tooltip="Strategy stops new entries when session P&L hits this level. Set to 80% of firm's daily limit.")
// ── State ────────────────────────────────────────────────
var float sessionPnL = 0.0
var bool killActive = false
// Reset at each session open
if session.isfirstbar_regular
sessionPnL := 0.0
killActive := false
// Accumulate closed-trade P&L within the session
if strategy.closedtrades > strategy.closedtrades[1]
sessionPnL += strategy.closedtrades.profit(strategy.closedtrades - 1)
// Activate kill switch when threshold is breached
if sessionPnL <= dailyLossLimit
killActive := true
// ── Entry logic (replace with your own conditions) ───────
longCondition = ta.crossover(ta.ema(close, 9), ta.ema(close, 21)) and not killActive
shortCondition = ta.crossunder(ta.ema(close, 9), ta.ema(close, 21)) and not killActive
if longCondition
strategy.entry("Long", strategy.long)
strategy.exit("Long Exit", "Long", profit=20, loss=10)
if shortCondition
strategy.entry("Short", strategy.short)
strategy.exit("Short Exit", "Short", profit=20, loss=10)
// Visual indicator
bgcolor(killActive ? color.new(color.red, 90) : na, title="Kill Switch Active")
Session Time Filter
Full page with examples →Uses TradingView's time() function to check whether the current bar falls inside a configurable session window. Any entry conditions evaluated outside the session are automatically blocked. The default is NY Regular Trading Hours (9:30–16:00 ET), but you can set any window using TradingView's session string format.
Bars outside the session are shaded gray so you can visually confirm the filter is active in backtests.
//@version=5
strategy("Session Filter — RTH Only", overlay=true)
// ── Inputs ──────────────────────────────────────────────
sessionInput = input.session("0930-1600", "Trading Session",
tooltip="Use TradingView session format. Default: NY RTH 9:30-16:00 ET.")
timezone = input.string("America/New_York", "Timezone")
// ── Session check ────────────────────────────────────────
inSession = not na(time(timeframe.period, sessionInput, timezone))
// ── Entry logic (replace with your own conditions) ───────
longCondition = ta.crossover(ta.ema(close, 9), ta.ema(close, 21)) and inSession
shortCondition = ta.crossunder(ta.ema(close, 9), ta.ema(close, 21)) and inSession
if longCondition
strategy.entry("Long", strategy.long)
strategy.exit("Long Exit", "Long", profit=20, loss=10)
if shortCondition
strategy.entry("Short", strategy.short)
strategy.exit("Short Exit", "Short", profit=20, loss=10)
// Visual: shade outside-session bars
bgcolor(not inSession ? color.new(color.gray, 92) : na, title="Outside Session")
Daily Profit Cap
Full page with examples →Mirrors the kill switch logic but in the opposite direction — stops new entries once you've hit a daily profit target. This is particularly important for Apex PA (Performer Account) holders, where the 30% consistency rule means a single outsized day can invalidate your account. Set the cap to roughly 25–30% of your total profit target per day.
The chart background turns green when the cap is reached, giving you a clear visual confirmation.
//@version=5
strategy("Daily Profit Cap", overlay=true)
// ── Inputs ──────────────────────────────────────────────
dailyProfitCap = input.float(800.0, "Daily Profit Cap ($)", step=50,
tooltip="Stop new entries once session profit hits this level. For Apex PA: set to ~25% of profit target.")
// ── State ────────────────────────────────────────────────
var float sessionProfit = 0.0
var bool capReached = false
if session.isfirstbar_regular
sessionProfit := 0.0
capReached := false
if strategy.closedtrades > strategy.closedtrades[1]
sessionProfit += strategy.closedtrades.profit(strategy.closedtrades - 1)
if sessionProfit >= dailyProfitCap
capReached := true
// ── Entry logic ──────────────────────────────────────────
longCondition = ta.crossover(ta.ema(close, 9), ta.ema(close, 21)) and not capReached
if longCondition
strategy.entry("Long", strategy.long)
strategy.exit("Exit", "Long", profit=20, loss=10)
// Visual
bgcolor(capReached ? color.new(color.green, 90) : na, title="Daily Cap Reached")
EOD Flatten
Full page with examples →Calls strategy.close_all() at a configurable time each session, ensuring no positions are held overnight. The default is 15:55 ET — five minutes before the 16:00 close — giving the market time to fill the exit at a reasonable price. Adjust the flatten hour and minute to match your firm's specific overnight hold rules.
Entry signals are also blocked once the EOD window is active, preventing new trades from opening and immediately being forced closed.
//@version=5
strategy("EOD Flatten", overlay=true)
// ── Inputs ──────────────────────────────────────────────
flattenHour = input.int(15, "Flatten Hour (ET)", minval=0, maxval=23)
flattenMin = input.int(55, "Flatten Minute", minval=0, maxval=59)
// ── EOD close logic ──────────────────────────────────────
nyHour = hour(time, "America/New_York")
nyMin = minute(time, "America/New_York")
isEOD = nyHour == flattenHour and nyMin >= flattenMin
if isEOD and strategy.position_size != 0
strategy.close_all(comment="EOD Flatten")
// ── Entry logic (only when not at EOD) ───────────────────
if not isEOD
if ta.crossover(ta.ema(close, 9), ta.ema(close, 21))
strategy.entry("Long", strategy.long)
strategy.exit("Exit", "Long", profit=20, loss=10)
// Visual
bgcolor(isEOD ? color.new(color.orange, 92) : na, title="EOD Window")
Bar-Close Entry Guard
Full page with examples →The most common source of strategy repainting is allowing entries to trigger mid-bar. When calc_on_every_tick=true (the default), a crossover can appear and disappear multiple times before the bar closes, causing backtest signals that never fire the same way in live trading. This snippet uses two layers of protection: calc_on_every_tick=false at the strategy level, and barstate.isconfirmed in the entry condition.
The result: what you see in the Strategy Tester is exactly what will execute when automated live.
//@version=5
// calc_on_every_tick=false is the key setting — signals only fire on confirmed bar closes.
// This prevents repainting: what you see in backtests is exactly what executes live.
strategy("Bar-Close Entry Guard", overlay=true, calc_on_every_tick=false)
// ── Indicators ───────────────────────────────────────────
ema9 = ta.ema(close, 9)
ema21 = ta.ema(close, 21)
// barstate.isconfirmed = true only on the final tick of a closed bar
longCondition = ta.crossover(ema9, ema21) and barstate.isconfirmed
shortCondition = ta.crossunder(ema9, ema21) and barstate.isconfirmed
// ── Entries ───────────────────────────────────────────────
if longCondition
strategy.entry("Long", strategy.long)
strategy.exit("Long Exit", "Long", profit=20, loss=10)
if shortCondition
strategy.entry("Short", strategy.short)
strategy.exit("Short Exit", "Short", profit=20, loss=10)
// ── Visuals ───────────────────────────────────────────────
plot(ema9, color=color.new(color.blue, 20), linewidth=1)
plot(ema21, color=color.new(color.orange, 20), linewidth=1)
Want a complete strategy that combines all these snippets?
Our scripts include kill switch, session filter, bar-close entries, and EOD flatten — pre-wired with your own entry logic built in and tested on 3 years of MES/NQ data. Instant delivery from $50.
View Plans — From $50