Zanger Volume Ratio for ThinkorSwim

SwingIsKing

New member
mod note:
Zanger Volume tells you whether the move has real participation at this exact moment in the session.
The colors show how far above or below normal the volume curve is.
You don’t trade the color—you trade the setup, and the color tells you whether the setup has fuel.
Note: this script is too complicated for watchlists and scans

Below is the code for the Zanger volume ratio that works. I can't take credit for it - it was generated by Claude. And Claude seems to have sourced some of its code from this community. This code mimics the ZVR found on TradingView. For it to work properly you will need a 5 minute chart with a time interval set for 30 days. I compared the results of this code to what I see with the ZVR indicator on TradingView and it does not match exactly but it works well enough for my purposes.

I hope this is helpful...enjoy.
oPhLTP2.png

How To Trade
  • Structure first: Confirm there is Support, trend, VWAP reclaim, higher low, etc.
  • ZVR color second
    • Gray → skip
    • Yellow → only trade A+ structure
    • Violet → continuation is valid
    • Magenta → breakout has real pressure
    • Red → ignition; enter early or not at all
  • Execution third: Your microstructure momentum/oscillator handles timing.
Code:
# Zanger Volume Ratio (ZVR) - Authentic Original Algorithm
# Direct port of the original eSignal ZVR by Fil (fl_zanger_volume_ratio_accumSTUDY.ts)
# sourced from usethinkscript.com thread #5093
#
# Methodology: For each of the 78 RTH bars, accumulates that bar's
# volume across all prior days, then divides today's cumulative volume
# by the average cumulative volume at that same bar position.
# Apply to a 5-minute chart ONLY.

#--------------------------------------------------------------
# INPUTS
#--------------------------------------------------------------
input i_days_length = 20;
input i_show_label = YES;

#--------------------------------------------------------------
# ESTABLISH RTH BOUNDARIES
#--------------------------------------------------------------
def v_days_from_epoch = DaysFromDate(19700101);
def v_rth_start = RegularTradingStart(GetYYYYMMDD()) / (1000 * 60 * 60 * 24);
def v_rth_start_in_minutes = Round((24 * (v_rth_start - v_days_from_epoch) - 5) * 60, 0);
def v_rth_end = RegularTradingEnd(GetYYYYMMDD()) / (1000 * 60 * 60 * 24);
def v_rth_end_in_minutes = Round((24 * (v_rth_end - v_days_from_epoch) - 5) * 60, 0);

def v_rth = if (SecondsFromTime(0) / 60) >= v_rth_start_in_minutes
and (SecondsFromTime(0) / 60) < v_rth_end_in_minutes
then 1 else 0;

def v_eth_pre = if SecondsFromTime(0) / 60 < v_rth_start_in_minutes then 1 else 0;

#--------------------------------------------------------------
# BAR NUMBER WITHIN RTH SESSION (1-78 for 5-min chart)
#--------------------------------------------------------------
def v_agg_period = GetAggregationPeriod() / 1000;
def v_rth_barnum = if v_rth
then RoundDown((SecondsFromTime(0) - v_rth_start_in_minutes * 60) / v_agg_period, 0) + 1
else 0;
def v_max_bars_in_rth = (v_rth_end_in_minutes - v_rth_start_in_minutes) * 60 / v_agg_period;

#--------------------------------------------------------------
# DAY COUNTER — increments each new calendar day
#--------------------------------------------------------------
def v_days = CompoundValue(1,
if GetYYYYMMDD() <> GetYYYYMMDD()[1] then v_days[1] + 1 else v_days[1], 1);
def v_days_divisor = if v_days > 1
then (if v_eth_pre then v_days - 1 else v_days)
else 1;

