Scripts

Daytrading banner

ADX

//@version=6
indicator("ADX_RD", format=format.price, precision=2, timeframe="", timeframe_gaps=true)

// ADX_RD - Average Directional Index (Ryan DeBraal)
// This indicator provides a complete visualization of trend strength and directional pressure
// using the classic ADX system with Wilder smoothing. It plots the ADX line along with the
// +DI (bullish pressure) and -DI (bearish pressure) lines to show both the strength and the
// dominant side of the market. The script enhances the standard ADX toolkit by adding dynamic
// line styling, adjustable smoothing, opacity control, and visual thresholds that help traders
// quickly assess whether a trend is worth trading.
//
// OVERVIEW
// ADX (Average Directional Index) measures the strength of a trend, regardless of whether
// the trend is moving up or down. By itself, ADX does not indicate direction. Instead, it
// quantifies how strong the current move is. The companion lines — +DI and -DI — indicate
// which side (buyers or sellers) is currently exerting more directional force.
//
// HOW IT WORKS
// - +DI rises when price makes stronger upward moves (higher highs).
// - -DI rises when price makes stronger downward moves (lower lows).
// - ADX rises when either side is pushing strongly and the market is becoming directional.
//   It falls when price movement becomes weak, noisy, or range-bound.
//
// ENHANCED FEATURES
// - Wilder-smoothing of +DI, -DI, and ADX for consistent trend-strength measurement.
// - Configurable threshold level (default 20), widely used to separate weak markets from
//   trending ones. When ADX remains below this threshold, conditions are often choppy.
// - Automatic color shifting of the ADX line:
//       ADX < threshold → white (weak or no trend)
//       ADX >= threshold → yellow (trend developing or strong)
// - Adaptive line thickness behavior: the ADX line becomes thicker when the trend is strong,
//   helping visually highlight actionable conditions.
// - Optional display of +DI and -DI lines, each rendered with adjustable opacity so they can
//   either stand out or stay subtle depending on the trader's preference.
// - Horizontal dotted reference line at the threshold for quick visual anchoring.
// - All smoothing lengths and display parameters can be customized.
//
// PURPOSE AND TRADING USE
// The goal of this indicator is to let traders quickly answer two questions:
//   1. Is the market trending or flat?
//   2. If trending, who is in control: buyers or sellers?
// ADX_RD is especially useful when:
// - Confirming breakouts (ADX rising above threshold)
// - Filtering entries for trend-following strategies
// - Avoiding low-probability trades during sideways or volatile chop
// - Pairing with MACD, EMA, RSI, VWAP, or price-action setups as a final trend-strength filter
//
// IMPORTANT NOTES
// - ADX measures *strength*, not direction.
// - Direction comes from +DI and -DI:
//       +DI above -DI → bullish pressure dominant
//       -DI above +DI → bearish pressure dominant
// - High ADX with a clean DI separation typically indicates the strongest opportunities.
// - Low ADX implies signals from other indicators may fail due to lack of trend.
//
// In short, ADX_RD provides a clean, enhanced visualization of trend conditions, helping traders
// avoid chop, focus on strong directional setups, and make more disciplined entries.

// Inputs
lineThickness = input.int(1, "ADX Line Thickness")
adxlen = input.int(14, "ADX Smoothing")
dilen = input.int(14, "DI Length")
showDI = input.bool(true, "Show +DI / -DI Lines")

// Directional Movement and DI calculation
dirmov(len) =>
    up = ta.change(high)
    down = -ta.change(low)
    plusDM = na(up) ? na : (up > down and up > 0 ? up : 0)
    minusDM = na(down) ? na : (down > up and down > 0 ? down : 0)
    truerange = ta.rma(ta.tr, len)
    plus = fixnan(100 * ta.rma(plusDM, len) / truerange)
    minus = fixnan(100 * ta.rma(minusDM, len) / truerange)
    [plus, minus]

// ADX calculation using Wilder smoothing
adx(dilen, adxlen) =>
    [plus, minus] = dirmov(dilen)
    sum = plus + minus
    adx = 100 * ta.rma(math.abs(plus - minus) / (sum == 0 ? 1 : sum), adxlen)

// Get DI and ADX values
[plusDI, minusDI] = dirmov(dilen)
sig = adx(dilen, adxlen)

