Strasmore Research
Learn am Matt ConnorBy Matt Connor · Updated 2026-10-18 · data as of October 18, 2026 · refreshed weekly

RVOL na Wetin? How to Read Relative Volume

RVOL na stock volume divide by im 20-day average. Above one mean trading dey busier than normal. See intraday time-of-day RVOL and wetin count as high.

Relative volume (RVOL) dey measure how busy stock dey trade compared with its own recent normal level: na the session share volume divide by the stock average daily volume, usually based on the last 20 sessions. RVOL of one mean say na normal day. Two mean say shares wey change hands na twice the usual amount. Zero point five 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? Simple definition

Raw volume by itself no talk much. Five million shares fit mean say mega-cap stock get very quiet day, but for small-cap stock e fit be event wey happen once a year. Relative volume make comparison with the stock’s normal activity clear:

RVOL = volume for the day ÷ 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 print 25 million by market close, e finish with RVOL of 2.5. (Print na trade wey dem report to the consolidated tape, the market-wide record of executions. “The tape” na trader shorthand for that record.) The 20-session lookback na common convention. But some platforms dey use 10, 30, or 50 days. E roughly represent one calendar month of trading. The window still carry the exchange calendar quirks. Holiday half-day add only 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 market participation, no be gauge for direction. High-RVOL days dey cluster around events wey traders 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 at 0.3 fit come from only small number of orders. Activity also dey move with tradability. Across stocks, the most thinly traded names get the widest bid-ask spreads, posted by market makers wey dey quote both sides throughout the day. For any one stock, quotes usually dey somewhat wider during quiet sessions than during the busiest ones. Volume also dey support VWAP, the volume-weighted average price, 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 accurate after market close. The trap na to calculate am halfway through the session. By 10:30 a.m., running total naturally still be only part of any full-day figure, so even violent morning activity fit look quiet. Intraday volume dey follow U-shape through the day. Any intraday RVOL must start from this pattern.

Na the pattern be this, measured on SPY, the S&P 500 ETF: median shares traded per minute for each 30-minute clock bucket across the last 30 completed sessions, including extended hours from 4:00 a.m. to 8:00 p.m. Eastern Time.

QuerySPY: median shares traded per minute, by 30-minute clock bucket (ET, last 30 days, extended hours)
32 rows (showing 20)
ET timemedian minute volume k
04:000.7
04:300.5
05:000.4
05:300.4
06:000.4
06:300.4
07:001.4
07:301.5
08:001.9
08:302.5
09:003.6
09:3095.5
10:0068.2
10:3058.9
11:0049.1
11:3045
12:0039.8
12:3037.8
13:0037.1
13:3034.2
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_time
Run am yourself

For the 9:30 bucket, wey be the first 30 minutes of regular trading, median pace na 95.5 thousand shares per minute. The 9:00 premarket bucket just before am record 3.6 thousand. Pace come reduce to 37.8 thousand for the 12:30 bucket, then e build toward market close: 138.9 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 for time of day

The fix dey change the denominator: compare today running total with the average running total for that same time of day. To do this, you need know the share of normal day volume wey don complete at each time. For here, dem measure am trade by trade from the consolidated tape for SPY last 20 completed sessions:

