---
title: "Non-Repainting Strategy Still Fires Twice? Here’s Why"
slug: non-repainting-strategy-still-fires-twice-heres-why
date: 2026-09-21
modified: 2026-09-21
author: Bhavishya Goyal
excerpt: ""
meta_description: "A default strategy runs once per bar close, so barstate.isconfirmed is true on 100%. Here\'s what sends a non-repainting strategy webhook."
focus_keyword: non-repainting strategy
canonical_url: "https://blog.pickmytrade.io/non-repainting-strategy-still-fires-twice-heres-why/"
og_title: "Non-Repainting Strategy Still Fires Twice? Here’s Why"
og_description: "A default strategy runs once per bar close, so barstate.isconfirmed is true on 100%. Here\'s what sends a non-repainting strategy webhook."
og_image: "https://blog.pickmytrade.io/wp-content/uploads/2026/09/Gemini_Generated_Image_yk038ayk038ayk03-1024x572.avif"
schema_type: FAQPage
categories:
  - TradingView
tags: []
reading_time: 18
word_count: 4345
robots: "index, follow"
lang: en-US
---

# Non-Repainting Strategy Still Fires Twice? Here’s Why

You did the thing everyone told you to do. The entry condition is wrapped in `barstate.isconfirmed`, the alert is set to Once Per Bar Close, and the signal arrow no longer jumps around on the right edge of the chart for non-repainting strategy, Then you check the account: two fills, eight seconds apart, on one crossover.

Table of Contents

