Strasmore Research
بررسی عمیق Matt Connorتوسط Matt Connor · به‌روزرسانی شده در 2026-07-24

تحلیل بازار در 24 مارس 2020 و چرخش روند

بررسی دقیق ریزش بازار، هجوم به نقدینگی و اقدامات بی‌سابقه Fed در 24 مارس 2020؛ واکاوی رالی صعودی بزرگ و چرخش تاریخی بازار سهام برای درک عمیق‌تر روندها.

در 23 مارس 2020، فدرال رزرو خرید بی‌انتها دارایی را اعلام کرد؛ یعنی QE بدون محدودیتی مشخص، به همراه اقدامی بی‌سابقه: ایجاد تسهیلاتی برای خرید اوراق قرضه شرکتی. پاسخ بازار در 24 مارس 2020 مشخص شد: رالی صعودی ناشی از محرک‌های COVID، که یکی از بزرگ‌ترین gains روزانه در بازار سهام ایالات متحده در تاریخ بود و — که تنها با نگاه به گذشته قابل درک است — دومین روز از یک بازار گاوی جدید محسوب می‌شد. نقطه کف بازار، درست در عصرِ پیش از انتشار این اعلامیه، بسته شده بود.

سقوط پیش از چرخش

خودِ سقوط صفحه اختصاصی خود را دارد؛ در اینجا اسناد مربوط به این دوره ارائه شده است — تمامی جلسات معاملاتی از نقطه اوج تاریخی تا کف بازار، به همراه بازدهی اوراق قرضه 10 ساله در واحد basis points:

پرس‌وجوقیمت بسته‌شدن روزانه SPY، میزان کاهش ارزش (drawdown) و بازدهی ۱۰ ساله — ۱۹ فوریه تا ۲۳ مارس ۲۰۲۰
کد دقیق SQL پشت هر عدد
WITH daily AS (
    SELECT
        toDate(toTimeZone(window_start, 'America/New_York')) AS et_date,
        round(argMaxIf(toFloat64(close), window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959), 2) AS close_usd
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'SPY'
      AND window_start >= toDateTime('2020-02-19 00:00:00') AND window_start < toDateTime('2020-03-24 04:00:00')
    GROUP BY et_date
    HAVING et_date >= toDate('2020-02-19') AND et_date <= toDate('2020-03-23') AND close_usd > 0
)
SELECT
    toString(d.et_date) AS session,
    d.close_usd,
    round((d.close_usd / (SELECT max(close_usd) FROM daily) - 1) * 100, 1) AS drawdown_pct,
    round(t.yield_10_year * 100) AS y10_bps
FROM daily AS d
LEFT JOIN global_markets.treasury_yields AS t ON t.date = d.et_date
ORDER BY d.et_date

از بسته‌ شدن در بالاترین سطح تاریخی با قیمت $338.31 در 2020-02-19، شاخص SPY تا 2020-03-23 به $222.51 کاهش یافت — یک ریزش -34.2%، که تمامی جلسات این روند نزولی در ردیف‌های 24 نمودار قرار دارند.

ستون بازدهی، نشانگر اصلی است. در طول 2020-03-09، بازدهی 10 ساله از 156 basis points به رکورد آن زمان یعنی 54 سقوط کرد — پدیده کلاسیک «فرار به امنیت» که در آن سرمایه از سهام خارج و به سمت اوراق قرضه حرکت می‌کند. سپس این الگو تغییر کرد: تا 2020-03-18، بازدهی با بیش از دو برابر شدن به 118 basis points رسید، در حالی که میزان ریزش SPY از -18.9% به -28.8% افزایش یافت. کاهش همزمان قیمت سهام و اوراق قرضه، نشانه‌ی فروش اجباری است — زمانی که دارندگان دارایی برای نقد کردن سرمایه، هر آنچه را که خریدار دارد، می‌فروشند. تا اواسط مارس، بحران نه بر سر قیمت سهام، بلکه بر سر زیرساخت‌های اعتباری بود.

آنچه فدرال رزرو واقعاً اعلام کرد — و آنچه بی‌ثمر ماند

کاهش نرخ بهره پیش‌تر امتحان شده بود. توالی زمانی و قدیمی، که هر مورد در پنل بالا قابل مشاهده است:

  • 2020-03-03 — یک کاهش اضطراری نیم‌واحدی نرخ بهره؛ اولین کاهش نرخ در میان جلسات از سال 2008. SPY در سطح $300.34 بسته شد، یعنی -11.2% پایین‌تر از نقطه اوج، و روند نزولی ادامه یافت.
  • 15 مارس، یک یکشنبه — نرخ‌ها به صفر رسید و یک برنامه خرید دارایی 700 میلیارد دلاری آغاز شد. در جلسه بعد، یعنی 2020-03-16، شاخص -29.2% پایین‌تر از اوج فوریه بسته شد که یکی از بدترین جلسات در کل دوران سقوط بود.
  • 23 مارس، ساعت 8:00 صبح به وقت ET — فدرال رزرو سقف را برداشت: خرید اوراق قرضه خزانه‌داری و اوراق بهادار با پشتوانه وام مسکن «در مقادیر مورد نیاز» و بدون محدودیت ادامه می‌یابد. PMCCF و SMCCF نیز ضمیمه شدند — اولین تسهیلات خرید اوراق قرضه شرکتی توسط فدرال رزرو — و TALF نیز برای حمایت از اعتبار مصرف‌کننده احیا شد. SPY در آن بعدازظهر همچنان در پایین‌ترین سطح بازار خرس بسته شد.
  • 24 مارس — جلسه زیر. در طول شب، کنگره بر سر قانون CARES با مبلغ تقریبی 2 تریلیون دلار به توافق رسید؛ این قانون در 27 مارس امضا شد، یعنی در میان آن دوره پرجنب‌وجوش سه روزه‌ای که در ادامه ذکر شده است.

دو تفاوت طراحی، بسته 23 مارس را از تلاش‌های پیش از آن متمایز کرد. یک برنامه با حجم مشخص، دارای تاریخ پایان است که بازارِ تحت فشار می‌تواند آن را پیش‌بینی کند؛ اما عبارت «در مقادیر مورد نیاز» چنین ویژگی‌ای ندارد. همچنین، تسهیلات شرکتی، یک خریدار دولتی را مستقیماً وارد بازارهای اعتباری کرد؛ جایی که زیرساخت‌های مالی دچار انسداد شده بود. اینکه آیا این تفاوت‌ها عامل اصلی بودند یا خیر، یک قضاوت شخصی است؛ اما سوابث بازار، توالی وقایع را ثبت کرده است: دو مرحله تشدید سیاست‌ها، تداوم کاهش قیمت‌ها، طراحی سوم، و سپس بازگشت بازار.

خلاصه‌ی روز

پرس‌وجووضعیت SPY در ۲۴ مارس ۲۰۲۰ — نقطه چرخش، ثبت شده
کد دقیق SQL پشت هر عدد
WITH
    (
        SELECT argMaxIf(toFloat64(close), window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959)
        FROM global_markets.delayed_stocks_minute_aggs
        WHERE ticker = 'SPY'
          AND window_start >= toDateTime('2020-03-23 00:00:00') AND window_start < toDateTime('2020-03-24 04:00:00')
    ) AS prior_rth_close
SELECT
    round(prior_rth_close, 2) AS prior_close,
    round(toFloat64(argMinIf(open, window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959)), 2) AS rth_open,
    round((toFloat64(argMinIf(open, window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959)) / prior_rth_close - 1) * 100, 1) AS gap_pct,
    round(minIf(toFloat64(low), (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959), 2) AS rth_low,
    formatDateTime(toTimeZone(argMinIf(window_start, (toFloat64(low), toInt64(toUnixTimestamp(window_start))), (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959), 'America/New_York'), '%H:%i') AS low_et,
    round(maxIf(toFloat64(high), (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959), 2) AS rth_high,
    round(toFloat64(argMaxIf(close, window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959)), 2) AS rth_close,
    round((toFloat64(argMaxIf(close, window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959)) / prior_rth_close - 1) * 100, 1) AS day_change_pct,
    round((minIf(toFloat64(low), (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) / prior_rth_close - 1) * 100, 1) AS low_vs_prior_pct,
    round(toFloat64(sum(volume)) / 1e6, 1) AS day_shares_m,
    countIf((toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) AS rth_minute_bars
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
  AND window_start >= toDateTime('2020-03-24 04:00:00') AND window_start < toDateTime('2020-03-24 23:59:00')

ETF مورد نظر (SPY) پس از بسته‌شدن در قیمت $222.51 در تاریخ 23 مارس — که آخرین روز بازار خرسی بود — با شکاف مثبت 5.4% در قیمت $234.42 باز شد. این شاخص در دقایق ابتدایی بازار (09:31 ET) به کف قیمتی $233.8 رسید اما هرگز نتوانست آن سطح را لمس کند؛ قیمت بسته‌شدن در $243.59 معادل 9.5% افزایش روزانه بود. این رالی که کف قیمتی آن در اولین دقیقه ثبت شده، دقیقاً عکس سقوطی است که در پایین‌ترین سطح خود بسته می‌شود. با این حال، یک روند خنثی مسیر را هموار می‌کند؛ نوار معاملات نیم‌ساعته در پایین، نشان‌دهنده کاهش روندی است که بازار در طول جلسه با آن مواجه شد.

ساختار جلسه معاملاتی

پرس‌وجوSPY در بازه‌های نیم‌ساعته — جلسه معاملاتی عادی ۲۴ مارس ۲۰۲۰
کد دقیق SQL پشت هر عدد
SELECT
    formatDateTime(toStartOfInterval(toTimeZone(window_start, 'America/New_York'), INTERVAL 30 MINUTE), '%H:%i') AS et_time,
    round(toFloat64(argMax(close, window_start)), 2) AS bucket_close,
    round(min(toFloat64(low)), 2) AS bucket_low,
    round(toFloat64(sum(volume)) / 1e6, 1) AS shares_m
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
  AND window_start >= toDateTime('2020-03-24 04:00:00') AND window_start < toDateTime('2020-03-24 23:59:00')
  AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
GROUP BY et_time
ORDER BY et_time

تحلیل‌ها صادقانه هستند: روند بازار تغییر کرد. کمترین قیمت در سطح $233.8 در اولین دقیقه ثبت شد و دیگر لمس نشد؛ این بخش از حرکت تک‌جهته بازار واقعی است. اما پس از رسیدن به $242.24 در بازه زمانی ظهر، قیمت‌ها به مدت دو ساعت کاهش یافتند. بازه ساعت 13:30 در سطح $237.25 بسته شد و بازه ساعت 14:00 پایین‌ترین سطح بعدازظهر یعنی $235.05 را ثبت کرد؛ بازه‌ای که می‌توانست به یک شکستِ بازگشتیِ ناموفق دیگر تبدیل شود. اما برخلاف انتظار، این کاهش قیمت بسیار بالاتر از کفِ قیمت در زمان بازگشایی باقی ماند. در نیم ساعت پایانی، قیمت در بالاترین سطح جلسه یعنی $243.59 با حجم معاملات 34.7 میلیون سهم بسته شد که سنگین‌ترین حجم در میان معاملات روزانه 232.4 میلیون سهم بود و حتی از حجم 27.3 میلیون سهم در زمان بازگشایی نیز فراتر رفت. یک کاهش قیمت در میانه روز که با ورود خریداران روبرو شد و سپس با حداکثر حجم معاملات، در بالاترین سطح بسته شد.

Broad rally, or narrow?

An index can be dragged higher by a handful of mega-caps. That is not what this was. Twelve funds — the three major index trackers plus nine S&P sector funds — on the same two closes:

پرس‌وجووضعیت شاخص‌ها و sector ETFها در ۲۴ مارس ۲۰۲۰ — صعود همگانی، با اولویت صنایع سیکلیکال
کد دقیق SQL پشت هر عدد
SELECT
    ticker,
    round(argMaxIf(toFloat64(close), window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959 AND toDate(toTimeZone(window_start, 'America/New_York')) = toDate('2020-03-23')), 2) AS mar23_close,
    round(argMaxIf(toFloat64(close), window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959 AND toDate(toTimeZone(window_start, 'America/New_York')) = toDate('2020-03-24')), 2) AS mar24_close,
    round((argMaxIf(toFloat64(close), window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959 AND toDate(toTimeZone(window_start, 'America/New_York')) = toDate('2020-03-24')) / argMaxIf(toFloat64(close), window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959 AND toDate(toTimeZone(window_start, 'America/New_York')) = toDate('2020-03-23')) - 1) * 100, 1) AS change_pct
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('SPY', 'DIA', 'QQQ', 'IWM', 'XLE', 'XLI', 'XLF', 'XLK', 'XLY', 'XLV', 'XLU', 'XLP')
  AND window_start >= toDateTime('2020-03-23 00:00:00') AND window_start < toDateTime('2020-03-25 00:00:00')
GROUP BY ticker
ORDER BY change_pct DESC

All 12 closed higher. Energy (XLE) led at +16.4%, with industrials (XLI, +12.8%) and financials (XLF, +12.7%) right behind — the most economically-sensitive corners of the market, the ones a shutdown threatens first. The Dow tracker DIA gained 11.3% — the move behind that week's "best day since 1933" headlines, a superlative that belongs to the Dow's longer price history. The smallest gains sat in the classic defensives, consumer staples (XLP, +5.1%) and healthcare (XLV, +7.4%), and the Nasdaq-100's QQQ (+7.7%) trailed SPY's +9.5%. A cyclicals-led, everything-green tape is the opposite shape of a narrow mega-cap squeeze — breadth was the day's signature.

این اتفاق واقعاً چقدر تاریخی بود؟

عبارت «بزرگ‌ترین روز از سال 1933» آماری از Dow است که در روزنامه‌های آن هفته منتشر شد. در اینجا آنچه داده‌های ما در محدوده پوشش خود تایید می‌کنند، آورده شده است:

پرس‌وجورتبه‌بندی ۲۴ مارس ۲۰۲۰ در مقایسه با تمامی جلسات SPY بر اساس داده‌های دقیق (minute tape)
کد دقیق SQL پشت هر عدد
SELECT
    countIf(isFinite(day_pct)) AS sessions_measured,
    toString(min(et_date)) AS first_session,
    round(mar24_d, 1) AS mar24_gain_pct,
    countIf(isFinite(day_pct) AND day_pct > mar24_d) AS bigger_days,
    countIf(isFinite(day_pct) AND day_pct > mar24_d) + 1 AS mar24_rank,
    arrayStringConcat(arraySort(groupArrayIf(toString(et_date), isFinite(day_pct) AND day_pct > mar24_d)), ', ') AS bigger_day_dates,
    round(mar26_b, 1) AS burst3_gain_pct,
    countIf(isFinite(burst3_pct) AND burst3_pct > mar26_b) AS bigger_bursts,
    round(mar24_r30, 2) AS vol_vs_30d,
    round(mar24_r250, 2) AS vol_vs_250d,
    round(mar24_shares / 1e6, 0) AS mar24_shares_m
FROM (
    SELECT
        et_date, day_pct, burst3_pct,
        max(if(et_date = toDate('2020-03-24'), day_pct, -999)) OVER () AS mar24_d,
        max(if(et_date = toDate('2020-03-26'), burst3_pct, -999)) OVER () AS mar26_b,
        max(if(et_date = toDate('2020-03-24'), shares / vol_avg_30, -999)) OVER () AS mar24_r30,
        max(if(et_date = toDate('2020-03-24'), shares / vol_avg_250, -999)) OVER () AS mar24_r250,
        max(if(et_date = toDate('2020-03-24'), shares, -999)) OVER () AS mar24_shares
    FROM (
        SELECT
            et_date,
            (close_usd / lagInFrame(close_usd, 1) OVER (ORDER BY et_date ASC ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) - 1) * 100 AS day_pct,
            (close_usd / lagInFrame(close_usd, 3) OVER (ORDER BY et_date ASC ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) - 1) * 100 AS burst3_pct,
            shares,
            avg(shares) OVER (ORDER BY et_date ASC ROWS BETWEEN 30 PRECEDING AND 1 PRECEDING) AS vol_avg_30,
            avg(shares) OVER (ORDER BY et_date ASC ROWS BETWEEN 250 PRECEDING AND 1 PRECEDING) AS vol_avg_250
        FROM (
            SELECT
                toDate(toTimeZone(window_start, 'America/New_York')) AS et_date,
                argMaxIf(toFloat64(close), window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) AS close_usd,
                toFloat64(sum(volume)) AS shares
            FROM global_markets.delayed_stocks_minute_aggs
            WHERE ticker = 'SPY' AND window_start < toDateTime('2026-01-01 00:00:00')
            GROUP BY et_date
            HAVING close_usd > 0
        )
    )
)
GROUP BY mar24_d, mar26_b, mar24_r30, mar24_r250, mar24_shares

از زمان 2003-09-10 — اولین جلسه از داده‌های دقیقه‌ای ما — SPY بازده روزانه از قیمت بسته تا بسته را در 5613 مورد ثبت کرده است. بازدهی +9.5% در تاریخ 24 مارس 2020 در رتبه #3 قرار دارد: دقیقاً 2 جلسه از آن پیشی گرفته‌اند (2008-10-13, 2008-10-28)، که هر دو مربوط به بحران اکتبر 2008 هستند. توالی سه روزه حتی نادرتر است: روند +17.5% از بسته شدن بازار در 23 مارس تا بسته شدن در 26 مارس، دارای 0 بزرگ‌ترین سود سه جلسه‌ای در کل نمونه است. در تمام داده‌های قابل بررسی در این مخزن، هیچ موردی با این جهش برابری نمی‌کند.

حجم معاملات داستان آرام‌تری را روایت می‌کند: 232 میلیون سهم SPY معامله شد که 2.86 برابر میانگین سال گذشته بود — و تنها 1.12 برابر میانگین 30 جلسه قبل بود. در مقایسه با هر بازه عادی از تاریخ، این فعالیت استثنایی بود؛ اما در مقایسه با هفته‌های سقوط پیش از آن، تنها یک روز دیگر در میان طوفان بود. رویدادهای تاریخی همیشه با حجم معاملات تاریخی همراه نیستند.

جهش سه‌روزه

پرس‌وجوقیمت بسته‌شدن SPY، ۲۳ تا ۲۶ مارس ۲۰۲۰ — جهش سه روزه
کد دقیق SQL پشت هر عدد
SELECT
    toString(et_date) AS session,
    close_usd,
    round(if(prev_close = 0, NULL, (close_usd / prev_close - 1) * 100), 1) AS change_pct,
    shares_m
FROM (
    SELECT et_date, close_usd, shares_m,
           lagInFrame(close_usd) OVER (ORDER BY et_date ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev_close
    FROM (
        SELECT
            toDate(toTimeZone(window_start, 'America/New_York')) AS et_date,
            round(argMaxIf(toFloat64(close), window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959), 2) AS close_usd,
            round(toFloat64(sum(volume)) / 1e6, 1) AS shares_m
        FROM global_markets.delayed_stocks_minute_aggs
        WHERE ticker = 'SPY'
          AND window_start >= toDateTime('2020-03-20 00:00:00') AND window_start < toDateTime('2020-03-26 23:59:00')
        GROUP BY et_date
    )
)
WHERE et_date >= toDate('2020-03-23') AND et_date <= toDate('2020-03-26')
ORDER BY et_date

روند صعودی بلافاصله شدت گرفت: %9.5% در تاریخ 24، %1.3% در تاریخ 25 و %5.9% در تاریخ 26؛ توالی سه‌جلسه‌ای که روند ریزشی چندین هفته را خنثی کرد و در تمام داده‌های نمونه، بزرگترین جهش محسوب می‌شود. الگوی مارس 2020 شباهت نزدیکی به مارس 2009 دارد: در هر دو مورد، پاسخ سیاستی تعیین‌کننده در نزدیکی نقطه کف رخ داد، اولین مرحله رالی بسیار شدید بود و روز با بیشترین فرصت خرید — در آن صبح — از نظر ظاهری با سایر بازگشت‌های بازار خرسی قابل تشخیص نبود.

Did the rally hold?

In real time, "bear-market bounce" was the consensus reading, and the skeptics had receipts of their own: eleven days earlier the tape had already produced a rally almost this size — from $248.1 on 2020-03-12 to $270.93 on 2020-03-13 — and the session after that closed at $239.41, the worst day of the whole crash. One green day proved nothing. What distinguishes March 24 is what came after:

پرس‌وجوآیا حمایت شد؟ بازبینی (retest) اتفاق‌نرفته و دو ساعتک بازیابی
کد دقیق SQL پشت هر عدد
SELECT
    round(ath_close, 2) AS feb19_ath_close,
    round(bottom_close, 2) AS mar23_bottom_close,
    toString(rec_date) AS recovery_date,
    countIf(et_date > toDate('2020-03-23') AND et_date <= rec_date) AS sessions_to_new_high,
    dateDiff('day', toDate('2020-03-23'), rec_date) AS days_low_to_new_high,
    dateDiff('day', toDate('2020-02-19'), rec_date) AS round_trip_days,
    round(minIf(close_usd, et_date > toDate('2020-03-23') AND et_date <= rec_date), 2) AS lowest_close_after,
    toString(argMinIf(et_date, (close_usd, et_date), et_date > toDate('2020-03-23') AND et_date <= rec_date)) AS lowest_close_date,
    round((minIf(close_usd, et_date > toDate('2020-03-23') AND et_date <= rec_date) / bottom_close - 1) * 100, 1) AS closest_retest_pct,
    toString(peak07_date) AS peak_2007_date,
    toString(rec07_date) AS recovery_2013_date,
    dateDiff('day', peak07_date, rec07_date) AS round_trip_2008_days
FROM (
    SELECT
        et_date, close_usd, ath_close, bottom_close, peak07_date,
        min(if(et_date > toDate('2020-03-23') AND close_usd >= ath_close, et_date, toDate('2099-01-01'))) OVER () AS rec_date,
        min(if(et_date >= toDate('2008-01-01') AND close_usd >= peak07_close, et_date, toDate('2099-01-01'))) OVER () AS rec07_date
    FROM (
        SELECT
            et_date, close_usd,
            max(if(et_date = toDate('2020-02-19'), close_usd, -999)) OVER () AS ath_close,
            max(if(et_date = toDate('2020-03-23'), close_usd, -999)) OVER () AS bottom_close,
            max(if(et_date >= toDate('2007-01-01') AND et_date < toDate('2008-01-01'), (close_usd, et_date), (-999., toDate('1970-01-01')))) OVER () .1 AS peak07_close,
            max(if(et_date >= toDate('2007-01-01') AND et_date < toDate('2008-01-01'), (close_usd, et_date), (-999., toDate('1970-01-01')))) OVER () .2 AS peak07_date
        FROM (
            SELECT
                toDate(toTimeZone(window_start, 'America/New_York')) AS et_date,
                argMaxIf(toFloat64(close), window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) AS close_usd
            FROM global_markets.delayed_stocks_minute_aggs
            WHERE ticker = 'SPY' AND window_start < toDateTime('2021-01-01 00:00:00')
            GROUP BY et_date
            HAVING close_usd > 0
        )
    )
)
GROUP BY ath_close, bottom_close, rec_date, peak07_date, rec07_date

The retest never came. After March 23, the lowest close SPY ever printed was $243.59 — on 2020-03-24, the stimulus-rally day itself. The market never again closed within 9.5% of the bottom. The pre-COVID high of $338.31 was recovered on 2020-08-18103 trading sessions after the low, a 181-day round trip from all-time high back to all-time high. The 2008 comparison, computed the same way: SPY's 2007-10-09 peak did not see a new closing high until 2013-03-14, 1983 days later. Two crises, two speeds, one market that had changed its metabolism in between.

آنچه این روز به ما می‌آموزد

سه نکته مهم را باید درک کرد. نخست، شکاف قیمتی نقش اصلی را ایفا کرد: بخش زیادی از سود امروز پیش از بازگشایی بازار حاصل شده بود؛ هر کسی که منتظر ورود در ساعات عادی بازار بود، در طول روز هزینه‌ی سنگینی پرداخت کرد — مکانیسم‌های شکاف شبانه در حداکثر دامنه خود بودند. دوم، کف قیمتی پیش از تایید نهایی رخ داد: قیمت بسته‌شدن در 23 مارس، کف قیمتی بود که تنها پس از گذشت جلسات معاملاتی مشابه امروز و عدم بازگشت قیمت به آن سطح، مشخص شد. سوم، سرعت هم‌زمان در هر دو جهت اثرگذار است: همان ساختار بازار که یک کاهش قیمت -34.2% را در سطوح 24 فشرده کرد، همان ساختار باعث شد بازیابی اولیه تنها در سه جلسه انجام شود. سرعت، ویژگی ساختار زیرساختی بازار در این دوران است، نه نتیجه‌ی اخبار خوب یا بد.

شکاکان آن هفته نادان نبودند: وسعت بازار، جهش قیمتی و بازگشت به سطح تست‌شدنی که هرگز رخ نداد — هر نشانه‌ای که 24 مارس را از رالی‌های ناموفق متمایز می‌کند، تنها با نگاه به گذشته قابل اندازه‌گیری است. تفاوت میان یک رالی در بازار خرسی و یک بازار گاوی جدید، در روز اول نامشخص است و تنها پس از گذشت چند ماه، کاملاً آشکار می‌شود.

COVID rally FAQ

What happened on March 24, 2020?

The first full session after the Fed's unlimited-QE announcement: SPY gapped +5.4% at the open and closed +9.5% — the #3 single-day gain in the 5613 sessions our minute tape covers, behind only two days in October 2008.

What did the Fed announce on March 23, 2020?

Open-ended purchases of Treasury and mortgage-backed securities — "in the amounts needed" — plus the PMCCF and SMCCF, its first-ever facilities for buying corporate bonds, and a revived TALF for consumer credit. The statement went out at 8:00 am ET, before the open; SPY still closed that day at its bear-market low.

Was March 23, 2020 the bottom of the COVID crash?

Yes, by closing price: SPY's low close of $222.51 printed on March 23, hours after the Fed's announcement. It was never revisited — the lowest close afterward came on 2020-03-24, 9.5% above the bottom.

When did the stock market recover its pre-COVID high?

SPY first closed above its February 19, 2020 all-time-high close on 2020-08-18, 103 trading sessions after the bottom — a 181-day round trip, against 1983 days for the 2008 crash's equivalent journey.

Could you have bought after the news and still done well?

The open gapped +5.4% before regular trading began, and the day kept climbing — every later entry cost more than the prior close, and still sat far below where the market stood at the August 2020 recovery.

Data notes
  • Closes are regular-session (9:30 am-4:00 pm ET) last prints from the minute tape; they can differ from official auction closes by a few cents.
  • Recovery dates are price-only; a total-return measure (dividends reinvested) recovers sooner by construction.
  • The 10-year yield joins the Treasury's daily series on trading dates; basis points are hundredths of a percentage point.
  • The rank panel's sample starts 2003-09-10 — "since 2003" on this page means that window, not all recorded market history.

Every panel above is a stored, versioned query over the historical tape — expand the SQL to see each measurement. Want to feel this day instead of reading it? It is one of the playable scenarios in the Strasmore Labs trading simulator.

#market history#covid rally#bull markets#federal reserve#spy