Consecutive Close Counter with Streak Statistics
This indicator counts and displays streaks of consecutive up and down closes, alongside a live statistics table showing current streak length, maximum streaks within a lookback period, and the frequency of streak changes. Traders and analysts use it to identify momentum persistence, detect trend breakdowns, and assess the statistical distribution of price direction changes within their chosen timeframe.
//@version=6
indicator("Consecutive Close Counter with Streak Statistics", overlay=false, max_bars_back=500)
// Inputs
lookbackBars = input(100, title="Lookback Period for Statistics", minval=10)
showTable = input(true, title="Show Statistics Table")
tablePos = input(position.top_right, title="Table Position")
// Direction: 1 = up close, -1 = down close, 0 = flat close
closeDir = close > close[1] ? 1 : (close < close[1] ? -1 : 0)
// Calculate consecutive streak length
streakLength = 0
if closeDir != 0
if closeDir == closeDir[1]
streakLength := nz(streakLength[1]) + 1
else
streakLength := 1
else
streakLength := nz(streakLength[1])
// Separate up and down streaks (one is zero each bar)
upStreak = closeDir == 1 ? streakLength : 0
dnStreak = closeDir == -1 ? streakLength : 0
// Plot current streaks symmetrically around zero
plot(upStreak, title="Up Streak", color=color.new(color.green, 20), linewidth=2)
plot(-dnStreak, title="Down Streak", color=color.new(color.red, 20), linewidth=2)
hline(0, color=color.gray, linestyle=hline.style_dashed, linewidth=1)
// Calculate statistics over lookback period
maxUpStreak = ta.highest(upStreak, lookbackBars)
maxDnStreak = ta.highest(dnStreak, lookbackBars)
// Count streak transitions (when direction changes from non-zero to different non-zero)
streakChange = closeDir != closeDir[1] and closeDir != 0 ? 1 : 0
streakChangeCount = ta.sum(streakChange, lookbackBars)
// Statistics table
if showTable
var tbl = table.new(tablePos, 2, 6, border_color=color.gray, border_width=1,
frame_color=color.gray, frame_width=1)
if barstate.islast
table.cell(tbl, 0, 0, "Metric", text_color=color.white, bgcolor=color.gray,
text_size=size.small)
table.cell(tbl, 1, 0, "Value", text_color=color.white, bgcolor=color.gray,
text_size=size.small)
table.cell(tbl, 0, 1, "Current Up", text_color=color.black,
bgcolor=color.new(color.green, 80), text_size=size.small)
table.cell(tbl, 1, 1, str.tostring(upStreak), text_color=color.black,
bgcolor=color.new(color.green, 80), text_size=size.small)
table.cell(tbl, 0, 2, "Current Down", text_color=color.black,
bgcolor=color.new(color.red, 80), text_size=size.small)
table.cell(tbl, 1, 2, str.tostring(dnStreak), text_color=color.black,
bgcolor=color.new(color.red, 80), text_size=size.small)
table.cell(tbl, 0, 3, "Max Up (" + str.tostring(lookbackBars) + ")",
text_color=color.black, bgcolor=color.new(color.green, 90), text_size=size.small)
table.cell(tbl, 1, 3, str.tostring(maxUpStreak), text_color=color.black,
bgcolor=color.new(color.green, 90), text_size=size.small)
table.cell(tbl, 0, 4, "Max Down (" + str.tostring(lookbackBars) + ")",
text_color=color.black, bgcolor=color.new(color.red, 90), text_size=size.small)
table.cell(tbl, 1, 4, str.tostring(maxDnStreak), text_color=color.black,
bgcolor=color.new(color.red, 90), text_size=size.small)
table.cell(tbl, 0, 5, "Direction Changes", text_color=color.black,
bgcolor=color.new(color.blue, 90), text_size=size.small)
table.cell(tbl, 1, 5, str.tostring(streakChangeCount), text_color=color.black,
bgcolor=color.new(color.blue, 90), text_size=size.small)
How the code works
The indicator compares each close to the previous close to determine direction: 1 for up (higher close), -1 for down (lower close), or 0 for unchanged. It then counts consecutive bars in the same direction by checking if the current direction matches the prior bar's direction. If they match, it increments the running counter; if they differ, it resets to 1. Up streaks display above zero as green columns; down streaks display below zero as red columns, creating a symmetrical visualization.
The statistics table updates only on the final bar of each candle (barstate.islast) to avoid repainting. It shows the current streak length in both directions, the maximum streak length observed within the lookback period using ta.highest(), and the count of direction changes by summing transitions over that period. The lookback period is user-configurable (default 100 bars), allowing adaptation to different trading timeframes.
Reading it on a chart
A rising green column indicates consecutive up closes, with the height showing how many bars in a row closed higher than the previous bar. A falling red column (plotted below zero) shows consecutive down closes. When a column drops to zero, the streak has ended and direction is reversing or flat. The table at top-right updates in real time, always showing the latest streak lengths and maximums. Spikes in the Max Up or Max Down values signal periods of strong directional momentum. A high Direction Changes count relative to the lookback bars indicates choppy, mean-reverting price action; a low count suggests sustained trends. Traders watch for current streaks approaching or exceeding the historical maximum as potential momentum exhaustion signals.
Limitations
This indicator uses closing prices only and ignores intra-bar wicks or volume context, missing potential rejections signaled by high-low ranges. The threshold for direction is a single tick of price movement; a close 0.01 higher than the previous close counts as a full "up" streak, which may overstate conviction in low-volatility assets. The lookback period is fixed across all bars; it does not adapt to market regime, so in choppy markets the max streak statistic may be stale compared to the most recent volatility. The indicator repaints if candles have not yet closed when you place a trade on the current bar, though barstate.islast limits refreshes to bar-close only. It reveals nothing about size, strength, or probability of continuation; ten consecutive up closes on declining volume carries different weight than ten on increasing volume, information this counter does not capture. Finally, streak statistics are sensitive to the exact timeframe and asset chosen: a 1-minute chart will show frequent short streaks, while a daily chart may show streaks of 20+ bars, making cross-timeframe comparisons misleading.
Key definitions
Consecutive closes: A run of closing prices that each close higher (or lower) than the previous close, with no direction reversal or flat close interrupting the sequence.
Streak length: The integer count of bars in the current run of closes in one direction (up or down).
Lookback period: The number of prior bars scanned to compute maximum streak length and direction change frequency; default is 100.
Momentum exhaustion: A colloquial trading concept suggesting that a streak nearing or matching its historical maximum may be near a reversal; not a statistically validated rule.
Direction change: A bar in which the close direction (up, down, or flat) differs from the prior bar's direction.
Repainting: A visual artifact where a plot updates intra-bar before the candle closes; this indicator's table only refreshes at barstate.islast to minimize this.
References
- TradingView, "Pine Script v6 Reference Manual: ta.highest()", TradingView. Https://www.tradingview.com/pine-script-reference/v6/#fun_ta.highest
- TradingView, "Pine Script v6 Reference Manual: barstate.islast", TradingView. Https://www.tradingview.com/pine-script-reference/v6/#var_barstate.islast
- Bulkowski, Thomas N., "Encyclopedia of Chart Patterns", 2nd ed. (2005). Discussion of trend exhaustion patterns and their limitations.
Educational research on historical data only. Not investment advice, not a signal, and never a performance promise. Past results do not predict future performance. Every reference is link-verified before publication and every paper is re-audited weekly against the library's editorial standard.
Last reviewed by the PropLedger research pipeline: 2026-09-27. Educational research on historical data, not financial advice.
Keep reading
Trend Day vs Range Day Classifier
Free open-source Pine Script indicator: trend day vs range day classifier (early session heuristics). Full code and a plain-English walkthrough.
Futures Contract Roll and Expiry Week Shading
Free open-source Pine Script indicator: contract roll and expiry week shading for futures. Full code and a plain-English walkthrough.
Value Area and Point of Control
Free open-source Pine Script indicator: value area and point of control from session volume. Full code and a plain-English walkthrough.