QuerySPY: average share of full-day volume wey don complete by each clock time (last 20 sessions)
ET checkpointaverage percent of day volume wey don done
10:0012
12:0034.3
14:0051.1
15:3064.9
16:0082.8
The exact SQL behind every number
WITH per_min AS (
    SELECT toDate(toTimeZone(sip_timestamp, 'America/New_York')) AS et_date,
           formatDateTime(toTimeZone(sip_timestamp, 'America/New_York'), '%H:%i') AS et_min,
           sum(toFloat64(size)) AS v
    FROM global_markets.stocks_trades
    WHERE ticker = 'SPY'
      AND sip_timestamp >= now() - INTERVAL 45 DAY
      AND toDate(toTimeZone(sip_timestamp, 'America/New_York')) < toDate(toTimeZone(now(), 'America/New_York'))
      AND NOT hasAny(conditions, [15, 16, 38])
    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 checkpoint
Run am yourself

By 10:00 a.m., 30 minutes into regular trading, SPY usually don print just 12% of the final full-day volume. By noon, na 34.3%. By 2:00 p.m., na 51.1%. By 3:30 p.m., e still be only 64.9%. Even for the 4:00 p.m. closing bell, the total reach 82.8%. Everything else dey get reported for or after 16:00. Most of am land within the first few minutes after the bell, when closing auction and other end-of-day trades hit the tape. The after-hours session itself dey far thinner.

This match the cliff for the chart above. Per-minute pace collapse for the bell even as meaningful part of the day total still dey get reported. Time-adjusted morning RVOL divides today 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 measure one name own.

Example wey show how e work: one real heavy-volume session (MU)

June 2026 na heavy month for Micron. the MU June 2026 deep-dive go through the full tape. Na the biggest-volume session for that month be this one, and we calculate the RVOL in two ways:

QueryMU, the session wey get the biggest volume for June 2026: time-adjusted vs. naive RVOL, plus the full-day figure
session datevolume by 1030 maverage volume by 1030 mRVOL 1030 adjustedRVOL 1030 naivesession volume mtrailing ADV mRVOL full day
2026-06-2532.817.31.90.6477.2511.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_day
Run am yourself

MU biggest session for the month happen on 2026-06-25. By 10:30 a.m. that day, 32.8 million shares don trade. The average by that same time across the previous 20 sessions na 17.3 million shares. That one give time-adjusted RVOL of 1.9. If you divide the morning total by the full-day average of 51 million shares instead, the naive reading na 0.64. That one make am look like below-average day, even though the morning pace dey almost two times the normal pace. The session close with 77.2 million shares traded, 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 of distribution, and we go measure that next.

Wetin count as high relative volume?

Trading forums dey throw around threshold like “RVOL above 2 na high.” But na measured version be this: full-day RVOL for every US-listed stock and ETF wey get 20-day average daily volume above 5 million shares, plus full 20 prior sessions of history. We rank dem by percentile across the group for the latest completed session inside our data. One thing about the label: the screen dey count shares, no be dollars. So this high-volume group cover mega-caps and ETFs, reach cheap small-caps wey get plenty churning. High share volume no mean say instrument easy to trade.

QueryFull-day RVOL percentiles across high-volume US stocks and ETFs (20-day ADV above 5M shares), latest completed session
percentileRVOL
p100.1
p250.77
p50 (median)1.05
p751.38
p901.81
p993.99
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 percentile
Run am yourself

The median name for this high-volume group traded at 1.05 times its own 20-day average. Nine out of ten names come below 1.81, and only one out of hundred pass 3.99. Put MU’s session from the previous section beside this table, e no longer look modest. 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.1. Readings wey low like this usually point to stock wey still get one very large session inside its 20-day average. After a spike, the inflated denominator go hold RVOL down for weeks. The window get memory, for both directions.

One caveat: this na cross-section from only one session. 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 differently. The regular weekly version dey here: unusual volume stocks this week. E show the ten highest full-day RVOL readings for the 2026-10-15 session among names wey dey average more than 5 million shares per day. Na the kind board wey screener go flag as unusual volume. The screen need full 20 prior sessions. New listings no get meaningful 20-day average, so without this rule dem fit fill the board with misleading results.

QueryTop 10 by full-day RVOL: latest completed session (20-day ADV above 5M shares, full history required)
tickersession datesession volume mADV 20d mRVOL
CCC2026-10-153189.334.1
WETO2026-10-15111.26.517
SDST2026-10-151641.1106.315.4
DKI2026-10-15125.719.16.6
WFF2026-10-15140.123.16.1
ERIC2026-10-1539.98.24.9
WULF2026-10-15105.926.54
CRWV2026-10-15127.532.63.9
HUMA2026-10-1520.75.33.9
KORU2026-10-1577.421.43.6
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 10
Run am yourself

At the top of the board, CCC print 318 million shares, compared with 20-day average of 9.3 million. That give am RVOL of 34.1. Every row pass its own average. Boards like this dey favor names wey no be household mega-caps. To double a very large average, the stock need extraordinary number of shares. But smaller name fit multiply its trading volume inside one session.

Data notes: how we choose sessions and exclusions

Both ranked tables use the same universe and the same session rule. We only count a candidate session as complete after SPY trading for that date reach at least 60% of SPY own prior-20-session average volume. The newest day data dey arrive with lag. This check stop us from treating a partly loaded day as finished session. Both tables also remove one symbol wey exchanges recently assign to a new listing. Vendor feeds carry the trading history of two different companies under that ticker, so its 20-day average no be meaningful baseline. The SQL exclusion list dey stay aligned with our symbol-identity checks every time we refresh. If any reused symbol get flagged again, we add am the same way.

FAQ

Good RVOL number na wetin?

No official threshold dey. For high-volume US stocks wey we measure for the latest completed session inside our data, the median stock trade at 1.05 times e 20-day average. The 90th percentile na 1.81, while the 99th percentile na 3.99.

RVOL of 2 mean wetin?

The stock don trade two times e average volume for the measured window, usually the trailing 20 sessions. Time of day matter. RVOL of 2 against the average for the same time of day na strong mid-session reading. RVOL of 2 at market close mean say the stock trade at double the normal daily pace.

How una dey calculate relative volume intraday?

Divide today cumulative volume by the average cumulative volume for that same time of day across your lookback window. If you divide mid-morning total by full-day average, you go seriously understate the reading. By 10:00 a.m., SPY don usually complete only 12% of the volume e go eventually trade that day.

Relative volume dey include premarket and after-hours trading?

Platform conventions no be the same. This page dey count the whole Eastern Time calendar day, including extended hours. For SPY, premarket contribution small well. The median na 3.6 thousand shares per minute for the 9:00 bucket, compared with 95.5 thousand just after the open.

High relative volume bullish or bearish?

None of the two. RVOL dey measure participation, no be direction. Heavy tape fit show for stock best days and worst days. Historically, high-RVOL sessions dey happen around earnings, index changes and headline news. The number only show say crowd show up; e no show which direction dem dey support.


Every panel above get the exact SQL wey produce am. Open any one, replace the ticker with your own, then measure RVOL for the names wey you actually trade on the Strasmore terminal.