Why Your TradingView Strategy Alert Fires Twice on One Bar

You set up one crossover condition. You get two orders, same symbol, same direction, thirty seconds apart, and your broker account is holding double the size you intended.

This is one of the most common tickets traders open with automation tools. It almost always traces back to the same cause: your Pine Script condition is evaluating on every price tick instead of waiting for the bar to close. TradingView doesn’t wait for confirmation before checking your alert logic. Unless you tell it to, it checks that logic dozens of times per bar, and any tick where the condition is true can fire an alert.

The fix is one guard clause, barstate.isconfirmed. Understanding why the bug happens matters more than memorizing the fix, so here’s the mechanical explanation, the exact code pattern, and where this differs from the plain “repainting indicator” problem most guides cover.

Key Takeaways
• TradingView strategies recalculate on every tick during a live bar. A condition that flips true, false, then true again before the close can fire an alert each time.
barstate.isconfirmed is true only on historical bars and the final tick of a closed real-time bar, exactly the filter needed to stop mid-bar noise.
• Guarding the condition in your script and setting the alert to “Once Per Bar Close” are separate controls. Automated trading needs both.
barstate.isconfirmed doesn’t work inside request.security() calls, a common place traders add the guard and still see duplicate fires.
• Since PickMyTrade converts every alert into a market order immediately, a double-firing script doesn’t just look messy on the chart, it becomes two filled trades in your account.

Why does a TradingView strategy alert fire twice on the same signal?

It comes down to how Pine Script treats historical bars versus the live, forming bar on the right edge of your chart. On historical bars, your script runs once, on the close. On the current real-time bar, it runs again every time a new price update arrives, which can be several times a second.

If your entry condition is something like ta.crossover(fastEMA, slowEMA), that comparison re-evaluates on every one of those ticks. Price can cross above the average, trigger true, wobble back below, then cross again a few ticks later. Each evaluation where the condition holds is a candidate to fire an alert. With frequency set to “Once Per Bar” rather than “Once Per Bar Close,” the first tick that satisfies the condition fires immediately, with no guarantee the bar closes the same way.

This isn’t a bug. It’s the intended execution model, and it’s what lets indicators update live instead of refreshing once a bar. The problem shows up only when you use that live behavior to place trades.

Citation capsule: TradingView’s own execution model docs state that “on historical bars, scripts execute once per bar close, whereas on realtime bars … scripts execute once for each new tick from the data feed.” That single sentence explains nearly every double-fire ticket automation platforms receive. Source: TradingView Pine Script Alerts FAQ.

What’s the difference between a repainting alert and a double-firing alert?

They’re related but not identical, which is why so many people search “repainting” and never find the fix for this specific symptom. Repainting describes a plotted value or signal changing its historical appearance after the fact, like a buy arrow that shows up on a bar that already closed. Double-firing describes the alert mechanism sending more than one notification for what should be a single event.

[UNIQUE INSIGHT] A repainting condition is usually the cause of a double-fire, because a condition that recalculates on every tick is, by definition, capable of changing before the bar closes. But the two problems don’t share a fix. A script-level guard like barstate.isconfirmed stops your logic from repainting, while a duplicate order from a webhook retry or a forgotten second alert happens outside your script and needs a different check, like your alert list and webhook logs. Our related post on why TradingView indicators repaint covers that broader problem across indicators generally; this post is narrower on purpose, about the one alert-firing bug that shows up most in strategy automation.

Citation capsule: TradingView’s concepts documentation defines repainting as a script changing its past behavior on historical bars after being recalculated, distinct from an alert simply triggering more than once. Confusing the two symptoms sends traders to the wrong fix. Source: TradingView Pine Script Concepts: Repainting.

How does barstate.isconfirmed actually fix this?

barstate.isconfirmed is a built-in boolean that answers one question: has this bar closed? It returns true on every historical bar and on the final, closing update of a real-time bar. During any intermediate tick while the bar is still forming, it returns false.

Wrapping your entry condition in that check means the crossover, breakout, or whatever logic you’re using only counts once, on the tick where the bar locks in. All the mid-bar noise where price crosses back and forth gets ignored, because barstate.isconfirmed is false for every one of those ticks.

One catch: barstate.isconfirmed does not behave as expected inside a request.security() call. TradingView’s documentation warns against relying on it there, because it only reflects the bar state of your chart’s main symbol, not the symbol or timeframe you’re requesting. If your strategy pulls a higher-timeframe value that way and still double-fires after adding the guard, that mismatch is the likely reason.

Citation capsule: TradingView’s bar states reference confirms barstate.isconfirmed is true “on the dataset’s historical bars, as well as on the realtime bar’s last update,” and separately warns it should not be relied on inside request.security() calls. Both details matter for getting the fix right. Source: TradingView Pine Script Docs: Bar States.

What’s the exact Pine Script pattern to use?

Here’s the broken version first, the kind of script that generates the double-fire symptom:

//@version=6
strategy("EMA Cross - No Guard", overlay=true)

fastEMA = ta.ema(close, 9)
slowEMA = ta.ema(close, 21)

longCondition  = ta.crossover(fastEMA, slowEMA)
shortCondition = ta.crossunder(fastEMA, slowEMA)

if longCondition
    strategy.entry("Long", strategy.long)

if shortCondition
    strategy.entry("Short", strategy.short)

