Repaints Welkin's Ultimate VWAP – with added Quarterly, Yearly & Multi-Year Anchors For ThinkOrSwim

Repaints

dart966

Member
VIP
Ultimate VWAP v4.3 – an update to Welkin's indicator

5JRkuOI.png


First and foremost, all credit goes to Welkin. His work with volume on this forum has shaped how I read charts. He hasn't been around in a long time, and his contributions are missed. I hope he's doing well.

The Ultimate VWAP is a valuable indicator because it shows where the volume actually traded, not just where price has been. The deviation bands make it easy to see at a glance when price has stretched far from that fair value, and seeing the MTF VWAPs together gives intraday, swing, and longer-term context in a single study.

Over time I've been updating the code, and I wanted to share it back with the community that made it possible. The core is still Welkin's original "Ultimate VWAP Indicator."

These are additions on top of his foundation:
  • Longer anchors: Quarterly, Yearly, and 2–5 Year VWAPs, so the bands work on weekly and monthly charts
  • Start-of-period guard: bands wait a few bars into each new period instead of showing a false extreme on the first bar
  • Cleaner alerts: an option to alert only after a bar closes across a level
  • Squeeze chips: these switch off on charts where they'd only repeat the chart-timeframe squeeze
Works well with VPA (Volume Price Analysis). This VIP Market Phase / VSA Candle Painting Indicator by @merryDay is a good one to use.

The code and a short quick-start guide are attached. Thank you, Welkin.

Code:
# Updated: 2026-09-29
#VWAP Deviation Bands
#VWAP DAILY x WEEKLY AND WEEKLY x MONTHLY 2nd deviation CROSSOVER CLOUDS
#VWAP Alerts
#Paint VWAP or Candlesticks according to Heiken Ashi Trend
#Bollinger and Keltner MTF Squeeze Clouds
#originally created by [email protected]
#version 7.29.2020 Welkin
#version 5.30.2026 dart966
#version 6.06.2026 v3 dart966 (finally started adding comments on edits in this version) - deviation-cloud/DevBW anchor follows vwapAggregation;
#  HA2 clamped to chart TF + warning; weekly/monthly band hiding aligned.
#version 6.11.2026 v4 dart966 - audit rewrite:
#  PERF: 16 deviation-band reference-VWAP calls replaced by exact arithmetic
#        (band_k = center +/- k*sigma, sigma = (UpperBand2 - VWAP)/2). Values
#        are identical to v3; study-engine load drops from ~26 reference
#        instantiations to 9 accesses across 3 timeframes.
#  PERF: chart-TF secondary-aggregation self-calls (HA1, Sqz1) replaced with
#        native open/high/low/close. Dead HA high/low recursion removed.
#  CORRECTNESS: HA recursion seed hardened to current-bar (o+c)/2 (v3 seeded
#        from the bar before bar 1, a NaN-propagation risk).
#  CORRECTNESS: squeeze test now checks BOTH bands (upper-only was valid only
#        while BB/KC share the same SIMPLE center; now robust to edits).
#        sqzXconf renamed inSqueezeX (old name was inverted). Existing alerts
#        still fire on squeeze START; optional FIRE (release) alerts added.
#  REPAINT: optional useConfirmedHTF - HA2 trend and Sqz2/Sqz3 status read
#        the last COMPLETED higher-TF bar ([1] on a secondary aggregation
#        indexes HTF bars). No repaint; lags one HTF bar. Default no.
#        NOTE: with this OFF, HA2/Sqz2/Sqz3 on HISTORICAL bars reflect the
#        finished HTF bar (look-ahead in any visual backtest) and can flicker
#        intrabar live. Inherent to all MTF display logic.
#  ROBUSTNESS: DxW clouds/label gated to chart TF < DAY, WxM to < WEEK
#        (daily VWAP is degenerate on daily+ charts). minDevBW dollar floor
#        gates the VPA confluence label and band-touch alerts against the
#        opening-bell sigma collapse (default 0 = v3 behavior). No-volume
#        warning label added. Optional cross-only VWAP alerts.
#  CANDLE PAINT NOTE: set paintHeikenAshiCandles = no when another study
#        on the chart paints candles; two AssignPriceColor studies conflict
#        (load-order dependent). Default left = yes for standalone use.
#  EXT-HOURS NOTE: reference VWAP follows the chart's EXT setting. With EXT
#        on, the daily anchor includes pre-market volume; keep the setting
#        consistent across Context/Setup/Trigger charts.
#version 9.29.2026 v4.1 dart966 - weekly/monthly chart usability:
#  NEW: vwapAggregation adds QUARTER and YEAR. The TOS built-in VWAP only
#        offers DAY/WEEK/MONTH, so these two are computed in-file with the
#        built-in's method (volume-weighted per-bar vwap, population sigma).
#        DAY/WEEK/MONTH still come from the built-in - their values are
#        unchanged. Center line = AnchorVWAPPlot. Use YEAR on Monthly charts,
#        QUARTER or YEAR on Weekly charts.
#  NEW: minAnchorBars (default 3). Until the anchor holds this many chart
#        bars, sigma is suppressed: the selected-anchor bands, deviation
#        clouds, VPA confluence label and band alerts stay off, and so do the
#        weekly/monthly +/-2 sigma lines and alerts on their own anchors.
#        Center lines and center-line alerts are not gated. Fixes the
#        sigma = 0 first-bar state that printed "+3 sigma EXTREME".
#  FIX: vwapAlertCrossOnly = yes now tests the last COMPLETED bar
#        (close[1] vs level[1]) and alerts at the open of the next bar.
#        v4 used the live price, so an intrabar cross that closed back
#        still alerted. Touch mode is unchanged (intrabar by design).
#  FIX: squeeze START alerts and vertical lines honor enableSqueezeN
#        (v4 gated only the FIRE alerts).
#version 9.29.2026 v4.2 dart966 - multi-year anchors:
#  NEW: vwapAggregation adds "2 YEARS", "3 YEARS", "4 YEARS", "5 YEARS",
#        computed in-file exactly like QUARTER/YEAR. Fixed calendar blocks:
#        the anchor resets on Jan 1 of years divisible by N (period index =
#        Floor(year / N)), e.g. 5 YEARS = 2025-2029, 2030-2034. Blocks start
#        at the chart's first loaded bar, so load enough history. Chart TFs
#        never reach these anchors (max TOS aggregation is YEAR), so no hide
#        rule or TF warning applies; minAnchorBars still gates the bands.
#version 9.29.2026 v4.3 dart966 - cleanup:
#  FIX: Sqz2/Sqz3 are switched off when their aggregation is at or below
#        the chart TF. There they clamp to the chart TF and only repeated
#        Sqz1 (chips, clouds, alerts, lines). The yellow warning now reads
#        "Sqz2 off: Time Frame >= SqzAggregation2".
#  FIX: the VWAPBullBear "Above"/"Below" colors now drive the Daily VWAP
#        line when paintVwapBullBear = yes (they were never read). Defaults
#        set to GREEN/RED so the line looks the same as v4.2.
#  FIX: VWAP alert names end in "Touch/Cross" (they fire on touch by
#        default, not only on a cross).

declare upper;
def NA = Double.NaN;

