HomePine Script Snippets › Bar-Close Entry Guard

Pine Script Bar-Close Entry Guard

Forces all entries to fire only on confirmed bar closes — eliminating repainting so your backtest results match live automated trading exactly.

Free snippet · Pine Script v5 · Works on TradingView free plan

//@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)

Why repainting destroys automation results

The most common complaint from traders who automate Pine Script strategies is that the live performance looks nothing like the backtest. Repainting is almost always the cause.

Here is how it happens: TradingView's default strategy setting is calc_on_every_tick=true. This means Pine Script recalculates on every price movement within a bar. An EMA crossover can appear, trigger a backtest signal, and then disappear — all before the bar closes. In the Strategy Tester, that signal gets recorded as if it fired, but in live trading, the crossover never actually occurred on a completed bar.

The fix is two lines of code:

  1. calc_on_every_tick=false in the strategy() declaration — recalculation only happens on bar closes.
  2. barstate.isconfirmed on every entry condition — an explicit gate that is only true on the final tick of a completed bar.

Together, these ensure that every signal your strategy fires in backtesting corresponds to a real, finalized bar close — the same point in time where TradersPost or any other automation bridge would receive and execute the alert.

How the two-layer protection works

SettingWhat it controlsWhy it matters
calc_on_every_tick=falseWhen Pine Script recalculates the strategyPrevents the strategy engine from evaluating signals on incomplete bar data
barstate.isconfirmedWhether the current bar is finalizedExplicit boolean gate — conditions can only fire on confirmed closes, not mid-bar ticks
For strategies on minute timeframes connected to TradersPost webhooks, calc_on_every_tick=false is the critical setting. Without it, your webhook alert can fire multiple times on the same bar as the price oscillates through a crossover.

How to add this to your existing strategy

  1. Find your strategy() declaration at the top of your script.
  2. Add calc_on_every_tick=false to it: strategy("My Strategy", overlay=true, calc_on_every_tick=false)
  3. On every entry condition (longCondition, shortCondition), append and barstate.isconfirmed.
  4. Run a fresh backtest. If your results change significantly, your original strategy was repainting — the new results are the true historical performance.

Frequently Asked Questions

What is repainting in Pine Script?

Repainting happens when a Pine Script strategy generates entry signals mid-bar that disappear or change before the bar closes. In backtesting, TradingView can see the full bar's data, so a crossover might appear and look valid — but in live trading, that same crossover never actually fired on the final tick. The result is a backtest that looks great but performs completely differently when automated live.

What does calc_on_every_tick=false do?

Setting calc_on_every_tick=false in your strategy() declaration tells Pine Script to only recalculate the strategy on completed bar closes, not on every price tick within a bar. This is the most effective way to prevent repainting because signals can only trigger at the same point in time that they would trigger in live trading — when a bar's OHLC data is finalized.

Do I need both calc_on_every_tick=false and barstate.isconfirmed?

Using both provides two layers of protection. calc_on_every_tick=false prevents recalculation mid-bar, which is the core fix. barstate.isconfirmed adds an explicit gate that only evaluates to true on the final tick of a closed bar. Together they handle edge cases where platform behavior might differ, making your strategy maximally resistant to repainting in both backtesting and live automation.

Related

Want a complete non-repainting strategy ready for automation?

Our scripts use bar-close entries, kill switch, session filter, and EOD flatten — pre-wired and verified against 3 years of MES/NQ data. Instant delivery from $50.

View Plans — From $50