monthly
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-18, from the-september-effect.
| label | avg_return_pct | median_return_pct | stdev_pct | hit_rate_pct | sample_count |
|---|---|---|---|---|---|
| Jan | 0.27 | 1.55 | 4.41 | 54.5 | 22 |
| Feb | 0.36 | 1.32 | 4.24 | 59.1 | 22 |
| Mar | 0.6 | 1 | 4.46 | 59.1 | 22 |
| Apr | 1.63 | 1.13 | 4.43 | 72.7 | 22 |
| May | 0.92 | 1.61 | 3.81 | 77.3 | 22 |
| Jun | -0.1 | -0.02 | 4.01 | 50 | 22 |
| Jul | 2.36 | 2.28 | 3.32 | 77.3 | 22 |
| Aug | 0.27 | 0.79 | 3.38 | 63.6 | 22 |
| Sep | -0.71 | 0.48 | 4.59 | 59.1 | 22 |
| Oct | 1.16 | 2.21 | 5.74 | 60.9 | 23 |
| Nov | 2.45 | 2.75 | 3.88 | 82.6 | 23 |
| Dec | 0.45 | 0.7 | 3.46 | 65.2 | 23 |
- Rows × columns
- 12 × 6
- 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 |
|---|---|---|---|
label |
text | 12 distinct values (Apr, Aug, Dec…) | |
avg_return_pct |
number | -0.71 to 2.45 | percent |
median_return_pct |
number | -0.02 to 2.75 | percent |
stdev_pct |
number | 3.32 to 5.74 | percent |
hit_rate_pct |
number | 50 to 82.6 | percent |
sample_count |
number | 22 to 23 | count |
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 month_ends AS
(
SELECT
toStartOfMonth(date) AS month_start,
argMax(toFloat64(close), date) AS month_end_close
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND date < toStartOfYear(today())
GROUP BY month_start
),
monthly_returns AS
(
SELECT
month_start,
month_end_close,
lagInFrame(month_end_close, 1) OVER (ORDER BY month_start ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS prev_close
FROM month_ends
)
SELECT
formatDateTime(month_start, '%b') AS label,
round(avg(month_end_close / prev_close - 1) * 100, 2) AS avg_return_pct,
round(quantileDeterministic(0.5)(month_end_close / prev_close - 1, toYYYYMM(month_start)) * 100, 2) AS median_return_pct,
round(stddevSamp(month_end_close / prev_close - 1) * 100, 2) AS stdev_pct,
round(countIf(month_end_close > prev_close) / count() * 100, 1) AS hit_rate_pct,
count() AS sample_count
FROM monthly_returns
WHERE prev_close > 0
GROUP BY toMonth(month_start), label
ORDER BY toMonth(month_start)
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 analysisthe-september-effect
septembers_by_year
ranking 22×2
→
worst_septembers
ranking 3×2
→
decades
ranking 3×4
→
The 2s10s spread, every print of the half
table 124×2
→
The 2s10s spread, every print of the half
table 124×2
→
Every half-year since 1976: the 2y and 10y change, the twist between them, and the half's lowest 2s10s print
table 100×7
→
See all 2,358 queries →