#---------------------------------------------------------------
# INPUTS
#---------------------------------------------------------------
#Colored VWAP to Heiken Ashi Trend toggles
input paintHeikenAshiCandles = yes;  # set NO if another study paints candles
input paintHeikenAshiVWAP = no;
input haAgg2 = AggregationPeriod.FIVE_MIN;
input paintVwapBullBear = yes;
input showHaLabels = yes;

#Repaint control: read completed higher-TF bars for HA2 and Sqz2/Sqz3.
#No repaint / no historical look-ahead; lags one HTF bar. Default no = v3 behavior.
input useConfirmedHTF = no;

#VWAP Deviation Band inputs
input vwapAggregation = {default "DAY", "WEEK", "MONTH", "QUARTER", "YEAR", "2 YEARS", "3 YEARS", "4 YEARS", "5 YEARS"};

#Bars the anchor period must hold before sigma is trusted. With one bar,
#sigma = 0 and every band sits on the center line.
input minAnchorBars = 3;

input vwapAlertSound = Sound.Ring;
input vwapAlertType = Alert.BAR;
input vwapAlertCrossOnly = no;  # yes = a COMPLETED bar's close crossed the level (alerts next bar); no = live bar touch (v3 behavior)

input alertVwapDaily = yes;
input alertVwapWeekly = yes;
input alertVwapMonthly = yes;

input alertVwapUB1   = no;
input alertVwapUB2   = yes;
input alertVwapUB3   = yes;
input alertVwapUB4   = yes;
input alertVwapWKHB  = yes;
input alertVwapMNTHHB = yes;

input alertVwapLB1   = no;
input alertVwapLB2   = yes;
input alertVwapLB3   = yes;
input alertVwapLB4   = yes;
input alertVwapWKLB  = yes;
input alertVwapMNTHLB = yes;

input enableDeviationClouds = yes;
input enableDailyXWeeklyClouds = yes;
input enableWeeklyXMonthlyClouds = yes;

input showVwapFromPriceLabels = yes;
input showDeviationBandWidthLabel = yes;
input showDxwLabel = yes;
input showWxmLabel = yes;

input band1Dev = 1.0;
input band2Dev = 2.0;
input band3Dev = 3.0;
input band4Dev = 4.0;
input band5Dev = 0.5;
input band6Dev = 1.5;
input band7Dev = 2.5;
input band8Dev = 3.5;

#Minimum 1-sigma bandwidth (dollars) before band-touch alerts and the VPA
#confluence label are allowed to fire. Guards the first minutes of a VWAP
#period when sigma ~ 0 and the +/-2 sigma bands hug the center line.
#0 = disabled (v3 behavior). Tune per symbol on intraday charts.
input minDevBW = 0.0;

#Bollinger and Keltner SQUEEZE inputs
input enableSqueeze1 = yes;
input enableSqueeze2 = yes;
input enableSqueeze3 = yes;

input sqzAggregation2 = AggregationPeriod.THIRTY_MIN;
def SqzAgg2 = if GetAggregationPeriod() > sqzAggregation2 then GetAggregationPeriod() else sqzAggregation2;
input sqzAggregation3 = AggregationPeriod.HOUR;
def SqzAgg3 = if GetAggregationPeriod() > sqzAggregation3 then GetAggregationPeriod() else sqzAggregation3;
#v4.3: Sqz2/Sqz3 only run when their aggregation is above the chart TF;
#at or below it they clamp to the chart TF and repeat Sqz1.
def sqz2On = enableSqueeze2 and GetAggregationPeriod() < sqzAggregation2;
def sqz3On = enableSqueeze3 and GetAggregationPeriod() < sqzAggregation3;

input showSqz1Label = yes;
input showSqz2Label = yes;
input showSqz3Label = yes;
input sqz1Alert = yes;          # fires on squeeze START (compression begins) - v3 behavior
input sqz2Alert = yes;
input sqz3Alert = yes;
input sqzFireAlerts = no;       # NEW: fires on squeeze RELEASE (BB exits KC)
input sqzAlertType = Alert.BAR;
input sqzAlertSound = Sound.Ding;
input sqz1VerticalLine = yes;
input sqz2VerticalLine = yes;
input sqz3VerticalLine = yes;

def length = 20;
def Num_Dev_Dn = -2.0;
def Num_Dev_up = 2.0;
def averageType = AverageType.SIMPLE;
def factor = 1.5;
def trueRangeAverageType = AverageType.SIMPLE;

#---------------------------------------------------------------
# WARNING LABELS
#---------------------------------------------------------------
#v4: message now respects which squeeze is actually enabled.
AddLabel(enableSqueeze2 and GetAggregationPeriod() >= sqzAggregation2, "Sqz2 off: Time Frame >= SqzAggregation2", Color.YELLOW);
AddLabel(enableSqueeze3 and GetAggregationPeriod() >= sqzAggregation3, "Sqz3 off: Time Frame >= SqzAggregation3", Color.YELLOW);

AddLabel(if (GetAggregationPeriod() >= AggregationPeriod.DAY and vwapAggregation == vwapAggregation."DAY") or (GetAggregationPeriod() >= AggregationPeriod.WEEK and vwapAggregation == vwapAggregation."WEEK") or (GetAggregationPeriod() >= AggregationPeriod.MONTH and vwapAggregation == vwapAggregation."MONTH") or (GetAggregationPeriod() >= AggregationPeriod.QUARTER and vwapAggregation == vwapAggregation."QUARTER") or (GetAggregationPeriod() >= AggregationPeriod.YEAR and vwapAggregation == vwapAggregation."YEAR") then 1 else 0, "Time Frame >= VWAPAggregation", Color.YELLOW);

#---------------------------------------------------------------
# COLOR HOLDERS
#---------------------------------------------------------------
plot VWAPBullBear = NA;
VWAPBullBear.HideTitle();
VWAPBullBear.DefineColor("Above", Color.GREEN);
VWAPBullBear.DefineColor("Below", Color.RED);

plot VWAPDevColoring = NA;
VWAPDevColoring.HideTitle();
VWAPDevColoring.DefineColor("UpperAbove", Color.GRAY);
VWAPDevColoring.DefineColor("UpperBelow", CreateColor(30, 30, 30));
VWAPDevColoring.DefineColor("LowerAbove", CreateColor(30, 30, 30));
VWAPDevColoring.DefineColor("LowerBelow", Color.GRAY);

plot DeviationClouds = NA;
DeviationClouds.HideTitle();
DeviationClouds.DefineColor("2+3 UpperBand", Color.GRAY);
DeviationClouds.DefineColor("1+2 UpperBand", Color.DARK_GRAY);
DeviationClouds.DefineColor("VWAP+1 UpperBand", Color.BLACK);
DeviationClouds.DefineColor("VWAP-1 LowerBand", Color.BLACK);
DeviationClouds.DefineColor("1-2 LowerBand", Color.DARK_GRAY);
DeviationClouds.DefineColor("2-3 LowerBand", Color.GRAY);

plot CrossoverClouds = NA;
CrossoverClouds.HideTitle();
CrossoverClouds.DefineColor("Daily x Weekly UpperBands", Color.DARK_ORANGE);
CrossoverClouds.DefineColor("Weekly x Monthly UpperBands", Color.RED);
CrossoverClouds.DefineColor("Daily x Weekly LowerBands", CreateColor(0, 100, 200));
CrossoverClouds.DefineColor("Weekly x Monthly LowerBands", Color.GREEN);

