Strasmore Research
Analizy Matt ConnorAutor: Matt Connor · Zaktualizowano 2026-09-28

Krach COVID 2020: przebieg i mechanizmy wstrzymania handlu

Analiza krachu z 2020 roku obejmująca cztery przerwy w handlu, brakujące zapisy sesji z dziewiątego marca oraz mapę spadków indeksu S&P 500 od szczytu do dołka.

Krach z 2020 roku

Krach wywołany pandemią COVID w 2020 roku doprowadził indeks S&P 500 od rekordowego zamknięcia w dniu dziewiętnastego lutego do spadku od szczytu do dołka w ciągu -34.2% sesji, co oznaczało stratę rzędu 23. W trakcie tego procesu czterokrotnie uruchamiano ogólnorynkowe mechanizmy wstrzymania handlu (circuit breakers), po raz pierwszy od 1997 roku. Niniejsza strona odtwarza pełny przebieg zdarzeń na podstawie danych z rynku: mapę krachu, minutowy zapis sesji z dziewiątego marca (w tym brakujące minuty, które stanowią najistotniejszy dowód w zestawieniu), spółki, które ucierpiały najbardziej, oraz zachowanie obligacji skarbowych i rynku opcji w tym samym czasie. Każda liczba pochodzi z zapytania do bazy danych; należy rozwinąć dowolny panel, aby wyświetlić kod SQL.

Cały krach w jednym zestawieniu

Przed słynnym pojedynczym dniem – mapa. Jedno zapytanie dotyczące dziennych cen zamknięcia SPY w trakcie regularnej sesji pozwala wyznaczyć szczyt, dołek, tempo spadków i odbicie, a także zestawić te dane z rynkiem niedźwiedzia z 2008 roku dla zachowania skali.

ZapytanieKrach COVID-19, od szczytu do dołka i odbicie: dzienne ceny zamknięcia SPY, zestawienie zbiorcze
data szczytuzamknięcie w szczyciedata dołkazamknięcie w dołkuspadek (%)sesje szczyt-dołekdni kalendarzowesesje do -30%GFC 2008 sesje do -30%data odrobienia stratsesje dołek-odrobienie
2020-02-19338.312020-03-23222.51-34.22333222502020-08-18103
Dokładny kod SQL dla każdej liczby
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
Uruchom samodzielnie

Szczytowa cena zamknięcia SPY wyniosła 338.31 USD w dniu 2020-02-19. Cena zamknięcia w dołku, wynosząca 222.51 USD w dniu 2020-03-23, znajduje się -34.2% poniżej szczytu. Rynek niedźwiedzia skompresowany do 23 sesji giełdowych, czyli 33 dni kalendarzowych. Często przywoływane twierdzenie o „najszybszym w historii spadku o trzydzieści procent” znajduje potwierdzenie w tym samym zestawieniu: cena zamknięcia SPY po raz pierwszy przebiła poziom trzydziestu procent poniżej szczytu po zaledwie 22 sesjach. Rynek niedźwiedzia z 2008 roku, mierzony w identyczny sposób od szczytu z października 2007 roku, potrzebował 250 sesji, aby stracić te same trzydzieści procent. To, co w 2008 roku zajęło około roku, w 2020 roku trwało około miesiąca.

Chronologiczny szkielet krachu, każda liczba pochodzi z paneli na tej stronie:

  • 19 lutego 2020 r., rekordowe zamknięcie SPY, 338.31 USD.
  • 9 marca, pierwsze od 1997 roku wstrzymanie notowań na całym rynku; SPY zamyka się ze spadkiem -7.7%. Szczegółowy zapis minutowy znajduje się poniżej.
  • 12, 16 i 18 marca, trzy kolejne przerwy w notowaniach poziomu pierwszego. Sesja 16 marca kończy się spadkiem o -11.6%, co stanowi najgorszy wynik w trakcie krachu.
  • 23 marca, dołek cen zamknięcia: 222.51 USD, czyli -34.2% od szczytu.
  • 24 marca, punkt zwrotny. Rajd stymulacyjny z 24 marca napędza notowania.
  • 2020-08-18, SPY ponownie zamyka się powyżej lutowego szczytu, 103 sesji po osiągnięciu dołka.

9 marca 2020 r.: sesja, która uruchomiła mechanizm przerwania obrotu

