Indicator · Pine Script v6 · On the chart

BTC Master Window Analysis

by ShubhRanpara

This overlay indicator divides Bitcoin price history into repeating time windows measured in days, with an optional gap between windows and an optional custom start date that phase-locks each cycle.

View on GitHub

GitHub stars1on the repository
Pine versionv6current
Lines of code234
Settings8inputs
LicenceMIT
Last update3 months ago7 Jul 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.

Source Code

234 lines of Pine Script v6 from My_Pinescripts/Window_Analysis_Master_Script.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.

Window_Analysis_Master_Script.pine
//@version=6
indicator("BTC Master Window Analysis", overlay=true, max_boxes_count=500, max_lines_count=500, max_labels_count=500)

//=============================================================================
// INPUTS
//=============================================================================
// windowLengthDays generalizes the daily (1), weekly (7), and monthly (~30)
// scripts into one setting. gapDays controls the space between the end of
// one window and the start of the next: 0 = perfectly back-to-back.
windowLengthDays = input.int(30, "Window Length (Days)", minval=1, tooltip="1 = daily behavior, 7 = weekly behavior, ~30 = monthly behavior, or any custom number of days.")
gapDays = input.int(0, "Gap Between Windows (Days)", minval=0, tooltip="0 = next window starts exactly when the previous one ends. >0 = leaves that many days empty between windows.")

// Optional anchor: if enabled, every window is phase-locked to repeat from
// this exact date. E.g. anchor it to a Monday with a 7-day window and every
// window will land on a Monday. Anchor it to the 15th with a 30-day window
// and every window will land on the 15th. Leave disabled to keep the
// original behavior (first window starts on the chart's first bar).
useCustomStart = input.bool(true, "Use Custom Window Start Date")
customStartTime = input.time(timestamp("1990-01-01 00:00"), "Window Start Date", tooltip="Only used when 'Use Custom Window Start Date' is enabled. Windows repeat every (Window Length + Gap) days from this date.")

rangePercent = input.float(15.0, "Range % Above/Below Center", step=0.1)
midTolerance = input.float(0.1, "Middle Zone Tolerance %", step=0.05)

showBoxes = input.bool(true, "Show Historical Windows")
showMiddleLine = input.bool(true, "Show Middle Line")

//=============================================================================
// STORAGE
//=============================================================================
var int insideCount = 0
var int breakoutCount = 0
var int middleCount = 0
var int totalWindows = 0

var float currentUpperPrice = na
var float currentLowerPrice = na
var float currentMiddlePrice = na

var float previousUpper = na
var float previousLower = na
var float previousMiddle = na

var float previousWindowClose = na

var bool insideSignal = false
var bool breakoutSignal = false
var bool middleSignal = false

var label upperLabel = na
var label lowerLabel = na

//=============================================================================
// WINDOW SCHEDULING (this is what makes it timeframe-agnostic and gap-exact)
//=============================================================================
// Instead of counting calendar-day transitions (which can drift out of sync
// with real elapsed time whenever the data has any gaps), we schedule the
// next window's start as an exact millisecond timestamp and fire the moment
// a bar reaches it. This guarantees the gap is exactly "gapDays", even with
// weekends, holidays, or missing bars in between.
var int nextWindowStartTime = na

cycleLengthMs = (windowLengthDays + gapDays) * 24 * 60 * 60 * 1000

// One-time setup on the very first bar: if a custom anchor date is set, work
// out the correct phase-aligned boundary instead of just starting at the
// first bar. This is what lets windows land on a specific weekday / day of
// month / date, even though the chart's data might start mid-cycle.
if barstate.isfirst and useCustomStart
    if customStartTime <= time
        elapsed = time - customStartTime
        cyclesElapsed = math.floor(elapsed / cycleLengthMs)
        nextWindowStartTime := customStartTime + cyclesElapsed * cycleLengthMs
    else
        nextWindowStartTime := customStartTime

isWindowCreationDay = na(nextWindowStartTime) or time >= nextWindowStartTime

//=============================================================================
// RESET SIGNALS
//=============================================================================
insideSignal := false
breakoutSignal := false
middleSignal := false

