◆ New — Strategy Validator, Code Fixer & Prop Compliance Checker are live. Try one free →
Home / Indicators / Relative Volume (RVOL)
Volume indicator

Relative Volume (RVOL)

A ratio comparing current volume to what is typical for that moment, so 'high volume' becomes a measured statement instead of a guess.

Illustrative diagram — not live market data.

What it is

Relative Volume (RVOL) expresses a bar's volume as a multiple of a baseline: a reading of 2.0 means volume is running at roughly twice its typical level, and 0.5 means about half. The entire meaning of the number depends on what 'typical' means, and this is where many free implementations quietly go wrong. Intraday volume is not flat across the day — it clusters around session opens and closes, around session overlaps in forex, and around scheduled news. Calculating RVOL correctly for intraday charts means comparing the current bar with the average volume of the same time-of-day slot across prior sessions (time-bucketed RVOL), not with a simple rolling average of the last N bars (naive RVOL). The two versions can disagree substantially on the same bar. RVOL is descriptive: it summarizes how active the market has been relative to its own history and says nothing about future direction. This is educational material, not financial advice, and all trading carries risk of loss.

How it works

Naive RVOL divides the current bar's volume by a simple moving average of recent volume — for example, volume divided by its 20-bar SMA. That baseline mixes together bars from very different parts of the trading day. Because intraday volume typically follows a U-shape (heavy near the open and close, light midday, and heavy at session overlaps in FX), naive RVOL systematically reads 'high' near every open — even a perfectly ordinary open — and 'low' through every lunchtime lull. Time-bucketed RVOL removes that seasonality: for the 09:35 bar, average the volume of the 09:35 bar from each of the prior K sessions and divide today's 09:35 volume by that slot average. A reading of 2.0 then means twice the volume normal for this specific time of day, which is the question traders actually mean to ask. On 24-hour markets with regular bars, the same slot sits a fixed number of bars back each day, which makes the calculation deterministic. One further honesty note: spot forex has no centralized volume, so 'volume' on FX charts is tick volume from your specific feed — RVOL there measures activity at your broker, not global traded volume.

How traders read it

Common settings

Time-bucketed versions typically average the same slot across 5-20 prior sessions (5-10 is common; more sessions smooth the baseline but adapt slower to regime changes). Naive versions usually divide by a 20-50 bar SMA of volume. On very low timeframes, a multi-day slot lookback can exceed the chart's available history, so shorter lookbacks are practical there. Equities and other session-gapped markets need session-aware bucketing rather than a fixed bar offset, and half-days, holidays, and DST shifts all distort the buckets.

Strengths

Pitfalls to watch

Pine v6 example

//@version=6
indicator("Time-of-Day RVOL vs Naive RVOL", overlay = false)

lookbackDays = input.int(5, "Slot Lookback (days)", minval = 1, maxval = 20)
naiveLen     = input.int(20, "Naive Average Length (bars)", minval = 1)

// Bars per day on regular intraday timeframes (24h markets like forex/crypto).
// Session-gapped markets (equities) need session-aware bucketing instead.
barsPerDay = math.max(1, math.round(86400.0 / timeframe.in_seconds()))

// Time-bucketed baseline: average volume at this SAME slot on prior days
float slotSum   = 0.0
int   slotCount = 0
for i = 1 to lookbackDays
    histVol = volume[i * barsPerDay]
    if not na(histVol)
        slotSum   += histVol
        slotCount += 1
slotAvg = slotCount > 0 ? slotSum / slotCount : na
rvolTod = not na(slotAvg) and slotAvg > 0 ? volume / slotAvg : na

// Naive baseline most free scripts use: a flat rolling average
naiveAvg  = ta.sma(volume, naiveLen)
rvolNaive = naiveAvg > 0 ? volume / naiveAvg : na

plot(rvolTod,   "RVOL (time-of-day)", color = color.teal)
plot(rvolNaive, "RVOL (naive)",       color = color.gray)
hline(1.0, "Baseline (typical volume)", color = color.gray)

Pro tip: Before trusting any RVOL number, ask one question: relative to what? Plot the time-bucketed and naive versions side by side for a week and watch how often they disagree at the open — that gap is measurement error, not market information. Read confirmed bars rather than the forming bar, and treat elevated RVOL as context about participation, never as a directional signal. This is educational content only, not financial advice; all trading carries risk of loss.

Built an indicator from this? Run it through the Validator to catch look-ahead bias and repainting, or convert a strategy to Pine Script.

Educational only — not financial advice, not a recommendation to trade. No indicator is predictive; trading involves substantial risk of loss.

Catch the bug that compiles.Run auditGet Pro