Indicator · Pine Script v5 · Own pane

RVol Panel

by samkdgit

RVol Panel plots relative volume in a separate pane for intraday charts.

View on GitHub

GitHub stars1on the repository
Pine versionv5runs as is
Lines of code247
Settings17inputs
LicenceMIT
Last update11 months ago18 Nov 2025

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

247 lines of Pine Script v5 from code.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.

code.pine
//@version=5
indicator("RVol Panel", shorttitle="RVol Panel", overlay=false,  max_bars_back = 5000)

//──────────────────── USER SETTINGS
daysRVol     = input.int(20,  "Days in RV Baseline")
volMALen     = input.int(20,  "Volume-MA Length")
th0          = input.float(0.50, "Thresh 0 (black → red)")
th1          = input.float(1.25, "Thresh 1 (red→orange)")
th2          = input.float(2.00, "Thresh 2 (orange→green)")
th3 = input.float(2.25, "Thresh 3  (green → light-blue)")
th4 = input.float(3.00, "Thresh 4  (light-blue → purple)")
useGradient  = input.bool(false, "Gradient bar colours?")

//──────────────────── ALERT SETTINGS
string grpAlert        = "RVol Alerts"
bool   enableRVolAlert = input.bool(true, "Enable high RVol streak alert", group=grpAlert)
int    alertBars       = input.int(2, "Consecutive bars (green or higher)", minval=1, maxval=10, group=grpAlert)

// New York cash session (09:30–16:00) in chart timezone
string alertSession    = input.session("0930-1600", "Alert session (New York time)", group=grpAlert)

//──────────────────── COLOURS (sampled from your screenshot)
chipMA   = color.rgb(123, 163, 255)
chipHist = color.rgb(255, 191, 126)
chipVol  = color.rgb(255, 231, 146)
chipCur  = color.rgb(120, 183, 242)
chipRVol = color.rgb(255, 255, 255)
txtCol   = color.rgb( 30, 30,  30)
borderCol= color.rgb(0, 0, 0)
colBlack = color.rgb(0, 0, 0)   // super‑low volume
colLightBlue = color.rgb(74, 155, 232)   // >2.25× RVOL
colPurple    = color.rgb(145, 56, 235)   // >3.00× RVOL

colRed    = color.rgb(160,  0,  0)
colOrange = color.rgb(230,130,  0)
colGreen  = color.rgb(  0,160,  0)

//──────────────────── HELPERS
fmt(v)  => str.tostring(v, format.volume)
pad(s)  => " " + s + " "                // thin padding

//──────────────────── SESSION STATE  (arrays → no bar-limit errors)
var float   cumVol   = 0.0
var int[]   dayStart = array.new_int()
var float[] cumBuf   = array.new_float()
var float[] volBuf   = array.new_float()

isNewDay() =>
    t = time("D")
    (na(t[1]) and not na(t)) or t[1] < t

if isNewDay()
    cumVol := 0
    array.push(dayStart, bar_index)
    if array.size(dayStart) > daysRVol + 1
        array.shift(dayStart)

cumVol += volume
array.push(cumBuf, cumVol)
array.push(volBuf, volume)

//────────────────────  RV CALC (bar-RV & cumulative-RV)
calcRV() =>
    float barAvg = 0.0
    float cumAvg = 0.0
    int   n      = array.size(dayStart)
    if n >= daysRVol + 1
        int barsIntoSess = bar_index - array.get(dayStart, n-1)
        for i = 1 to daysRVol
            int d0  = array.get(dayStart, n - i - 1)
            int d1  = (i == 1) ? bar_index : array.get(dayStart, n - i) - 1
            int idx = math.min(d0 + barsIntoSess, d1)         // clamp if that day was shorter
            barAvg += array.get(volBuf, idx) / daysRVol
            cumAvg += array.get(cumBuf, idx) / daysRVol
    [barAvg > 0 ? volume / barAvg : 0,
     cumAvg > 0 ? cumVol  / cumAvg : 0,
     barAvg, cumAvg]

[barRV, cumRV, histBarAvg, histCumAvg] = calcRV()

