Strasmore Research
Learn Matt ConnorBy Matt Connor · Updated 2026-08-25 · data as of August 25, 2026 · refreshed weekly

Unusual Volume Stocks This Week, Measured

Unusual volume stocks this week, ranked: trailing-week turnover vs. each name's prior 40 sessions, with weekly returns, rarity context and persistence.

Unusual volume means a stock trading far above its own normal, not the market's. A megacap doing 40 million shares is a Tuesday; a small-cap doing it is an event. This page ranks the unusual volume stocks of the week just ended: each name's trailing five-session average volume divided by its own average over the prior forty sessions, with a dollar floor so every row is a stock a person could actually trade. It refreshes weekly, and the "data as of" stamp is the window. The measurement itself, relative volume, has its own full guide.

This week's unusual-volume leaders

Three columns do the work. The multiple says how far above its own normal a stock traded. The baseline says what normal was, and a huge multiple off a starving baseline is a smaller event than a modest one off a busy tape. The dollars say whether the activity was economically real. The last column, the week's open-to-close change, is the one most volume screens leave out.

QueryHighest relative volume this week: trailing 5 sessions vs. the prior 40, for names trading $500M+ in the week
tickerrvol_weekrecent_adv_mbaseline_adv_mweek_dollar_bnweek_pct
PFSA8.98.330.940.6-50.2
MRNA6.133.375.4324.42120.6
IPST56.561.310.5312.9
AMLX3.65.291.490.8929.3
UGI3.23.2210.637.8
KLAR2.79.413.50.71-9.6
SAN2.524.229.811.731.2
IEUR2.21.690.760.660.8
The exact SQL behind every number
WITH sess AS (
    SELECT ticker,
           toDate(toTimeZone(window_start, 'America/New_York')) AS d,
           sum(toFloat64(volume)) AS vol,
           sum(toFloat64(close) * toFloat64(volume)) AS dollars,
           argMin(toFloat64(open), toTimeZone(window_start, 'America/New_York')) AS day_open,
           argMax(toFloat64(close), toTimeZone(window_start, 'America/New_York')) AS day_close
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE window_start >= now() - INTERVAL 70 DAY
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) >= 570
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) < 960
      AND ticker NOT IN ('SPCX')
    GROUP BY ticker, d
),
cal AS (
    SELECT d, row_number() OVER (ORDER BY d DESC) AS rn
    FROM (SELECT DISTINCT d FROM sess)
),
per_name AS (
    SELECT s.ticker AS ticker,
           avgIf(s.vol, c.rn <= 5) AS adv_recent,
           avgIf(s.vol, c.rn BETWEEN 6 AND 45) AS adv_base,
           sumIf(s.dollars, c.rn <= 5) AS dollar_recent,
           argMaxIf(s.day_open, c.rn, c.rn <= 5) AS week_open,
           argMinIf(s.day_close, c.rn, c.rn <= 5) AS week_close,
           countIf(c.rn <= 5) AS recent_sessions,
           countIf(c.rn BETWEEN 6 AND 45) AS base_sessions
    FROM sess s INNER JOIN cal c ON s.d = c.d
    GROUP BY s.ticker
    HAVING adv_base > 100000 AND dollar_recent >= 500000000 AND recent_sessions = 5 AND base_sessions >= 35
)
SELECT ticker,
       round(adv_recent / adv_base, 1) AS rvol_week,
       round(adv_recent / 1e6, 2) AS recent_adv_m,
       round(adv_base / 1e6, 2) AS baseline_adv_m,
       round(dollar_recent / 1e9, 2) AS week_dollar_bn,
       round(100.0 * (week_close / week_open - 1), 1) AS week_pct
FROM per_name
ORDER BY rvol_week DESC, ticker ASC
LIMIT 8
Run this yourself

Every row, read in order:

  • PFSA, 8.9x its own norm, the top of the board: 8.33M shares a day against a baseline of 0.94M, $0.6B traded, and an open-to-close change of -50.2%.
  • MRNA, 6.1x on a 5.43M-share baseline, with $24.42B of turnover behind it; the week's change was 120.6%.
  • IPST, 5x, but on a thin 1.31M baseline and only $0.53B of turnover; change on the week, 12.9%.
  • AMLX, 3.6x, 5.29M shares a day versus 1.49M normally; 29.3% open-to-close.
  • UGI, 3.2x, $0.63B traded, 7.8% on the week.
  • KLAR, 2.7x on a 3.5M-share baseline, $0.71B traded, -9.6% open-to-close.
  • SAN, 2.5x, 24.22M shares a day, $1.73B; the week's change, 1.2%.
  • IEUR, the eighth and last row, at 2.2x with $0.66B traded and a 0.8% change.

