whipsaw
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-13, from can-a-death-cross-be-bullish.
| death_cross | golden_cross | session_count | change_pct |
|---|---|---|---|
| Aug 18, 2004 | Nov 5, 2004 | 56 | 6.6 |
| Jul 19, 2006 | Sep 11, 2006 | 37 | 3.8 |
| Dec 21, 2007 | Jun 23, 2009 | 377 | -39.7 |
| Jul 6, 2010 | Oct 22, 2010 | 77 | 15 |
| Aug 12, 2011 | Jan 31, 2012 | 117 | 11.2 |
| Aug 28, 2015 | Dec 17, 2015 | 77 | 2.8 |
| Jan 11, 2016 | Apr 25, 2016 | 72 | 8.6 |
| Dec 7, 2018 | Apr 1, 2019 | 77 | 8.4 |
| Mar 30, 2020 | Jul 9, 2020 | 70 | 20.2 |
| Mar 14, 2022 | Feb 2, 2023 | 224 | -0.1 |
| Apr 14, 2025 | Jul 1, 2025 | 53 | 14.6 |
- Rows × columns
- 11 × 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 |
|---|---|---|---|
death_cross |
text | 11 distinct values (Apr 14, 2025, Aug 12, 2011, Aug 18, 2004…) | |
golden_cross |
text | 11 distinct values (Apr 1, 2019, Apr 25, 2016, Dec 17, 2015…) | |
session_count |
number | 37 to 377 | count |
change_pct |
number | -39.7 to 20.2 | percent |
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
bars AS
(
SELECT
date,
toFloat64(argMax(close, _ingest_time)) AS px
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
GROUP BY date
),
smas AS
(
SELECT
date,
px,
row_number() OVER (ORDER BY date) AS rn,
avg(px) OVER (ORDER BY date ROWS BETWEEN 49 PRECEDING AND CURRENT ROW) AS avg_50,
avg(px) OVER (ORDER BY date ROWS BETWEEN 199 PRECEDING AND CURRENT ROW) AS avg_200
FROM bars
),
states AS
(
SELECT
*,
(avg_50 < avg_200) AS below,
lagInFrame((avg_50 < avg_200), 1) OVER (ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS prev_below
FROM smas
),
flags AS
(
SELECT
*,
(rn >= 201 AND below = 1 AND prev_below = 0) AS is_death,
(rn >= 201 AND below = 0 AND prev_below = 1) AS is_golden
FROM states
),
events AS
(
SELECT date, px, rn, is_death
FROM flags
WHERE is_death OR is_golden
),
paired AS
(
SELECT
date,
px,
rn,
is_death,
leadInFrame(date, 1) OVER (ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS next_date,
leadInFrame(px, 1) OVER (ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS next_px,
leadInFrame(rn, 1) OVER (ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS next_rn
FROM events
)
SELECT
concat(formatDateTime(date, '%b'), ' ', toString(toDayOfMonth(date)), ', ', toString(toYear(date))) AS death_cross,
if(next_rn > 0,
concat(formatDateTime(next_date, '%b'), ' ', toString(toDayOfMonth(next_date)), ', ', toString(toYear(next_date))),
'none yet') AS golden_cross,
if(next_rn > 0, toInt64(next_rn) - toInt64(rn), NULL) AS session_count,
if(next_rn > 0, round((next_px / px - 1) * 100, 1), NULL) AS change_pct
FROM paired
WHERE is_death
ORDER BY date
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 analysiscan-a-death-cross-be-bullish
trace_2020
series 126×4
→
death_crosses
table 11×6
→
forward_record
table 4×9
→
window
scalar 1×11
→
covid_2020
scalar 1×16
→
Top 25 weekly-options underlyings by distinct contracts traded, with expiration weekdays
ranking 25×4
→
See all 2,225 queries →