Ogólnorynkowe mechanizmy typu circuit breaker są powiązane z indeksem S&P 500, dlatego niniejsze zestawienie analizuje wstrzymanie notowań na podstawie SPY, czyli ETF-u na S&P 500, a nie innych instrumentów zastępczych. W trakcie poprzedzającego weekendu wycena rynkowa pod wpływem pandemii zderzyła się z szokiem podażowym na rynku ropy (więcej informacji poniżej), przez co rynek nie otworzył się w sposób uporządkowany.

ZapytanieSPY, 9 marca 2020 r.: sesja z uruchomieniem mechanizmu circuit-breaker, zapis transakcji
poprz. zamknięcieotwarcie RTHluka (%)pierwsze zawieszenie ETminuty zawieszeniaminimum RTHminimum ETzamknięcie RTHzmiana dzienna (%)wolumen dzienny (mln)słupki minutowe RTH
297.42275.3-7.409:3514273.4514:44274.4-7.7304.6376
Dokładny kod SQL dla każdej liczby
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')
Uruchom samodzielnie

Dwie liczby na wstępie. Po pierwsze, luka: SPY otworzył się na poziomie 275.3 USD, czyli -7.4% USD poniżej piątkowego zamknięcia na poziomie 297.42 USD, a w ciągu pierwszych minut spadek S&P 500 osiągnął próg 7% dla pierwszego poziomu (Level-1) zabezpieczeń. Po drugie, co istotniejsze: 376 minutowych słupków sesji regularnej zamiast standardowych trzystu dziewięćdziesięciu. Taśma zatrzymała się po godzinie 9:34: począwszy od 09:35 czasu ET, przez 14 kolejnych minut nie odnotowano żadnych transakcji. Nigdzie nie zawarto żadnej transakcji. Luka w danych jest samym mechanizmem circuit breaker. Sesja zakończyła się na poziomie 274.4 USD, ze spadkiem o -7.7% USD, przy wolumenie 304.6 mln akcji.

Struktura sesji z przerwą w notowaniach

ZapytanieSPY w interwałach 30-minutowych: sesja z 9 marca 2020 r., wolumen z fazy closing cross
czas ETzamknięcie przedziałuminimum przedziałuwolumen (mln)
09:30279.93273.517.4
10:00280.72275.623.4
10:30278.61275.519.1
11:00281.03275.517.2
11:30282.69280.0619.1
12:00281.01280.9517.2
12:30279.71275.9513.4
13:00278.59278.2411.5
13:30275.84275.3419.4
14:00274.95274.0621.2
14:30276.59273.4525.9
15:00277.9275.5524.5
15:30274.4274.3750.2
Dokładny kod SQL dla każdej liczby
SELECT
    b.et_time                                                                   AS et_time,
    b.bucket_close                                                              AS bucket_close,
    b.bucket_low                                                                AS bucket_low,
    round((b.bar_shares + if(b.et_time = '15:30', p.print_shares, 0)) / 1e6, 1) AS shares_m
FROM
(
    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,
        toFloat64(sum(volume)) AS bar_shares
    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
) AS b
CROSS JOIN
(
    SELECT toFloat64(maxIf(size, has(conditions, 8))) AS print_shares
    FROM global_markets.stocks_trades
    WHERE ticker = 'SPY'
      AND sip_timestamp >= toDateTime('2020-03-09 20:00:00', 'UTC')
      AND sip_timestamp <  toDateTime('2020-03-09 20:15:00', 'UTC')
) AS p
ORDER BY et_time
Uruchom samodzielnie

Pierwszy interwał czasowy obejmuje krach, wstrzymanie notowań oraz ich wznowienie: minimum na poziomie 273.5 USD znajduje się zaledwie kilka centów od dziennego minimum wynoszącego 273.45 USD, a transakcja z godziny 14:44 czasu ET jedynie przetestowała poranny poziom. Po wznowieniu notowań kurs niemal nie uległ zmianie: każde półgodzinne zamknięcie mieściło się w przedziale kilku dolarów od ceny otwarcia, a główny spadek wartości nastąpił w pierwszych minutach sesji. Wolumen potwierdził ten scenariusz w odwrotny sposób; ostatnie pół godziny z obrotem na poziomie 50.2 miliona akcji było najbardziej aktywnym interwałem dnia ze względu na przepływy związane z zamknięciem sesji. Mechanizmy typu circuit breaker zostały zaprojektowane właśnie w celu wywołania takiej struktury: zatrzymania gwałtownej przeceny, wymuszenia aukcji otwarcia i powrotu do ciągłego systemu notowań po skorygowaniu wyceny. Zegar rynku ma obecnie ten mechanizm trwale wbudowany w swoją strukturę.