Direction is not part of the ranking, and the two right-hand columns make that concrete: the board's leader ended the week -50.2% from its opening print while the eighth name ended 0.8% from its own, one screen, opposite experiences. Heavy tape marks the sessions when a stock's float is genuinely being tested; it says nothing about which side of that test won.

How the multiple is calculated

Take a stock that averaged 200,000 shares a day across the prior forty sessions. Over the past week it trades 1,000,000, then 1,400,000, then 900,000, then 1,100,000, then 600,000 shares, a five-session average of 1,000,000. Divide: 1,000,000 ÷ 200,000 = 5.0x. Give the same stock a two-million-share baseline instead and that identical week reads 0.5x. The numerator is this week; the denominator is who the stock normally is. (The denominator itself is just average daily volume, measured over forty sessions rather than the usual twenty.)

Why forty sessions? It runs about two calendar months, long enough that one prior spike cannot dominate the denominator, short enough to still describe the stock as it trades today. Why five for the numerator? A full week, so a single halted session or one-off block does not own the reading.

The arithmetic carries an honest warning: the thinner the baseline, the cheaper the multiple. This week's leader carries a baseline of just 0.94M shares a day, at that size, one crowded session drags the whole weekly average up with it, which is exactly why the board demands a six-figure baseline and a $500M week before a name can appear at all.

How rare is a week like this?

A multiple only means something against the distribution it came from. Same universe, same window, every qualifying name bucketed by its multiple:

QueryHow the whole qualifying universe traded this week, bucketed by relative volume
rvol_bucketnamespct_of_universeuniverse_names
10x or more00508
5x to 10x20.4508
3x to 5x30.6508
2x to 3x61.2508
1.5x to 2x20.4508
1x to 1.5x102508
below 1x48595.5508
The exact SQL behind every number
WITH sess AS (
    SELECT ticker,
           toDate(toTimeZone(window_start, 'America/New_York')) AS d,
           sum(toFloat64(volume)) AS vol,
           sum(toFloat64(close) * toFloat64(volume)) AS dollars
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE window_start >= now() - INTERVAL 70 DAY
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) >= 570
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) < 960
      AND ticker NOT IN ('SPCX')
    GROUP BY ticker, d
),
cal AS (
    SELECT d, row_number() OVER (ORDER BY d DESC) AS rn
    FROM (SELECT DISTINCT d FROM sess)
),
per_name AS (
    SELECT s.ticker AS ticker,
           avgIf(s.vol, c.rn <= 5) AS adv_recent,
           avgIf(s.vol, c.rn BETWEEN 6 AND 45) AS adv_base,
           sumIf(s.dollars, c.rn <= 5) AS dollar_recent,
           countIf(c.rn <= 5) AS recent_sessions,
           countIf(c.rn BETWEEN 6 AND 45) AS base_sessions
    FROM sess s INNER JOIN cal c ON s.d = c.d
    GROUP BY s.ticker
    HAVING adv_base > 100000 AND dollar_recent >= 500000000 AND recent_sessions = 5 AND base_sessions >= 35
),
scored AS (
    SELECT ticker,
           multiIf(adv_recent / adv_base >= 10, 1,
                   adv_recent / adv_base >= 5, 2,
                   adv_recent / adv_base >= 3, 3,
                   adv_recent / adv_base >= 2, 4,
                   adv_recent / adv_base >= 1.5, 5,
                   adv_recent / adv_base >= 1, 6, 7) AS bucket_key
    FROM per_name
),
buckets AS (
    SELECT arrayJoin([(1, '10x or more'), (2, '5x to 10x'), (3, '3x to 5x'), (4, '2x to 3x'),
                      (5, '1.5x to 2x'), (6, '1x to 1.5x'), (7, 'below 1x')]) AS bk
)
SELECT bk.2 AS rvol_bucket,
       countIf(scored.bucket_key = bk.1) AS names,
       round(100.0 * countIf(scored.bucket_key = bk.1) / count(), 1) AS pct_of_universe,
       count() AS universe_names
FROM scored CROSS JOIN buckets
GROUP BY bk
ORDER BY bk.1 ASC
Run this yourself

