Крах ринку через COVID у 2020 році
Аналіз обвалу S&P 500 у 2020 році: чотири зупинки торгів за вісім днів та детальна карта падіння SPY від піку до дна. Вивчіть хронологію подій та дані ринку.
Крах через COVID у 2020 році призвів до падіння S&P 500 з рекордного рівня закриття 19 лютого до втрати у -34.2% від піку до дна за 23 торгових днів. Протягом цього періоду чотири рази спрацьовували ринкові автоматичні зупинки торгів (circuit-breakers), що вперше сталося з 1997 року. На цій сторінці представлено повну хронологію подій: карту обвалу, поминутовий звіт сесії зупинки торгів 9 березня (включаючи хвилини, відсутні в даних, які є найкращим підтвердженням на сторінці), перелік активів, що продемонстрували найбільше падіння, а також динаміку Treasury та ринку опціонів. Кожне число отримано шляхом запиту до бази даних; ви можете розгорнути будь-яку панель, щоб переглянути SQL-код.
Весь крах в одному рядку
Карта подвального стану ринку перед тим відомим днем. Один запит за ціною закриття SPY під час регулярних торгових сесій фіксує пік, мінімум, швидкість та відновлення — а також аналогічний показник для порівняння з ведмежим ринком 2008 року.
Точний SQL-код для кожного числа
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 dailiesПік ціни закриття SPY склав $338.31 у 2020-02-19. Мінімум закриття, $222.51 у 2020-03-23, знаходиться на -34.2% нижче — ведмежий ринок, стиснутий у 23 торгових сесій або 33 календарних днів. Твердження про «найшвидше падіння на тридцять відсотків в історії», яке часто цитують, підтверджується в тому ж рядку: ціна закриття SPY вперше опустилася на 30% нижче піку лише за 22 сесій. Ведмежий ринок 2008 року, виміряний так само від піку закриття у жовтні 2007 року, потребував 250 сесій, щоб втратити ті ж 30%. Те, що у 2008 році зайняло приблизно рік, у 2020 році зайняло близько місяця.
Хронологія краху, де кожне число взято з панелей на цій сторінці:
- 19 лютого 2020 року — рекордне закриття SPY, $338.31.
- 9 березня — перше загальноринкове зупинення торгів (circuit breaker) з 1997 року; SPY закривається падінням на -7.7%. Детальний звіт наведено нижче.
- 12, 16 та 18 березня — ще три зупинення Level-1. 16 березня закривається на -11.6%, що стало найгіршою окремою сесією під час краху.
- 23 березня — мінімум закриття: $222.51, що на -34.2% нижче піку.
- 24 березня — розворот. Ралі на фоні стимулів 24 березня визначає цей тренд.
- 2020-08-18 — SPY знову закривається вище піку лютого через 103 сесій після мінімуму.
9 березня 2020 року: сесія, що активувала механізм призупинення торгів
Ринкові автоматичні вимикачі (circuit breakers) прив'язані до S&P 500, тому в цій панелі відображення зупинки торгів здійснюється через SPY — ETF на S&P 500 — а не через будь-який інший проксі-інструмент. Протягом попередніх вихідних переоцінка ринку через пандемію поєдналася з шоком пропозиції нафти (детальніше нижче), через що ринок не відкрився належним чином.
Точний 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-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')Два показники на початку. По-перше, розрив: SPY відкрився на рівні $275.3, що на -7.4% нижче за ціною закриття п'ятниці у $297.42 — і протягом перших хвилин падіння S&P 500 досягло порогу Level-1 у 7%. По-друге, важливий момент: 376 хвилинних барів у межах регулярної сесії замість звичних 390. Потік даних зупиняється після 09:34 за часом ET: починаючи з 09:35 ET, 14 хвилин поспіль не відображають жодних барів. Торгівлі не було ніде. Цей розрив у даних і є ознакою спрацювання автоматичного вимикача. Сесія закрилася на рівні $274.4, що на -7.7% нижче, обсягом 304.6 мільйонів акцій.
Структура сесії з зупинкою торгів
Точний 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-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_timeПочатковий сегмент включає обвал, зупинку торгів та відновлення одночасно: мінімум на рівні $273.5 перебуває у межах кількох центів від мінімуму за весь день у $273.45 — денна ціна на 14:44 ET лише повторно протестувала ранковий рівень. Після відновлення торгів динаміка ціни була мінімальною: кожне півгодинне закриття коливалося в межах кількох доларів від ціни відкриття, а основне падіння відбулося протягом перших хвилин. Обсяги торгів підтверджують це: останнє півгодиння з обсягом 46.7 мільйонів акцій було найбільш активним за весь день через закриття позицій. Механізми автоматичної зупинки торгів (circuit breakers) розроблені саме для такої структури: зупинити падіння, ініціювати аукціон для відновлення торгів та дозволити безперервним торгам відновитися на переоціненому рівні. Годинник ринку тепер має цей механізм постійно вбудованим.
Чотири зупинки за вісім сесій
9 березня була лише першою.
Точний SQL-код для кожного числа
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_dateЗупинки рівня Level-1 також відбулися 12 березня (закриття -9.6%), 16 березня (закриття -11.6% на рівні $239.41 — найбільше одноденне відсоткове падіння S&P 500 з 1987 року) та 18 березня (зупинка під час торгової сесії, закриття -5.2%). Чотири загальноринкові зупинки за вісім торгових днів після двадцяти трьох років їх відсутності. Зверніть увагу на те, чого не сталося: кожна зупинка була рівня Level 1, тобто 7-відсоткового рівня. Рівні 13% та 20% не були досягнуті — навіть 16 березня після зупинки падіння сповільнилося, і сесія завершилася в межах лінії Level-2.
Хто постраждав найбільше
Показник індексу приховує розбіжність показників окремих активів. Порівняння середніх значень за ціною закриття для кількох репрезентативних компаній з великою капіталізацією демонструє реальний масштаб падіння — як безпосередньо 9 березня, так і протягом усього періоду зниження з 19 лютого по 23 березня.
Точний SQL-код для кожного числа
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 ASCНайбільш постраждала компанія в вибірці, CCL (Carnival, оператор круїзних лайнерів), втратила -19.9% лише 9 березня і -72.3% від піку до дна. United Airlines втратила -66.9% під час обвалу; ExxonMobil -47.9%; JPMorgan -42.6%. На їхньому фоні показник -34.2% індексу SPY виглядає майже незначним; Apple впала приблизно разом із ринком на -31%, а Walmart — продукти харчування, товари першої необхідності, що залишалися попитною категорією під час локдаунів — завершила той самий період лише з втратою -2.9%. Сектори подорожей та енергетики пройшли переоцінку через зупинку світової економіки; споживчі товари першої необхідності майже не змінилися.
Коротко про війну цін на нафту
Вищезгаданий енергетичний конфлікт потребує окремого пояснення, оскільки термін «війна цін на нафту» відображає другу сторону подій від 9 березня. Переговори OPEC+ щодо обсягів видобутку між Саудівською Аравією та Росією завершилися без домовленостей у п'ятницю, 6 березня 2020 року. Протягом вихідних Саудівська Аравія знизила офіційні ціни на продаж і оголосила про плани збільшення видобутку в умовах, коли попит на перевезення вже різко скорочувався — це створило шок пропозиції на фоні шоку попиту. Початок торгів на ринку акцій у понеділок відобразив обидва фактори одночасно, що видно з наведеної вище таблиці: ExxonMobil впала на -12.2% того понеділка порівняно з -7.7% індексу SPY.
Біг до безпечних активів — та тиждень, коли він змінився
Акції були лише половиною історії. Іншою половиною був ринок Treasury, де класичний біг до безпечних активів досяг рекордних показників, а потім, протягом одного надзвичайного тижня, змінив напрямок.
Точний SQL-код для кожного числа
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 dateДохідність 10-річних облігацій становила 1.56% на піку ринку акцій 19 лютого. До 9 березня — під час призупинення торгів — вона закрилася на рівні 0.54%, що стало історичним мінімумом, коли покупці погодилися на пів відсотка річних протягом десятиліття в обмін на безпеку. Потім патерн змінився: до 18 березня дохідність 10-річних облігацій зросла до 1.18%, тоді як акції продовжували падати — це був «погоня за готівкою», тиждень, коли фонди, компанії та іноземні власники продавали всі ліквідні активи, включаючи Treasury, щоб залучити долари. Тим часом 3-місячні векселі закрилися того дня на рівні 0.02% — еквіваленти готівки були притиснуті до нуля. Коли найбезпечніший актив і найризикованіший актив падають одночасно, об'єктом купівлі стає сама ліквідність. Крива доходності назавжди зафіксувала цей епізод у своїй історії.
Що показує лента опціонів
Ліквідні опціони на SPY — основний інструмент ринкового хеджування — зафіксували паніку, і ключовим фактором є час її виникнення.
Точний SQL-код для кожного числа
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 sessionСпіввідношення обсягів путів та коллів досягло піку на рівні 1.95 — майже на два пути припадало по одному коллу — у п'ятницю, 6 березня, до призупинення торгів. Сама по собі 9 березня, обсяг путів склав 4.35 мільйонів проти 2.38 мільйонів коллів, що дало співвідношення 1.83. До 12 березня — -9.6% сесії — цей показник знизився до 1.32, оскільки обсяг коллів почав зростати разом із путами. Найбільший перекіс у бік путів спостерігався на початку падіння, а не на його завершенні: захист купували на ранніх етапах, тоді як пізніші та масштабніші дні падіння торгувалися за більш збалансованою лентою опціонів.
Як насправді працює загальноринкове призупинення торгів
Механізм роботи, оскільки він застосовується досить рідко, щоб про нього забували між випадками використання: загальноринкові запобіжники спрацьовують залежно від падіння індексу S&P 500 відносно попереднього закриття — падіння на 7% (Level 1) та на 13% (Level 2) призводять до 15-хвилинного призупинення торгів, якщо це стається до 15:25 ET; падіння на 20% (Level 3) повністю завершує торгову сесію. Під час призупинення торги на жодній біржі не проводяться; ордери накопичуються для аукціону після перерви, який концентрує накопичений інтерес в одній ціні, подібно до того, як це робить відкривальний аукціон щоранку. Ця структура з'явилася після flash crash 2010 року, коли стало зрозуміло, що старі пороги були занадто високими, щоб спрацювати навіть під час справжнього каскадного падіння.
Березень 2020 року став першим — і наразі єдиним — реальним випробуванням цієї структури, і висновок міститься у панелях вище: чотири призупинення рівня Level 1, кожне з яких супроводжувалося впорядкованим відновленням торгів; рівнів Level 2 або Level 3 досягнуто не було, а ринок функціонував під час кожної з 23 сесій найшвидшого великого просідання в історії індексу. Після цього правила залишилися незмінними: ті самі пороги 7/13/20 відносно S&P 500 діють і сьогодні. Система витримала навантаження; механізм спрацював.
COVID crash FAQ
What triggered the circuit breaker on March 9, 2020?
The S&P 500 falling 7% from its prior close — the Level-1 market-wide threshold — within the opening minutes. Trading halted for 15 minutes market-wide, then reopened via auction. The halt is visible in this page's minute tape as 14 consecutive missing bars starting at 09:35 ET.
How much did the stock market fall in the COVID crash?
Measured on SPY's daily closes, -34.2% — from $338.31 on February 19, 2020 to $222.51 on March 23, 2020, across 23 trading sessions.
How many circuit breakers were hit in March 2020?
Four market-wide Level-1 halts: March 9, 12, 16, and 18. They were the first since October 1997.
Were Level 2 or Level 3 circuit breakers ever hit in 2020?
No. All four 2020 halts were Level 1 (7%). No Level-2 (13%) or Level-3 (20%) market-wide halt has ever fired under the current design — not even on March 16, the crash's worst session at -11.6%.
Did the market fully recover from the COVID crash?
Yes. SPY closed above its February 19, 2020 peak on 2020-08-18 — 103 trading sessions after the March 23 low, one of the fastest full recoveries from a bear market of this depth.
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.