Strasmore Research
深度研究 Matt Connor作者: Matt Connor · 更新于 2026-07-23

2020年新冠疫情股市崩盘回顾

回顾 SPY 暴跌历程:解析 8 天内触发 4 次熔断的极端行情,包含 3 月 9 日缺失的分钟级数据。

2020年新冠疫情引发的股市崩盘,使 S&P 500 指数从 2 月 19 日的历史高点,在 23 个交易日内经历了 -34.2% 的峰值跌幅。期间市场触发了四次全市场熔断机制,这是自 1997 年以来的首次。本页面通过历史数据重现了整个过程:包括崩盘走势图、3 月 9 日熔断期间的逐分钟记录(包含数据缺失的分钟,这些缺失部分是本页最重要的凭证)、跌幅最大的个股,以及国债和期权市场的同步表现。所有数据均可通过存储查询获取;您可以展开任何面板以查看 SQL 语句。

一行数据看清全过程

在那个著名的单日暴跌之前,市场走势如下。通过对 SPY 日内常规交易收盘价的查询,可以锁定峰值、谷值、跌幅速度及回升情况。同时,我们也对 2008 年熊市进行了相同维度的测量,以便进行对比。

查询COVID崩盘:从高峰到谷底再到复苏 — SPY日收盘价,单行
每个数字背后的完整 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 在 2020-02-19 达到峰值收盘价 $338.31。随后在 2020-03-23 跌至谷值收盘价 $222.51,较峰值下跌了 -34.2%。这场熊市仅用了 23 个交易日(即 33 个日历日)便完成。常被引用的“史上最快 30% 回撤”在数据中得到了证实:SPY 在交易仅 22 个交易日后,收盘价便首次跌破峰值 30%。若以 2007 年 10 月的峰值收盘价为基准进行相同测量,2008 年的熊市需要 250 个交易日才下跌了 30%。2008 年耗时约一年的跌幅,在 2020 年仅用约一个月便完成了。

以下是此次崩盘的时间线,所有数据均源自本页图表:

  • 2020 年 2 月 19 日 — SPY 创下历史收盘高点,$338.31
  • 3 月 9 日 — 自 1997 年以来首次触发全市场熔断;SPY 收盘下跌 -7.7%。详细分钟级数据见下文。
  • 3 月 12 日、16 日和 18 日 — 三次一级熔断。其中 3 月 16 日收跌 -11.6%,是此次崩盘中表现最差的单日。
  • 3 月 23 日 — 触及收盘最低点:$222.51,较峰值下跌 -34.2%。
  • 3 月 24 日 — 市场反转。3 月 24 日的刺激政策反弹带动了行情。
  • 2020-08-18 — SPY 在触底 103 个交易日后,收盘价再次突破 2 月份的峰值。

2020年3月9日:触发熔断的交易日

全市场熔断机制以 S&P 500 为基准,因此本面板通过 SPY(S&P 500 ETF)而非其他代理指数来读取停盘数据。上周末,疫情引发的价格重估与石油供应冲击(详见下文)发生碰撞,导致市场开盘时局势混乱。

查询2020年3月9日 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-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,较周五收盘价 $297.42 下跌了 -7.4% —— 在开盘后的最初几分钟内,S&P 500 的跌幅便触及了 7% 的一级熔断阈值。第二是正面数据:376 个常规交易时段的分钟线,而非通常的 390 个。行情在东部时间上午 9:34 停止:从 09:35 开始,14 个连续分钟内完全没有行情数据。全市场没有任何成交。数据中的这一空白即代表了熔断。该交易日收于 $274.4,跌幅为 -7.7,成交量为 304.6 百万股。

停牌交易的走势特征

查询SPY每半小时走势 — 2020年3月9日常规交易时段
每个数字背后的完整 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 的午后成交价仅是再次测试了早盘水平。复牌后价格几乎没有波动:每半小时的收盘价均在复牌价上下几美元范围内,全天的跌幅在开盘后的最初几分钟内便已完成。成交量从反向印证了这一情况——在收盘流涌入时,最后半小时的成交量达到 46.7 百万股,是全天最活跃的时段。熔断机制的设计初衷正是如此:阻止价格瀑布式下跌,强制进行复牌集合竞价,并让连续交易在重新定价的水平上恢复。市场机制 现已永久嵌入了这一流程。

八个交易日内四次熔断

3月9日仅是开始。

查询2020年3月四次熔断交易日 — SPY收盘价、涨跌幅、成交量
每个数字背后的完整 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 熔断机制在3月12日(收盘下跌 -9.6%)、3月16日(收盘下跌 -11.6%,跌至 $239.41 —— 这是 S&P 指数自1987年以来最大的单日跌幅)、以及3月18日(盘中熔断,收盘下跌 -5.2%)均被触发。在连续23年未发生熔断后,市场在8个交易日内经历了四次全市场熔断。请注意:所有熔断均属于 Level-1(7% 档位)。市场从未触及 13% 或 20% 的熔断档位 —— 即便是3月16日,在触发熔断后跌势有所放缓,收盘价仍维持在 Level-2 限制线以内。

Who fell hardest

An index number hides the dispersion underneath it. The same daily-close arithmetic, run across a handful of representative large-caps, shows where the crash actually landed — both on March 9 itself and across the full February 19 to March 23 slide.

查询3月9日及崩盘期间走势 — 邮轮、航空、能源、银行、科技、必需消费品 vs SPY
每个数字背后的完整 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

