RVOL na Wetin? How to Read Relative Volume
RVOL na stock volume ÷ im 20-day average. Above 1 mean trading dey busier than normal. Learn intraday time-of-day RVOL and wetin count as high.
Relative volume (RVOL) dey measure how busy stock trading be compared with im recent normal: na the session share volume divide by the stock average daily volume, usually based on the last 20 sessions. RVOL of 1 mean ordinary day, 2 mean shares wey change hands na two times the usual amount, while 0.5 show say session dey run at half speed. Every figure for this page come from minute-level US market data, and exact query dey attached to each panel.
Relative volume na wetin? Plain-English meaning
Raw volume no mean much by itself: five million shares fit be very quiet day for mega-cap, but na event wey small-cap fit see only once every year. Relative volume makes comparison with the stock’s normal activity clear:
RVOL = the day’s volume ÷ the stock’s average daily volume (normally the last 20 sessions)
Make we use hypothetical example: if stock dey average 10 million shares per day and e prints 25 million before market close, e finish with RVOL of 2.5. (Print na trade wey dem report to consolidated tape, the market-wide record of executions. “The tape” na trader shorthand for that record.) The 20-session lookback na convention. Some platforms dey use 10, 30 or 50 days. E roughly represent one calendar month of trading. The window still dey reflect the exchange calendar quirks: holiday half-day dey add only small part of normal session volume to the average, and market holidays and early closes show where those ones dey happen.
Why traders dey watch relative volume?
RVOL na gauge for participation, e no be gauge for direction. High-RVOL days dey gather around events wey people fit identify, like earnings, index additions and headline news. When price move print on heavy volume, crowd dey behind am. But the same move with RVOL of 0.3 fit come from just small number of orders. Activity dey move together with tradability too. Across stocks, names wey dey trade thinly usually get the widest bid-ask spreads. Na the market makers wey quote both sides throughout the day dey post those spreads. For any one stock, quotes normally dey somewhat wider on quiet sessions than on busy ones. Volume also dey support VWAP, the volume-weighted average price, wey be another major volume-based reference.
How to calculate relative volume, and the time-of-day trap
The full-day calculation na one division: total volume for the session ÷ 20-session average daily volume. E only dey honest after market close. The trap na to calculate am mid-session: by 10:30 a.m., running total naturally be just part of any full-day figure, so even strong morning activity fit look weak. Intraday volume dey follow U-shape as the day dey move, and any intraday RVOL need start from that pattern.
Na this be the pattern, measured for SPY, the S&P 500 ETF: median shares traded per minute for each 30-minute clock bucket across the last 30 days of completed sessions, including extended hours from 4:00 a.m. to 8:00 p.m. Eastern Time.
| ET time | median minute volume k |
|---|---|
| 04:00 | 0.6 |
| 04:30 | 0.3 |
| 05:00 | 0.3 |
| 05:30 | 0.3 |
| 06:00 | 0.4 |
| 06:30 | 0.5 |
| 07:00 | 1.1 |
| 07:30 | 1.6 |
| 08:00 | 2.2 |
| 08:30 | 3.3 |
| 09:00 | 4.7 |
| 09:30 | 113.2 |
| 10:00 | 82.9 |
| 10:30 | 77.6 |
| 11:00 | 64.3 |
| 11:30 | 52.3 |
| 12:00 | 49.3 |
| 12:30 | 43.5 |
| 13:00 | 43.4 |
| 13:30 | 36.8 |
The exact SQL behind every number
SELECT formatDateTime(toStartOfInterval(toTimeZone(window_start, 'America/New_York'), INTERVAL 30 MINUTE), '%H:%i') AS et_time,
round(quantileDeterministic(0.5)(toFloat64(volume), toUInt64(toUnixTimestamp(window_start))) / 1000, 1) AS median_minute_volume_k
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
AND window_start >= now() - INTERVAL 30 DAY
AND toDate(toTimeZone(window_start, 'America/New_York')) < toDate(toTimeZone(now(), 'America/New_York'))
GROUP BY et_time
HAVING et_time >= '04:00' AND et_time < '20:00'
ORDER BY et_timeThe 9:30 bucket, wey be the first half hour of regular trading, get median of 113.2 thousand shares per minute, compared with 4.7 thousand for the 9:00 premarket bucket just before am. The pace reduce to 43.5 thousand for the 12:30 bucket, then e build toward market close: 152.6 thousand for the 3:30 bucket, as trading dey move toward the closing auction, and well above the lunchtime low. After the 4:00 p.m. bell, per-minute pace drop sharply into after-hours trading.
Intraday relative volume: adjust am based on time of day
The correction dey change the denominator: compare today’s running total with the average running total for that same time on the clock. To do this, you need know the share of normal day’s volume wey don already complete at each time, based here on SPY’s last 20 completed sessions:
| ET checkpoint | avg % of day volume done |
|---|---|
| 10:00 | 20.7 |
| 12:00 | 42.6 |
| 14:00 | 57.2 |
| 15:30 | 71.2 |
| 16:00 | 87.5 |
The exact SQL behind every number
WITH per_min AS (
SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS et_date,
formatDateTime(toTimeZone(window_start, 'America/New_York'), '%H:%i') AS et_min,
sum(toFloat64(volume)) AS v
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
AND window_start >= now() - INTERVAL 45 DAY
AND toDate(toTimeZone(window_start, 'America/New_York')) < toDate(toTimeZone(now(), 'America/New_York'))
GROUP BY et_date, et_min
),
last20 AS (
SELECT DISTINCT et_date FROM per_min ORDER BY et_date DESC LIMIT 20
)
SELECT checkpoint AS et_checkpoint,
round(avg(share) * 100, 1) AS avg_pct_of_day_volume_done
FROM (
SELECT et_date,
checkpoint,
sumIf(v, et_min < checkpoint) / sum(v) AS share
FROM (
SELECT et_date, et_min, v, arrayJoin(['10:00', '12:00', '14:00', '15:30', '16:00']) AS checkpoint
FROM per_min
WHERE et_date IN (SELECT et_date FROM last20)
)
GROUP BY et_date, checkpoint
)
GROUP BY checkpoint
ORDER BY checkpointBy 10:00 a.m., after half an hour of regular trading, SPY normally don print just 20.7% of the full-day volume wey e go eventually reach. By noon, na 42.6%. By 2:00 p.m., na 57.2%. By 3:30 p.m., e still be only 71.2%. Even when the 4:00 p.m. closing bell ring, total volume na 87.5%. Everything else dey get reported at or after 16:00. Most of am enter the tape during the first few minutes after the bell, when the closing auction and other end-of-day trades happen. The after-hours session itself dey far thinner.
This one match the sharp drop for the chart above. Per-minute trading pace collapse at the bell, even though meaningful part of the day’s total still dey get reported. Time-adjusted morning RVOL divides today’s cumulative volume by the 20-day average multiplied by the checkpoint share.
One caveat: this schedule na SPY own. Each stock get its own clock. The worked example below measures one particular name’s.
One worked example: real heavy-volume session (MU)
June 2026 heavy month for Micron, the MU June 2026 deep-dive dey show the full tape. Na the month’s single biggest-volume session be this, with RVOL math done for both methods:
| session date | vol by 1030 m | avg vol by 1030 m | rvol 1030 adjusted | rvol 1030 naive | session volume m | trailing ADV m | rvol full day |
|---|---|---|---|---|---|---|---|
| 2026-06-25 | 32.8 | 17.3 | 1.9 | 0.64 | 77.2 | 51 | 1.5 |
The exact SQL behind every number
WITH mu_daily AS (
SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS et_date,
sum(toFloat64(volume)) AS day_volume,
sumIf(toFloat64(volume), formatDateTime(toTimeZone(window_start, 'America/New_York'), '%H:%i') < '10:30') AS vol_by_1030
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'MU'
AND window_start >= toDateTime('2026-04-15 00:00:00', 'America/New_York')
AND window_start < toDateTime('2026-07-01 00:00:00', 'America/New_York')
GROUP BY et_date
HAVING day_volume > 1000000
),
biggest AS (
SELECT et_date, day_volume, vol_by_1030
FROM mu_daily
WHERE et_date >= toDate('2026-06-01') AND et_date <= toDate('2026-06-30')
ORDER BY day_volume DESC
LIMIT 1
),
trailing AS (
SELECT sum(day_volume) / 20 AS adv, sum(vol_by_1030) / 20 AS avg_by_1030
FROM (
SELECT day_volume, vol_by_1030
FROM mu_daily
WHERE et_date < (SELECT et_date FROM biggest)
ORDER BY et_date DESC
LIMIT 20
)
)
SELECT formatDateTime((SELECT et_date FROM biggest), '%Y-%m-%d') AS session_date,
round((SELECT vol_by_1030 FROM biggest) / 1e6, 1) AS vol_by_1030_m,
round((SELECT avg_by_1030 FROM trailing) / 1e6, 1) AS avg_vol_by_1030_m,
round((SELECT vol_by_1030 FROM biggest) / (SELECT avg_by_1030 FROM trailing), 1) AS rvol_1030_adjusted,
round((SELECT vol_by_1030 FROM biggest) / (SELECT adv FROM trailing), 2) AS rvol_1030_naive,
round((SELECT day_volume FROM biggest) / 1e6, 1) AS session_volume_m,
round((SELECT adv FROM trailing) / 1e6, 1) AS trailing_adv_m,
round((SELECT day_volume FROM biggest) / (SELECT adv FROM trailing), 1) AS rvol_full_dayMU’s biggest session for the month happen on 2026-06-25. By 10:30 a.m. that day, 32.8 million shares don trade, compared with average of 17.3 million by that same time across the previous 20 sessions. That one give time-adjusted RVOL of 1.9. If you divide the morning total by the full-day average of 51 million instead, the naive reading be 0.64: a below-average day, even though the morning pace dey almost twice the normal rate. The session close with 77.2 million shares, giving full-day RVOL of 1.5.
That closing figure fit look small beside screenshots of movers wey trade at ten-times-average volume. Whether e really small na matter for distribution, and we go measure that next.
Wetín count as high relative volume?
Trading forums dey use thresholds like “RVOL above two na high.” But here na the measured version: we calculate full-day RVOL for every US-listed stock and ETF wey get 20-day average daily volume above 5 million shares, plus full history for 20 previous sessions. Then we rank am by percentile across the group for the latest completed session for our data. One thing about the label: the screen dey count shares, no be dollar value. So this high-volume group cover mega-caps and ETFs down to cheap, high-churn small-caps. High share volume no mean say the instrument easy to trade.
| percentile | rvol |
|---|---|
| p10 | 0.08 |
| p25 | 0.57 |
| p50 (median) | 0.86 |
| p75 | 1.2 |
| p90 | 1.69 |
| p99 | 3.43 |
The exact SQL behind every number
WITH daily AS (
SELECT ticker,
toDate(toTimeZone(window_start, 'America/New_York')) AS et_date,
toFloat64(sum(volume)) AS day_volume
FROM global_markets.delayed_stocks_minute_aggs
WHERE window_start >= now() - INTERVAL 40 DAY
AND toDate(toTimeZone(window_start, 'America/New_York')) < toDate(toTimeZone(now(), 'America/New_York'))
GROUP BY ticker, et_date
),
spy_days AS (
SELECT et_date,
day_volume,
avg(day_volume) OVER (ORDER BY et_date ROWS BETWEEN 20 PRECEDING AND 1 PRECEDING) AS prior_avg
FROM daily
WHERE ticker = 'SPY' AND day_volume > 10000000
),
sessions AS (
SELECT et_date FROM spy_days
),
latest AS (
SELECT max(et_date) AS d FROM spy_days WHERE prior_avg > 0 AND day_volume >= 0.6 * prior_avg
),
prior20 AS (
SELECT et_date FROM sessions WHERE et_date < (SELECT d FROM latest) ORDER BY et_date DESC LIMIT 20
),
rvols AS (
SELECT ticker, day_vol / adv20 AS rvol
FROM (
SELECT ticker,
sumIf(day_volume, et_date = (SELECT d FROM latest)) AS day_vol,
sumIf(day_volume, et_date IN (SELECT et_date FROM prior20)) / 20 AS adv20,
countIf(day_volume > 0 AND et_date IN (SELECT et_date FROM prior20)) AS sessions_traded
FROM daily
WHERE ticker NOT IN ('SPCX')
GROUP BY ticker
HAVING adv20 > 5000000 AND day_vol > 0 AND sessions_traded = 20
)
)
SELECT pair.1 AS percentile,
round(pair.2, 2) AS rvol
FROM (
SELECT arrayJoin(arrayZip(['p10', 'p25', 'p50 (median)', 'p75', 'p90', 'p99'], quantilesExact(0.1, 0.25, 0.5, 0.75, 0.9, 0.99)(rvol))) AS pair
FROM rvols
)
ORDER BY percentileThe median name for this high-volume group traded at 0.86 times its own 20-day average. Nine out of ten names came below 1.69, and only one out of every hundred passed 3.43. Put MU’s session from the previous section beside this table and e no go look modest again. Even busy names spend most days near their own average. Multiples of that average dey rare.
The bottom tail matter too. The 10th percentile sit at 0.08. Readings this low usually show say one very large session still dey inside the stock’s 20-day average. After a spike, that inflated denominator fit hold RVOL down for weeks. The window get memory, both ways.
One warning: this na cross-section from one session only. Percentiles fit shift from day to day. Market-wide event days, like index rebalances and option expirations, fit lift the whole curve.
Which stocks get unusual volume? The RVOL leaderboard
Na the same universe, but dem rank am (the regular weekly version dey for unusual volume stocks this week): the ten highest full-day RVOL readings for the 2026-08-21 session among names wey dey average above 5 million shares per day. Na the stocks wey screener go flag as unusual volume. The screen require full 20 prior sessions. New listings never get meaningful 20-day average, so without this rule dem fit fill the board with bad results.
| ticker | session date | session volume m | ADV 20d m | rvol |
|---|---|---|---|---|
| HOWL | 2026-08-21 | 265 | 5.3 | 50 |
| CAN | 2026-08-21 | 93 | 11 | 8.5 |
| LGCL | 2026-08-21 | 88.1 | 13.1 | 6.8 |
| MRNA | 2026-08-21 | 88.1 | 16 | 5.5 |
| PURR | 2026-08-21 | 36.7 | 9.8 | 3.8 |
| BABA | 2026-08-21 | 32.1 | 8.7 | 3.7 |
| COIN | 2026-08-21 | 24.5 | 7.1 | 3.4 |
| BITX | 2026-08-21 | 26.7 | 8.3 | 3.2 |
| GOSS | 2026-08-21 | 130.9 | 41 | 3.2 |
| TEM | 2026-08-21 | 16.2 | 5.1 | 3.2 |
The exact SQL behind every number
WITH daily AS (
SELECT ticker,
toDate(toTimeZone(window_start, 'America/New_York')) AS et_date,
toFloat64(sum(volume)) AS day_volume
FROM global_markets.delayed_stocks_minute_aggs
WHERE window_start >= now() - INTERVAL 40 DAY
AND toDate(toTimeZone(window_start, 'America/New_York')) < toDate(toTimeZone(now(), 'America/New_York'))
GROUP BY ticker, et_date
),
spy_days AS (
SELECT et_date,
day_volume,
avg(day_volume) OVER (ORDER BY et_date ROWS BETWEEN 20 PRECEDING AND 1 PRECEDING) AS prior_avg
FROM daily
WHERE ticker = 'SPY' AND day_volume > 10000000
),
sessions AS (
SELECT et_date FROM spy_days
),
latest AS (
SELECT max(et_date) AS d FROM spy_days WHERE prior_avg > 0 AND day_volume >= 0.6 * prior_avg
),
prior20 AS (
SELECT et_date FROM sessions WHERE et_date < (SELECT d FROM latest) ORDER BY et_date DESC LIMIT 20
)
SELECT ticker,
formatDateTime((SELECT d FROM latest), '%Y-%m-%d') AS session_date,
round(day_vol / 1e6, 1) AS session_volume_m,
round(adv20 / 1e6, 1) AS adv_20d_m,
round(day_vol / adv20, 1) AS rvol
FROM (
SELECT ticker,
sumIf(day_volume, et_date = (SELECT d FROM latest)) AS day_vol,
sumIf(day_volume, et_date IN (SELECT et_date FROM prior20)) / 20 AS adv20,
countIf(day_volume > 0 AND et_date IN (SELECT et_date FROM prior20)) AS sessions_traded
FROM daily
WHERE ticker NOT IN ('SPCX')
GROUP BY ticker
HAVING adv20 > 5000000 AND day_vol > 0 AND sessions_traded = 20
)
ORDER BY rvol DESC, ticker
LIMIT 10HOWL dey top the board. The stock print 265 million shares, against 20-day average of 5.3 million. Its RVOL na 50. Every row pass its own average. Boards like this dey move away from household mega-caps. To double an already-enormous average, the stock need trade extraordinary number of shares. But smaller name fit multiply its trading volume for one session.
Data notes: how we choose sessions and exclusions
Both ranked tables use the same universe and the same session rule. Candidate session only count as complete after SPY tape for that date reach at least 60% of SPY own prior-20-session average volume. Newest day data dey arrive with delay. This check stop partially loaded day from looking like finished session. Both tables also exclude one symbol wey exchanges recently assign to a new listing. Vendor feeds carry the history of two different companies under that ticker, so its 20-day average no be meaningful baseline. The exclusion list inside the SQL dey stay aligned with our symbol-identity checks for every refresh. Any new reused symbol wey dem flag, we add am the same way.
FAQ
RVOL number wey good na which one?
Official threshold no dey. For high-volume US stocks wey our data measure during the latest completed session, the median stock trade at 0.86 times its 20-day average, the 90th percentile na 1.69, and the 99th na 3.43.
Wetin RVOL of 2 mean?
The stock don trade two times its average volume for the measured window, usually the trailing 20 sessions. The time of day matter: 2 compared with the average for the same time of day na strong mid-session reading; 2 at the close mean say the day trade at double the normal pace.
How una dey calculate relative volume intraday?
Divide today’s cumulative volume by the average cumulative volume for that same clock time across your lookback window. If you divide mid-morning total by full-day average, you go understate the reading badly. By 10:00 a.m., SPY usually don complete only 20.7% of its final day volume.
Relative volume include premarket and after-hours trading?
Platform conventions dey differ. This page count every minute bar for the Eastern Time calendar day, including extended hours. For SPY, premarket contribution small clearly: median of 4.7 thousand shares per minute for the 9:00 bucket, compared with 113.2 thousand just after the open.
High relative volume bullish or bearish?
None of the two. RVOL measure participation, no be direction. Heavy tape dey show for stock’s best days and worst days alike. Historically, high-RVOL sessions dey happen together with earnings, index changes and headline news. The number only show say crowd show up; e no say which direction dem dey support.
Every panel above get the exact SQL wey produce am. Open one, put your own ticker, and measure RVOL for the names wey you actually trade on the Strasmore terminal.