508 stocks and ETFs cleared the floor this week. Of those, 0 traded at ten times their own norm or more, 0% of the universe. Another 2 landed in the 5x-to-10x bucket and 3 in the 3x-to-5x bucket. The leaderboard above is drawn from that thin top of the table. Below that, 6 names traded at 2x to 3x their own norm (1.2% of the universe) and 2 landed in the 1.5x-to-2x band (0.4%). A further 10 sat at a merely elevated 1x to 1.5x, 2% of the qualifying names.

The other end of the table is the part nobody screenshots: 485 names, 95.5% of the universe, traded below their own forty-session average this week. That is the ordinary state of the market, and it is what makes the top of the board a genuine outlier rather than a rounding error.

Does unusual volume stick around?

The folk claim is that unusual volume persists for days, so a name near the top of a board like this has usually already done its moving. That is testable. For each of the eight leaders: how many of the five sessions ran at twice the baseline or better, how big the single heaviest session was, and how many sessions separated that heaviest session from the week's last.

QueryPersistence check: the eight leaders' daily relative volume across the five sessions
tickerweek_rvoldays_above_2xpeak_day_rvolsessions_since_peak
IEUR2.2110.23
IPST5123.64
MRNA6.1129.63
PFSA8.9142.94
SAN2.526.83
KLAR2.728.54
UGI3.22124
AMLX3.6212.74
The exact SQL behind every number
WITH sess AS (
    SELECT ticker,
           toDate(toTimeZone(window_start, 'America/New_York')) AS d,
           sum(toFloat64(volume)) AS vol,
           sum(toFloat64(close) * toFloat64(volume)) AS dollars
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE window_start >= now() - INTERVAL 70 DAY
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) >= 570
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) < 960
      AND ticker NOT IN ('SPCX')
    GROUP BY ticker, d
),
cal AS (
    SELECT d, row_number() OVER (ORDER BY d DESC) AS rn
    FROM (SELECT DISTINCT d FROM sess)
),
per_name AS (
    SELECT s.ticker AS ticker,
           avgIf(s.vol, c.rn <= 5) AS adv_recent,
           avgIf(s.vol, c.rn BETWEEN 6 AND 45) AS adv_base,
           sumIf(s.dollars, c.rn <= 5) AS dollar_recent,
           countIf(c.rn <= 5) AS recent_sessions,
           countIf(c.rn BETWEEN 6 AND 45) AS base_sessions
    FROM sess s INNER JOIN cal c ON s.d = c.d
    GROUP BY s.ticker
    HAVING adv_base > 100000 AND dollar_recent >= 500000000 AND recent_sessions = 5 AND base_sessions >= 35
),
leaders AS (
    SELECT ticker, adv_recent / adv_base AS rvol_week, adv_base
    FROM per_name
    ORDER BY rvol_week DESC, ticker ASC
    LIMIT 8
),
daily AS (
    SELECT l.ticker AS ticker,
           l.rvol_week AS rvol_week,
           c.rn AS rn,
           s.vol / l.adv_base AS rvol_day
    FROM sess s
    INNER JOIN cal c ON s.d = c.d
    INNER JOIN leaders l ON s.ticker = l.ticker
    WHERE c.rn <= 5
)
SELECT ticker,
       round(max(rvol_week), 1) AS week_rvol,
       countIf(rvol_day >= 2) AS days_above_2x,
       round(max(rvol_day), 1) AS peak_day_rvol,
       argMax(rn, (rvol_day, -rn)) - 1 AS sessions_since_peak
FROM daily
GROUP BY ticker
ORDER BY days_above_2x ASC, peak_day_rvol ASC, ticker ASC
Run this yourself

Sorted by persistence, the least persistent name on the board, IEUR, cleared twice its baseline on 1 of the five sessions, peaking at 10.2x. The most persistent, AMLX, did it on 2 of five, with a peak of 12.7x. These are multi-session events, not single prints, which is the mechanical reason a weekly board and a daily board tend to name the same stocks.

The last column is the timing one: sessions between the heaviest day and the week's final session, 3 for IEUR, 4 for AMLX. Where that gap is above zero, the loudest tape had already printed before the week closed. The board describes the week that ended; it does not forecast the one that starts.

The leader's fifteen sessions, day by day

The weekly average hides the shape. Here is the current leader's daily relative volume, each session's shares against that same forty-session baseline, alongside each session's open-to-close change, over the last fifteen sessions:

QueryThe board leader, day by day: daily relative volume and open-to-close change (last 15 sessions)
session_datesession_labelrvol_dayday_pctpeak_rvol_day
2026-08-04Aug 40.10.342.9
2026-08-05Aug 50.1-2.342.9
2026-08-06Aug 60.10.142.9
2026-08-07Aug 700.642.9
2026-08-10Aug 100-1.742.9
2026-08-11Aug 1103.242.9
2026-08-12Aug 120-0.542.9
2026-08-13Aug 130.211.842.9
2026-08-14Aug 140.1-3.342.9
2026-08-17Aug 171.76.442.9
2026-08-18Aug 1842.920442.9
2026-08-19Aug 191.1-1842.9
2026-08-20Aug 200.4-5.942.9
2026-08-21Aug 2100.142.9
2026-08-24Aug 240.1-5.142.9
The exact SQL behind every number
WITH sess AS (
    SELECT ticker,
           toDate(toTimeZone(window_start, 'America/New_York')) AS d,
           sum(toFloat64(volume)) AS vol,
           sum(toFloat64(close) * toFloat64(volume)) AS dollars,
           argMin(toFloat64(open), toTimeZone(window_start, 'America/New_York')) AS day_open,
           argMax(toFloat64(close), toTimeZone(window_start, 'America/New_York')) AS day_close
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE window_start >= now() - INTERVAL 70 DAY
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) >= 570
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) < 960
      AND ticker NOT IN ('SPCX')
    GROUP BY ticker, d
),
cal AS (
    SELECT d, row_number() OVER (ORDER BY d DESC) AS rn
    FROM (SELECT DISTINCT d FROM sess)
),
per_name AS (
    SELECT s.ticker AS ticker,
           avgIf(s.vol, c.rn <= 5) AS adv_recent,
           avgIf(s.vol, c.rn BETWEEN 6 AND 45) AS adv_base,
           sumIf(s.dollars, c.rn <= 5) AS dollar_recent,
           countIf(c.rn <= 5) AS recent_sessions,
           countIf(c.rn BETWEEN 6 AND 45) AS base_sessions
    FROM sess s INNER JOIN cal c ON s.d = c.d
    GROUP BY s.ticker
    HAVING adv_base > 100000 AND dollar_recent >= 500000000 AND recent_sessions = 5 AND base_sessions >= 35
),
leader AS (
    SELECT ticker, adv_base
    FROM per_name
    ORDER BY adv_recent / adv_base DESC, ticker ASC
    LIMIT 1
),
path AS (
    SELECT formatDateTime(s.d, '%Y-%m-%d') AS session_date,
           formatDateTime(s.d, '%b %e') AS session_label,
           s.vol / l.adv_base AS rvol_day,
           100.0 * (s.day_close / s.day_open - 1) AS day_pct
    FROM sess s
    INNER JOIN cal c ON s.d = c.d
    INNER JOIN leader l ON s.ticker = l.ticker
    WHERE c.rn <= 15
)
SELECT session_date,
       session_label,
       round(rvol_day, 1) AS rvol_day,
       round(day_pct, 1) AS day_pct,
       round(max(rvol_day) OVER (), 1) AS peak_rvol_day
FROM path
ORDER BY session_date ASC
Run this yourself

Fifteen sessions ago the stock was running 0.1x its baseline, an ordinary, quiet name. The heaviest session in the stretch hit 42.9x. On the most recent session, Aug 24, the tape still ran 0.1x with an open-to-close change of -5.1%.

Note what the chart does not do: decay in an orderly line. Elevated volume comes in clusters, and the sessions after a peak can re-accelerate rather than fade, one reason "volume is drying up" is a claim to check against the daily series instead of assuming. The same daily series is where an intraday pace measure would start, the one built from scratch in the relative volume guide and used by VWAP.

What the screen filters out

Four rules keep the board honest, and each one throws away something a reader might want to see:

  1. A $500M dollar-volume floor for the week. Share counts alone fill a leaderboard with names where a million shares is pocket change.
  2. A baseline above 100,000 shares a day, so the denominator is a real number rather than a rounding artifact.
  3. At least 35 of the prior 40 sessions traded, which excludes brand-new listings, a fresh IPO has no meaningful "normal" to divide by, and would otherwise own this board for weeks.
  4. One reused symbol excluded: a ticker the exchanges recently reassigned to a new listing, whose vendor history splices two different companies together. Its baseline would be fiction.

Rule 1 is the one that removes the wildest multiples on the tape. Here are the six biggest excluded by it:

QueryWild multiples the dollar floor removes: highest relative volume among names trading under $500M this week
tickerrvol_weekweek_dollar_mavg_share_pricebaseline_adv_m
XOS65.1238.74.220.17
BIAF4129.90.490.3
CDTG40410.25.340.38
CAST27.3245.61.71.06
SLE25.41415.060.22
DAIC16.8983.620.32
The exact SQL behind every number
WITH sess AS (
    SELECT ticker,
           toDate(toTimeZone(window_start, 'America/New_York')) AS d,
           sum(toFloat64(volume)) AS vol,
           sum(toFloat64(close) * toFloat64(volume)) AS dollars
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE window_start >= now() - INTERVAL 70 DAY
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) >= 570
      AND toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York')) < 960
      AND ticker NOT IN ('SPCX')
    GROUP BY ticker, d
),
cal AS (
    SELECT d, row_number() OVER (ORDER BY d DESC) AS rn
    FROM (SELECT DISTINCT d FROM sess)
),
per_name AS (
    SELECT s.ticker AS ticker,
           avgIf(s.vol, c.rn <= 5) AS adv_recent,
           avgIf(s.vol, c.rn BETWEEN 6 AND 45) AS adv_base,
           sumIf(s.dollars, c.rn <= 5) AS dollar_recent,
           countIf(c.rn <= 5) AS recent_sessions,
           countIf(c.rn BETWEEN 6 AND 45) AS base_sessions
    FROM sess s INNER JOIN cal c ON s.d = c.d
    GROUP BY s.ticker
    HAVING adv_base > 100000 AND recent_sessions = 5 AND base_sessions >= 35
       AND dollar_recent > 0 AND dollar_recent < 500000000
)
SELECT ticker,
       round(adv_recent / adv_base, 1) AS rvol_week,
       round(dollar_recent / 1e6, 1) AS week_dollar_m,
       round(dollar_recent / (adv_recent * 5), 2) AS avg_share_price,
       round(adv_base / 1e6, 2) AS baseline_adv_m
FROM per_name
ORDER BY rvol_week DESC, ticker ASC
LIMIT 6
Run this yourself

XOS traded 65.1x its own norm, yet turned over only $238.7M all week at an average share price of $4.22. Behind it: BIAF at 41x on $29.9M (average price $0.49), CDTG at 40x on $410.2M, CAST at 27.3x on $245.6M, SLE at 25.4x on $141M, and DAIC at 16.8x on $98M. Real activity, genuinely unusual for those names, and a category where the multiple flatters a very small amount of money.

Where unusual volume comes from

The recurring producers, so the board reads faster: earnings weeks, the one scheduled source; corporate events, mergers, offerings, index adds and deletes, which arrive with mechanical volume that has nothing to do with opinion; squeeze dynamics, where volume stacks on top of price velocity, the pattern the short squeeze explainer documents; and new listings, which dominate their own tape until the float seasons. Any given week's board is usually a blend, plus one or two genuine mysteries, and the mysteries are the rows worth the extra minute.

Unusual volume FAQ

What counts as unusual volume for a stock?

There is no official threshold, so use the distribution: of the 508 names clearing this page's floor this week, only 0 traded at 10x their own norm or more, and 95.5% actually traded below their own average. Anything above roughly 2x is already in the top few percent of the market on a given week.

Is unusual volume bullish or bearish?

Neither, it is attention, and attention arrives with rallies and collapses alike. This week the board's leader finished the five sessions -50.2% from its opening print and the eighth name finished 0.8%; both qualified on exactly the same measurement.

How long does unusual volume last?

Usually longer than a day. The persistence panel counts each board name's sessions above twice baseline: this week they run from 1 of five (IEUR) to 2 of five (AMLX), and the heaviest session typically lands before the week ends rather than on its final day.

Why does the list use a dollar-volume floor?

A share-count screen without one fills up with cheap tickers where the multiple is huge and the money is not: this week's biggest excluded name traded 65.1x its norm on $238.7M total, at an average price of $4.22 a share. The $500M weekly floor keeps every row on the board economically real.

Does unusual stock volume show up in the options market too?

Often, yes, heavy equity tape and heavy options tape tend to arrive together on the same names, which is why traders watch both. Options activity is measured differently, though: contracts traded is a flow number, while open interest counts positions still standing, and the two answer different questions, see options volume vs. open interest before reading anything into an "unusual options activity" alert.


Every number above is a stored, versioned query, expand the SQL under any panel to see the exact measurement, or run the same screen over any window you like on the Strasmore terminal.