plot SqueezeClouds = NA;
SqueezeClouds.HideTitle();
SqueezeClouds.DefineColor("Squeeze1", Color.YELLOW);
SqueezeClouds.DefineColor("Squeeze2", Color.DARK_ORANGE);
SqueezeClouds.DefineColor("Squeeze3", Color.RED);

plot HeikenAshiPaintColors = NA;
HeikenAshiPaintColors.HideTitle();
HeikenAshiPaintColors.DefineColor("Heiken Up", Color.GREEN);
HeikenAshiPaintColors.DefineColor("Heiken Down", Color.RED);
HeikenAshiPaintColors.DefineColor("Neutral", Color.YELLOW);

#---------------------------------------------------------------
# HELPERS
#---------------------------------------------------------------
#Level-touch / cross detector for VWAP alerts. Touch mode (crossOnly = no)
#fires on every bar that straddles the level - in chop around VWAP that is
#once per bar (Alert.BAR caps it there). Cross mode (v4.1) requires the last
#completed bar to have closed across the level - no intrabar false alerts.
#The cross test reads the two prior bars, so it is NaN-guarded on those.
#Script inputs cannot be indexed (lvl[1] is a compile error), so the test
#runs on dist = close - lvl, a series: a sign change from bar t-2 to t-1
#is a completed-bar cross (same rule as Crosses(): touch-then-leave counts).
script LvlHit {
    input lvl = 0.0;
    input crossOnly = no;
    def dist = close - lvl;
    plot hit = if crossOnly then (if IsNaN(dist[1]) or IsNaN(dist[2]) then 0
                                  else (dist[2] <= 0 and dist[1] > 0) or (dist[2] >= 0 and dist[1] < 0))
               else if IsNaN(lvl) then 0
               else high >= lvl and low <= lvl;
}

#---------------------------------------------------------------
# MTF HEIKEN ASHI TREND
#---------------------------------------------------------------
def h = high;
def l = low;
def c = close;

#HA1 - chart timeframe, native series (v3 routed this through a redundant
#secondary-aggregation call of the chart's own period).
#Only open-vs-close is needed for trend; the v3 HA high/low recursion was
#dead code (never read) and used HAclose[1] instead of HAclose besides.
def HA1close = (open + high + low + close) / 4;
def HA1open = CompoundValue(1, (HA1open[1] + HA1close[1]) / 2, (open + close) / 2);

#HA2 - higher timeframe, clamped up to the chart TF (requesting an
#aggregation below the chart is unsupported and silently breaks).
def haAgg2eff = if GetAggregationPeriod() > haAgg2 then GetAggregationPeriod() else haAgg2;
def o2raw = open("period" = haAgg2eff);
def h2raw = high("period" = haAgg2eff);
def l2raw = low("period" = haAgg2eff);
def c2raw = close("period" = haAgg2eff);
#Confirmed mode: [1] on a secondary-aggregation series indexes HTF bars,
#so these are the last COMPLETED higher-TF bar. No repaint, one-bar lag.
def o2 = if useConfirmedHTF then o2raw[1] else o2raw;
def h2 = if useConfirmedHTF then h2raw[1] else h2raw;
def l2 = if useConfirmedHTF then l2raw[1] else l2raw;
def c2 = if useConfirmedHTF then c2raw[1] else c2raw;

def HA2close = (o2 + h2 + l2 + c2) / 4;
def HA2open = CompoundValue(1, (HA2open[1] + HA2close[1]) / 2, (o2 + c2) / 2);

def HA1 = HA1close > HA1open;
def HA2 = HA2close > HA2open;

AddLabel(showHaLabels, "HA1", if HA1 then HeikenAshiPaintColors.Color("Heiken Up") else HeikenAshiPaintColors.Color("Heiken Down"));
AddLabel(showHaLabels, "HA2", if HA2 then HeikenAshiPaintColors.Color("Heiken Up") else HeikenAshiPaintColors.Color("Heiken Down"));
AddLabel(GetAggregationPeriod() > haAgg2, "HA2 TF < Chart - clamped to chart TF", Color.YELLOW);

#Paint Heiken Candles
#NOTE: conflicts with any other AssignPriceColor study on the chart
#(e.g. another candle-coloring study). Disable here in that case.
AssignPriceColor(if !paintHeikenAshiCandles then Color.CURRENT else if HA1 and HA2 then HeikenAshiPaintColors.Color("Heiken Up") else if !HA1 and !HA2 then HeikenAshiPaintColors.Color("Heiken Down") else HeikenAshiPaintColors.Color("Neutral"));

#---------------------------------------------------------------
# VWAP - DAILY / WEEKLY / MONTHLY (9 reference accesses total)
#---------------------------------------------------------------
#v4.1 anchor period indexes. DAY/WEEK/MONTH use the same period index as
#the TOS built-in VWAP so the bar counts reset on the same bar it does.
def yyyyMmDd = GetYYYYMMDD();
def anchorYear = RoundDown(yyyyMmDd / 10000, 0);
def anchorMonth = RoundDown(yyyyMmDd / 100, 0) - anchorYear * 100;
def weekIdx = Floor((DaysFromDate(First(yyyyMmDd)) + GetDayOfWeek(First(yyyyMmDd))) / 7);
def monthIdx = RoundDown(yyyyMmDd / 100, 0);
def quarterIdx = anchorYear * 10 + Ceil(anchorMonth / 3);

#Chart bars since each anchor rolled (1 on the first bar of the period).
def wkRolled = CompoundValue(1, weekIdx != weekIdx[1], yes);
def wkBars = CompoundValue(1, if wkRolled then 1 else wkBars[1] + 1, 1);
def mnRolled = CompoundValue(1, monthIdx != monthIdx[1], yes);
def mnBars = CompoundValue(1, if mnRolled then 1 else mnBars[1] + 1, 1);

plot VWAPDAY = reference VWAP("num dev dn" = -2.0, "num dev up" = 2.0, "time frame" = "DAY");
plot VWAPWK = reference VWAP("num dev dn" = -2.0, "num dev up" = 2.0, "time frame" = "WEEK");
plot VWAPMNTH = reference VWAP("num dev dn" = -2.0, "num dev up" = 2.0, "time frame" = "MONTH");

VWAPDAY.SetHiding(GetAggregationPeriod() >= AggregationPeriod.DAY);
VWAPWK.SetHiding(GetAggregationPeriod() >= AggregationPeriod.WEEK);
VWAPMNTH.SetHiding(GetAggregationPeriod() >= AggregationPeriod.MONTH);

def VWAPDAYLB = reference VWAP("num dev dn" = -2.0, "num dev up" = 2.0, "time frame" = "DAY")."LowerBand";
#v4.1: weekly/monthly +/-2 sigma lines are blank until their own anchor
#holds minAnchorBars bars (sigma = 0 on the first bar of the period).
plot VWAPWKLB = if wkBars >= minAnchorBars then reference VWAP("num dev dn" = -2.0, "num dev up" = 2.0, "time frame" = "WEEK")."LowerBand" else NA;
plot VWAPMNTHLB = if mnBars >= minAnchorBars then reference VWAP("num dev dn" = -2.0, "num dev up" = 2.0, "time frame" = "MONTH")."LowerBand" else NA;

