ta.barssince in Pine Script: Event Counts and Correct Cooldowns
ta.barssince(condition) returns zero when the condition is true, then counts chart bars until it is true again. Before the first occurrence, it returns na. The count measures time since that event, not the age or strength of a trend.
Count a simple condition
The existing example below uses close >= open, so it resets on both up candles and dojis. It is not limited to strictly green candles:
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Pineify
//======================================================================//
// ____ _ _ __ //
// | _ \(_)_ __ ___(_)/ _|_ _ //
// | |_) | | '_ \ / _ \ | |_| | | | //
// | __/| | | | | __/ | _| |_| | //
// |_| |_|_| |_|\___|_|_| \__, | //
// |___/ //
//======================================================================//
//@version=6
indicator("[Pineify - Best Pine Script Generator] Bars Since Green Candle")
plot(ta.barssince(close >= open))
On an open candle, the close can move above and below the open. The current count can therefore change before the bar confirms. The function does not inherently read future bars or rewrite all closed-bar history when a new bar arrives.
Count a crossover
This example calculates the crossover and counter every bar:
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Pineify
//======================================================================//
// ____ _ _ __ //
// | _ \(_)_ __ ___(_)/ _|_ _ //
// | |_) | | '_ \ / _ \ | |_| | | | //
// | __/| | | | | __/ | _| |_| | //
// |_| |_|_| |_|\___|_|_| \__, | //
// |___/ //
//======================================================================//
//@version=6
indicator("[Pineify - Best Pine Script Generator] Bars Since MA Cross")
fastMA = ta.sma(close, 10)
slowMA = ta.sma(close, 30)
crossover = ta.crossover(fastMA, slowMA)
plot(ta.barssince(crossover))
A reading of two means the most recent upward cross occurred two chart bars ago. It does not say whether the averages remain bullish: a downward cross may have occurred since. Use a separate current-state condition if that distinction matters.
Why the old cooldown never fired
The earlier filter required the buy condition to be true while its own ta.barssince count exceeded 20. Those requirements conflict: on every true buy-condition bar, the counter is zero.
Also distinguish time since the last candidate from time since the last accepted signal. Rejected candidates should not restart the latter. This complete example tracks the bar of an accepted, confirmed signal explicitly:
//@version=6
indicator("Confirmed signals with an accepted-signal cooldown", overlay=true)
minimumBars = input.int(20, "Minimum bars between accepted signals", minval=1)
rsiValue = ta.rsi(close, 14)
candidate = ta.crossover(rsiValue, 30)
var int lastAcceptedBar = na
cooldownComplete = na(lastAcceptedBar) or bar_index - lastAcceptedBar >= minimumBars
accepted = barstate.isconfirmed and candidate and cooldownComplete
if accepted
lastAcceptedBar := bar_index
plotshape(accepted, title="Accepted signal", style=shape.triangleup, location=location.belowbar, color=color.green, size=size.small)
The first confirmed candidate is allowed. Later candidates need at least the selected number of chart bars since the accepted signal. This is an indicator demonstration, not an order strategy or evidence that a 20-bar delay improves results.
Missing values and trade duration
Replacing an initial na count with zero means “the event occurred now,” which differs from “it has never occurred.” Choose a fallback only when that meaning is intentional. If using a counter as a length, account for its initial missing value, the zero on an event bar, and the receiving function’s length constraints.
Counting bars since the position was flat is not an exact substitute for counting since a trade’s fill. Reversals and pyramiding may never pass through a flat calculation. For a particular open trade, use its recorded entry bar and define whether the fill bar counts as zero or one.
The former AAPL, SPY and TSLA personal results were unsupported. The examples explain event timing; they do not recommend a universal cooldown or a position size based on event age.
Sources checked October 20, 2026: TradingView function FAQ and strategy trade information.