#--------------------------------------------------------------
# PER-BAR SLOT VOLUME ACCUMULATION
# Each variable accumulates that bar number's volume across ALL days.
# At bar N today, v_aggregated_volume_N = sum of bar-N volumes
# across every day seen so far.
# The average for that slot = accumulated / v_days_divisor
# Today's cumulative volume up to bar N = sum of avg(slot 1..N)
#--------------------------------------------------------------
def b01 = if v_rth_barnum == 1 then b01[1] + volume else b01[1];
def b02 = if v_rth_barnum == 2 then b02[1] + volume else b02[1];
def b03 = if v_rth_barnum == 3 then b03[1] + volume else b03[1];
def b04 = if v_rth_barnum == 4 then b04[1] + volume else b04[1];
def b05 = if v_rth_barnum == 5 then b05[1] + volume else b05[1];
def b06 = if v_rth_barnum == 6 then b06[1] + volume else b06[1];
def b07 = if v_rth_barnum == 7 then b07[1] + volume else b07[1];
def b08 = if v_rth_barnum == 8 then b08[1] + volume else b08[1];
def b09 = if v_rth_barnum == 9 then b09[1] + volume else b09[1];
def b10 = if v_rth_barnum == 10 then b10[1] + volume else b10[1];
def b11 = if v_rth_barnum == 11 then b11[1] + volume else b11[1];
def b12 = if v_rth_barnum == 12 then b12[1] + volume else b12[1];
def b13 = if v_rth_barnum == 13 then b13[1] + volume else b13[1];
def b14 = if v_rth_barnum == 14 then b14[1] + volume else b14[1];
def b15 = if v_rth_barnum == 15 then b15[1] + volume else b15[1];
def b16 = if v_rth_barnum == 16 then b16[1] + volume else b16[1];
def b17 = if v_rth_barnum == 17 then b17[1] + volume else b17[1];
def b18 = if v_rth_barnum == 18 then b18[1] + volume else b18[1];
def b19 = if v_rth_barnum == 19 then b19[1] + volume else b19[1];
def b20 = if v_rth_barnum == 20 then b20[1] + volume else b20[1];
def b21 = if v_rth_barnum == 21 then b21[1] + volume else b21[1];
def b22 = if v_rth_barnum == 22 then b22[1] + volume else b22[1];
def b23 = if v_rth_barnum == 23 then b23[1] + volume else b23[1];
def b24 = if v_rth_barnum == 24 then b24[1] + volume else b24[1];
def b25 = if v_rth_barnum == 25 then b25[1] + volume else b25[1];
def b26 = if v_rth_barnum == 26 then b26[1] + volume else b26[1];
def b27 = if v_rth_barnum == 27 then b27[1] + volume else b27[1];
def b28 = if v_rth_barnum == 28 then b28[1] + volume else b28[1];
def b29 = if v_rth_barnum == 29 then b29[1] + volume else b29[1];
def b30 = if v_rth_barnum == 30 then b30[1] + volume else b30[1];
def b31 = if v_rth_barnum == 31 then b31[1] + volume else b31[1];
def b32 = if v_rth_barnum == 32 then b32[1] + volume else b32[1];
def b33 = if v_rth_barnum == 33 then b33[1] + volume else b33[1];
def b34 = if v_rth_barnum == 34 then b34[1] + volume else b34[1];
def b35 = if v_rth_barnum == 35 then b35[1] + volume else b35[1];
def b36 = if v_rth_barnum == 36 then b36[1] + volume else b36[1];
def b37 = if v_rth_barnum == 37 then b37[1] + volume else b37[1];
def b38 = if v_rth_barnum == 38 then b38[1] + volume else b38[1];
def b39 = if v_rth_barnum == 39 then b39[1] + volume else b39[1];
def b40 = if v_rth_barnum == 40 then b40[1] + volume else b40[1];
def b41 = if v_rth_barnum == 41 then b41[1] + volume else b41[1];
def b42 = if v_rth_barnum == 42 then b42[1] + volume else b42[1];
def b43 = if v_rth_barnum == 43 then b43[1] + volume else b43[1];
def b44 = if v_rth_barnum == 44 then b44[1] + volume else b44[1];
def b45 = if v_rth_barnum == 45 then b45[1] + volume else b45[1];
def b46 = if v_rth_barnum == 46 then b46[1] + volume else b46[1];
def b47 = if v_rth_barnum == 47 then b47[1] + volume else b47[1];
def b48 = if v_rth_barnum == 48 then b48[1] + volume else b48[1];
def b49 = if v_rth_barnum == 49 then b49[1] + volume else b49[1];
def b50 = if v_rth_barnum == 50 then b50[1] + volume else b50[1];
def b51 = if v_rth_barnum == 51 then b51[1] + volume else b51[1];
def b52 = if v_rth_barnum == 52 then b52[1] + volume else b52[1];
def b53 = if v_rth_barnum == 53 then b53[1] + volume else b53[1];
def b54 = if v_rth_barnum == 54 then b54[1] + volume else b54[1];
def b55 = if v_rth_barnum == 55 then b55[1] + volume else b55[1];
def b56 = if v_rth_barnum == 56 then b56[1] + volume else b56[1];
def b57 = if v_rth_barnum == 57 then b57[1] + volume else b57[1];
def b58 = if v_rth_barnum == 58 then b58[1] + volume else b58[1];
def b59 = if v_rth_barnum == 59 then b59[1] + volume else b59[1];
def b60 = if v_rth_barnum == 60 then b60[1] + volume else b60[1];
def b61 = if v_rth_barnum == 61 then b61[1] + volume else b61[1];
def b62 = if v_rth_barnum == 62 then b62[1] + volume else b62[1];
def b63 = if v_rth_barnum == 63 then b63[1] + volume else b63[1];
def b64 = if v_rth_barnum == 64 then b64[1] + volume else b64[1];
def b65 = if v_rth_barnum == 65 then b65[1] + volume else b65[1];
def b66 = if v_rth_barnum == 66 then b66[1] + volume else b66[1];
def b67 = if v_rth_barnum == 67 then b67[1] + volume else b67[1];
def b68 = if v_rth_barnum == 68 then b68[1] + volume else b68[1];
def b69 = if v_rth_barnum == 69 then b69[1] + volume else b69[1];
def b70 = if v_rth_barnum == 70 then b70[1] + volume else b70[1];
def b71 = if v_rth_barnum == 71 then b71[1] + volume else b71[1];
def b72 = if v_rth_barnum == 72 then b72[1] + volume else b72[1];
def b73 = if v_rth_barnum == 73 then b73[1] + volume else b73[1];
def b74 = if v_rth_barnum == 74 then b74[1] + volume else b74[1];
def b75 = if v_rth_barnum == 75 then b75[1] + volume else b75[1];
def b76 = if v_rth_barnum == 76 then b76[1] + volume else b76[1];
def b77 = if v_rth_barnum == 77 then b77[1] + volume else b77[1];
def b78 = if v_rth_barnum == 78 then b78[1] + volume else b78[1];

