{"slug":"can-a-death-cross-be-bullish","qid":"window","label":"window","post_title":"can-a-death-cross-be-bullish","post_url":"/blog/can-a-death-cross-be-bullish#q-window","columns":["first_session","last_session","session_count","median_off_high_pct","min_off_high_pct","max_off_high_pct","death_cross_count","golden_cross_count","min_sessions_to_golden","median_sessions_to_golden","max_sessions_to_golden"],"rows":[{"first_session":"Sep 10, 2003","last_session":"Sep 11, 2026","session_count":5788,"median_off_high_pct":10.2,"min_off_high_pct":5.2,"max_off_high_pct":22.7,"death_cross_count":11,"golden_cross_count":11,"min_sessions_to_golden":37,"median_sessions_to_golden":77,"max_sessions_to_golden":377}],"shape":"scalar","sql":"WITH\nbars AS\n(\n    SELECT\n        date,\n        toFloat64(argMax(close, _ingest_time)) AS px\n    FROM global_markets.stocks_daily_aggs\n    WHERE ticker = 'SPY'\n    GROUP BY date\n),\nsmas AS\n(\n    SELECT\n        date,\n        px,\n        row_number() OVER (ORDER BY date) AS rn,\n        avg(px) OVER (ORDER BY date ROWS BETWEEN 49 PRECEDING AND CURRENT ROW) AS avg_50,\n        avg(px) OVER (ORDER BY date ROWS BETWEEN 199 PRECEDING AND CURRENT ROW) AS avg_200,\n        max(px) OVER (ORDER BY date ROWS BETWEEN 251 PRECEDING AND CURRENT ROW) AS high_1y\n    FROM bars\n),\nstates AS\n(\n    SELECT\n        *,\n        (avg_50 < avg_200) AS below,\n        lagInFrame((avg_50 < avg_200), 1) OVER (ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS prev_below\n    FROM smas\n),\nflags AS\n(\n    SELECT\n        *,\n        (rn >= 201 AND below = 1 AND prev_below = 0) AS is_death,\n        (rn >= 201 AND below = 0 AND prev_below = 1) AS is_golden\n    FROM states\n),\nevents AS\n(\n    SELECT date, rn, is_death\n    FROM flags\n    WHERE is_death OR is_golden\n),\npaired AS\n(\n    SELECT\n        rn,\n        is_death,\n        leadInFrame(rn, 1) OVER (ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS next_rn\n    FROM events\n),\ncross_stats AS\n(\n    SELECT\n        countIf(is_death)                                                           AS death_cross_count,\n        countIf(NOT is_death)                                                       AS golden_cross_count,\n        minIf(toInt64(next_rn) - toInt64(rn), is_death AND next_rn > 0)            AS min_sessions_to_golden,\n        quantileExactIf(toInt64(next_rn) - toInt64(rn), is_death AND next_rn > 0)  AS median_sessions_to_golden,\n        maxIf(toInt64(next_rn) - toInt64(rn), is_death AND next_rn > 0)            AS max_sessions_to_golden\n    FROM paired\n),\nspan AS\n(\n    SELECT\n        concat(formatDateTime(min(date), '%b'), ' ', toString(toDayOfMonth(min(date))), ', ', toString(toYear(min(date)))) AS first_session,\n        concat(formatDateTime(max(date), '%b'), ' ', toString(toDayOfMonth(max(date))), ', ', toString(toYear(max(date)))) AS last_session,\n        count()                                                        AS session_count,\n        round(quantileExactIf((1 - px / high_1y) * 100, is_death), 1)  AS median_off_high_pct,\n        round(minIf((1 - px / high_1y) * 100, is_death), 1)            AS min_off_high_pct,\n        round(maxIf((1 - px / high_1y) * 100, is_death), 1)            AS max_off_high_pct\n    FROM flags\n)\nSELECT *\nFROM span, cross_stats","computed_at":"2026-09-13T15:00:29.375756+00:00","elapsed":0.007007013}