//──────────────────── BAR COLOUR
getBarCol(rv) =>
    // ── Simple traffic‑light (no gradient) ───────────────────────────
    if not useGradient
        rv < th0 ? colBlack :            rv < th1 ? colRed   :           rv < th2 ? colOrange:    rv < th3 ? colGreen :    rv < th4 ? colLightBlue : colPurple  
    // ── Smooth gradient version ─────────────────────────────────────
    else
        rv < th0 ? colBlack :rv < th1 ? color.from_gradient(rv, th0, th1, colBlack, colRed) :rv < th2 ? color.from_gradient(rv, th1, th2, colRed,   colOrange) : color.from_gradient(rv, th2, th2*2, colOrange, colGreen)
//──────────────────── PLOTS
// MA first (bars will overlap it)
// Historical same-bar average volume baseline from past daysRVol sessions
avgVolBaseline = histBarAvg > 0 ? histBarAvg : na
plot(avgVolBaseline, color=chipMA, linewidth=2, title="Avg Volume (same-bar baseline)")


// Bars on top
plot(volume,
     style     = plot.style_columns,
     color     = getBarCol(barRV),
     linewidth = 3,
     title     = "Bar Volume")

hline(0, color=color.new(color.gray, 90))   // keep zero visible

//──────────────────── LEGEND TABLE  (2 cols × 5 rows)
var table panel = table.new(position.top_right, 2, 1, border_width=1, border_color=borderCol)


//──────────────────── APPEND — EXTRA CUMV STATS (add-only, no edits above)

// Human-friendly K/M/B formatter
fmtKM(v) =>
    string out = na
    if na(v)
        out := "na"
    else
        float av = math.abs(v)
        out := av >= 1e9 ? str.tostring(v / 1e9, "#.##") + "B" :
               av >= 1e6 ? str.tostring(v / 1e6, "#.##") + "M" :
               av >= 1e3 ? str.tostring(v / 1e3, "#.##") + "K" :
                           str.tostring(v, "#")
    out

// Gather indices safely
int nDays = array.size(dayStart)
bool haveYday = nDays >= 2
bool have3    = nDays >= 4

int yStart = na
int yEndEx = na
int yEndIx = na
float yCumTotal = na

if haveYday
    yStart := array.get(dayStart, nDays - 2)
    yEndEx := array.get(dayStart, nDays - 1)
    yEndIx := yEndEx - 1
    yCumTotal := array.get(cumBuf, yEndIx)

// Last 3 complete days average cumulative volume
float avg3Total = na
if have3
    float s = 0.0
    int c = 0
    for i = 1 to 3
        int dStart = array.get(dayStart, nDays - i - 1)
        int dEndEx = array.get(dayStart, nDays - i)
        int dEndIx = dEndEx - 1
        float totI = array.get(cumBuf, dEndIx)
        s += totI
        c += 1
    avg3Total := c > 0 ? s / c : na

// % of today's cumulative (at this time) vs yesterday's same time
float pctVsY_sameTime = na
if haveYday
    int currStart = array.get(dayStart, nDays - 1)
    int barsInto  = bar_index - currStart
    int ySameIx   = math.min(yStart + barsInto, yEndIx)
    float ySame   = array.get(cumBuf, ySameIx)
    pctVsY_sameTime := ySame > 0 ? (cumVol / ySame) * 100.0 : na

// Table (separate from your existing 'panel' variable; zero edits to it)
var table rvolExtra = table.new(position.top_right, 2, 3, border_width=1, border_color=borderCol)

// Update table cells each bar
table.cell(rvolExtra, 0, 0, "Yday CV", text_color=txtCol, bgcolor=chipVol)
table.cell(rvolExtra, 1, 0, fmtKM(yCumTotal), text_color=txtCol)

table.cell(rvolExtra, 0, 1, "3d CV", text_color=txtCol, bgcolor=chipVol)
table.cell(rvolExtra, 1, 1, fmtKM(avg3Total), text_color=txtCol)