def VWAPDAYHB = reference VWAP("num dev dn" = -2.0, "num dev up" = 2.0, "time frame" = "DAY")."UpperBand";
plot VWAPWKHB = if wkBars >= minAnchorBars then reference VWAP("num dev dn" = -2.0, "num dev up" = 2.0, "time frame" = "WEEK")."UpperBand" else NA;
plot VWAPMNTHHB = if mnBars >= minAnchorBars then reference VWAP("num dev dn" = -2.0, "num dev up" = 2.0, "time frame" = "MONTH")."UpperBand" else NA;

VWAPWKLB.SetHiding(GetAggregationPeriod() >= AggregationPeriod.WEEK);
VWAPWKHB.SetHiding(GetAggregationPeriod() >= AggregationPeriod.WEEK);
VWAPMNTHLB.SetHiding(GetAggregationPeriod() >= AggregationPeriod.MONTH);
VWAPMNTHHB.SetHiding(GetAggregationPeriod() >= AggregationPeriod.MONTH);

#No-volume guard: VWAP is undefined on volume-less symbols (e.g. SPX) and
#every plot silently NaNs. Make that state explicit.
AddLabel(IsNaN(VWAPDAY) and !IsNaN(c), "No volume data - VWAP unavailable", Color.RED);

#VWAP Distance Label - color = which VWAP price is closest to.
def VWAPDAYDistance = c - VWAPDAY;
def VWAPWKDistance = c - VWAPWK;
def VWAPMNTHDistance = c - VWAPMNTH;
def vwDayAbs = AbsValue(VWAPDAYDistance);
def vwWkAbs = AbsValue(VWAPWKDistance);
def vwMnthAbs = AbsValue(VWAPMNTHDistance);
def vwNearest = Min(vwDayAbs, Min(vwWkAbs, vwMnthAbs));
AddLabel(showVwapFromPriceLabels,
    "DVWAP: " + AsDollars(VWAPDAYDistance) +
    " WVWAP: " + AsDollars(VWAPWKDistance) +
    " MVWAP: " + AsDollars(VWAPMNTHDistance),
    if vwNearest == vwDayAbs then Color.WHITE
    else if vwNearest == vwWkAbs then Color.DARK_ORANGE
    else Color.RED);

#---------------------------------------------------------------
# SELECTED-AGGREGATION CENTER + SIGMA (replaces 17 reference calls in v3)
#---------------------------------------------------------------
#TOS VWAP bands are linear in the deviation multiple: Band(n) = VWAP + n*sigma,
#with the same volume-weighted sigma for every n. So sigma is recovered
#exactly from the +/-2 band already fetched above, and every deviation band
#becomes arithmetic. Values are identical to v3's per-band reference calls.
#v4.1: QUARTER/YEAR (v4.2: and 2-5 YEARS) are not offered by the built-in, so they are computed
#here with its method: running sums of volume, volume*vwap and
#volume*vwap^2 reset at the period roll; sigma = sqrt(E[x^2] - E[x]^2).
#Per-bar vwap falls back to hlc3 where the platform supplies none.
#v4.2: multi-year anchors = fixed calendar blocks of N years.
def multiYears = if vwapAggregation == vwapAggregation."2 YEARS" then 2
                 else if vwapAggregation == vwapAggregation."3 YEARS" then 3
                 else if vwapAggregation == vwapAggregation."4 YEARS" then 4
                 else if vwapAggregation == vwapAggregation."5 YEARS" then 5
                 else 0;
def isLongAnchor = vwapAggregation == vwapAggregation."QUARTER" or vwapAggregation == vwapAggregation."YEAR" or multiYears > 0;
def selIdx = if multiYears > 0 then Floor(anchorYear / multiYears)
             else if vwapAggregation == vwapAggregation."YEAR" then anchorYear
             else if vwapAggregation == vwapAggregation."QUARTER" then quarterIdx
             else if vwapAggregation == vwapAggregation."MONTH" then monthIdx
             else if vwapAggregation == vwapAggregation."WEEK" then weekIdx
             else yyyyMmDd;
def selRolled = CompoundValue(1, selIdx != selIdx[1], yes);
def selBars = CompoundValue(1, if selRolled then 1 else selBars[1] + 1, 1);

def anchorPx = if IsNaN(vwap) then hlc3 else vwap;
def aVolSum = CompoundValue(1, if selRolled then volume else aVolSum[1] + volume, volume);
def aPvSum = CompoundValue(1, if selRolled then volume * anchorPx else aPvSum[1] + volume * anchorPx, volume * anchorPx);
def aPv2Sum = CompoundValue(1, if selRolled then volume * Sqr(anchorPx) else aPv2Sum[1] + volume * Sqr(anchorPx), volume * Sqr(anchorPx));
def longVWAP = aPvSum / aVolSum;
def longSigma = Sqrt(Max(aPv2Sum / aVolSum - Sqr(longVWAP), 0));

plot AnchorVWAPPlot = if isLongAnchor then longVWAP else NA;
AnchorVWAPPlot.SetHiding(!isLongAnchor or (vwapAggregation == vwapAggregation."QUARTER" and GetAggregationPeriod() >= AggregationPeriod.QUARTER) or (vwapAggregation == vwapAggregation."YEAR" and GetAggregationPeriod() >= AggregationPeriod.YEAR));
AnchorVWAPPlot.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
AnchorVWAPPlot.SetDefaultColor(Color.MAGENTA);

def VWAPCENTER = if isLongAnchor then longVWAP
                 else if vwapAggregation == vwapAggregation."WEEK" then VWAPWK
                 else if vwapAggregation == vwapAggregation."MONTH" then VWAPMNTH
                 else VWAPDAY;
def rawSigma = if isLongAnchor then longSigma
               else ((if vwapAggregation == vwapAggregation."WEEK" then VWAPWKHB - VWAPWK
                      else if vwapAggregation == vwapAggregation."MONTH" then VWAPMNTHHB - VWAPMNTH
                      else VWAPDAYHB - VWAPDAY) / 2);

#v4.1: sigma is NaN until the selected anchor holds minAnchorBars bars, which
#blanks every deviation band, deviation cloud, band alert and the confluence
#label. The center line stays.
def vwapSigma = if selBars >= minAnchorBars then rawSigma else NA;
AddLabel(selBars < minAnchorBars and !IsNaN(c), "VWAP bands off: " + selBars + "/" + minAnchorBars + " bars in anchor", Color.GRAY);

#Bandwidth gate for alerts and the VPA confluence bridge (0 = disabled).
def bwOK = minDevBW <= 0 or vwapSigma >= minDevBW;

#---------------------------------------------------------------
# CROSSOVER CLOUD VALIDATIONS (TF-gated in v4)
#---------------------------------------------------------------
#Daily VWAP is degenerate on daily+ charts (one bar per period); DxW clouds
#there are noise. Same for WxM on weekly+ charts.
def dxwOK = enableDailyXWeeklyClouds and GetAggregationPeriod() < AggregationPeriod.DAY;
def wxmOK = enableWeeklyXMonthlyClouds and GetAggregationPeriod() < AggregationPeriod.WEEK;