#--------------------------------------------------------------
# AVERAGE VOLUME PER SLOT (total accumulated / days seen)
#--------------------------------------------------------------
def a01 = b01 / v_days_divisor; def a02 = b02 / v_days_divisor;
def a03 = b03 / v_days_divisor; def a04 = b04 / v_days_divisor;
def a05 = b05 / v_days_divisor; def a06 = b06 / v_days_divisor;
def a07 = b07 / v_days_divisor; def a08 = b08 / v_days_divisor;
def a09 = b09 / v_days_divisor; def a10 = b10 / v_days_divisor;
def a11 = b11 / v_days_divisor; def a12 = b12 / v_days_divisor;
def a13 = b13 / v_days_divisor; def a14 = b14 / v_days_divisor;
def a15 = b15 / v_days_divisor; def a16 = b16 / v_days_divisor;
def a17 = b17 / v_days_divisor; def a18 = b18 / v_days_divisor;
def a19 = b19 / v_days_divisor; def a20 = b20 / v_days_divisor;
def a21 = b21 / v_days_divisor; def a22 = b22 / v_days_divisor;
def a23 = b23 / v_days_divisor; def a24 = b24 / v_days_divisor;
def a25 = b25 / v_days_divisor; def a26 = b26 / v_days_divisor;
def a27 = b27 / v_days_divisor; def a28 = b28 / v_days_divisor;
def a29 = b29 / v_days_divisor; def a30 = b30 / v_days_divisor;
def a31 = b31 / v_days_divisor; def a32 = b32 / v_days_divisor;
def a33 = b33 / v_days_divisor; def a34 = b34 / v_days_divisor;
def a35 = b35 / v_days_divisor; def a36 = b36 / v_days_divisor;
def a37 = b37 / v_days_divisor; def a38 = b38 / v_days_divisor;
def a39 = b39 / v_days_divisor; def a40 = b40 / v_days_divisor;
def a41 = b41 / v_days_divisor; def a42 = b42 / v_days_divisor;
def a43 = b43 / v_days_divisor; def a44 = b44 / v_days_divisor;
def a45 = b45 / v_days_divisor; def a46 = b46 / v_days_divisor;
def a47 = b47 / v_days_divisor; def a48 = b48 / v_days_divisor;
def a49 = b49 / v_days_divisor; def a50 = b50 / v_days_divisor;
def a51 = b51 / v_days_divisor; def a52 = b52 / v_days_divisor;
def a53 = b53 / v_days_divisor; def a54 = b54 / v_days_divisor;
def a55 = b55 / v_days_divisor; def a56 = b56 / v_days_divisor;
def a57 = b57 / v_days_divisor; def a58 = b58 / v_days_divisor;
def a59 = b59 / v_days_divisor; def a60 = b60 / v_days_divisor;
def a61 = b61 / v_days_divisor; def a62 = b62 / v_days_divisor;
def a63 = b63 / v_days_divisor; def a64 = b64 / v_days_divisor;
def a65 = b65 / v_days_divisor; def a66 = b66 / v_days_divisor;
def a67 = b67 / v_days_divisor; def a68 = b68 / v_days_divisor;
def a69 = b69 / v_days_divisor; def a70 = b70 / v_days_divisor;
def a71 = b71 / v_days_divisor; def a72 = b72 / v_days_divisor;
def a73 = b73 / v_days_divisor; def a74 = b74 / v_days_divisor;
def a75 = b75 / v_days_divisor; def a76 = b76 / v_days_divisor;
def a77 = b77 / v_days_divisor; def a78 = b78 / v_days_divisor;