table.cell(rvolExtra, 0, 2, "% vs Y", text_color=txtCol, bgcolor=chipVol)
table.cell(rvolExtra, 1, 2, na(pctVsY_sameTime) ? "na" : str.tostring(pctVsY_sameTime, "#.##") + "%", text_color=txtCol)

//──────── DAILY TOTALS (consolidated) — append-only
float dVol = request.security(syminfo.tickerid, "D", volume)  // daily aggregated volume
float ydayDTotal = dVol[1]
float avg3DTotal = ta.sma(dVol[1], 3)

//──────── SCALE “@now vs Yday” to daily-consolidated totals — append-only
float yIntraTotal = haveYday ? array.get(cumBuf, yEndIx) : na
float scaleY = haveYday and yIntraTotal > 0 ? ydayDTotal / yIntraTotal : na
float ySameScaled = not na(scaleY) ? (array.get(cumBuf, math.min(yStart + (bar_index - array.get(dayStart, nDays - 1)), yEndIx)) * scaleY) : na
float pctVsY_sameTime_adj = not na(ySameScaled) and ySameScaled > 0 ? (cumVol / ySameScaled) * 100.0 : na

//──────────────────── ALERT LOGIC — append-only

// "Green or higher" = barRV >= th2
bool isHighRVol = not na(barRV) and barRV >= th2

// Running streak of consecutive high-RVol bars
var int streakHighRVol = 0
if isHighRVol
    streakHighRVol := streakHighRVol + 1
else
    streakHighRVol := 0

// Condition: at least `alertBars` consecutive green-or-higher bars
bool highRVolStreak = enableRVolAlert and streakHighRVol >= alertBars

// Optional visual marker in the pane
// plotshape(highRVolStreak, title="High RVol streak", style=shape.triangleup, location=location.top, size=size.tiny, color=colGreen)

// Alert condition — set alert to "Once per bar close"
alertcondition(highRVolStreak, "RVol: high streak", "RVol Panel: high RVol streak")



//──────────────────── APPEND — EXTRA PANEL STYLE (fixed)

// Inputs
string grpStyle      = "RVol Extra — Style"
bool   compactLbls   = input.bool(true,  "Compact labels", group=grpStyle)
string txtSizeOpt    = input.string("Tiny", "Text size", options=["Tiny","Small","Normal"], group=grpStyle)
color  hdrBgCol      = input.color(color.new(color.yellow, 10), "Header BG",  group=grpStyle)
color  valBgCol      = input.color(color.new(color.black,   0), "Value BG",   group=grpStyle)
color  tblBorderCol  = input.color(borderCol, "Border color",    group=grpStyle)
int    tblBorderW    = input.int(1, "Border width", minval=0, maxval=3, group=grpStyle)

// Map string → enum size  (no type annotation; just assign)
txtSize = txtSizeOpt == "Tiny"  ? size.tiny :
          txtSizeOpt == "Small" ? size.small :
                                  size.normal


// Slimmer borders/frame
table.set_border_color(rvolExtra, tblBorderCol)
table.set_border_width(rvolExtra, tblBorderW)
table.set_frame_color(rvolExtra,  tblBorderCol)
table.set_frame_width(rvolExtra,  tblBorderW)

// Compact labels
string lblY    = compactLbls ? "Yday"    : "Yday CumVol"
string lblAvg3 = compactLbls ? "Avg 3d"  : "Avg 3d CumVol"
string lblPct  = compactLbls ? "% Yday@" : "% vs Yday @now"

// Repaint cells with smaller text + chosen colors
table.cell(rvolExtra, 0, 0, lblY,                  text_color=txtCol, bgcolor=hdrBgCol, text_size=txtSize)
table.cell(rvolExtra, 1, 0, fmtKM(yCumTotal),      text_color=txtCol, bgcolor=valBgCol, text_size=txtSize)

table.cell(rvolExtra, 0, 1, lblAvg3,               text_color=txtCol, bgcolor=hdrBgCol, text_size=txtSize)
table.cell(rvolExtra, 1, 1, fmtKM(avg3Total),      text_color=txtCol, bgcolor=valBgCol, text_size=txtSize)

