{"slug":"what-is-maximum-drawdown","qid":"spy_drawdown_episodes","label":"Completed SPY drawdowns since 2016: depth, days falling, days climbing back","post_title":"What Is Maximum Drawdown? Depth vs Recovery","post_url":"/blog/what-is-maximum-drawdown#q-spy_drawdown_episodes","columns":["episode_label","fall_from_peak_pct","days_to_trough","days_to_new_high","days_underwater"],"rows":[{"episode_label":"Feb 2020","fall_from_peak_pct":34.2,"days_to_trough":33,"days_to_new_high":148,"days_underwater":181},{"episode_label":"Jan 2022","fall_from_peak_pct":25.4,"days_to_trough":282,"days_to_new_high":464,"days_underwater":746},{"episode_label":"Sep 2018","fall_from_peak_pct":20.2,"days_to_trough":95,"days_to_new_high":126,"days_underwater":221},{"episode_label":"Feb 2025","fall_from_peak_pct":19,"days_to_trough":48,"days_to_new_high":80,"days_underwater":128},{"episode_label":"Jan 2018","fall_from_peak_pct":10.1,"days_to_trough":66,"days_to_new_high":144,"days_underwater":210},{"episode_label":"Sep 2020","fall_from_peak_pct":9.8,"days_to_trough":21,"days_to_new_high":51,"days_underwater":72},{"episode_label":"Jan 2026","fall_from_peak_pct":9.1,"days_to_trough":62,"days_to_new_high":16,"days_underwater":78},{"episode_label":"Jan 2016","fall_from_peak_pct":9.1,"days_to_trough":37,"days_to_new_high":29,"days_underwater":66}],"shape":"table","sql":"WITH daily AS (\n    SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS session_date,\n           argMax(toFloat64(close), window_start) AS close_px\n    FROM global_markets.delayed_stocks_minute_aggs\n    WHERE ticker = 'SPY'\n      AND toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2016-01-01')\n      AND toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-07-31')\n      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60\n           + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959\n    GROUP BY session_date\n),\nruns AS (\n    SELECT session_date,\n           close_px,\n           max(close_px) OVER (ORDER BY session_date\n                               ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS running_peak\n    FROM daily\n),\nepisodes AS (\n    SELECT running_peak AS peak_px,\n           min(session_date) AS peak_date,\n           argMin(session_date, close_px) AS trough_date,\n           min(close_px) AS trough_px\n    FROM runs\n    GROUP BY running_peak\n),\nsequenced AS (\n    SELECT peak_px,\n           peak_date,\n           trough_date,\n           trough_px,\n           leadInFrame(peak_date, 1) OVER (ORDER BY peak_date\n                                           ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) AS recovery_date\n    FROM episodes\n)\nSELECT formatDateTime(peak_date, '%b %Y') AS episode_label,\n       round(100 * (1 - trough_px / peak_px), 1) AS fall_from_peak_pct,\n       dateDiff('day', peak_date, trough_date) AS days_to_trough,\n       dateDiff('day', trough_date, recovery_date) AS days_to_new_high,\n       dateDiff('day', peak_date, recovery_date) AS days_underwater\nFROM sequenced\nWHERE recovery_date > trough_date\n  AND round(100 * (1 - trough_px / peak_px), 1) >= 5\nORDER BY fall_from_peak_pct DESC\nLIMIT 8","computed_at":"2026-08-05T03:38:16.300997+00:00","elapsed":0.004523523}