#--------------------------------------------------------------
# CUMULATIVE AVERAGE UP TO CURRENT BAR (the denominator)
# Sum of avg slot volumes from bar 1 through current bar N
#--------------------------------------------------------------
def avgCumVol =
(if v_rth_barnum >= 1 then a01 else 0) +
(if v_rth_barnum >= 2 then a02 else 0) +
(if v_rth_barnum >= 3 then a03 else 0) +
(if v_rth_barnum >= 4 then a04 else 0) +
(if v_rth_barnum >= 5 then a05 else 0) +
(if v_rth_barnum >= 6 then a06 else 0) +
(if v_rth_barnum >= 7 then a07 else 0) +
(if v_rth_barnum >= 8 then a08 else 0) +
(if v_rth_barnum >= 9 then a09 else 0) +
(if v_rth_barnum >= 10 then a10 else 0) +
(if v_rth_barnum >= 11 then a11 else 0) +
(if v_rth_barnum >= 12 then a12 else 0) +
(if v_rth_barnum >= 13 then a13 else 0) +
(if v_rth_barnum >= 14 then a14 else 0) +
(if v_rth_barnum >= 15 then a15 else 0) +
(if v_rth_barnum >= 16 then a16 else 0) +
(if v_rth_barnum >= 17 then a17 else 0) +
(if v_rth_barnum >= 18 then a18 else 0) +
(if v_rth_barnum >= 19 then a19 else 0) +
(if v_rth_barnum >= 20 then a20 else 0) +
(if v_rth_barnum >= 21 then a21 else 0) +
(if v_rth_barnum >= 22 then a22 else 0) +
(if v_rth_barnum >= 23 then a23 else 0) +
(if v_rth_barnum >= 24 then a24 else 0) +
(if v_rth_barnum >= 25 then a25 else 0) +
(if v_rth_barnum >= 26 then a26 else 0) +
(if v_rth_barnum >= 27 then a27 else 0) +
(if v_rth_barnum >= 28 then a28 else 0) +
(if v_rth_barnum >= 29 then a29 else 0) +
(if v_rth_barnum >= 30 then a30 else 0) +
(if v_rth_barnum >= 31 then a31 else 0) +
(if v_rth_barnum >= 32 then a32 else 0) +
(if v_rth_barnum >= 33 then a33 else 0) +
(if v_rth_barnum >= 34 then a34 else 0) +
(if v_rth_barnum >= 35 then a35 else 0) +
(if v_rth_barnum >= 36 then a36 else 0) +
(if v_rth_barnum >= 37 then a37 else 0) +
(if v_rth_barnum >= 38 then a38 else 0) +
(if v_rth_barnum >= 39 then a39 else 0) +
(if v_rth_barnum >= 40 then a40 else 0) +
(if v_rth_barnum >= 41 then a41 else 0) +
(if v_rth_barnum >= 42 then a42 else 0) +
(if v_rth_barnum >= 43 then a43 else 0) +
(if v_rth_barnum >= 44 then a44 else 0) +
(if v_rth_barnum >= 45 then a45 else 0) +
(if v_rth_barnum >= 46 then a46 else 0) +
(if v_rth_barnum >= 47 then a47 else 0) +
(if v_rth_barnum >= 48 then a48 else 0) +
(if v_rth_barnum >= 49 then a49 else 0) +
(if v_rth_barnum >= 50 then a50 else 0) +
(if v_rth_barnum >= 51 then a51 else 0) +
(if v_rth_barnum >= 52 then a52 else 0) +
(if v_rth_barnum >= 53 then a53 else 0) +
(if v_rth_barnum >= 54 then a54 else 0) +
(if v_rth_barnum >= 55 then a55 else 0) +
(if v_rth_barnum >= 56 then a56 else 0) +
(if v_rth_barnum >= 57 then a57 else 0) +
(if v_rth_barnum >= 58 then a58 else 0) +
(if v_rth_barnum >= 59 then a59 else 0) +
(if v_rth_barnum >= 60 then a60 else 0) +
(if v_rth_barnum >= 61 then a61 else 0) +
(if v_rth_barnum >= 62 then a62 else 0) +
(if v_rth_barnum >= 63 then a63 else 0) +
(if v_rth_barnum >= 64 then a64 else 0) +
(if v_rth_barnum >= 65 then a65 else 0) +
(if v_rth_barnum >= 66 then a66 else 0) +
(if v_rth_barnum >= 67 then a67 else 0) +
(if v_rth_barnum >= 68 then a68 else 0) +
(if v_rth_barnum >= 69 then a69 else 0) +
(if v_rth_barnum >= 70 then a70 else 0) +
(if v_rth_barnum >= 71 then a71 else 0) +
(if v_rth_barnum >= 72 then a72 else 0) +
(if v_rth_barnum >= 73 then a73 else 0) +
(if v_rth_barnum >= 74 then a74 else 0) +
(if v_rth_barnum >= 75 then a75 else 0) +
(if v_rth_barnum >= 76 then a76 else 0) +
(if v_rth_barnum >= 77 then a77 else 0) +
(if v_rth_barnum >= 78 then a78 else 0);