// Dynamic color: white if below 20, yellow if above
sigColor = sig < 20 ? color.new(color.white, 95) : color.yellow

// ADX plot
plot(sig, color=sigColor, title="ADX", linewidth=lineThickness * 2)

// +DI / -DI plots (optional)
plot(showDI ? plusDI : na, title="+DI", color=color.new(color.green, 0), linewidth=1)
plot(showDI ? minusDI : na, title="-DI", color=color.new(color.red, 0), linewidth=1)

// Horizontal dotted line at 20
hline(20, "Threshold 20", color=color.gray, linestyle=hline.style_dotted, linewidth=1)


Fair Price VWAP

//@version=6
indicator("FAIRPRICE_VWAP_RD", overlay = true)

// FAIRPRICE_VWAP_RD
// This script plots an **anchored VWAP (Volume Weighted Average Price)** that resets
// based on the user-selected anchor period. It acts as a dynamic “fair value” line
// that reflects where the market has actually transacted during the chosen period.
//
// FEATURES
// - Multiple anchor options: Session, Week, Month, Quarter, Year, Decade, Century,
//   Earnings, Dividends, or Splits.
// - Intelligent handling of the “Session” anchor so it works correctly on both 1m
//   (resets each new day) and 1D (continuous, non-resetting VWAP).
// - Manual VWAP calculation using cumulative(price * volume) and cumulative(volume),
//   ensuring the line is stable and works on all timeframes.
// - Optional hiding of VWAP on daily or higher charts.
// - Offset input for horizontal shifting if desired.
// - VWAP provides a true “fair price” reference for trend, mean-reversion,
//   and institutional-level analysis.
//
// PURPOSE
// This indicator solves the common problem of VWAP behaving incorrectly on higher
// timeframes, on synthetic data, or with unusual anchors. By implementing VWAP
// manually and allowing flexible reset conditions, it functions reliably as
// an institutional-style fair value benchmark across any timeframe.

// Inputs
lineThickness = input.int(1)
hideonDWM = input.bool(false, title = "Hide VWAP on 1D or Above")
anchor    = input.string(defval = "Session", title  = "Anchor Period", options = ["Session", "Week", "Month", "Quarter", "Year", "Decade", "Century", "Earnings", "Dividends", "Splits"])
src    = input(hlc3, title = "Source")
offset = input.int(0, title = "Offset (bars, usually 0)", minval = 0)

//---------------------
// Volume check
//---------------------
cumVolume = ta.cum(volume)
if barstate.islast and cumVolume == 0
    runtime.error("No volume is provided by the data vendor.")

//---------------------
// Anchor logic
//---------------------
new_earnings  = request.earnings(syminfo.tickerid, earnings.actual,
                                 barmerge.gaps_on, barmerge.lookahead_on, ignore_invalid_symbol = true)
new_dividends = request.dividends(syminfo.tickerid, dividends.gross,
                                  barmerge.gaps_on, barmerge.lookahead_on, ignore_invalid_symbol = true)
new_split     = request.splits(syminfo.tickerid, splits.denominator,
                               barmerge.gaps_on, barmerge.lookahead_on, ignore_invalid_symbol = true)

// Special handling for "Session" so it works on both 1m and 1D
sessNew =
     timeframe.isintraday ? timeframe.change("D") :    // intraday: reset each new day
     timeframe.isdaily    ? false                :    // daily: no reset, full-history VWAP
                           false

isNewPeriod = switch anchor
    "Earnings"  => not na(new_earnings)
    "Dividends" => not na(new_dividends)
    "Splits"    => not na(new_split)
    "Session"   => sessNew
    "Week"      => timeframe.change("W")
    "Month"     => timeframe.change("M")
    "Quarter"   => timeframe.change("3M")
    "Year"      => timeframe.change("12M")
    "Decade"    => timeframe.change("12M") and year % 10 == 0
    "Century"   => timeframe.change("12M") and year % 100 == 0
    => false

isEsdAnchor = anchor == "Earnings" or anchor == "Dividends" or anchor == "Splits"

// On the very first bar, force a reset (for non-E/D/S anchors)
if na(src[1]) and not isEsdAnchor
    isNewPeriod := true

//---------------------
// Manual anchored VWAP
//---------------------
var float cumPV  = na
var float cumVol = na
float vwapValue  = na