def VDAYxWKLBDiffH = if !dxwOK then NA else if VWAPWKLB - VWAPDAYLB <= 0 then NA else VWAPWKLB;
def VDAYxWKLBDiffL = if !dxwOK then NA else if VWAPWKLB - VWAPDAYLB <= 0 then NA else VWAPDAYLB;
def VDAYxWKHBDiffH = if !dxwOK then NA else if VWAPDAYHB - VWAPWKHB <= 0 then NA else VWAPDAYHB;
def VDAYxWKHBDiffL = if !dxwOK then NA else if VWAPDAYHB - VWAPWKHB <= 0 then NA else VWAPWKHB;

def VWKxMNTHLBDiffH = if !wxmOK then NA else if VWAPMNTHLB - VWAPWKLB <= 0 then NA else VWAPMNTHLB;
def VWKxMNTHLBDiffL = if !wxmOK then NA else if VWAPMNTHLB - VWAPWKLB <= 0 then NA else VWAPWKLB;
def VWKxMNTHHBDiffH = if !wxmOK then NA else if VWAPWKHB - VWAPMNTHHB <= 0 then NA else VWAPWKHB;
def VWKxMNTHHBDiffL = if !wxmOK then NA else if VWAPWKHB - VWAPMNTHHB <= 0 then NA else VWAPMNTHHB;

#---------------------------------------------------------------
# FORMAT MAIN VWAP LINES
#---------------------------------------------------------------
VWAPDAY.DefineColor("Default", Color.YELLOW);
VWAPDAY.AssignValueColor(if !paintHeikenAshiVWAP and !paintVwapBullBear then VWAPDAY.Color("Default") else if paintHeikenAshiVWAP and HA1 and HA2 then HeikenAshiPaintColors.Color("Heiken Up") else if paintHeikenAshiVWAP and !HA1 and !HA2 then HeikenAshiPaintColors.Color("Heiken Down") else if paintHeikenAshiVWAP and (HA1 and !HA2) or paintHeikenAshiVWAP and (!HA1 and HA2) then HeikenAshiPaintColors.Color("Neutral") else if paintVwapBullBear and c > VWAPDAY then VWAPBullBear.Color("Above") else VWAPBullBear.Color("Below"));
VWAPDAY.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);

VWAPWK.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VWAPWK.SetDefaultColor(Color.DARK_ORANGE);
VWAPWKHB.SetStyle(Curve.SHORT_DASH);
VWAPWKHB.SetDefaultColor(Color.DARK_ORANGE);
VWAPWKLB.SetStyle(Curve.SHORT_DASH);
VWAPWKLB.SetDefaultColor(Color.DARK_ORANGE);

VWAPMNTH.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VWAPMNTH.SetDefaultColor(Color.RED);
VWAPMNTHHB.SetStyle(Curve.LONG_DASH);
VWAPMNTHHB.SetDefaultColor(Color.RED);
VWAPMNTHLB.SetStyle(Curve.LONG_DASH);
VWAPMNTHLB.SetDefaultColor(Color.RED);

AddCloud(VDAYxWKLBDiffH, VDAYxWKLBDiffL, CrossoverClouds.Color("Daily x Weekly LowerBands"), CrossoverClouds.Color("Daily x Weekly LowerBands"));
AddCloud(VDAYxWKHBDiffH, VDAYxWKHBDiffL, CrossoverClouds.Color("Daily x Weekly UpperBands"), CrossoverClouds.Color("Daily x Weekly UpperBands"));
AddCloud(VWKxMNTHLBDiffH, VWKxMNTHLBDiffL, CrossoverClouds.Color("Weekly x Monthly LowerBands"), CrossoverClouds.Color("Weekly x Monthly LowerBands"));
AddCloud(VWKxMNTHHBDiffH, VWKxMNTHHBDiffL, CrossoverClouds.Color("Weekly x Monthly UpperBands"), CrossoverClouds.Color("Weekly x Monthly UpperBands"));

#---------------------------------------------------------------
# DEVIATION BANDS (pure arithmetic - exact equivalents of v3's plots)
#---------------------------------------------------------------
plot VWAPUB1 = VWAPCENTER + band1Dev * vwapSigma;
plot VWAPUB2 = VWAPCENTER + band2Dev * vwapSigma;
plot VWAPUB3 = VWAPCENTER + band3Dev * vwapSigma;
plot VWAPUB4 = VWAPCENTER + band4Dev * vwapSigma;
plot VWAPUB5 = VWAPCENTER + band5Dev * vwapSigma;
plot VWAPUB6 = VWAPCENTER + band6Dev * vwapSigma;
plot VWAPUB7 = VWAPCENTER + band7Dev * vwapSigma;
plot VWAPUB8 = VWAPCENTER + band8Dev * vwapSigma;

VWAPUB1.Hide();
VWAPUB2.Hide();
VWAPUB3.Hide();
VWAPUB4.Hide();

plot VWAPLB1 = VWAPCENTER - band1Dev * vwapSigma;
plot VWAPLB2 = VWAPCENTER - band2Dev * vwapSigma;
plot VWAPLB3 = VWAPCENTER - band3Dev * vwapSigma;
plot VWAPLB4 = VWAPCENTER - band4Dev * vwapSigma;
plot VWAPLB5 = VWAPCENTER - band5Dev * vwapSigma;
plot VWAPLB6 = VWAPCENTER - band6Dev * vwapSigma;
plot VWAPLB7 = VWAPCENTER - band7Dev * vwapSigma;
plot VWAPLB8 = VWAPCENTER - band8Dev * vwapSigma;

VWAPLB1.Hide();
VWAPLB2.Hide();
VWAPLB3.Hide();
VWAPLB4.Hide();

#---------------------------------------------------------------
# VWAP ALERTS (touch by default; cross-only via input; bw-gated)
#---------------------------------------------------------------
Alert(if alertVwapDaily then LvlHit(VWAPDAY, vwapAlertCrossOnly) else NA, "VWAP Daily Touch/Cross", vwapAlertType, vwapAlertSound);
Alert(if alertVwapWeekly then LvlHit(VWAPWK, vwapAlertCrossOnly) else NA, "VWAP Weekly Touch/Cross", vwapAlertType, vwapAlertSound);
Alert(if alertVwapMonthly then LvlHit(VWAPMNTH, vwapAlertCrossOnly) else NA, "VWAP Monthly Touch/Cross", vwapAlertType, vwapAlertSound);

Alert(if alertVwapUB1 and bwOK then LvlHit(VWAPUB1, vwapAlertCrossOnly) else NA, "VWAP Upper 1 Std Dev Touch/Cross", vwapAlertType, vwapAlertSound);
Alert(if alertVwapUB2 and bwOK then LvlHit(VWAPUB2, vwapAlertCrossOnly) else NA, "VWAP Upper 2 Std Dev Touch/Cross", vwapAlertType, vwapAlertSound);
Alert(if alertVwapUB3 and bwOK then LvlHit(VWAPUB3, vwapAlertCrossOnly) else NA, "VWAP Upper 3 Std Dev Touch/Cross", vwapAlertType, vwapAlertSound);
Alert(if alertVwapUB4 and bwOK then LvlHit(VWAPUB4, vwapAlertCrossOnly) else NA, "VWAP Upper 4 Std Dev Touch/Cross", vwapAlertType, vwapAlertSound);
Alert(if alertVwapWKHB then LvlHit(VWAPWKHB, vwapAlertCrossOnly) else NA, "VWAP Weekly Upper 2 Std Dev Touch/Cross", vwapAlertType, vwapAlertSound);
Alert(if alertVwapMNTHHB then LvlHit(VWAPMNTHHB, vwapAlertCrossOnly) else NA, "VWAP Monthly Upper 2 Std Dev Touch/Cross", vwapAlertType, vwapAlertSound);