string pctText = na(pctVsY_sameTime) ? "na" : str.tostring(pctVsY_sameTime, "#.##") + "%"
table.cell(rvolExtra, 0, 2, lblPct,                text_color=txtCol, bgcolor=hdrBgCol, text_size=txtSize)
table.cell(rvolExtra, 1, 2, pctText,               text_color=txtCol, bgcolor=valBgCol, text_size=txtSize)

Overview

RVol Panel compares each bar’s volume with the same bar position across a configurable number of recent sessions and also tracks cumulative session volume against that baseline. Bars are colored by adjustable relative-volume thresholds, with an optional gradient. A table shows current readings. An optional alert fires after a chosen streak of high relative-volume bars during the New York cash session. It does not generate entries or exits.

Details

Published by

samkdgit on GitHub

Type

Indicator, Pine Script v5

Draws

Separate pane below the chart

Category

Volume, Sessions & time, Screeners & dashboards

Markets

Any symbol

Timeframes

M15-H1

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
Days in RV Baselineint20daysRVol
Volume-MA Lengthint20volMALen
Thresh 0 (black → red)float0.50th0
Thresh 1 (red→orange)float1.25th1
Thresh 2 (orange→green)float2.00th2
Thresh 3 (green → light-blue)float2.25th3
Thresh 4 (light-blue → purple)float3.00th4
Gradient bar colours?boolfalseuseGradient
Enable high RVol streak alertbooltrueenableRVolAlert
Consecutive bars (green or higher)int2alertBars
Alert session (New York time)session0930-1600alertSession
Compact labelsbooltruecompactLbls
Show all 17 settings
SettingTypeDefaultVariable
Text sizestringTinytxtSizeOpt
Header BGcolorcolor.new(color.yellow, 10)hdrBgCol
Value BGcolorcolor.new(color.black, 0)valBgCol
Border colorcolorborderColtblBorderCol
Border widthint1tblBorderW
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

Equity Intraday Analyst

by chris-c-thomas
14 stars

Equity Intraday Analyst is a comprehensive intraday overlay indicator for US equities and ETFs. It evaluates multi-EMA ribbons, session-anchored VWAP bands, OBV trends, momentum oscillators, TTM Squeeze, and optional market breadth indicators like NYSE TICK an

Indicator v6 TrendVolume
Updated 6 months ago · MIT GitHub repository of Equity Intraday Analyst
9 stars

Peak Trading Activity Graphs displays historical market activity across cyclical timeframes directly on the main chart using an on-screen dashboard table. It evaluates volume or volatility across selected periods, including hours of the day, days of the week,

Indicator v6 VolumeVolatility & bands
Updated 4 months ago · MIT GitHub repository of Peak Trading Activity Graphs [LuxAlgo]
9 stars

Smart Money Dashboard plots key Smart Money Concepts on the price chart, including Order Blocks with mitigation tracking, Fair Value Gaps, and Equal Highs or Lows sweeps. It analyzes Cumulative Volume Delta for divergence and combines multi-timeframe structure

Indicator v6 SMC / ICT / price actionVolume
Updated yesterday · MIT GitHub repository of Smart Money Dashboard

CRT State Engine

by alboogycOdR
6 stars

This overlay indicator runs a CRT state engine on the price chart. It can analyze draw-on-liquidity pivots, a session state machine, and optional 1AM, 5AM, and 9AM CRT models. Optional modules track market structure, liquidity pools, volume-profile levels, and

Indicator v5 SMC / ICT / price actionSessions & time
Updated 7 months ago · None stated GitHub repository of CRT State Engine

SUMMARY

by ryangaraygay
2 stars

This indicator aggregates multiple technical signals into an on-chart summary table. It calculates a session-based VWAP, a triple-EMA-smoothed price-volume oscillator, an EMA 9/21 trend spread, multi-timeframe Donchian channel breakouts, and an opening range h

Indicator v6 Screeners & dashboardsSessions & time
Updated 1 year ago · MIT GitHub repository of SUMMARY

More indicators

Trade Your Charts With a Regulated Broker

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

Compare brokers