if not (hideonDWM and timeframe.isdwm)
    if isNewPeriod or na(cumVol)
        // Reset VWAP at new anchor
        cumPV  := src * volume
        cumVol := volume
    else
        cumPV  += src * volume
        cumVol += volume

    vwapValue := cumVol != 0 ? cumPV / cumVol : na

//---------------------
// Plot: VWAP line
//---------------------
plot(vwapValue, title = "VWAP", color = color.new(color.aqua, 50), offset = offset, linewidth = lineThickness)

RSI

//@version=6
indicator("RSI_RD", format=format.price, timeframe="", timeframe_gaps=true)

// RSI_RD - RSI Divergence Detector (Ryan DeBraal)
// This script plots a standard RSI along with advanced automatic divergence detection.
// It identifies four types of divergences using pivot logic and configurable
// lookback windows. Signals appear directly on the RSI line as plotted marks and labels.
//
// FEATURES
// - Standard RSI with user-defined length and source.
// - Midline (50), overbought (70), and oversold (30) levels with shaded background.
// - Automatic detection of:
//       • Regular Bullish Divergence
//       • Regular Bearish Divergence
//       • Hidden Bullish Divergence
//       • Hidden Bearish Divergence
// - Each divergence type can be toggled on/off individually.
// - Pivot-based detection using left/right lookback lengths.
// - Range filter (bars since pivot) to avoid stale or invalid divergences.
// - Colored markers and labels placed exactly on pivot points.
// - Alerts for all four divergence conditions.
//
// PURPOSE
// This indicator makes RSI divergence trading systematic and visual.
// It highlights when price action disagrees with RSI momentum — often signaling
// exhaustion, reversal setups, or continuation opportunities depending on the divergence type.
// Ideal for combining with trend filters, VWAP, or ORB structures.

// Inputs
lineThickness = input.int(2)
len = input.int(title="RSI Period", minval=1, defval=14)
src = input(title="RSI Source", defval=close)
lbR = input(title="Pivot Lookback Right", defval=5, display = display.data_window)
lbL = input(title="Pivot Lookback Left", defval=5, display = display.data_window)
rangeUpper = input(title="Max of Lookback Range", defval=60, display = display.data_window)
rangeLower = input(title="Min of Lookback Range", defval=5, display = display.data_window)
plotBull = input(title="Plot Bullish", defval=true, display = display.data_window)
plotHiddenBull = input(title="Plot Hidden Bullish", defval=false, display = display.data_window)
plotBear = input(title="Plot Bearish", defval=true, display = display.data_window)
plotHiddenBear = input(title="Plot Hidden Bearish", defval=false, display = display.data_window)

bearColor = color.red
bullColor = color.green
hiddenBullColor = color.new(color.green, 80)
hiddenBearColor = color.new(color.red, 80)
textColor = color.white
noneColor = color.new(color.white, 100)
aboveColor = color.blue
belowColor = color.blue
// RSI
osc = ta.rsi(src, len)
// green above 50, red below 50
rsiColor = osc >= 50 ? aboveColor : belowColor