Alert(if alertVwapLB1 and bwOK then LvlHit(VWAPLB1, vwapAlertCrossOnly) else NA, "VWAP Lower 1 Std Dev Touch/Cross", vwapAlertType, vwapAlertSound);
Alert(if alertVwapLB2 and bwOK then LvlHit(VWAPLB2, vwapAlertCrossOnly) else NA, "VWAP Lower 2 Std Dev Touch/Cross", vwapAlertType, vwapAlertSound);
Alert(if alertVwapLB3 and bwOK then LvlHit(VWAPLB3, vwapAlertCrossOnly) else NA, "VWAP Lower 3 Std Dev Touch/Cross", vwapAlertType, vwapAlertSound);
Alert(if alertVwapLB4 and bwOK then LvlHit(VWAPLB4, vwapAlertCrossOnly) else NA, "VWAP Lower 4 Std Dev Touch/Cross", vwapAlertType, vwapAlertSound);
Alert(if alertVwapWKLB then LvlHit(VWAPWKLB, vwapAlertCrossOnly) else NA, "VWAP Weekly Lower 2 Std Dev Touch/Cross", vwapAlertType, vwapAlertSound);
Alert(if alertVwapMNTHLB then LvlHit(VWAPMNTHLB, vwapAlertCrossOnly) else NA, "VWAP Monthly Lower 2 Std Dev Touch/Cross", vwapAlertType, vwapAlertSound);

#---------------------------------------------------------------
# FORMAT DEVIATION BANDS
#---------------------------------------------------------------
VWAPUB1.SetStyle(Curve.FIRM);
VWAPUB1.AssignValueColor(if h >= VWAPUB1 then VWAPDevColoring.Color("UpperAbove") else VWAPDevColoring.Color("UpperBelow"));
VWAPUB2.SetStyle(Curve.FIRM);
VWAPUB2.AssignValueColor(if h >= VWAPUB2 then VWAPDevColoring.Color("UpperAbove") else VWAPDevColoring.Color("UpperBelow"));
VWAPUB3.SetStyle(Curve.FIRM);
VWAPUB3.AssignValueColor(if h >= VWAPUB3 then VWAPDevColoring.Color("UpperAbove") else VWAPDevColoring.Color("UpperBelow"));
VWAPUB4.SetStyle(Curve.FIRM);
VWAPUB4.AssignValueColor(if h >= VWAPUB4 then VWAPDevColoring.Color("UpperAbove") else VWAPDevColoring.Color("UpperBelow"));
VWAPUB5.SetStyle(Curve.SHORT_DASH);
VWAPUB5.SetDefaultColor(CreateColor(30, 30, 30));
VWAPUB6.SetStyle(Curve.SHORT_DASH);
VWAPUB6.SetDefaultColor(CreateColor(30, 30, 30));
VWAPUB7.SetStyle(Curve.SHORT_DASH);
VWAPUB7.SetDefaultColor(CreateColor(30, 30, 30));
VWAPUB8.SetStyle(Curve.SHORT_DASH);
VWAPUB8.SetDefaultColor(CreateColor(30, 30, 30));

VWAPLB1.SetStyle(Curve.FIRM);
VWAPLB1.AssignValueColor(if l >= VWAPLB1 then VWAPDevColoring.Color("LowerAbove") else VWAPDevColoring.Color("LowerBelow"));
VWAPLB2.SetStyle(Curve.FIRM);
VWAPLB2.AssignValueColor(if l >= VWAPLB2 then VWAPDevColoring.Color("LowerAbove") else VWAPDevColoring.Color("LowerBelow"));
VWAPLB3.SetStyle(Curve.FIRM);
VWAPLB3.AssignValueColor(if l >= VWAPLB3 then VWAPDevColoring.Color("LowerAbove") else VWAPDevColoring.Color("LowerBelow"));
VWAPLB4.SetStyle(Curve.FIRM);
VWAPLB4.AssignValueColor(if l >= VWAPLB4 then VWAPDevColoring.Color("LowerAbove") else VWAPDevColoring.Color("LowerBelow"));
VWAPLB5.SetStyle(Curve.SHORT_DASH);
VWAPLB5.SetDefaultColor(CreateColor(30, 30, 30));
VWAPLB6.SetStyle(Curve.SHORT_DASH);
VWAPLB6.SetDefaultColor(CreateColor(30, 30, 30));
VWAPLB7.SetStyle(Curve.SHORT_DASH);
VWAPLB7.SetDefaultColor(CreateColor(30, 30, 30));
VWAPLB8.SetStyle(Curve.SHORT_DASH);
VWAPLB8.SetDefaultColor(CreateColor(30, 30, 30));

#Clouds for Deviation Bands
AddCloud(if enableDeviationClouds then VWAPUB3 else NA, VWAPUB2, DeviationClouds.Color("2+3 UpperBand"), DeviationClouds.Color("2+3 UpperBand"), no);
AddCloud(if enableDeviationClouds then VWAPUB2 else NA, VWAPUB1, DeviationClouds.Color("1+2 UpperBand"), DeviationClouds.Color("1+2 UpperBand"), yes);
AddCloud(if enableDeviationClouds then VWAPUB1 else NA, VWAPCENTER, DeviationClouds.Color("VWAP+1 UpperBand"), DeviationClouds.Color("VWAP+1 UpperBand"), no);
AddCloud(if enableDeviationClouds then VWAPCENTER else NA, VWAPLB1, DeviationClouds.Color("VWAP-1 LowerBand"), DeviationClouds.Color("VWAP-1 LowerBand"), no);
AddCloud(if enableDeviationClouds then VWAPLB1 else NA, VWAPLB2, DeviationClouds.Color("1-2 LowerBand"), DeviationClouds.Color("1-2 LowerBand"), yes);
AddCloud(if enableDeviationClouds then VWAPLB2 else NA, VWAPLB3, DeviationClouds.Color("2-3 LowerBand"), DeviationClouds.Color("2-3 LowerBand"), no);

#Deviation Bandwidth Label (1-sigma width of the selected anchor)
AddLabel(showDeviationBandWidthLabel, "DevBW: $" + AsText(vwapSigma, NumberFormat.TWO_DECIMAL_PLACES), Color.GRAY);

#DxW and WxM Crossover Labels (TF-gated with the clouds)
AddLabel(if dxwOK and showDxwLabel then 1 else 0, "DxW", if VWAPDAYHB > VWAPWKHB then CrossoverClouds.Color("Daily x Weekly UpperBands") else if VWAPDAYLB < VWAPWKLB then CrossoverClouds.Color("Daily x Weekly LowerBands") else Color.DARK_GRAY);
AddLabel(if wxmOK and showWxmLabel then 1 else 0, "WxM", if VWAPWKHB > VWAPMNTHHB then CrossoverClouds.Color("Weekly x Monthly UpperBands") else if VWAPWKLB < VWAPMNTHLB then CrossoverClouds.Color("Weekly x Monthly LowerBands") else Color.DARK_GRAY);

