What it does
Raw volume is hard to compare across instruments and times of day. Relative volume (RVOL) solves that by expressing each bar's volume as a multiple of a recent average. An RVOL of 1.0 is average, 2.0 is twice the usual, 0.5 is half.
This indicator plots RVOL as columns, colors them by candle direction, and highlights bars above a high and an extreme threshold. You can also paint those candles on the price chart.
How it works
- Baseline = SMA, EMA or median of volume over the previous N bars. The current bar is excluded, so a spike does not inflate its own baseline.
- RVOL = current bar volume ÷ baseline.
- Columns are colored by candle direction (close at or above open = up color, otherwise down color). Bars at or above the high threshold use the highlight color, and extreme bars use it at full strength. Low-RVOL bars are faded.
- Alerts fire on each closed bar whose RVOL is at or above the high or extreme threshold.
How to use it
Unusual volume often accompanies the moments that matter: a breakout from a range, a rejection at a key level, or a reaction to economic data. RVOL makes those bars easy to spot.
Ways traders use it:
- Breakout confirmation: a range break on RVOL above 2 is generally regarded as better supported than one on below-average volume.
- Rejection candles: a long wick at resistance with high RVOL shows strong participation at that level.
- Session awareness: on intraday forex charts, RVOL naturally rises at the London and New York opens. The forex market hours page shows when those sessions overlap.
- Quiet markets: a long run of low RVOL bars often precedes larger moves, which pairs well with volatility tools.
The median baseline is less affected by one-off spikes than the SMA; the EMA reacts faster to recent changes.
Settings
| Input | Default | What it changes |
|---|---|---|
| Average length (bars) | 20 | Bars in the baseline. |
| Average type | SMA | SMA, EMA or median. |
| High RVOL threshold | 2.0 | First highlight level. |
| Extreme RVOL threshold | 3.0 | Second highlight level. |
| Low RVOL threshold | 0.5 | Bars below this are faded. |
| Color columns by candle direction | on | Direction coloring. |
| Highlight high-RVOL candles | off | Paints price candles. |
Limitations
- The baseline is a simple bar-count average, not a time-of-day average. Intraday RVOL will often read high at session opens and low overnight simply because of the daily rhythm.
- On spot forex, TradingView volume is generally tick volume from one feed.
- The live bar's RVOL rises as the bar trades; it only becomes final at the close. Alerts wait for the close.
- High volume does not say which side won. Read it together with price.
- The script stops with an error on symbols with no volume data.
Pine Script source
In TradingView open Pine Editor, paste the code, click Save and then Add to chart.
FXP_RelativeVolume.pine
54 lines
// © FXPIPS ONLINE — https://fxpips.online/tradingview-indicators/relative-volume/
// License: MIT. Educational tool — not financial advice. Trading involves substantial risk.
//@version=6
indicator("FXP Relative Volume", shorttitle = "FXP RVOL", overlay = false)
// ── Inputs ─────────────────────────────────────────────────────────────
grpR = "Relative volume"
avgLen = input.int(20, "Average length (bars)", minval = 2, group = grpR)
avgType = input.string("SMA", "Average type", options = ["SMA", "EMA", "Median"], group = grpR)
highLvl = input.float(2.0, "High RVOL threshold", minval = 1.0, step = 0.1, group = grpR)
extremeLvl = input.float(3.0, "Extreme RVOL threshold", minval = 1.0, step = 0.1, group = grpR)
lowLvl = input.float(0.5, "Low RVOL threshold", minval = 0.0, maxval = 1.0, step = 0.05, group = grpR)
grpVis = "Display"
dirColors = input.bool(true, "Color columns by candle direction", group = grpVis)
paintBars = input.bool(false, "Highlight high-RVOL candles on the price chart", group = grpVis)
upCol = input.color(color.teal, "Up-candle color", group = grpVis)
dnCol = input.color(color.red, "Down-candle color", group = grpVis)
hotCol = input.color(color.orange, "High-RVOL color", group = grpVis)
// ── Calculation ────────────────────────────────────────────────────────
// The baseline uses the previous N bars only, so a volume spike does not dilute its own reading.
float vol = nz(volume)
float avgSma = ta.sma(vol, avgLen)
float avgEma = ta.ema(vol, avgLen)
float avgMed = ta.median(vol, avgLen)
float baseNow = avgType == "SMA" ? avgSma : avgType == "EMA" ? avgEma : avgMed
float base = baseNow[1]
float rvol = base > 0 ? vol / base : na
bool isHigh = rvol >= highLvl
bool isExtreme = rvol >= extremeLvl
bool isLow = rvol <= lowLvl
bool highBar = barstate.isconfirmed and isHigh
bool extBar = barstate.isconfirmed and isExtreme
float cumVol = ta.cum(vol)
if barstate.islast and cumVol == 0
runtime.error("This symbol provides no volume data, so relative volume cannot be calculated.")
// ── Plots ──────────────────────────────────────────────────────────────
color baseCol = dirColors ? (close >= open ? upCol : dnCol) : color.gray
color colCol = isExtreme ? hotCol : isHigh ? color.new(hotCol, 40) : isLow ? color.new(baseCol, 80) : color.new(baseCol, 45)
plot(rvol, "RVOL", style = plot.style_columns, color = colCol)
hline(1.0, "Average (1.0)", color = color.new(color.gray, 40), linestyle = hline.style_dotted)
plot(highLvl, "High threshold", color = color.new(hotCol, 40), style = plot.style_line, display = display.pane)
plot(extremeLvl, "Extreme threshold", color = color.new(hotCol, 0), style = plot.style_line, display = display.pane)
plot(base, "Baseline volume", display = display.data_window)
barcolor(paintBars and isHigh ? hotCol : na)
// ── Alerts ─────────────────────────────────────────────────────────────
alertcondition(highBar, "High relative volume", "FXP RVOL: a bar closed above the high RVOL threshold on {{ticker}} {{interval}}")
alertcondition(extBar, "Extreme relative volume", "FXP RVOL: a bar closed above the extreme RVOL threshold on {{ticker}} {{interval}}")

