window_volume
Answered against 22 years of US equities and 12 years of US options data and published with the query that produced it. This result is stored as of 2026-09-17, from santa-claus-rally.
| bucket | avg_volume_vs_year_pct | median_volume_vs_year_pct | years_measured |
|---|---|---|---|
| Dec -5 | 52.3 | 39.2 | 23 |
| Dec -4 | 57.8 | 52.3 | 23 |
| Dec -3 | 72.1 | 65.3 | 23 |
| Dec -2 | 66.3 | 56.8 | 23 |
| Dec -1 | 90.4 | 88.1 | 23 |
| Jan +1 | 110.2 | 92.2 | 23 |
| Jan +2 | 94.9 | 90.3 | 23 |
- Rows × columns
- 7 × 4
- Computed
- Completeness
- No missing values
- Source
- US exchange, SIP and OPRA market data
- Licence
- Strasmore terms · free, no signup
What each column holds
| Column | Type | Range | Notes |
|---|---|---|---|
bucket |
text | 7 distinct values (Dec -1, Dec -2, Dec -3…) | |
avg_volume_vs_year_pct |
number | 52.3 to 110.2 | percent |
median_volume_vs_year_pct |
number | 39.2 to 92.2 | percent |
years_measured |
number | every row is 23 |
Computed from Strasmore's warehouse of US exchange, SIP and OPRA market data. Equity prices are delayed; options greeks and implied volatility are end-of-day. This result is stored, not recomputed on load — it is exactly the numbers that were returned on , and the query below is what returned them.
the exact SQL behind every number
WITH
spy_days AS
(
SELECT
date,
toYear(date) AS y,
toMonth(date) AS m,
argMax(toFloat64(volume), _ingest_time) AS volume
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
GROUP BY date
),
yearly AS
(
SELECT
y,
avg(volume) AS avg_volume
FROM spy_days
GROUP BY y
),
ranked AS
(
SELECT
date,
y,
m,
volume,
row_number() OVER (PARTITION BY y, m ORDER BY date DESC) AS sessions_from_end,
row_number() OVER (PARTITION BY y, m ORDER BY date ASC) AS sessions_from_start
FROM spy_days
WHERE m IN (12, 1)
),
slots AS
(
SELECT
if(r.m = 12, concat('Dec -', toString(r.sessions_from_end)),
concat('Jan +', toString(r.sessions_from_start))) AS bucket,
if(r.m = 12, toInt32(0) - toInt32(r.sessions_from_end),
toInt32(r.sessions_from_start)) AS slot_order,
r.y AS y,
r.volume / yr.avg_volume * 100 AS volume_vs_year_pct
FROM ranked AS r
INNER JOIN yearly AS yr ON yr.y = r.y
WHERE (r.m = 12 AND r.sessions_from_end <= 5)
OR (r.m = 1 AND r.sessions_from_start <= 2)
)
SELECT
bucket,
round(avg(volume_vs_year_pct), 1) AS avg_volume_vs_year_pct,
round(quantileDeterministic(0.5)(volume_vs_year_pct, toUInt32(y)), 1) AS median_volume_vs_year_pct,
count() AS years_measured
FROM slots
GROUP BY bucket, slot_order
ORDER BY slot_order
Run your own version of this
The same 22 years of US equities and 12 years of options data are queryable in SQL or plain English. A free account runs 100 queries a day and takes no card.
More from this analysissanta-claus-rally
santa_windows
table 23×5
→
worst_windows
table 5×5
→
window_vs_december
table 3×8
→
folklore_test
table 2×6
→
Top 25 weekly-options underlyings by distinct contracts traded, with expiration weekdays
ranking 25×4
→
Annualized volatility vs total return, 25 large caps, calmest to wildest (~2 years)
ranking 25×3
→
See all 2,309 queries →