#---------------------------------------------------------------
# BOLLINGER x KELTNER MTF SQUEEZE
#---------------------------------------------------------------
#Sqz1 = chart TF (native series; v3's secondary-agg self-call removed).
#Sqz2/Sqz3 = higher TFs, optionally read from completed HTF bars.
def price1 = close;
def h1s = high;
def l1s = low;
def c1s = close;

def price2raw = close("Period" = SqzAgg2);
def h2sr = high("Period" = SqzAgg2);
def l2sr = low("Period" = SqzAgg2);
def price3raw = close("Period" = SqzAgg3);
def h3sr = high("Period" = SqzAgg3);
def l3sr = low("Period" = SqzAgg3);

def price2 = if useConfirmedHTF then price2raw[1] else price2raw;
def h2s = if useConfirmedHTF then h2sr[1] else h2sr;
def l2s = if useConfirmedHTF then l2sr[1] else l2sr;
def price3 = if useConfirmedHTF then price3raw[1] else price3raw;
def h3s = if useConfirmedHTF then h3sr[1] else h3sr;
def l3s = if useConfirmedHTF then l3sr[1] else l3sr;

#Bollinger Bands
def sDev1 = StDev(data = price1, length = length);
def sDev2 = StDev(data = price2, length = length);
def sDev3 = StDev(data = price3, length = length);
def MidLine1 = MovingAverage(averageType, data = price1, length = length);
def MidLine2 = MovingAverage(averageType, data = price2, length = length);
def MidLine3 = MovingAverage(averageType, data = price3, length = length);

def BLowerBand1 = MidLine1 + Num_Dev_Dn * sDev1;
def BLowerBand2 = MidLine2 + Num_Dev_Dn * sDev2;
def BLowerBand3 = MidLine3 + Num_Dev_Dn * sDev3;
def BUpperBand1 = MidLine1 + Num_Dev_up * sDev1;
def BUpperBand2 = MidLine2 + Num_Dev_up * sDev2;
def BUpperBand3 = MidLine3 + Num_Dev_up * sDev3;

#Keltner Channels (same center as BB by construction)
def shift1 = factor * MovingAverage(trueRangeAverageType, TrueRange(h1s, c1s, l1s), length);
def shift2 = factor * MovingAverage(trueRangeAverageType, TrueRange(h2s, price2, l2s), length);
def shift3 = factor * MovingAverage(trueRangeAverageType, TrueRange(h3s, price3, l3s), length);

def KUpperBand1 = MidLine1 + shift1;
def KUpperBand2 = MidLine2 + shift2;
def KUpperBand3 = MidLine3 + shift3;
def KLowerBand1 = MidLine1 - shift1;
def KLowerBand2 = MidLine2 - shift2;
def KLowerBand3 = MidLine3 - shift3;

#Squeeze = BB fully inside KC. v3 tested the upper side only, which was
#valid solely because both channels share the same SIMPLE center; the
#two-sided test costs one comparison and survives future edits.
def inSqueeze1 = BUpperBand1 < KUpperBand1 and BLowerBand1 > KLowerBand1;
def inSqueeze2 = BUpperBand2 < KUpperBand2 and BLowerBand2 > KLowerBand2;
def inSqueeze3 = BUpperBand3 < KUpperBand3 and BLowerBand3 > KLowerBand3;

def BollKeltUB1DiffH = if !enableSqueeze1 then NA else if !inSqueeze1 then NA else KUpperBand1;
def BollKeltUB1DiffL = if !enableSqueeze1 then NA else if !inSqueeze1 then NA else BUpperBand1;
def BollKeltLB1DiffH = if !enableSqueeze1 then NA else if !inSqueeze1 then NA else BLowerBand1;
def BollKeltLB1DiffL = if !enableSqueeze1 then NA else if !inSqueeze1 then NA else KLowerBand1;

def BollKeltUB2DiffH = if !sqz2On then NA else if !inSqueeze2 then NA else KUpperBand2;
def BollKeltUB2DiffL = if !sqz2On then NA else if !inSqueeze2 then NA else BUpperBand2;
def BollKeltLB2DiffH = if !sqz2On then NA else if !inSqueeze2 then NA else BLowerBand2;
def BollKeltLB2DiffL = if !sqz2On then NA else if !inSqueeze2 then NA else KLowerBand2;

def BollKeltUB3DiffH = if !sqz3On then NA else if !inSqueeze3 then NA else KUpperBand3;
def BollKeltUB3DiffL = if !sqz3On then NA else if !inSqueeze3 then NA else BUpperBand3;
def BollKeltLB3DiffH = if !sqz3On then NA else if !inSqueeze3 then NA else BLowerBand3;
def BollKeltLB3DiffL = if !sqz3On then NA else if !inSqueeze3 then NA else KLowerBand3;

plot Sqz1H = BollKeltUB1DiffL;
plot Sqz1L = BollKeltLB1DiffH;
plot Sqz2H = BollKeltUB2DiffL;
plot Sqz2L = BollKeltLB2DiffH;
plot Sqz3H = BollKeltUB3DiffL;
plot Sqz3L = BollKeltLB3DiffH;

#Labels: lit while in squeeze
AddLabel(if enableSqueeze1 and showSqz1Label then 1 else 0, "Sqz1", if inSqueeze1 then SqueezeClouds.Color("Squeeze1") else Color.DARK_GRAY);
AddLabel(if sqz2On and showSqz2Label then 1 else 0, "Sqz2", if inSqueeze2 then SqueezeClouds.Color("Squeeze2") else Color.DARK_GRAY);
AddLabel(if sqz3On and showSqz3Label then 1 else 0, "Sqz3", if inSqueeze3 then SqueezeClouds.Color("Squeeze3") else Color.DARK_GRAY);

#Alerts: squeeze START (compression begins) - identical timing to v3.
Alert(if sqz1Alert and enableSqueeze1 then !inSqueeze1[1] and inSqueeze1 else NA, "Squeeze1", sqzAlertType, sqzAlertSound);
Alert(if sqz2Alert and sqz2On then !inSqueeze2[1] and inSqueeze2 else NA, "Squeeze2", sqzAlertType, sqzAlertSound);
Alert(if sqz3Alert and sqz3On then !inSqueeze3[1] and inSqueeze3 else NA, "Squeeze3", sqzAlertType, sqzAlertSound);

#NEW v4: squeeze FIRE (release) alerts - the conventional actionable event.
Alert(if sqzFireAlerts and enableSqueeze1 then inSqueeze1[1] and !inSqueeze1 else NA, "Squeeze1 FIRE", sqzAlertType, sqzAlertSound);
Alert(if sqzFireAlerts and sqz2On then inSqueeze2[1] and !inSqueeze2 else NA, "Squeeze2 FIRE", sqzAlertType, sqzAlertSound);
Alert(if sqzFireAlerts and sqz3On then inSqueeze3[1] and !inSqueeze3 else NA, "Squeeze3 FIRE", sqzAlertType, sqzAlertSound);