Cztery przerwy w notowaniach w ciągu ośmiu sesji

9 marca był dopiero początkiem.

ZapytanieCztery sesje z uruchomieniem circuit-breaker w marcu 2020 r.: cena zamknięcia, zmiana i wolumen SPY
SesjaZamknięcie (USD)Zmiana (%)wolumen (mln)
2020-03-09274.4-7.7304.6
2020-03-12248.1-9.6389.3
2020-03-16239.41-11.6291.5
2020-03-18241.01-5.2324.7
Dokładny kod SQL dla każdej liczby
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
Uruchom samodzielnie

Mechanizmy zabezpieczające poziomu pierwszego (Level-1) zadziałały również 12 marca (zamknięcie -9.6%), 16 marca (zamknięcie -11.6% na poziomie 239.41 USD, co stanowiło największy jednodniowy spadek procentowy S&P 500 od 1987 roku) oraz 18 marca (wstrzymanie notowań w trakcie sesji, zamknięcie -5.2%). Odnotowano cztery ogólnorynkowe przerwy w ciągu ośmiu sesji giełdowych, po dwudziestu trzech latach bez ani jednego takiego zdarzenia. Należy zwrócić uwagę na to, co nie nastąpiło: każda przerwa dotyczyła poziomu pierwszego, czyli progu siedmiu procent. Progi trzynastu i dwudziestu procent nigdy nie zostały osiągnięte; nawet 16 marca kaskadowa wyprzedaż wyhamowała po wznowieniu notowań, a sesja zakończyła się powyżej granicy poziomu drugiego.

Kto ucierpiał najbardziej

Liczba indeksowa ukrywa rozproszenie wyników, które kryje się pod jej powierzchnią. Ta sama arytmetyka cen zamknięcia, zastosowana do grupy reprezentatywnych spółek o dużej kapitalizacji, pokazuje, gdzie faktycznie uderzył krach – zarówno w samym dniu 9 marca, jak i w całym okresie spadków od 19 lutego do 23 marca.

ZapytanieRuchy cenowe 9 marca oraz w trakcie całego krachu: rejsy, linie lotnicze, energetyka, banki, technologia, dobra podstawowe na tle SPY
tickerMar9 (%)Spadek (%)
CCL-19.9-72.3
UAL-10.4-66.9
XOM-12.2-47.9
JPM-13.7-42.6
SPY-7.7-34.2
AAPL-7.9-31
WMT-0.1-2.9
Dokładny kod SQL dla każdej liczby
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
Uruchom samodzielnie

Najmocniej przecenionym podmiotem w zestawieniu była spółka CCL (Carnival, operator wycieczkowców), która tylko 9 marca straciła -19.9%, a od szczytu do dołka zanotowała spadek o -72.3%. United Airlines straciły -66.9% w trakcie krachu; ExxonMobil -47.9%; JPMorgan -42.6%. Na ich tle wynik SPY na poziomie -34.2% wygląda niemal łagodnie, Apple spadło w tempie zbliżonym do rynku, tracąc -31%, natomiast Walmart – sprzedawca artykułów spożywczych i pierwszej potrzeby, działający mimo lockdownów – zakończył ten sam okres ze spadkiem wynoszącym zaledwie -2.9%. Sektory turystyczny i energetyczny zostały wycenione na nowo w obliczu zatrzymania gospodarki; spółki dóbr podstawowych niemal nie odczuły zmian.

Krótko o wojnie cenowej na rynku ropy

Powyższy spór energetyczny wymaga krótkiego wyjaśnienia, gdyż termin „wojna cenowa na rynku ropy” stanowi drugą część historii z dziewiątego marca. Rozmowy OPEC+ dotyczące wydobycia, prowadzone między Arabią Saudyjską a Rosją, zakończyły się fiaskiem w piątek, szóstego marca dwa tysiące dwudziestego roku. W weekend Arabia Saudyjska obniżyła oficjalne ceny sprzedaży i ogłosiła plany zwiększenia produkcji w warunkach, w których popyt na podróże już wygasał. Był to szok podażowy nałożony na szok popytowy. Poniedziałkowe otwarcie sesji na rynku akcji uwzględniło oba te czynniki jednocześnie, a skutki przedstawiono w powyższym panelu: akcje ExxonMobil spadły w tamten poniedziałek o -12.2%, podczas gdy SPY stracił -7.7%.