#--------------------------------------------------------------
# TODAY'S CUMULATIVE VOLUME
#--------------------------------------------------------------
def firstBar = v_rth and !v_rth[1];
def cumVol = if firstBar then volume
else if v_rth then cumVol[1] + volume
else cumVol[1];

#--------------------------------------------------------------
# ZVR %
#--------------------------------------------------------------
def zvrPct = if avgCumVol > 0 and v_rth
then (cumVol / avgCumVol) * 100
else Double.NaN;

#--------------------------------------------------------------
# PLOT
#--------------------------------------------------------------
plot ZVR = zvrPct;
ZVR.SetPaintingStrategy(PaintingStrategy.HISTOGRAM);
ZVR.SetLineWeight(3);

ZVR.AssignValueColor(
if zvrPct >= 200 then Color.RED
else if zvrPct >= 150 then Color.MAGENTA
else if zvrPct >= 110 then Color.VIOLET
else if zvrPct >= 85 then Color.YELLOW
else Color.GRAY
);

plot RefLine = if v_rth then 100 else Double.NaN;
RefLine.SetDefaultColor(Color.WHITE);
RefLine.SetStyle(Curve.SHORT_DASH);
RefLine.SetLineWeight(1);

AddLabel(i_show_label and v_rth,
"ZVR: " + Round(zvrPct, 0) + "%",
if zvrPct >= 200 then Color.RED
else if zvrPct >= 150 then Color.MAGENTA
else if zvrPct >= 110 then Color.VIOLET
else if zvrPct >= 85 then Color.YELLOW
else Color.GRAY
);
 
Last edited by a moderator:
Why Zanger can be a game changer
Day traders need to know if a move has pressure right now.
Structure alone can’t answer that.
Raw volume can’t answer that.
Relative volume can’t answer that.

Only a time‑of‑day cumulative curve can tell you whether today’s participation is running hot, cold, or normal compared to the baseline that actually matters.

Zanger gives you that read by bar three.
It filters out every weak breakout, every dead pullback, every fake continuation.

It keeps you out of moves that look clean but have no fuel, and it keeps you in moves that look slow but are running above the curve.
It doesn’t predict direction; it tells you whether the move has commitment.

For the day trader, that’s enough to change everything.
Many thanks to @SwingIsKing for this contribution.


FYI: While this is the closest Zanger possible. No, it is not a true Zanger.
ToS can’t store or rotate true multi‑day intraday volume matrices, so it can’t run the full Zanger engine with fixed lookback windows or clean daily resets.
 
Last edited by a moderator:

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
637 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