//=============================================================================
// NEW WINDOW START (also closes/evaluates the previous window)
//=============================================================================
if isWindowCreationDay

    // Last completed bar before this window began (covers the window itself
    // plus any gap that preceded it)
    previousWindowClose := close[1]

    // Evaluate the window that just closed (skipped on the very first window,
    // since there is nothing to evaluate yet)
    if not na(previousUpper) and not na(previousWindowClose)

        middleUpper = previousMiddle * (1 + midTolerance / 100)
        middleLower = previousMiddle * (1 - midTolerance / 100)

        insideCondition = previousWindowClose <= previousUpper and previousWindowClose >= previousLower
        breakoutCondition = previousWindowClose > previousUpper or previousWindowClose < previousLower
        middleCondition = previousWindowClose >= middleLower and previousWindowClose <= middleUpper

        insideSignal := insideCondition
        breakoutSignal := breakoutCondition
        middleSignal := middleCondition

        totalWindows += 1

        if insideCondition
            insideCount += 1

        if breakoutCondition
            breakoutCount += 1

        if middleCondition
            middleCount += 1

    // First candle of the new window
    windowOpen = open

    currentMiddlePrice := windowOpen
    currentUpperPrice := windowOpen * (1 + rangePercent / 100)
    currentLowerPrice := windowOpen * (1 - rangePercent / 100)

    previousUpper := currentUpperPrice
    previousLower := currentLowerPrice
    previousMiddle := currentMiddlePrice

    windowStart = time
    windowEnd = windowStart + windowLengthDays * 24 * 60 * 60 * 1000

    // Schedule the next window. If an anchor is active, advance strictly by
    // whole cycle lengths from the anchor so the phase never drifts; the
    // window boundary itself still uses this bar's actual timestamp.
    nextWindowStartTime := windowEnd + gapDays * 24 * 60 * 60 * 1000

    if showBoxes
        box.new(
             left=windowStart,
             right=windowEnd,
             top=currentUpperPrice,
             bottom=currentLowerPrice,
             xloc=xloc.bar_time,
             bgcolor=color.new(color.blue, 88),
             border_color=color.blue,
             border_width=1)

    if showMiddleLine
        line.new(
             x1=windowStart,
             y1=currentMiddlePrice,
             x2=windowEnd,
             y2=currentMiddlePrice,
             xloc=xloc.bar_time,
             color=color.yellow,
             width=2,
             style=line.style_dashed)

//=============================================================================
// PLOTS
//=============================================================================
plot(currentUpperPrice, title="Upper", color=color.green, linewidth=2, trackprice=true)
plot(currentLowerPrice, title="Lower", color=color.red, linewidth=2, trackprice=true)
plot(currentMiddlePrice, title="Middle", color=color.yellow, linewidth=1)

//=============================================================================
// SIGNALS
//=============================================================================
plotshape(insideSignal, title="Inside", style=shape.circle, color=color.green, size=size.normal, location=location.abovebar)
plotshape(breakoutSignal, title="Breakout", style=shape.triangledown, color=color.red, size=size.normal, location=location.abovebar)
plotshape(middleSignal, title="Middle", style=shape.square, color=color.yellow, size=size.normal, location=location.abovebar)

//=============================================================================
// LABELS
//=============================================================================
if barstate.islast and not na(currentUpperPrice)
    label.delete(upperLabel)
    label.delete(lowerLabel)

    upperLabel := label.new(bar_index, currentUpperPrice, "Upper: " + str.tostring(currentUpperPrice, format.mintick), style=label.style_label_left, color=color.green, textcolor=color.white)
    lowerLabel := label.new(bar_index, currentLowerPrice, "Lower: " + str.tostring(currentLowerPrice, format.mintick), style=label.style_label_left, color=color.red, textcolor=color.white)

//=============================================================================
// STATISTICS
//=============================================================================
insidePercent = totalWindows > 0 ? insideCount * 100.0 / totalWindows : 0
breakoutPercent = totalWindows > 0 ? breakoutCount * 100.0 / totalWindows : 0
middlePercent = totalWindows > 0 ? middleCount * 100.0 / totalWindows : 0

//=============================================================================
// TABLE
//=============================================================================
var table statsTable = table.new(position.top_right, 4, 10, border_width=1)