The hardest-hit name in the panel, CCL (Carnival, the cruise operator), lost -19.9% on March 9 alone and -72.3% peak to trough. United Airlines gave up -66.9% over the crash; ExxonMobil -47.9%; JPMorgan -42.6%. Against them, SPY's -34.2% looks almost gentle, Apple fell roughly with the market at -31%, and Walmart — groceries, essentials, open through lockdowns — finished the same window at just -2.9%. Travel and energy repriced for a stopped world; staples barely moved.

油价战简述

上述能源争端值得单独说明,因为“油价战”构成了 3 月 9 日报道的另一半内容。2020 年 3 月 6 日(周五),沙特阿拉伯与俄罗斯之间的 OPEC+ 增产谈判未能达成协议。周末期间,沙特下调了官方售价,并宣布在旅游需求萎缩的背景下提高产量——这在需求冲击的基础上叠加了供应冲击。周一股市开盘同时受到这两方面影响,结果如上表所示:ExxonMobil 在该周一下跌了 -12.2%,而 SPY 下跌了 -7.7%。

避险情绪——以及打破常规的一周

股市的表现仅是市场的一半缩影。另一半在于国债市场:传统的避险情绪曾一度推向历史新高,但在一个非同寻常的周内,趋势发生了逆转。

查询崩盘期间10年期及3个月期国债收益率,日收盘价
每个数字背后的完整 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

在2月19日股市达到峰值时,10年期国债收益率为 1.56%。到3月9日(交易暂停日),收益率收于 0.54% 的历史低点;为了规避风险,投资者愿意接受十年期年化0.5%的收益率。随后,这一模式发生反转:截至3月18日,在股市持续下跌的同时,10年期收益率反而上升1.18%。这便是“现金狂潮”:基金、公司及外国持有者抛售包括国债在内的各类流动资产,以筹集美元。与此同时,3个月期国债当日收于 0.02%,现金等价物收益率几乎降至零。当最安全的资产与风险最高的资产同步下跌时,市场追求的本质是流动性本身。收益率曲线将这一事件永久载入史册。

期权交易数据分析

SPY 的上市期权是市场主要的对冲场所。其交易数据反映了市场恐慌情绪,且其发生的时间点值得关注。

查询SPY期权:看跌 vs 看涨成交量,2020年3月2–13日(百万份合约)
每个数字背后的完整 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

3 月 6 日(停牌交易前),看跌/看涨期权成交量比率达到峰值 1.95 —— 即每 1 份看涨期权对应近 2 份看跌期权。3 月 9 日当天,看跌期权成交量为 4.35 百万份,看涨期权为 2.38 百万份,比率为 1.83。到 3 月 12 日(-9.6% 交易日),随着看涨期权成交量同步回升,该比率降至 1.32。期权偏向性最严重的阶段出现在行情下跌的初期,而非底部:投资者在早期便购买了避险工具,而随后的剧烈下跌日,期权交易则呈现出更均衡的双向特征。

全市场熔断机制的运作原理

由于熔断机制触发频率较低,其运作原理常被遗忘:全市场熔断机制基于 S&P 500 指数较前一交易日收盘价的跌幅。若在东部时间下午 3:25 前触及跌幅 7%(第一级)或 13%(第二级),将触发 15 分钟的交易暂停;若跌幅达到 20%(第三级),则直接结束当日交易。暂停期间,所有交易所均停止交易;订单将进入重开拍卖队列,通过集中买卖意向来确定单一价格,其方式与每日早间的 开盘拍卖 相同。该设计源于 2010 年闪崩事件 之后,当时暴露出的旧版阈值过低,即使在真实的连锁反应中也无法触发。

2020 年 3 月是该设计首次——也是迄今为止唯一一次——实战测试,结论如上图所示:共触发了四次第一级熔断,每次熔断后均有序重开;未触发第二级或第三级熔断;在指数历史上最快速的大幅回撤期间,每一个 23 交易日市场均正常运行。此后,规则得以保留:以 S&P 500 为基准的 7/13/20 阈值沿用至今。系统虽经受压力,但机制运行稳健。

COVID 崩盘常见问题解答

2020年3月9日触发熔断的原因是什么?

S&P 500 指数在开盘后的几分钟内较前一交易日下跌了 7%,触及了第一级(Level-1)全市场熔断阈值。全市场交易暂停 15 分钟,随后通过集合竞价重新开盘。在本页的分时数据中,从东部时间 09:35 开始,会出现 14 个连续缺失的 K 线柱。

COVID 崩盘期间股市跌幅是多少?

以 SPY 的每日收盘价计算,在 23 个交易日内,从 2020 年 2 月 19 日的 $338.31 下跌至 2020 年 3 月 23 日的 $222.51,跌幅为 -34.2%。

2020 年 3 月共触发了多少次熔断?

共触发了四次全市场第一级(Level-1)熔断:分别在 3 月 9 日、12 日、16 日和 18 日。这是自 1997 年 10 月以来的首次。

2020 年是否触发过第二级或第三级熔断?

没有。2020 年的所有四次熔断均为第一级(7%)熔断。在现行机制下,从未触发过第二级(13%)或第三级(20%)全市场熔断——即使是在跌幅达 -11.6% 的崩盘最剧烈交易日(3 月 16 日)也是如此。

市场是否从 COVID 崩盘中完全恢复?

是的。SPY 在 2020-08-18 突破了 2020 年 2 月 19 日的高点,即在 3 月 23 日低点之后的 103 个交易日内实现。这是从如此深度的熊市中实现完全恢复最快的案例之一。


以上每个面板都是针对历史行情数据的存储版本化查询——您可以展开 SQL 代码查看各项测量指标。想亲身体验这一天,而不仅仅是阅读文字吗?您可以在 Strasmore Labs 交易模拟器 中运行该场景。

#market history#covid crash#circuit breakers#spy