1. [barstate.isconfirmed does nothing in a default non-repainting strategy](https://blog.pickmytrade.io/#barstate-isconfirmed-does-nothing-in-a-default-non-repainting-strategy)
2. [Which alert triggers can your guard actually reach?](https://blog.pickmytrade.io/#which-alert-triggers-can-your-guard-actually-reach)
3. [Why does one signal produce two fills?](https://blog.pickmytrade.io/#why-does-one-signal-produce-two-fills)
4. [The explicit reversal sends two orders](https://blog.pickmytrade.io/#the-explicit-reversal-sends-two-orders)
5. [The single-entry reversal sends one](https://blog.pickmytrade.io/#the-single-entry-reversal-sends-one)
6. [Brackets and calc_on_order_fills add more](https://blog.pickmytrade.io/#brackets-and-calc_on_order_fills-add-more)
7. [What in the Properties tab overrides your code?](https://blog.pickmytrade.io/#what-in-the-properties-tab-overrides-your-code)
8. [How does the Create Alert dropdown double your signal?](https://blog.pickmytrade.io/#how-does-the-create-alert-dropdown-double-your-signal)
9. [Where does the guard fail outright rather than idle?](https://blog.pickmytrade.io/#where-does-the-guard-fail-outright-rather-than-idle)
10. [Repainting and double-firing are two different bugs](https://blog.pickmytrade.io/#repainting-and-double-firing-are-two-different-bugs)
11. [How does the bridge decide whether two alerts become two positions?](https://blog.pickmytrade.io/#how-does-the-bridge-decide-whether-two-alerts-become-two-positions)
12. [Two templates, two stacking defaults](https://blog.pickmytrade.io/#two-templates-two-stacking-defaults)
13. [Two flags that block the repeat](https://blog.pickmytrade.io/#two-flags-that-block-the-repeat)
14. [What the risk settings can’t catch](https://blog.pickmytrade.io/#what-the-risk-settings-cant-catch)
15. [How do you find which stage sent the second order?](https://blog.pickmytrade.io/#how-do-you-find-which-stage-sent-the-second-order)
16. [Fix it in this order](https://blog.pickmytrade.io/#fix-it-in-this-order)
17. [Frequently Asked Questions](https://blog.pickmytrade.io/#frequently-asked-questions)
18. [Test it somewhere it can’t cost you](https://blog.pickmytrade.io/#test-it-somewhere-it-cant-cost-you)

So the guard didn’t work? It worked exactly as designed. The uncomfortable part is that in a default strategy it was never doing anything at all. The thing that sent your second webhook lives in a part of the pipeline Pine Script can’t reach.

This is the article for people who already applied the fix. Still stuck on the earlier question of why a signal repaints mid-bar? Start with our guide to [repainting versus non-repainting indicators](https://blog.pickmytrade.io/repainting-vs-non-repainting-indicators-futures-trading/) and come back.

&gt; **Key Takeaways**
&gt; 
&gt; 
&gt; 
&gt; 
&gt; 
&gt; 
&gt; 
&gt; - Strategies run once per closed bar by default, so `barstate.isconfirmed` is true on 100% of executions.
&gt; - Order fill alerts ignore every script execution setting. No Pine guard reaches them.
&gt; - `strategy.close()` plus `strategy.entry()` is two orders, two fills, two webhooks.
&gt; - Your alert JSON, not Pine, decides whether a repeat alert stacks into a doubled position.

## barstate.isconfirmed does nothing in a default non-repainting strategy {#barstate-isconfirmed-does-nothing-in-a-default-non-repainting-strategy}

A default strategy executes your code exactly once per bar, on the closing tick, so your guard is checking a variable that’s true 100% of the time. **A non-repainting strategy** is one whose signals, once printed, never change on a closed bar, and a plain `strategy()` script already behaves that way out of the box. Nothing you add changes that until you change a setting.

**`barstate.isconfirmed`** is a built-in boolean that returns true on all historical bars and on the last, closing update of a realtime bar. Read that against the default execution model and the arithmetic falls out. The script only ever runs on the closing update, so the guard never gets a chance to say no. `if myCondition and barstate.isconfirmed` is just `if myCondition` wearing a costume.

&gt; **What we found:** the guard is not wrong. It’s inert. Adding it to a default strategy and watching the duplicates continue is not evidence that the fix failed. It’s evidence that the duplicate was never coming from mid-bar evaluation.

![Close-up of a code editor showing syntax-highlighted lines with inline comments on a dark background.](https://images.pexels.com/photos/4976712/pexels-photo-4976712.jpeg?auto=compress&amp;cs=tinysrgb&amp;w=1200&amp;fm=webp)

The guard earns its keep in exactly two situations: an `indicator()` script, which genuinely does run once per tick on the realtime bar, and a strategy where somebody has ticked **On realtime bar tick** in the settings. Outside those two, you’ve added a line that costs nothing and does nothing. Is that harmful? Not at all. It’s just not the fix.

That’s also why copying the pattern from an indicator tutorial into a strategy causes so much confusion. The advice is sound; the context isn’t. We’ve covered the wider family of bar-state tricks, and where each one belongs, in [the barstate.islast pattern and its traps](https://blog.pickmytrade.io/ftmo-barstate-islast-tradingview-trick/).

So if the guard isn’t the problem, what is? Follow the second order backwards. Something generated an event, something turned that event into an HTTP request, and something turned that request into a position. Three stages, and only the first is written in Pine.

## Which alert triggers can your guard actually reach? {#which-alert-triggers-can-your-guard-actually-reach}

A script alert built on a strategy can fire on three different things: `alert()` function calls, order fill events, or both. Your Pine guard has authority over exactly one of them. That split is the most useful thing to understand about duplicate orders, and it rarely gets drawn explicitly.

What barstate.isconfirmed can and cannot gate
  Two columns. The left column lists what a barstate.isconfirmed guard in Pine Script controls: alert function calls, alertcondition triggers, plotted output, and whether an order is placed at all. The right column lists what sits outside the guard’s reach: order fill alerts, broker emulator fills, a second active alert on the same script, and the Script execution checkboxes in the Properties tab.
  
  What your guard can and cannot gate
  A barstate.isconfirmed check lives inside Pine. Half the pipeline is outside it.
  
  
  
  Your guard controls
  
  ✓
  alert() function calls
  
  ✓
  alertcondition()
  triggers
  
  ✓
  plot, label and marker
  output
  
  ✓
  whether an order is
  placed
  
  
  
  Outside its reach
  
  ✕
  order fill alerts
  
  ✕
  broker emulator fills
  
  ✕
  a second alert on the
  script
  
  ✕
  Properties tab
  checkboxes

  The guard sits in the left column. Everything in the right column fires without asking it.
*The guard sits in the left column. Everything in the right column fires without asking it.*

**An order fill event** is any event the broker emulator generates that causes a simulated order to execute. It’s the software equivalent of a broker confirming a trade. Once your script hands an order to the emulator, the emulator owns it: the script isn’t told when the order fills, and it can’t intervene. That’s exactly why `alert()` calls can’t be coded to trigger on fills.

Which leaves an awkward conclusion. Alerts from order fill events execute immediately, regardless of the script’s execution settings. Not once per bar close. Not when `barstate.isconfirmed` says so. Immediately, on the tick the fill happens, whatever your code contains.

So which path is your webhook on? If its body carries `{{strategy.order.action}}` and `{{strategy.order.contracts}}`, it’s the order-fill path, because fills are what supply those values. Our guide to [setting up TradingView alerts for automated trading](https://docs.pickmytrade.io/docs/setting-up-tradingview-alerts-for-automated-trading/) shows where that message gets pasted. Your guard is guarding a door nobody walks through.

There’s a second irony on top of that. In a strategy, `alert()` calls are forced to the `alert.freq_once_per_bar_close` frequency regardless of the `freq` argument you pass. The only exception is when tick-level calculation is on. So on the one trigger type your guard can reach, TradingView had already applied the same restriction for you.

## Why does one signal produce two fills? {#why-does-one-signal-produce-two-fills}

Two fills on one bar isn’t a malfunction. It’s what the code asked for. When we analyzed the order-placement commands against the fill events each one generates, the most ordinary-looking reversal in Pine turned out to produce two of them.

Webhook POSTs produced by one signal
  Horizontal bar chart. A single strategy.entry call on a flat account produces one webhook POST, and so does a strategy.entry that reverses an existing position. A strategy.close followed by strategy.entry produces two. An entry that fills and a bracket exit that fills on the same bar produces two. Two active alerts on the same script produce two. A close plus entry pair that also carries its own alert call produces three.
  
  Webhook POSTs produced by one signal
  Same crossover, same bar close. The Pine pattern decides how many requests leave.
  strategy.entry() on a flat account
  
  
  1
  strategy.entry() reversing a position
  
  
  1
  strategy.close() then strategy.entry()
  
  
  2
  Entry fills, bracket exit fills same bar
  
  
  2
  Two active alerts on the same script
  
  
  2
  close() + entry() + its own alert() call
  
  
  3
  
  Requests sent per confirmed signal

  Counted from the order commands inside the condition block, not the number of conditions.
*Counted from the order commands inside the condition block, not the number of conditions.*

### The explicit reversal sends two orders {#the-explicit-reversal-sends-two-orders}

Consider a reversal written the explicit way:

```
if longCondition
    strategy.close("Short")
    strategy.entry("Long", strategy.long, qty = 1)
```

That’s two orders. Two orders fill separately, so the emulator generates two fill events. The alert fires twice, and your endpoint receives two POSTs. Nothing repainted, and nothing evaluated mid-bar. The script did precisely what those three lines told it to do, and the account has two fills to prove it.

### The single-entry reversal sends one {#the-single-entry-reversal-sends-one}

Now the same reversal written the other way:

```
if longCondition
    strategy.entry("Long", strategy.long, qty = 1)
```

A single `strategy.entry()` in the opposite direction closes the open position _and_ opens the new one as one order. One order, one fill, one webhook. The contract count arrives as the combined size, because the order has to flatten the old position before it can establish the new one. Ever seen a quantity of 2 on an alert when your size is 1? That’s why. Which placeholder you put in `quantity` changes what the bridge receives, and we compare the options in [position size versus market position placeholders](https://blog.pickmytrade.io/strategy-market-position-vs-size/).

### Brackets and calc_on_order_fills add more {#brackets-and-calc_on_order_fills-add-more}

Brackets add a third shape. An entry fills at the open, price runs to the take-profit inside the same bar, and the exit fills too. That’s two fill events on one bar from a script with one entry condition. The behaviour is perfectly correct. You still get two webhooks, and the bridge has to work out whether the second is a new trade or a close.

One more multiplier is worth knowing. `calc_on_order_fills` is off by default. When it’s on, the script runs an extra time on every tick where an order fills, and it can place new orders during that run. Turn it on with a condition that’s still true and you’ve built a small machine for generating orders.

## What in the Properties tab overrides your code? {#what-in-the-properties-tab-overrides-your-code}

Four settings in the Properties tab can override your `strategy()` declaration, and the override wins every time. So before you edit a single line, open the script’s Settings and read that tab. Whoever last touched the chart chose those values. That includes you, six months ago, debugging something.

| Properties setting | Code parameter | Default | What changes when it’s on |
| --- | --- | --- | --- |
| On realtime bar tick | calc_on_every_tick | off | Script runs on every incoming tick of the open bar |
| On order fill | calc_on_order_fills | off | Extra execution on each fill tick; new orders can be placed there |
| On history bar tick | calc_on_every_history_tick | off | Historical bars are re-run tick by tick to match realtime behaviour |
| Order execution delay: None | process_orders_on_close | one tick | Orders created on the close can fill on that same tick |

The first row is the one that matters here. Tick **On realtime bar tick** and your strategy starts behaving like an indicator on the open bar, evaluating on every price update. That’s the moment `barstate.isconfirmed` stops being decorative and starts being load-bearing. It’s also the moment a condition that flips true, false, then true again can hand the emulator more than one order. Guess which checkbox gets ticked during debugging and never unticked?

![A person in a blue shirt holding a clipboard and working through a handwritten checklist with a marker.](https://images.pexels.com/photos/5756660/pexels-photo-5756660.jpeg?auto=compress&amp;cs=tinysrgb&amp;w=1200&amp;fm=webp)

Changing these settings can also introduce repainting in the strategy’s own calculations and results. Historical and realtime bars carry different levels of intrabar detail, so the two stop behaving alike. That touches order placement, alerts, and anything declared with `varip`. The checkbox that makes a forward test feel more responsive is the same one that makes it stop matching the backtest.

Two practical notes. These settings live with the saved chart layout rather than the published script, so the same strategy can behave differently on two of your own tabs. And when you add a published strategy, you get the defaults written in its code, which aren’t necessarily the settings its author tested with. Our rundown of [what breaks when Pine v6 hits live automation](https://blog.pickmytrade.io/pine-script-v6-what-breaks-your-live-automation/) covers the version-upgrade half of this problem.

## How does the Create Alert dropdown double your signal? {#how-does-the-create-alert-dropdown-double-your-signal}

Create an alert on a strategy and TradingView asks what should trigger it. The Condition section offers three choices: order fills and `alert()` function calls, order fills only, or `alert()` function calls only. It’s easy to accept whatever’s preselected and never open that menu again.

Now picture a script that does both. It calls `strategy.entry()` on a crossover. Because some tutorial suggested it, it also calls `alert()` on the same crossover to push a message to Discord. Leave the condition on “order fills and alert() function calls” and one crossover produces two alert events: the `alert()` call at the bar’s close and the fill at the next bar’s open. One condition, two outbound requests moments apart, and both look completely legitimate in the log.

The other version is even simpler: two saved alerts on the same script. Alerts survive script edits. You tweak the strategy, create a fresh alert to test it, and the original is still sitting in the alert manager, still pointed at the same webhook URL. Nothing in TradingView warns you that two alerts share a destination. When did you last open the alert manager and read the whole list?

Driving one endpoint from several indicators is its own coordination problem, and we walk through that setup in [combining two indicators into one alert](https://blog.pickmytrade.io/two-indicators-one-alert-tradingview/).

## Where does the guard fail outright rather than idle? {#where-does-the-guard-fail-outright-rather-than-idle}

There’s one context where `barstate.isconfirmed` isn’t inert. It’s broken: inside a `request.security()` call, where the variable simply doesn’t work. Move it outside the call and it works again, but it now describes the chart’s bar, not the timeframe you requested.

![A dark monitor displaying a candlestick chart with a price ladder and open order panel.](https://images.pexels.com/photos/6770775/pexels-photo-6770775.jpeg?auto=compress&amp;cs=tinysrgb&amp;w=1200&amp;fm=webp)

That matters for any multi-timeframe setup. Say you’re on a 5-minute chart pulling a 1-hour trend filter. You add a confirmation check, expecting it to wait for the hourly bar to close. What you get is the 5-minute bar’s state, which confirms twelve times an hour while the hourly value keeps moving underneath it. The filter you thought was gating the signal is releasing it on every chart bar.

The fix isn’t a better guard. It’s requesting a value that’s already settled, an offset series rather than a live one, so there’s nothing left to confirm. That’s a different technique with a different failure mode, and it belongs with the rest of the [common Pine Script mistakes that break live strategies](https://blog.pickmytrade.io/debugging-tradingview-strategies-10-common-pine-script-mistakes/).

## Repainting and double-firing are two different bugs {#repainting-and-double-firing-are-two-different-bugs}

Repainting and double-firing produce the same complaint, an unexpected trade, from two different causes. They get conflated all the time. That’s how a repainting fix ends up applied to a duplication problem, and why automation then looks broken.

Repainting is a _history_ problem: a value or signal changes its appearance on a bar that has already closed, so what you backtest isn’t what you traded. Double-firing is a _count_ problem. The signal itself is stable and correct, and the pipeline simply emitted it more than once.

The two overlap in one direction only. A condition that recalculates mid-bar can produce both symptoms, which is where the confusion starts. But a perfectly stable, confirmed-bar-only signal can still arrive at your broker twice. No amount of extra confirmation logic touches that, because the duplication happened after the signal was final.

Diagnose them differently. Did the arrow move, or did it stay put? If it moved, it’s repainting, so check your data sources and your confirmation logic. If the arrow stayed put and the fill count is wrong, it’s duplication, so check the three stages after Pine. Our [guide to TradingView alert automation](https://blog.pickmytrade.io/tradingview-alerts-automation-guide-2026/) covers the setup side of that pipeline end to end.

## How does the bridge decide whether two alerts become two positions? {#how-does-the-bridge-decide-whether-two-alerts-become-two-positions}

Two webhooks are not automatically two positions. The JSON flags in the alert body decide what the second request does, and the template you copied chose those flags for you. So what does the second request actually do when it lands?

What the bridge does with a duplicate same-direction alert
  Four JSON flags, each shown on its own. With pyramid set to true, a second same-direction alert stacks on the first and the position doubles. With pyramid set to false, the second alert closes the position and reopens it, producing churn and extra commission. With duplicate_position_allow set to false, the duplicate trade is blocked and the position is unchanged. With same_direction_ignore set to true, the second alert is discarded and the position is unchanged.
  
  What the bridge does with the second alert
  Two identical buy alerts arrive seconds apart. The JSON flags decide the outcome.
  
  
  “pyramid”: true
  Stacking on
  Second alert stacks on the first
  
  Doubled position
  
  
  “pyramid”: false
  Stacking off
  Second alert closes, then reopens
  
  Churn + commission
  
  
  “duplicate_position_allow”: false
  Opt-in filter, Rithmic JSON guide
  Duplicate trade is blocked
  
  Position unchanged
  
  
  “same_direction_ignore”: true
  Opt-in filter, JSON reference
  Second alert is discarded
  
  Position unchanged

  Documented effect of each flag on its own. Templates combine several, so fire a test duplicate on demo before trusting a default.
*Documented effect of each flag on its own. Templates combine several, so fire a test duplicate on demo before trusting a default.*

### Two templates, two stacking defaults {#two-templates-two-stacking-defaults}

The default depends on which template you started from. When we compared PickMyTrade’s documented pairings, we discovered they ship opposite stacking defaults. The order pair sends `{{strategy.order.action}}` and `{{strategy.order.contracts}}` with `"pyramid": true`, so a repeat buy stacks on the first. The position pair in the [Rithmic JSON guide](https://docs.pickmytrade.io/docs/rithmic-json-configuration-for-tradingview-integration/) sends `{{strategy.market_position}}` and `{{strategy.market_position_size}}` instead, and ships with `"pyramid": false`, `"reverse_order_close": true` and `"duplicate_position_allow": true`.

Neither default is a mistake. Each is paired with a different set of placeholders. What matters is that the second request inherits whatever flags your alert body carries, so a template you copied months ago decides how today’s double-fire lands. Open the alert, read the flags, and match them to the rows in the chart. Which pairing are you actually on?

![Fibre-optic patch cables in teal running into a rack-mounted network switch.](https://images.pexels.com/photos/5073493/pexels-photo-5073493.jpeg?auto=compress&amp;cs=tinysrgb&amp;w=1200&amp;fm=webp)

### Two flags that block the repeat {#two-flags-that-block-the-repeat}

Two flags exist specifically to stop a repeat. **`duplicate_position_allow`** is the one the Rithmic guide documents: set it to `false` and duplicate trades in the same direction are blocked. Both of that guide’s templates ship it as `true`, so blocking is opt-in. The general JSON reference documents a second flag, `same_direction_ignore`. It blocks a same-direction alert while an order or position is already active, and still lets the first opposite signal through.

The trade-off is real, so decide deliberately. Either filter also blocks genuine scaling-in, because the bridge can’t tell a deliberate second entry from an accidental one. If your strategy legitimately pyramids, fix the duplicate upstream in Pine rather than filtering it downstream. For one-position-at-a-time logic, a duplicate filter turns a code bug into a logged rejection instead of a doubled position.

`reverse_order_close` rounds this out. On an opposite signal, `true` [closes the open position and opens the reverse one](https://docs.pickmytrade.io/docs/reverse-order-close-pickmytrade/), while `false` only closes it. Indicator alerts lean on this because an indicator has no idea what you’re holding. For example, a LuxAlgo-style buy signal doesn’t know you’re short, so the bridge has to flatten first.

### What the risk settings can’t catch {#what-the-risk-settings-cant-catch}

One honest limitation. The account risk settings cover [Daily Loss, Daily Profit, Weekly Loss and Weekly Profit](https://blog.pickmytrade.io/daily-loss-limit-automated-trading/). There’s no maximum-trades-per-day counter and no cooldown timer between orders, so a rate limit can’t catch a duplicate. Deduplication has to happen by direction or not at all.

## How do you find which stage sent the second order? {#how-do-you-find-which-stage-sent-the-second-order}

It takes about five minutes to find which of the three stages produced the extra order, and you need that answer before you can fix anything. The instinct is to start rewriting Pine. Start by counting instead.

- **Open the TradingView alert log and read the Webhook status column.** It records delivery for each request. Two rows for one bar means TradingView sent two; one row means the duplication happened downstream, at the bridge or the broker.
- **Count the active alerts pointed at that webhook URL.** Open the alert manager and look for a second alert on the same script. It’s the fastest check. Do it first.
- **Open the Create Alert dialog on the live alert and read the Condition section.** If it says order fills _and_ `alert()` function calls, and your script contains both, that’s your duplicate.
- **Open Settings, then the Properties tab, and read the Script execution checkboxes.** On realtime bar tick and On order fill both change how many orders get placed, whatever the code says.
- **Check the bridge’s own alert log for two received alerts versus one.** Two received means the requests genuinely arrived twice. One received with two fills points at the broker or the account.

Only after all five of those checks come back clean should you open the Pine editor and start reading code. When you do, the question isn’t “where do I add a guard.” It’s “how many orders does this block actually place?” Count the `strategy.*` calls inside the `if`, not the number of conditions.

One note on delivery. TradingView cancels a webhook request if the receiving server takes longer than three seconds, and it only sends to ports 80 and 443. A cancelled request is a missing order, not a doubled one. But a trader who sees a failure in the log may re-fire manually, and that’s a duplicate with an entirely human cause. If failures are what you’re seeing, our write-ups on [webhook 403 and 401 errors](https://blog.pickmytrade.io/tradingview-webhook-403-401-error-fix/) and [allowlisting TradingView’s four webhook IPs](https://blog.pickmytrade.io/how-to-allowlist-tradingviews-4-webhook-ips/) cover the usual causes.

### Fix it in this order {#fix-it-in-this-order}

1. Delete the duplicate alert, if there is one. Free, instant, no code.
2. Set the Create Alert condition to order fills only, unless you actively need `alert()` events.
3. Uncheck On realtime bar tick and On order fill in Properties unless you know why they’re on.
4. Collapse `strategy.close()` plus `strategy.entry()` into a single `strategy.entry()` reversal.
5. Add a duplicate filter to the alert JSON as a backstop, if your logic never scales in.

---

**Want the backstop without rebuilding your script?** PickMyTrade routes [TradingView alerts](https://pickmytrade.io "PickMyTrade - Automate TradingView") to Tradovate, Rithmic, Interactive Brokers, TradeStation and the major prop firms, with per-alert JSON control over stacking, reversals and duplicate handling. Plans run $50/month, $120 per quarter or $350 a year, and there’s a [7-day free trial with no card required](https://pickmytrade.io/pricing/). Wiring up a strategy for the first time? [The TradingView automation overview](https://pickmytrade.io/tradingview-automation/) is the place to start.

## Frequently Asked Questions {#frequently-asked-questions}

**Does barstate.isconfirmed do anything at all in a strategy?** 

Only when tick-level calculation is on. A strategy executes once per closed bar by default, so the variable is already true on 100% of runs. Enable On realtime bar tick in Properties and the guard starts to matter, because the script then evaluates on every incoming tick of the open bar.

 
 
**Will Once Per Bar Close stop order fill alerts firing twice?** 

No. Order fill alerts fire the moment the broker emulator fills an order, regardless of the script’s execution settings or the frequency you picked. A bar with 2 fills sends 2 alerts. The frequency control governs `alert()` calls only, so if your webhook carries `{{strategy.order.action}}`, it doesn’t apply.

 
 
**Why did one alert arrive with double the contract count?** 

Because a single `strategy.entry()` in the opposite direction closes the open position and opens the new one as one order. Flattening 1 contract and establishing 1 more is 2 contracts of work, so `{{strategy.order.contracts}}` reports 2. That’s a correct reversal, not a duplicate. Splitting it into two orders is what creates duplicates.

 
 
**Does TradingView retry a webhook that failed to deliver?** 

No retry behaviour is documented. Webhooks can occasionally fail to arrive, a request is cancelled if your server takes longer than 3 seconds, and the Webhook status column in the alert log is your delivery record. Treat each request as fire-and-forget, and confirm fills at the broker rather than assuming delivery.

 
 
**Should I fix the Pine Script or block duplicates in the alert JSON?** 

Fix the script first if you can identify the cause, because a JSON filter hides the symptom without correcting the 2 orders your backtest still shows. Then add `duplicate_position_allow: false` or `same_direction_ignore: true` as a backstop, as long as your logic never scales in. Running both layers is what we’d suggest for a funded account.

 
 

## Test it somewhere it can’t cost you {#test-it-somewhere-it-cant-cost-you}

A duplicate order is cheap to reproduce and expensive to discover live. Run the strategy on a demo connection for ten signals, then count rows in three places: the TradingView alert log, the bridge’s alert log, and the broker’s order history. If the three numbers match, you’re clean. If they don’t, the stage where they diverge is your bug, and you now know which of the causes above lives there.

The pattern underneath all of this is worth keeping. Pine controls whether a signal exists, the alert configuration controls how many times that signal gets announced, and the bridge controls what it finally becomes. A guard written in the first stage can’t fix a fault in the second or third. That’s exactly why a genuinely non-repainting strategy can still hand you two fills on one bar.

Working through a first live deployment? [Paper trading an automated strategy first](https://blog.pickmytrade.io/paper-trading-automated-strategy-test-before-going-live/) and [taking Pine Script to live trading](https://blog.pickmytrade.io/pine-script-to-live-trading/) both cover the handover in more depth. You can see which brokers and prop firms are supported on the [supported prop firms page](https://pickmytrade.io/supported-propfirms/), or read more [about the team](https://pickmytrade.io/about/) behind the platform.

---

_**Disclaimer:**  
This content is for informational purposes only and does not constitute financial, investment, or trading advice. Trading and investing in financial markets involve risk, and it is possible to lose some or all of your capital. Always perform your own research and consult with a licensed financial advisor before making any trading decisions. The mention of any proprietary trading firms, brokers, does not constitute an endorsement or partnership. Ensure you understand all terms, conditions, and compliance requirements of the firms and platforms you use._

---

Also Checkout: [Rithmic vs Tradovate vs CQG: Fees &amp; Latency Measured (2026)](https://blog.pickmytrade.io/rithmic-vs-tradovate-vs-cqg-fees-latency-measured-2026/)

**Automate Your TradingView Strategies**  
Connect your alerts with [PickMyTrade](https://pickmytrade.io "PickMyTrade") — automated trade execution, no coding required. [Start free →](https://pickmytrade.io/pricing)

For AI tools &amp; developers:[View Markdown →](https://blog.pickmytrade.io/non-repainting-strategy-still-fires-twice-heres-why.md)<!--pmtA1-clean-->