plot(osc, "RSI", color=rsiColor, linewidth=lineThickness)
hline(50, "Middle Line", #787B86, hline.style_dotted)
obLevel = hline(70, "Overbought", #787B86, hline.style_dotted)
osLevel = hline(30, "Oversold", #787B86, hline.style_dotted)
fill(obLevel, osLevel, color=color.rgb(33, 150, 243, 90))

// Pivots
plFound = not na(ta.pivotlow(osc, lbL, lbR))
phFound = not na(ta.pivothigh(osc, lbL, lbR))

_inRange(cond) =>
    bars = ta.barssince(cond)
    rangeLower <= bars and bars <= rangeUpper

//------------------------------------------------------------------------------
// Regular Bullish
inRangePl = _inRange(plFound[1])
oscHL = osc[lbR] > ta.valuewhen(plFound, osc[lbR], 1) and inRangePl
priceLL = low[lbR] < ta.valuewhen(plFound, low[lbR], 1)
bullCondAlert = priceLL and oscHL and plFound
bullCond = plotBull and bullCondAlert

plot(plFound ? osc[lbR] : na, "Regular Bullish", color=bullCond ? bullColor : noneColor, offset=-lbR, display=display.pane, editable=plotBull)

//------------------------------------------------------------------------------
// Hidden Bullish
oscLL = osc[lbR] < ta.valuewhen(plFound, osc[lbR], 1) and inRangePl
priceHL = low[lbR] > ta.valuewhen(plFound, low[lbR], 1)
hiddenBullCondAlert = priceHL and oscLL and plFound
hiddenBullCond = plotHiddenBull and hiddenBullCondAlert

plot(plFound ? osc[lbR] : na, "Hidden Bullish", color=hiddenBullCond ? hiddenBullColor : noneColor, offset=-lbR, display=display.pane, editable=plotHiddenBull)

//------------------------------------------------------------------------------
// Regular Bearish
inRangePh = _inRange(phFound[1])
oscLH = osc[lbR] < ta.valuewhen(phFound, osc[lbR], 1) and inRangePh
priceHH = high[lbR] > ta.valuewhen(phFound, high[lbR], 1)
bearCondAlert = priceHH and oscLH and phFound
bearCond = plotBear and bearCondAlert

plot(phFound ? osc[lbR] : na, "Regular Bearish", color=bearCond ? bearColor : noneColor, offset=-lbR, display=display.pane, editable=plotBear)

//------------------------------------------------------------------------------
// Hidden Bearish
oscHH = osc[lbR] > ta.valuewhen(phFound, osc[lbR], 1) and inRangePh
priceLH = high[lbR] < ta.valuewhen(phFound, high[lbR], 1)
hiddenBearCondAlert = priceLH and oscHH and phFound
hiddenBearCond = plotHiddenBear and hiddenBearCondAlert

plot(phFound ? osc[lbR] : na, "Hidden Bearish", color=hiddenBearCond ? hiddenBearColor : noneColor, linewidth=2, offset=-lbR, display=display.pane, editable=plotHiddenBear)

// Alerts
alertcondition(bullCondAlert, "Regular Bullish Divergence", "Regular Bullish Divergence")
alertcondition(hiddenBullCondAlert, "Hidden Bullish Divergence", "Hidden Bullish Divergence")
alertcondition(bearCondAlert, "Regular Bearish Divergence", "Regular Bearish Divergence")
alertcondition(hiddenBearCondAlert, "Hidden Bearish Divergence", "Hidden Bearish Divergence")

MACD

//@version=6
indicator("MACD_RD", timeframe="", timeframe_gaps=true)

// MACD_RD - Moving Average Convergence Divergence (Ryan DeBraal)
// This indicator plots a standard MACD along with a color-adaptive histogram and
// integrated momentum-shift alerts. It preserves the normal MACD structure while
// improving visual clarity and signal recognition.
//
// FEATURES
// -----------------------------------------------------------------------------
// • Standard MACD Calculation
//     - Fast MA (12 by default)
//     - Slow MA (26)
//     - Signal line (9)
//     - Choice between SMA/EMA for both MACD and Signal smoothing
//
// • Color-Changing Histogram
//     - Green shades for positive momentum
//     - Red shades for negative momentum
//     - Lighter/darker tones depending on whether momentum is increasing or fading
//     - 50% opacity for improved readability
//
// • Crossover-Based MACD Line Coloring
//     - MACD line turns green on bullish cross (MACD > Signal)
//     - MACD line turns red on bearish cross (MACD < Signal)
//     - Default blue when no crossover occurs
//
// • Momentum-Shift Alerts
//     - Alerts when histogram flips direction
//
// PURPOSE
// -----------------------------------------------------------------------------
// This MACD version emphasizes momentum shifts and trend transitions by
// highlighting subtle histogram changes and providing clean crossover visuals.
// Ideal for:
//      • Identifying early momentum reversals
//      • Filtering breakout/trend setups
//      • Confirming trend continuation vs exhaustion

// Inputs
lineThickness = input.int(2)
fast_length   = input.int(title="Fast Length", defval=12)
slow_length   = input.int(title="Slow Length", defval=26)
src           = input(title="Source", defval=close)
signal_length = input.int(title="Signal Smoothing", minval=1, maxval=50, defval=9, display=display.data_window)
sma_source    = input.string(title="Oscillator MA Type", defval="EMA", options=["SMA","EMA"], display=display.data_window)
sma_signal    = input.string(title="Signal Line MA Type", defval="EMA", options=["SMA","EMA"], display=display.data_window)

// MACD Calculations
fast_ma = sma_source == "SMA" ? ta.sma(src, fast_length) : ta.ema(src, fast_length)
slow_ma = sma_source == "SMA" ? ta.sma(src, slow_length) : ta.ema(src, slow_length)
macd = fast_ma - slow_ma
signal = sma_signal == "SMA" ? ta.sma(macd, signal_length) : ta.ema(macd, signal_length)
hist = macd - signal

// Histogram reversal alerts
alertcondition(hist[1] >= 0 and hist < 0, title="Rising to falling", message="MACD histogram switched from rising to falling")
alertcondition(hist[1] <= 0 and hist > 0, title="Falling to rising", message="MACD histogram switched from falling to rising")

// Zero line
hline(0, "Zero Line", color=color.new(#787B86, 50))

// Histogram with opacity 50%
plot(hist, title="Histogram", style=plot.style_columns,
     color=color.new(hist >= 0 ? (hist[1] < hist ? #26A69A : #B2DFDB)
                               : (hist[1] < hist ? #FFCDD2 : #FF5252), 80))

// MACD crossover logic
bullCross = ta.crossover(macd, signal)
bearCross = ta.crossunder(macd, signal)

// MACD line color on crossovers
macdColor = bullCross ? color.new(color.white, 0) : bearCross ? color.new(color.white, 0) : color.new(color.orange, 0)

// Plot MACD and Signal
plot(macd,   title="MACD",   color=macdColor, linewidth=lineThickness)
plot(signal, title="Signal", color=color.new(color.gray, 0), linewidth=lineThickness)

Trend 34 EMA

//@version=6
indicator("TREND_34EMA_RD", overlay = true)

// TREND_34EMA_RD — Enhanced 34 EMA Trend Suite (Ryan DeBraal)

// DESCRIPTION
//--------------------------------------------------------------------------------------------------
// This indicator visualizes market trend behavior using a trend-adaptive 34-period EMA combined
// with ATR-based volatility analysis, trend-strength grading, and optional crossover signals.
// It is designed to deliver a fast, intuitive read on market direction, momentum quality,
// and volatility conditions.
//
// FEATURES
//--------------------------------------------------------------------------------------------------
// • 34 EMA Trend Line
//     - Standard 34-period exponential moving average
//     - Clean aqua color scheme for immediate visibility
//     - Adjustable line thickness
//
// • Trend Strength Grading
//     - Measures the absolute percent distance between price and the 34 EMA
//     - Converts trend strength into a letter grade (A through F) or percent distance
//     - Grade scale based on realistic 34-EMA deviation thresholds
//     - Auto-updates on the last bar with a color-coded label:
//         • Gray  = weak trend
//         • Orange = moderate trend
//         • Green  = strong trend
//
// • Optional Crossover Signals
//     - Detects when price crosses above or below the 34 EMA
//     - Displays up/down arrows at crossover points
//     - Includes built-in alert conditions for bullish and bearish crossovers
//
// PURPOSE
//--------------------------------------------------------------------------------------------------
// This tool provides a clear, minimalistic framework for monitoring:
//     • Early trend shifts
//     • Trend continuation
//     • Trend strength and momentum quality
//     • Price over-extension via volatility bands
//
// The indicator is ideal for traders seeking a clean, high-signal trend-reading tool suited for
// discretionary, algorithmic, or confirmation-based trading approaches.

// Inputs
lineThickness = input.int(1)
emaLength = input.int(34, "EMA Length", minval = 1)
showTrendLabel = input.bool(true, "Show Trend Strength Label")
labelMode = input.string("Grade", "Label Mode", options = ["Grade", "Percent"])
showCrossMarks = input.bool(false, "Show Crossover Arrows")

// EMA
emaLine = ta.ema(close, emaLength)
plot(emaLine, "34 EMA", color.new(color.orange, 50), lineThickness)

// Trend Strength (distance from EMA)
distancePct = emaLine != 0 ? math.abs(close - emaLine) / emaLine * 100.0 : 0.0

// Grade mapping
grade = distancePct >= 20 ? "A" : distancePct >= 14 ? "A-" : distancePct >= 11 ? "B+" : distancePct >= 8.5 ? "B" : distancePct >= 6.5 ? "B-" : distancePct >= 5 ? "C+" : distancePct >= 3.5 ? "C" : distancePct >= 2.5 ? "C-" : distancePct >= 1.5 ? "D+" : distancePct >= 0.75 ? "D" : distancePct >= 0.25 ? "D-" : "F"

// Label color
labelColor = distancePct < 2.5 ? color.new(color.gray, 10) : distancePct < 6.5 ? color.new(color.orange, 0) : color.new(color.green, 0)

// Trend label
var label trendLabel = na
if showTrendLabel and barstate.islast
    if not na(trendLabel)
        label.delete(trendLabel)
    labelText = labelMode == "Percent" ? str.tostring(distancePct, "#.0") + "%" : grade
    trendLabel := label.new(bar_index, emaLine, labelText, style=label.style_label_left, color=labelColor, textcolor=color.white, size=size.small)

// Crossovers
bullCross = ta.crossover(close, emaLine)
bearCross = ta.crossunder(close, emaLine)
plotshape(showCrossMarks and bullCross, title="Bullish", color=color.new(color.green, 0), style=shape.triangleup, location=location.belowbar, size=size.tiny)
plotshape(showCrossMarks and bearCross, title="Bearish", color=color.new(color.red, 0), style=shape.triangledown, location=location.abovebar, size=size.tiny)

// Alerts
alertcondition(bullCross, "Bullish EMA Crossover", "Price crossed ABOVE the 34 EMA")
alertcondition(bearCross, "Bearish EMA Crossover", "Price crossed BELOW the 34 EMA")

ORB

//@version=6
indicator("ORB_RD", overlay = true)

// ORB_RD - Opening Range Box (Ryan DeBraal)
// This indicator automatically draws a high/low box for the first portion of
// each trading day, stepping the range window from 15 to 30 minutes after
// the session starts. The box updates live as the range forms, then
// optionally extends across the rest of the session.
//
// FEATURES
// -----------------------------------------------------------------------------
// • Opening Range Detection
//     - Automatically ladders the range window: 0-15, then 0-30 minutes
//     - Automatic reset at each new trading day
//     - Live high/low updates while inside the 0-30 minute window
//
// • Auto-Drawing Range Box
//     - Draws a dynamic rectangle as the range forms
//     - Top and bottom update with every new high/low
//     - Extends sideways in real time during formation
//     - Optional full-day extension after the 30-minute range finalizes
//
// • Customizable Visuals
//     - Adjustable fill transparency
//     - Mild green tint by default for clarity
//
// PURPOSE
// -----------------------------------------------------------------------------
// This tool highlights the evolving opening range, a widely used intraday
// reference for breakout traders, mean-reversion setups, and session structure
// analysis. Ideal for:
//      • Identifying early support and resistance
//      • Framing breakout and pullback decisions
//      • Tracking intraday trend bias after the morning range

extend_today = input.bool(true, "Extend today's box across day")
fill_transp  = input.int(95, "Box transparency", minval = 0, maxval = 100)
box_color    = color.new(color.green, 80)

var int   first_bar_index = na
var int   day_start_ts    = na
var float rng_hi          = na
var float rng_lo          = na
var box   rng_box         = na

new_day = ta.change(time("D")) != 0

if new_day
    // New day starts: clear old box and start a new 0-15 minute laddered window
    if not na(rng_box)
        box.delete(rng_box)
        rng_box := na
    first_bar_index := bar_index
    rng_hi          := high
    rng_lo          := low
    day_start_ts    := time

// Compute elapsed minutes since the first bar of the day
elapsed_ms  = not na(day_start_ts) ? time - day_start_ts : 0
elapsed_min = elapsed_ms / 60000.0

// Active opening range window: update from 0-15 and 0-30 minutes
in_window = elapsed_min <= 30

if in_window
    // While inside the first 30 minutes, keep updating the growing range
    rng_hi := na(rng_hi) ? high : math.max(rng_hi, high)
    rng_lo := na(rng_lo) ? low  : math.min(rng_lo, low)

    if na(rng_box)
        rng_box := box.new(left = first_bar_index, top = rng_hi, right = bar_index, bottom = rng_lo, xloc = xloc.bar_index, border_color = box_color, bgcolor = color.new(box_color, fill_transp))
    else
        box.set_top(rng_box, rng_hi)
        box.set_bottom(rng_box, rng_lo)
        box.set_right(rng_box, bar_index)

// After the 30-minute window ends, just extend the finalized box to the right if desired
if extend_today and not na(rng_box) and not in_window
    box.set_right(rng_box, bar_index)