AddVerticalLine(if sqz1VerticalLine and enableSqueeze1 then !inSqueeze1[1] and inSqueeze1 else NA, "Sqz1", SqueezeClouds.Color("Squeeze1"), stroke = Curve.POINTS);
AddVerticalLine(if sqz2VerticalLine and sqz2On then !inSqueeze2[1] and inSqueeze2 else NA, "Sqz2", SqueezeClouds.Color("Squeeze2"), stroke = Curve.POINTS);
AddVerticalLine(if sqz3VerticalLine and sqz3On then !inSqueeze3[1] and inSqueeze3 else NA, "Sqz3", SqueezeClouds.Color("Squeeze3"), stroke = Curve.POINTS);

Sqz1H.SetPaintingStrategy(PaintingStrategy.LINE);
Sqz1H.AssignValueColor(SqueezeClouds.Color("Squeeze1"));
Sqz1H.SetLineWeight(1);
Sqz1L.SetPaintingStrategy(PaintingStrategy.LINE);
Sqz1L.AssignValueColor(SqueezeClouds.Color("Squeeze1"));
Sqz1L.SetLineWeight(1);
Sqz2H.SetPaintingStrategy(PaintingStrategy.LINE);
Sqz2H.AssignValueColor(SqueezeClouds.Color("Squeeze2"));
Sqz2H.SetLineWeight(1);
Sqz2L.SetPaintingStrategy(PaintingStrategy.LINE);
Sqz2L.AssignValueColor(SqueezeClouds.Color("Squeeze2"));
Sqz2L.SetLineWeight(1);
Sqz3H.SetPaintingStrategy(PaintingStrategy.LINE);
Sqz3H.AssignValueColor(SqueezeClouds.Color("Squeeze3"));
Sqz3H.SetLineWeight(1);
Sqz3L.SetPaintingStrategy(PaintingStrategy.LINE);
Sqz3L.AssignValueColor(SqueezeClouds.Color("Squeeze3"));
Sqz3L.SetLineWeight(1);

#Clouds for Squeezes (gap between KC and BB while compressed)
AddCloud(BollKeltUB1DiffH, BollKeltUB1DiffL, SqueezeClouds.Color("Squeeze1"), SqueezeClouds.Color("Squeeze1"));
AddCloud(BollKeltLB1DiffH, BollKeltLB1DiffL, SqueezeClouds.Color("Squeeze1"), SqueezeClouds.Color("Squeeze1"));
AddCloud(BollKeltUB2DiffH, BollKeltUB2DiffL, SqueezeClouds.Color("Squeeze2"), SqueezeClouds.Color("Squeeze2"));
AddCloud(BollKeltLB2DiffH, BollKeltLB2DiffL, SqueezeClouds.Color("Squeeze2"), SqueezeClouds.Color("Squeeze2"));
AddCloud(BollKeltUB3DiffH, BollKeltUB3DiffL, SqueezeClouds.Color("Squeeze3"), SqueezeClouds.Color("Squeeze3"));
AddCloud(BollKeltLB3DiffH, BollKeltLB3DiffL, SqueezeClouds.Color("Squeeze3"), SqueezeClouds.Color("Squeeze3"));

# #######################################################
# VPA CONFLUENCE BRIDGE  (v2 addition; v4 adds bandwidth gate)
# #######################################################
# Flags when price has reached a VWAP band EXTREME - the statistical
# fair-value stretch where volume price analysis (VPA) reversal signals (climax /
# spring / upthrust / test) carry the most weight. LOCATION filter only:
#   - at/beyond +2 to +3 sigma -> overextended ABOVE fair value;
#     a VPA selling-climax / upthrust here is higher conviction (short).
#   - at/beyond -2 to -3 sigma -> overextended BELOW fair value;
#     a VPA buying-climax / spring here is higher conviction (long).
# Does NOT generate trades and does NOT compute any VPA bar logic itself.
# v4: gated by bwOK so a near-zero sigma in the first minutes of a new
# VWAP period cannot flag a trivially small move as a "2-sigma stretch."
# v4.1: also silent until the anchor holds minAnchorBars bars (bands NaN).
# #######################################################
input showVpaConfluenceLabel = yes;

def atUpperStretch = bwOK and !IsNaN(VWAPUB2) and h >= VWAPUB2;   # >= +2 sigma
def atUpperExtreme = bwOK and !IsNaN(VWAPUB3) and h >= VWAPUB3;   # >= +3 sigma
def atLowerStretch = bwOK and !IsNaN(VWAPLB2) and l <= VWAPLB2;   # <= -2 sigma
def atLowerExtreme = bwOK and !IsNaN(VWAPLB3) and l <= VWAPLB3;   # <= -3 sigma

AddLabel(showVpaConfluenceLabel and (atUpperStretch or atLowerStretch),
    if atUpperExtreme then "VWAP: +3 sigma EXTREME - overextended above fair value (watch VPA sell-climax/upthrust)"
    else if atUpperStretch then "VWAP: +2 sigma stretch - above fair value (VPA reversal context)"
    else if atLowerExtreme then "VWAP: -3 sigma EXTREME - overextended below fair value (watch VPA buy-climax/spring)"
    else "VWAP: -2 sigma stretch - below fair value (VPA reversal context)",
    if atUpperStretch then Color.RED else Color.GREEN);
# #######################################################
# END VPA CONFLUENCE BRIDGE
# #######################################################
 

Attachments

  • Ultimate-VWAP-v4.3-Quick-Guide.docx
    37.7 KB · Views: 75
Last edited:
Examples of how to swing trade using the Ultimate VWAP v4.3:

I manually drew the Green and Red vertical time lines to represent buy and sell times.
 

Attachments

  • VWAP Ex 01.jpg
    VWAP Ex 01.jpg
    474.1 KB · Views: 50
  • VWAP Ex 02.jpg
    VWAP Ex 02.jpg
    490.9 KB · Views: 48
  • VWAP Ex 03.jpg
    VWAP Ex 03.jpg
    488.2 KB · Views: 49

Join useThinkScript to post your question to a community of 21,000+ developers and traders.

Similar threads

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

87k+ Posts
1035 Online
Create Post

Similar threads

Similar threads

The Market Trading Game Changer

Join 2,500+ subscribers inside the useThinkScript VIP Membership Club
  • Exclusive indicators
  • Proven strategies & setups
  • Private Discord community
  • ‘Buy The Dip’ signal alerts
  • Exclusive members-only content
  • Add-ons and resources
  • 1 full year of unlimited support

Frequently Asked Questions

What is useThinkScript?

useThinkScript is the #1 community of stock market investors using indicators and other tools to power their trading strategies. Traders of all skill levels use our forums to learn about scripting and indicators, help each other, and discover new ways to gain an edge in the markets.

How do I get started?

We get it. Our forum can be intimidating, if not overwhelming. With thousands of topics, tens of thousands of posts, our community has created an incredibly deep knowledge base for stock traders. No one can ever exhaust every resource provided on our site.

If you are new, or just looking for guidance, here are some helpful links to get you started.

What are the benefits of VIP Membership?
VIP members get exclusive access to these proven and tested premium indicators: Buy the Dip, Advanced Market Moves 2.0, Take Profit, and Volatility Trading Range. In addition, VIP members get access to over 50 VIP-only custom indicators, add-ons, and strategies, private VIP-only forums, private Discord channel to discuss trades and strategies in real-time, customer support, trade alerts, and much more. Learn all about VIP membership here.
How can I access the premium indicators?
To access the premium indicators, which are plug and play ready, sign up for VIP membership here.
Back
Top