Ucieczka do bezpiecznych przystani i tydzień, w którym ten mechanizm zawiódł

Akcje stanowiły zaledwie połowę obrazu sytuacji. Drugą połowę tworzył rynek obligacji skarbowych, na którym klasyczna ucieczka do bezpiecznych przystani osiągnęła rekordowy poziom, a następnie, przez jeden niezwykły tydzień, zaczęła przebiegać w odwrotnym kierunku.

ZapytanieRentowność 10-letnich i 3-miesięcznych obligacji skarbowych w trakcie krachu: dzienne ceny zamknięcia
31 rows (showing 20)
DataRentowność 10-letnich obligacji skarbowych (%)Rentowność 3-miesięcznych obligacji skarbowych (%)
2020-02-181.551.58
2020-02-191.561.58
2020-02-201.521.58
2020-02-211.461.56
2020-02-241.381.53
2020-02-251.331.53
2020-02-261.331.53
2020-02-271.31.45
2020-02-281.131.27
2020-03-021.11.13
2020-03-031.020.95
2020-03-041.020.72
2020-03-050.920.62
2020-03-060.740.45
2020-03-090.540.33
2020-03-100.760.44
2020-03-110.820.42
2020-03-120.880.33
2020-03-130.940.28
2020-03-160.730.24
Dokładny kod SQL dla każdej liczby
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
Uruchom samodzielnie

Rentowność 10-letnich obligacji skarbowych wynosiła 1.56% w dniu szczytu notowań akcji, 19 lutego. Do 9 marca, czyli sesji, w której nastąpiło wstrzymanie handlu, zamknęła się ona na poziomie 0.54%, co stanowiło historyczne minimum. Inwestorzy godzili się na pół procent rocznie przez dekadę w zamian za bezpieczeństwo. Następnie schemat uległ odwróceniu: do 18 marca rentowność 10-letnich obligacji wzrosła do 1.18%, podczas gdy akcje nadal traciły na wartości. Był to okres „pogoni za gotówką” – tydzień, w którym fundusze, przedsiębiorstwa oraz zagraniczni posiadacze aktywów wyprzedawali wszystko, co było płynne, w tym obligacje skarbowe, aby pozyskać USD. W tym samym czasie 3-miesięczne bony skarbowe zamknęły się tego dnia na poziomie 0.02%, co oznacza, że ekwiwalenty gotówki zostały „zakotwiczone” w okolicach zera. Gdy najbezpieczniejsze i najbardziej ryzykowne aktywa tracą na wartości jednocześnie, przedmiotem zakupu staje się sama płynność. Krzywa rentowności na trwałe zapisała ten epizod w swojej historii.

Co pokazuje rynek opcji

Notowane opcje na SPY, będące głównym instrumentem zabezpieczającym na rynku, odnotowały ślady paniki, a moment ich wystąpienia jest szczególnie interesujący.

ZapytanieOpcje na SPY: wolumen obrotu opcjami typu put i call, 2–13 marca 2020 r. (w milionach kontraktów)
SesjaKontrakty put (mln)Kontrakty call (mln)Wskaźnik put/call
2020-03-023.742.541.47
2020-03-033.142.241.4
2020-03-043.062.271.35
2020-03-053.141.821.73
2020-03-064.642.381.95
2020-03-094.352.381.83
2020-03-103.612.41.5
2020-03-113.752.441.54
2020-03-124.533.431.32
2020-03-134.633.271.41
Dokładny kod SQL dla każdej liczby
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
Uruchom samodzielnie

Wskaźnik wolumenu put/call osiągnął szczyt na poziomie 1.95, co oznacza, że w piątek 6 marca, jeszcze przed sesją z przerwaniem notowań, na każdą opcję call przypadały niemal dwie opcje put. W samym dniu 9 marca wolumen opcji put wyniósł 4.35 mln, podczas gdy wolumen opcji call osiągnął 2.38 mln, co daje wskaźnik na poziomie 1.83. Do 12 marca, czyli sesji -9.6%, wskaźnik ten spadł do 1.32, ponieważ wraz z opcjami put wzrósł również wolumen opcji call. Największa przewaga opcji put wystąpiła na początku spadków, a nie w ich końcowej fazie: zabezpieczenie kupowano wcześnie, natomiast w późniejszych dniach, charakteryzujących się większymi spadkami, obrót na rynku opcji był bardziej dwustronny.

Jak w praktyce działa ogólnorynkowe wstrzymanie notowań

Mechanizmy te uruchamiane są na tyle rzadko, że często zapomina się o ich działaniu. Ogólnorynkowe bezpieczniki (market-wide breakers) bazują na spadku indeksu S&P 500 względem poprzedniego zamknięcia. Spadek o siedem procent (poziom pierwszy) oraz trzynaście procent (poziom drugi) powoduje piętnastominutowe wstrzymanie notowań, o ile nastąpi przed godziną piętnastą dwadzieścia pięć czasu wschodnioamerykańskiego (ET). Spadek o dwadzieścia procent (poziom trzeci) kończy sesję całkowicie. W trakcie wstrzymania na żadnej giełdzie nie są zawierane transakcje. Zlecenia trafiają do kolejki w oczekiwaniu na aukcję wznowieniową, która koncentruje skumulowany popyt i podaż w jednej cenie, podobnie jak ma to miejsce podczas aukcji otwarcia każdego ranka. Konstrukcja ta wywodzi się z okresu po flash crash z 2010 roku, który wykazał, że poprzednie progi były zbyt wysokie, aby zadziałać nawet w warunkach gwałtownej kaskadowej wyprzedaży.

Marzec 2020 roku był pierwszym i jak dotąd jedynym sprawdzianem tego systemu w warunkach rzeczywistych. Wnioski przedstawiono w powyższych panelach: cztery wstrzymania pierwszego poziomu, z których każde zakończyło się uporządkowanym wznowieniem notowań. Nigdy nie osiągnięto poziomu drugiego ani trzeciego, a rynek funkcjonował poprawnie podczas każdej z 23 sesji najszybszego dużego obsunięcia kapitału w historii indeksu. Zasady pozostały niezmienione: te same progi siedmiu, trzynastu i dwudziestu procent, odnoszące się do S&P 500, obowiązują do dziś. System ugiął się, ale infrastruktura wytrzymała.

FAQ dotyczące krachu covidowego

Co wywołało mechanizm "circuit breaker" 9 marca 2020 roku?

Spadek indeksu S&P 500 o siedem procent względem poprzedniego zamknięcia, co stanowi pierwszy poziom (Level-1) progu wstrzymania obrotu, w ciągu pierwszych minut sesji. Handel na całym rynku został wstrzymany na piętnaście minut, a następnie wznowiony w drodze aukcji. Wstrzymanie jest widoczne w minutowym zapisie transakcji na tej stronie jako 14 kolejne brakujące słupki, począwszy od godziny 09:35 czasu wschodniego (ET).

O ile spadł rynek akcji podczas krachu covidowego?

Mierząc na podstawie cen zamknięcia ETF-u SPY, -34.2%, spadek wyniósł od 338.31 USD w dniu 19 lutego 2020 roku do 222.51 USD w dniu 23 marca 2020 roku, w ciągu 23 sesji giełdowych.

Ile razy uruchomiono mechanizm "circuit breaker" w marcu 2020 roku?

Cztery razy wstrzymano handel na całym rynku na pierwszym poziomie (Level-1): 9, 12, 16 i 18 marca. Były to pierwsze takie przypadki od października 1997 roku.

Czy w 2020 roku doszło do uruchomienia mechanizmów Level 2 lub Level 3?

Nie. Wszystkie cztery wstrzymania w 2020 roku dotyczyły poziomu pierwszego (siedem procent). Żaden mechanizm wstrzymania handlu na poziomie drugim (trzynaście procent) ani trzecim (dwadzieścia procent) nie został nigdy uruchomiony w obecnym systemie, nawet 16 marca, podczas najgorszej sesji krachu, kiedy spadek wyniósł -11.6%.

Czy rynek w pełni odrobił straty po krachu covidowym?

Tak. SPY zamknął się powyżej szczytu z 19 lutego 2020 roku w dniu 2020-08-18, czyli 103 sesji giełdowych po dołku z 23 marca. Było to jedno z najszybszych pełnych wyjść z bessy o takiej skali.


Każdy z powyższych paneli stanowi wynik zapytania do historycznej bazy danych; należy rozwinąć kod SQL, aby zobaczyć szczegóły każdego pomiaru. Chcesz poczuć emocje tamtego dnia zamiast o nich czytać? Jest to jeden ze scenariuszy dostępnych w symulatorze handlu Strasmore Labs.

#market history#covid crash#circuit breakers#spy