Santa Claus Rally: Hit Rate and Returns by Year
The five weakest Santa Claus windows on record, with the calendar year that followed eachtable ·
2026-11-01 · 5×5
Santa Claus window vs. the rest of December vs. the whole month, SPY, all years on recordtable ·
2026-11-01 · 3×8
SPY volume in each Santa Claus window session as a share of its year's average daily volumeranking ·
2026-11-01 · 7×4
Santa Claus rally window return by year, SPY, with the full calendar December alongsidetable ·
2026-11-01 · 23×5
Failed vs. successful Santa Claus windows and the calendar year that followedtable ·
2026-11-01 · 2×6
The September Effect: Is It Real? SPY Data
The three worst SPY Septembers on recordranking ·
2026-09-26 · 3×2
SPY September price return, year by yearranking ·
2026-09-26 · 22×2
SPY monthly price returns by calendar month, complete years onlytable ·
2026-09-26 · 12×6
Average September vs. the other eleven months, by decaderanking ·
2026-09-26 · 3×4
The five weakest Santa Claus windows on record, with the calendar year that followed each
The five weakest Santa Claus windows on record, with the calendar year that followed each
| label | measured_from | measured_to | santa_window_pct | following_year_pct |
|---|---|---|---|---|
| Dec 2014 to Jan 2015 | Dec 23 | Jan 5 | -2.9 | -0.81 |
| Dec 2015 to Jan 2016 | Dec 23 | Jan 5 | -2.26 | 9.64 |
| Dec 2007 to Jan 2008 | Dec 21 | Jan 3 | -2.21 | -38.28 |
| Dec 2004 to Jan 2005 | Dec 23 | Jan 4 | -1.61 | 3.01 |
| Dec 2023 to Jan 2024 | Dec 21 | Jan 3 | -0.83 | 23.3 |
the exact SQL behind every number
WITH
spy_days AS
(
SELECT
date,
toYear(date) AS y,
toMonth(date) AS m,
argMax(toFloat64(close), _ingest_time) AS close
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
GROUP BY date
),
ranked AS
(
SELECT
date,
y,
m,
close,
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)
),
windows AS
(
SELECT
toUInt16(if(m = 1, y - 1, y)) AS year,
toUInt16(year + 1) AS next_year,
anyIf(date, m = 12 AND sessions_from_end = 6) AS base_date,
anyIf(date, m = 1 AND sessions_from_start = 2) AS end_date,
anyIf(close, m = 12 AND sessions_from_end = 6) AS base_close,
anyIf(close, m = 12 AND sessions_from_end = 1) AS december_close,
anyIf(close, m = 1 AND sessions_from_start = 2) AS end_close
FROM ranked
GROUP BY year
HAVING countIf(m = 12 AND sessions_from_end = 6) = 1
AND countIf(m = 1 AND sessions_from_start = 2) = 1
),
year_ends AS
(
SELECT
y,
argMax(close, date) AS year_end_close
FROM spy_days
WHERE m = 12
AND date < toStartOfYear(today())
GROUP BY y
)
SELECT
concat('Dec ', toString(w.year), ' to Jan ', toString(w.next_year)) AS label,
concat(formatDateTime(w.base_date, '%b '), toString(toDayOfMonth(w.base_date))) AS measured_from,
concat(formatDateTime(w.end_date, '%b '), toString(toDayOfMonth(w.end_date))) AS measured_to,
round((w.end_close / w.base_close - 1) * 100, 2) AS santa_window_pct,
round((n.year_end_close / w.december_close - 1) * 100, 2) AS following_year_pct
FROM windows AS w
INNER JOIN year_ends AS n ON n.y = w.next_year
ORDER BY santa_window_pct ASC
LIMIT 5
More from this analysisSanta Claus Rally: Hit Rate and Returns by Year
Santa Claus rally window return by year, SPY, with the full calendar December alongside
table 23×5
→
Santa Claus window vs. the rest of December vs. the whole month, SPY, all years on record
table 3×8
→
Failed vs. successful Santa Claus windows and the calendar year that followed
table 2×6
→
SPY volume in each Santa Claus window session as a share of its year's average daily volume
ranking 7×4
→
See all 3,293 queries →