if barstate.islast
    table.cell(statsTable, 0, 0, "Condition", bgcolor=color.blue, text_color=color.white)
    table.cell(statsTable, 1, 0, "Signal", bgcolor=color.blue, text_color=color.white)
    table.cell(statsTable, 2, 0, "Count", bgcolor=color.blue, text_color=color.white)
    table.cell(statsTable, 3, 0, "Percent", bgcolor=color.blue, text_color=color.white)

    table.cell(statsTable, 0, 1, "Inside")
    table.cell(statsTable, 1, 1, "●")
    table.cell(statsTable, 2, 1, str.tostring(insideCount))
    table.cell(statsTable, 3, 1, str.tostring(math.round(insidePercent, 2)) + "%")

    table.cell(statsTable, 0, 2, "Breakout")
    table.cell(statsTable, 1, 2, "▼")
    table.cell(statsTable, 2, 2, str.tostring(breakoutCount))
    table.cell(statsTable, 3, 2, str.tostring(math.round(breakoutPercent, 2)) + "%")

    table.cell(statsTable, 0, 3, "Middle")
    table.cell(statsTable, 1, 3, "■")
    table.cell(statsTable, 2, 3, str.tostring(middleCount))
    table.cell(statsTable, 3, 3, str.tostring(math.round(middlePercent, 2)) + "%")

    table.cell(statsTable, 0, 4, "Total Windows")
    table.cell(statsTable, 2, 4, str.tostring(totalWindows))

    table.cell(statsTable, 0, 5, "Window Length")
    table.cell(statsTable, 1, 5, str.tostring(windowLengthDays) + " day(s)")

    table.cell(statsTable, 0, 6, "Gap")
    table.cell(statsTable, 1, 6, str.tostring(gapDays) + " day(s)")

    table.cell(statsTable, 0, 7, "Range")
    table.cell(statsTable, 1, 7, "±" + str.tostring(rangePercent) + "%")

    table.cell(statsTable, 0, 8, "Anchor")
    table.cell(statsTable, 1, 8, useCustomStart ? "Custom" : "Auto")

    table.cell(statsTable, 0, 9, "Upper / Lower")
    table.cell(statsTable, 1, 9, str.tostring(currentUpperPrice, format.mintick) + " / " + str.tostring(currentLowerPrice, format.mintick))

Overview

For each window it sets a center and upper and lower bounds from a percentage range, plus a middle zone defined by a tolerance. It can draw historical window boxes and a middle line on the price chart and tracks inside, breakout, and middle outcomes. Window length, gap, range, and display toggles are user settings. No stop, target, or trade rules are included.

Details

Published by

ShubhRanpara on GitHub

Draws

On the price chart

Markets

Crypto

Timeframes

Any timeframe

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
Window Length (Days)int30windowLengthDays
Gap Between Windows (Days)int0gapDays
Use Custom Window Start DatebooltrueuseCustomStart
Window Start Datetimetimestamp("1990-01-01 00:00")customStartTime
Range % Above/Below Centerfloat15.0rangePercent
Middle Zone Tolerance %float0.1midTolerance
Show Historical WindowsbooltrueshowBoxes
Show Middle LinebooltrueshowMiddleLine
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

Sideway Zones Live

by dearvn
257 stars

Sideway Zones Live is an overlay indicator that estimates inner and outer sideways bands from recent highs and lows with a rational quadratic kernel. It tracks swing pivots over a loopback period and counts bars that remain between the outer high and low. Afte

Indicator v5 TrendSupport & resistance
Updated 7 weeks ago · None stated GitHub repository of Sideway Zones Live
228 stars

This indicator plots dynamic support and resistance levels on the price chart. It detects pivot highs and lows using the pivot length and tracks touches to build strength-based levels. Support and resistance zones appear as colored boxes while lines mark key l

Indicator v6 Support & resistanceBreakout
Updated 3 months ago · None stated GitHub repository of Dynamic Support & Resistance
220 stars

This indicator identifies High Of Low Price (HOLP) and Low Of High Price (LOHP) candlestick setups based on price extremes over a specified lookback period. A HOLP signal triggers when the current bar closes above the high of a recent session low, whereas a LO

Indicator v5 Candlestick patternsBreakout
Updated 1 year ago · None stated GitHub repository of Candlestick Patterns - HOLP-LOHP

Donchian Channels (DC)

by mihakralj
99 stars

This indicator calculates and plots Donchian Channels directly on the price chart. It determines the highest high and lowest low over a user-selected lookback period using an optimized monotonic deque algorithm, as well as a middle basis line computed as their

Indicator v6 Volatility & bandsSupport & resistance
Updated 4 weeks ago · Apache-2.0 GitHub repository of Donchian Channels (DC)

Lows from New Highs

by be-thomas
65 stars

This indicator tracks bar lows during consecutive rising highs using Pine Script arrays. When at least four lows accumulate or the price breaches the minimum low in the stack, the script sorts the recorded lows in ascending order and flushes them. It plots up

Indicator v4 Support & resistanceBreakout
Updated 6 days ago · GPL-3.0 GitHub repository of Lows from New Highs

This indicator tracks smart money market structure directly on the price chart. It calculates dual-period swing highs and swing lows to detect Changes of Character (CHoCH), Breaks of Structure (BOS), inducements, and liquidity sweeps. When structural levels ar

Indicator v5 SMC / ICT / price actionSupport & resistance
Updated 1 year ago · Apache-2.0 GitHub repository of Market Structure with Inducements & Sweeps [LuxAlgo]

More Support & resistance scripts

Related on ForexR

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers