COVID crash 2020: apat na halts at peak to trough
Ang COVID crash noong 2020: ang mga nawawalang minuto sa tape noong March 9, apat na circuit breakers sa loob ng walong araw, at ang peak-to-trough map sa SPY.
Dinala ng COVID crash noong 2020 ang S&P 500 mula sa record close noong February 19 tungo sa isang -34.2% peak-to-trough loss sa loob ng 23 trading days — na may apat na market-wide circuit-breaker halts sa proseso, ang una mula noong 1997. Inuulit ng pahinang ito ang buong arc mula sa tape: ang mapa ng crash, ang halt session noong March 9 minute by minute (kasama ang mga minutong nawawala sa data, na siyang pinakamagandang resibo sa pahina), ang mga pangalang pinakamalakas ang pagbagsak, at ang ginawa ng mga Treasury at ng options tape kasabay nito. Ang bawat numero ay isang stored query; i-expand ang anumang panel para sa SQL.
Ang buong crash, sa isang row
Bago ang sikat na iisang araw, narito ang map. Isang query sa daily regular-session closes ng SPY ang nagtutukoy sa peak, trough, bilis, at recovery — kasama ang parehong measurement sa 2008 bear market para sa scale.
Ang eksaktong SQL sa likod ng bawat numero
WITH dailies AS (
SELECT
toDate(toTimeZone(window_start, 'America/New_York')) AS d,
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 c
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
AND window_start >= toDateTime('2020-02-01 00:00:00') AND window_start < toDateTime('2020-09-01 00:00:00')
GROUP BY d
),
peak AS (SELECT argMax(d, (c, -toInt32(d))) AS pd, max(c) AS pc FROM dailies WHERE d < toDate('2020-03-01')),
trough AS (SELECT argMin(d, (c, toInt32(d))) AS td, min(c) AS tc FROM dailies WHERE d < toDate('2020-04-01')),
gfc AS (
SELECT
toDate(toTimeZone(window_start, 'America/New_York')) AS d,
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 c
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
AND window_start >= toDateTime('2007-06-01 00:00:00') AND window_start < toDateTime('2009-01-01 00:00:00')
GROUP BY d
),
gpeak AS (SELECT argMax(d, (c, -toInt32(d))) AS pd, max(c) AS pc FROM gfc WHERE d < toDate('2008-01-01'))
SELECT
toString((SELECT pd FROM peak)) AS peak_date,
round((SELECT pc FROM peak), 2) AS peak_close,
toString((SELECT td FROM trough)) AS trough_date,
round((SELECT tc FROM trough), 2) AS trough_close,
round(((SELECT tc FROM trough) / (SELECT pc FROM peak) - 1) * 100, 1) AS decline_pct,
countIf(d > (SELECT pd FROM peak) AND d <= (SELECT td FROM trough)) AS sessions_peak_to_trough,
dateDiff('day', (SELECT pd FROM peak), (SELECT td FROM trough)) AS calendar_days,
countIf(d > (SELECT pd FROM peak) AND d <= (SELECT min(d) FROM dailies WHERE c <= 0.7 * (SELECT pc FROM peak))) AS sessions_to_minus_30,
(SELECT countIf(d > (SELECT pd FROM gpeak) AND d <= (SELECT min(d) FROM gfc WHERE c <= 0.7 * (SELECT pc FROM gpeak))) FROM gfc) AS gfc_2008_sessions_to_minus_30,
toString((SELECT min(d) FROM dailies WHERE d > (SELECT td FROM trough) AND c >= (SELECT pc FROM peak))) AS recovery_date,
countIf(d > (SELECT td FROM trough) AND d <= (SELECT min(d) FROM dailies WHERE d > (SELECT td FROM trough) AND c >= (SELECT pc FROM peak))) AS sessions_trough_to_recovery
FROM dailiesAng peak close ng SPY ay $338.31 noong 2020-02-19. Ang trough close, $222.51 noong 2020-03-23, ay nasa -34.2% sa ibaba nito — isang bear market na nangyari sa loob lamang ng 23 trading sessions, o 33 calendar days. Ang madalas banggitin na "fastest thirty-percent drawdown on record" ay napatunayan sa parehong row: ang close ng SPY ay unang bumaba ng 30% mula sa peak pagkatapos lamang ng 22 sessions. Ang 2008 bear market, na sinukat sa parehong paraan mula sa October 2007 peak close, ay nangailangan ng 250 sessions para mawala ang parehong 30%. Ang kumuha ng halos isang taon noong 2008 ay nangyari ng mga isang buwan noong 2020.
Ang dated skeleton ng crash, kung saan ang bawat numero ay galing sa mga panel sa page na ito:
- February 19, 2020 — record close ng SPY, $338.31.
- March 9 — ang unang market-wide circuit breaker mula noong 1997; nag-close ang SPY na -7.7% down. Detalyado ang bawat minuto sa ibaba.
- March 12, 16, at 18 — tatlo pang Level-1 halts. Ang March 16 ay nag-close sa -11.6%, ang pinakamalalang iisang session ng crash.
- March 23 — ang closing low: $222.51, -34.2% mula sa peak.
- March 24 — ang pagbaliktad. Ang stimulus rally ng March 24 ang nagdala ng tape na iyon.
- 2020-08-18 — muling nag-close ang SPY sa itaas ng February peak, 103 sessions matapos ang low.
Marso 9, 2020: ang session na nag-trigger ng breaker
Ang mga market-wide circuit breaker ay nakabase sa S&P 500, kaya binabasa ng panel na ito ang halt sa pamamagitan ng SPY — ang S&P 500 ETF — sa halip na anumang ibang proxy. Noong nakaraang weekend, nagbanggaan ang pandemic repricing at isang oil-supply shock (karagdagang detalye sa ibaba), at hindi talaga nagbukas ang market sa isang maayos na paraan.
Ang eksaktong SQL sa likod ng bawat numero
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-06 00:00:00') AND window_start < toDateTime('2020-03-09 04:00:00')
) AS prior_rth_close,
(
SELECT (formatDateTime(toTimeZone(addMinutes(prev_bar, 1), 'America/New_York'), '%H:%i'), gap_minutes - 1)
FROM (
SELECT
lagInFrame(window_start) OVER (ORDER BY window_start ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev_bar,
dateDiff('minute', prev_bar, window_start) AS gap_minutes
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
AND window_start >= toDateTime('2020-03-09 04:00:00') AND window_start < toDateTime('2020-03-09 23:59:00')
AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
)
WHERE prev_bar > toDateTime('2020-03-09 00:00:00')
ORDER BY gap_minutes DESC
LIMIT 1
) AS halt_gap
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,
halt_gap.1 AS halt_first_missing_et,
halt_gap.2 AS halt_missing_minutes,
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(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(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-09 04:00:00') AND window_start < toDateTime('2020-03-09 23:59:00')Dalawang numero ang dapat tandaan. Una, ang gap: nagbukas ang SPY sa $275.3, -7.4% sa ibaba ng close noong Biyernes na $297.42 — at sa loob ng unang ilang minuto, ang pagbaba ng S&P 500 ay umabot sa 7% Level-1 threshold. Pangalawa, at mas mahalaga: 376 regular-session minute bars sa halip na ang karaniwang 390. Huminto ang tape pagkatapos ng 9:34 am: simula 09:35 ET, 14 magkakasunod na minuto ang walang anumang print ng bars. Walang anumang na-trade kahit saan. Ang gap sa data ay ang circuit breaker. Nagsara ang session sa $274.4, -7.7% ang ibinaba, na may 304.6 million shares.
Ang anyo ng isang nahintong session
Ang eksaktong SQL sa likod ng bawat numero
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-09 04:00:00') AND window_start < toDateTime('2020-03-09 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_timeNasa opening bucket na ang crash, ang halt, at ang resumption nang sabay-sabay: ang low nito na $273.5 ay ilang cents na lang ang layo sa full day low na $273.45 — ang afternoon print sa 14:44 ET ay muling sinubukan lamang ang level ng umaga. Pagkatapos ng reopening, halos hindi na gumalaw ang tape: ang bawat half-hour close ay nanatili sa loob ng ilang dolyar mula sa reopening price, at ang pinsala ng araw ay nangyari na sa mga unang minuto ng clock time. Ibang kwento naman ang ipinakita ng volume — ang huling half hour, sa 46.7 million shares, ang pinakamabigat na bucket ng araw habang nag-cross ang closing flows. Ang mga circuit breaker ay idinisenyo para gumawa ng eksaktong anyong ito: itigil ang waterfall, pilitin ang isang reopening auction, at hayaang magpatuloy ang continuous trading sa repriced level. Ang oras ng merkado ay mayroon nang permanenteng machinery na ito.
Apat na halt sa loob ng walong session
Noong March 9 lamang ang una.
Ang eksaktong SQL sa likod ng bawat numero
SELECT
toString(et_date) AS session,
close_usd,
change_pct,
shares_m
FROM (
SELECT et_date, close_usd, shares_m,
round((close_usd / lagInFrame(close_usd) OVER (ORDER BY et_date ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) - 1) * 100, 1) AS change_pct
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-06 00:00:00') AND window_start < toDateTime('2020-03-19 00:00:00')
GROUP BY et_date
)
)
WHERE toString(et_date) IN ('2020-03-09', '2020-03-12', '2020-03-16', '2020-03-18')
ORDER BY et_dateNag-trip din ang mga Level-1 breaker noong March 12 (sumara sa -9.6%), March 16 (sumara sa -11.6% sa $239.41 — ang pinakamalaking one-day percentage drop ng S&P mula noong 1987), at March 18 (huminto intraday, sumara sa -5.2%). May apat na market-wide halt sa loob ng walong trading days, matapos ang dalawampu't tatlong taon na walang ganoon. Pansinin ang hindi nangyari: lahat ng halt ay Level 1, ang 7% tier. Hindi kailanman naabot ang 13% at 20% tiers — kahit noong March 16, bumagal ang cascade pagkatapos ng halt at natapos ang session sa loob ng Level-2 line.
Sino ang pinakamalaking bumagsak
Itinatago ng isang index number ang dispersion sa ilalim nito. Ang parehong daily-close arithmetic, kapag ginamit sa ilang representative large-caps, ay nagpapakita kung saan talaga tumama ang crash — kapwa noong March 9 mismo at sa buong slide mula February 19 hanggang March 23.
Ang eksaktong SQL sa likod ng bawat numero
WITH dailies AS (
SELECT
ticker,
toDate(toTimeZone(window_start, 'America/New_York')) AS d,
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 c
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('UAL', 'CCL', 'XOM', 'JPM', 'AAPL', 'WMT', 'SPY')
AND window_start >= toDateTime('2020-02-18 00:00:00') AND window_start < toDateTime('2020-03-25 00:00:00')
GROUP BY ticker, d
)
SELECT
ticker,
round((anyIf(c, d = toDate('2020-03-09')) / anyIf(c, d = toDate('2020-03-06')) - 1) * 100, 1) AS mar9_pct,
round((anyIf(c, d = toDate('2020-03-23')) / anyIf(c, d = toDate('2020-02-19')) - 1) * 100, 1) AS crash_pct
FROM dailies
GROUP BY ticker
ORDER BY crash_pct ASCAng pinaka-apektadong pangalan sa panel, CCL (Carnival, ang cruise operator), ay nawalan ng -19.9% noong March 9 lamang at -72.3% mula peak hanggang trough. Ang United Airlines ay bumaba ng -66.9% noong crash; ang ExxonMobil ay -47.9%; ang JPMorgan ay -42.6%. Kumpara sa kanila, ang -34.2% ng SPY ay mukhang banayad, ang Apple ay bumagsak kasabay ng market sa -31%, at ang Walmart — groceries, essentials, bukas sa gitna ng lockdowns — ay natapos ang parehong window sa -2.9% lamang. Ang travel at energy ay nag-reprice para sa isang mundong huminto; ang staples ay halos hindi gumalaw.
Ang digmaan sa presyo ng langis, sa madaling salita
Nararapat lamang na bigyan ng isang talatang paliwanag ang hidwaan sa enerhiya sa itaas, dahil ang "oil-price war" ang bumubuo sa kabilang bahagi ng kuwento noong March 9. Ang mga usapan sa produksyon ng OPEC+ sa pagitan ng Saudi Arabia at Russia ay natapos nang walang kasunduan noong Biyernes, March 6, 2020. Nitong weekend, ibinaba ng Saudi Arabia ang kanilang mga opisyal na selling price at nag-anunsyo ng mga plano na itaas ang output sa isang mundo kung saan ang travel demand ay nagsasara na — isang supply shock na sumabay sa isang demand shock. Sabay na dinala ng equity open noong Lunes ang dalawang ito, at makikita ang resulta sa panel sa itaas: bumagsak ang ExxonMobil ng -12.2% noong Lunes na iyon kumpara sa -7.7% ng SPY.
Ang pagtakbo sa safety — at ang linggong nasira ito
Kalahati lang ng kuwento ang equities. Ang kabilang kalahati ay ang Treasury market, kung saan ang klasikong flight to safety ay umabot sa record — at pagkatapos, sa loob ng isang pambihirang linggo, ay bumaliktad.
Ang eksaktong SQL sa likod ng bawat numero
SELECT
toString(date) AS date,
round(yield_10_year, 2) AS ten_year_pct,
round(yield_3_month, 2) AS three_month_pct
FROM global_markets.treasury_yields
WHERE date >= '2020-02-18' AND date <= '2020-03-31'
AND isNotNull(yield_10_year)
ORDER BY dateAng 10-year yield ay nasa 1.56% noong peak ng equity noong February 19. Pagdating ng March 9 — ang halt session — nagsara ito sa 0.54%, isang all-time low, kung saan tinanggap ng mga buyer ang half a percent kada taon sa loob ng isang dekada kapalit ng safety. Pagkatapos ay nag-invert ang pattern: hanggang March 18, ang 10-year yield ay tumaas sa 1.18% habang patuloy na bumabagsak ang equities — ang "dash for cash," isang linggo kung kailan ibinenta ng mga fund, kumpanya, at foreign holder ang anumang liquid, kasama na ang Treasuries, upang makalikom ng dollars. Samantala, ang 3-month bill ay nagsara sa araw na iyon sa 0.02% — ang mga cash equivalent ay nanatiling pinned sa zero. Kapag ang pinakaligtas na asset at ang pinaka-risky na asset ay sabay na bumabagsak, ang binibili ay ang liquidity mismo. Ang yield curve ay permanenteng dala ang episode na ito sa kasaysayan nito.
Ano ang ipinapakita ng options tape
Ang mga listed options ng SPY — ang pangunahing hedging venue ng merkado — ay nag-iwan ng sariling rekord ng panic, at ang timing nito ang kawili-wiling bahagi.
Ang eksaktong SQL sa likod ng bawat numero
SELECT
toString(toDate(toTimeZone(sip_timestamp, 'America/New_York'))) AS session,
round(sumIf(toFloat64(size), substring(ticker, 12, 1) = 'P') / 1e6, 2) AS put_contracts_m,
round(sumIf(toFloat64(size), substring(ticker, 12, 1) = 'C') / 1e6, 2) AS call_contracts_m,
round(sumIf(toFloat64(size), substring(ticker, 12, 1) = 'P') / sumIf(toFloat64(size), substring(ticker, 12, 1) = 'C'), 2) AS put_call_ratio
FROM global_markets.options_trades
WHERE ticker >= 'O:SPY2' AND ticker < 'O:SPY3'
AND sip_timestamp >= toDateTime('2020-03-02 00:00:00') AND sip_timestamp < toDateTime('2020-03-14 00:00:00')
GROUP BY session
ORDER BY sessionAng put/call volume ratio ay pumutok sa 1.95 — halos two puts ang na-trade para sa bawat call — noong Biyernes, March 6, bago ang halt session. Noong March 9 mismo, 4.35 million puts ang na-trade laban sa 2.38 million calls, isang ratio na 1.83. Pagdating ng March 12 — isang -9.6% session — ang ratio ay bumaba sa 1.32 habang tumaas ang call volume kasabay ng mga put. Ang pinakamabigat na put skew ay nangyari sa simula ng cascade, hindi sa dulo nito: maagang bumili ng proteksyon, at ang mga sumunod na mas malalaking down days ay na-trade sa isang mas two-sided na options tape.
Paano talaga gumagana ang market-wide halt
Ang mga mekanismo, dahil bihirang mangyari para malimutan sa pagitan ng mga paggamit: ang mga market-wide breaker ay nakabase sa pagbaba ng S&P 500 mula sa prior close — 7% (Level 1) at 13% (Level 2) ay nagti-trigger ng 15-minute halt kung matatamaan bago ang 3:25 pm ET; ang 20% (Level 3) ay tuluyan nang nagtatapos sa session. Habang may halt, walang trade na nangyayari sa anumang exchange; ang mga order ay pumipila para sa isang reopening auction, na pinagsasama ang naipong interest sa isang presyo gaya ng ginagawa ng opening auction tuwing umaga. Ang disenyong ito ay nagmula sa aftermath ng the 2010 flash crash, na nagpakita na ang mga lumang threshold ay masyadong maluwag para mag-fire kahit sa isang tunay na cascade.
Ang Marso 2020 ang unang — at sa ngayon ay tanging — live test ng disenyong iyon, at ang hatol ay nasa mga panel sa itaas: apat na Level-1 halt, na bawat isa ay sinundan ng isang orderly reopening, walang Level 2 o Level 3 na naabot, at isang gumaganang market sa bawat isa sa 23 sessions ng pinakamabilis na malaking drawdown sa kasaysayan ng index. Nanatili ang mga panuntunan pagkatapos nito: ang parehong 7/13/20 thresholds, na nakabase sa S&P 500, ay nananatiling may bisa hanggang ngayon. Yumuko ang sistema; ngunit nanatiling matatag ang plumbing.
FAQ sa COVID crash
Ano ang nag-trigger ng circuit breaker noong March 9, 2020?
Ang pagbaba ng S&P 500 nang 7% mula sa prior close — ang Level-1 market-wide threshold — sa loob ng mga unang minuto ng pagbubukas. Huminto ang trading sa buong market sa loob ng 15 minutes, at muling nagbukas via auction. Makikita ang halt sa minute tape ng page na ito bilang 14 sunod-sunod na missing bars simula sa 09:35 ET.
Gaano kalaki ang ibinaba ng stock market sa COVID crash?
Base sa daily closes ng SPY, -34.2% — mula $338.31 noong February 19, 2020 hanggang $222.51 noong March 23, 2020, sa loob ng 23 trading sessions.
Ilang circuit breaker ang tinamaan noong March 2020?
Apat na market-wide Level-1 halts: March 9, 12, 16, at 18. Ito ang mga una simula noong October 1997.
May tinamaan bang Level 2 o Level 3 circuit breakers noong 2020?
Wala. Lahat ng apat na halts noong 2020 ay Level 1 (7%). Wala pang Level-2 (13%) o Level-3 (20%) market-wide halt na nag-fire sa ilalim ng kasalukuyang design — kahit noong March 16, ang pinakamalalang session ng crash sa -11.6%.
Ganap bang nakabawi ang market mula sa COVID crash?
Oo. Nag-close ang SPY sa itaas ng February 19, 2020 peak nito noong 2020-08-18 — 103 trading sessions matapos ang March 23 low, isa sa mga pinakamabilis na full recoveries mula sa isang bear market na may ganitong lalim.
Ang bawat panel sa itaas ay isang stored, versioned query mula sa historical tape — i-expand ang SQL para makita ang bawat measurement. Gusto mong maranasan ang araw na ito sa halip na basahin lang? Isa ito sa mga playable scenarios sa Strasmore Labs trading simulator.