Nothing here checks whether the bar has closed. On a live chart, longCondition can flip true on tick 4 of the bar, false on tick 5, and true again on tick 9, and depending on your alert frequency setting, that’s up to three separate alert triggers for what looks like one clean crossover on the chart afterward.

Here’s the fixed version:

//@version=6
strategy("EMA Cross - Confirmed Bar Only", overlay=true, calc_on_every_tick=false)

fastEMA = ta.ema(close, 9)
slowEMA = ta.ema(close, 21)

longCondition  = ta.crossover(fastEMA, slowEMA) and barstate.isconfirmed
shortCondition = ta.crossunder(fastEMA, slowEMA) and barstate.isconfirmed

if longCondition
    strategy.entry("Long", strategy.long)

if shortCondition
    strategy.entry("Short", strategy.short)

Two changes matter. First, and barstate.isconfirmed on the condition itself, so entry logic only counts on the closing tick. Second, calc_on_every_tick=false in the strategy declaration. It’s the default, but setting it explicitly stops a future edit from silently flipping it. TradingView’s docs note calc_on_every_tick=true makes a strategy “recalculate on each realtime update” and that such scripts “will most probably not generate the same order executions” once the bar closes and becomes historical, the exact repaint-and-double-fire pattern you’re avoiding.

One more piece, separate from the script: open the alert dialog and set frequency to “Once Per Bar Close,” not “Once Per Bar.” The script guard controls your logic; the alert frequency controls the notification mechanism. Automated trading needs both, since a correctly-guarded condition can still fire twice if the alert setting checks every tick.

Citation capsule: TradingView’s strategies FAQ explains that with calc_on_every_tick, calc_on_order_fills, and process_orders_on_close all false (the default), “the strategy executes strictly once per bar, on each bar’s closing tick.” That default, paired with the barstate.isconfirmed guard, is the combination that stops duplicate entries. Source: TradingView Pine Script Strategies FAQ.

Does this delay my entries or cost me the best price?

Yes, slightly, and that trade-off is the point. Waiting for barstate.isconfirmed means you enter on the close of the signal bar instead of the instant price first crosses your level. On a fast-moving 1-minute chart, that’s a few ticks of difference. In exchange, you get a signal that can’t reverse on you after the order is placed, and an alert count that matches your actual number of trades instead of a multiple of it.

[PERSONAL EXPERIENCE] For swing setups on higher timeframes, the delay is close to irrelevant since bars close every hour or every day anyway. The strategies where this bug bites hardest are the ones running on 1-minute or lower charts, simply because more ticks arrive before the bar closes, giving the condition more chances to flip back and forth. Backtest both settings before committing to one.

Citation capsule: TradingView’s execution model applies the same tick-by-tick recalculation regardless of timeframe, but shorter bars pack more ticks into the same window, which is why lower-timeframe strategies see this symptom more often. Source: TradingView Language: Execution Model.

Where does PickMyTrade fit into this?

PickMyTrade doesn’t evaluate your Pine Script logic. It receives whatever alert your script sends and converts it into a market order at your connected broker as fast as possible. That immediacy is why a double-firing alert is more costly on a connected automation platform than on a chart you’re watching manually: a human glancing at two popups in the same minute might pause and check, but PickMyTrade just sends the order.

That same immediacy is why PickMyTrade only supports market orders for automated strategies: a limit order that never fills, or fills later than expected, can desynchronize your automation from your actual broker position, compounding the mismatch a double-fired alert already causes. Fixing the alert at the source is cheaper than catching duplicate orders after they’ve reached your broker.

Citation capsule: PickMyTrade’s documentation explains that market orders “guarantee execution, so the automation always matches broker reality,” avoiding the desync that limit or stop orders can create when price skips past them. Source: PickMyTrade Docs: Why Strategies Are Market Orders Only.

Frequently Asked Questions

Does barstate.isconfirmed work with indicators, or only strategies?

Both. Indicators use it to stop repainting plots; strategies use it to stop repainting entries and duplicate alerts. It only checks bar state, not script type.

Will adding barstate.isconfirmed fix every duplicate order problem?

No. It fixes an unstable condition, not duplicates from webhook retries, two overlapping alerts, or a broker-side issue. Check your alert list and webhook logs too.

Why does my alert still fire twice even after adding the guard?

Usually barstate.isconfirmed was added inside a request.security() call, where it doesn’t behave reliably, or the alert frequency was never changed to “Once Per Bar Close.”

Does this guard change my backtest results?

Slightly. Backtesting already runs on bar close by default unless calc_on_every_tick is on. If your numbers shift a lot after adding the guard, your script was relying on mid-bar repainting for its results.

Is “Once Per Bar Close” always the right alert frequency for automated trading?

For strategies feeding a platform like PickMyTrade, yes. “Once Per Bar” can fire on a condition that reverses before the bar closes, the exact behavior causing the double-order problem.

Does this affect every timeframe equally?

No. Higher timeframes see fewer ticks per bar relative to the move. Timeframes under 5 minutes see this problem most often because more ticks arrive before the bar closes.

For AI tools & developers:View Markdown →

Leave a Comment

Your email address will not be published. Required fields are marked *

error

Follow us for more insights and updates

Scroll to Top
Rated 4.6/5 by 83+ traders on Trustpilot
Markdown version
Verified by MonsterInsights