STRASMORE/EXPLORE 2,225 QUERIES

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.

as of ranking 11×4read in context →
whipsaw — 11 rows by 4 columns, computed from US exchange, SIP and OPRA data.
death_crossgolden_crosssession_countchange_pct
Aug 18, 2004Nov 5, 2004566.6
Jul 19, 2006Sep 11, 2006373.8
Dec 21, 2007Jun 23, 2009377-39.7
Jul 6, 2010Oct 22, 20107715
Aug 12, 2011Jan 31, 201211711.2
Aug 28, 2015Dec 17, 2015772.8
Jan 11, 2016Apr 25, 2016728.6
Dec 7, 2018Apr 1, 2019778.4
Mar 30, 2020Jul 9, 20207020.2
Mar 14, 2022Feb 2, 2023224-0.1
Apr 14, 2025Jul 1, 20255314.6
Rows × columns
11 × 4
Computed
Completeness
No missing values
Source
US exchange, SIP and OPRA market data
Licence
Strasmore terms · free, no signup
Formats
JSON · CSV · the SQL below

What each column holds

Column definitions for whipsaw, derived from the stored result.
ColumnTypeRangeNotes
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 →