2009年3月9日:金融危機底部
2009年3月9日那個安靜的星期一,正是金融危機的谷底。近看世代級低點,盤勢毫無戲劇性反轉的跡象。
2009年3月9日是現代市場史上最重要的日期之一:金融危機的收盤低點——較2007年10月高點下跌-56.5%——也是隨後延續超過十年多頭市場的起點。歷史記載引用了那個週一的指數水準:標普500收在676.53點,道瓊收在6,547點。以下數據使用標普500 ETF——SPY,本資料庫儲存其自2003年以來的逐分鐘交易紀錄。而這份紀錄保存了一個令人不安的事實:當天的盤勢完全沒有預示這一切。 沒有投降式的爆量高潮,沒有戲劇性的反轉——只是一個安靜、緩步走低的紅色星期一,恰好成為最後一個下跌日。每一項數字都是預存查詢的結果;展開任一區塊即可查看SQL。
通往谷底之路
這場危機是分階段到來的,而這些日期對於理解以下所有內容至關重要。貝爾斯登於2008年3月被出售給摩根大通。雷曼兄弟在2008年9月15日星期一申請破產——這裡有專門頁面記錄當日盤勢。國會在10月3日通過了問題資產紓困計畫,即7000億美元的銀行救助基金。美國國際集團的政府紓困方案被擴大了兩次。花旗集團在11月接受了第二次聯邦擔保。冬季的反彈行情消退,到2009年2月下旬,各大指數已跌破11月的低點並持續下挫。下面這一行數據,概括了那長達十七個月的走勢:
每個數據背後的精確 SQL 語法
WITH daily AS (
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('2007-01-02 00:00:00') AND window_start < toDateTime('2013-07-01 00:00:00')
GROUP BY et_date
),
(SELECT max(close_usd) FROM daily WHERE et_date < toDate('2008-01-01')) AS peak_close_usd
SELECT
round(peak_close_usd, 2) AS peak_close,
toString(argMaxIf(et_date, (close_usd, et_date), et_date < toDate('2008-01-01'))) AS peak_date,
round(minIf(close_usd, et_date BETWEEN toDate('2008-07-01') AND toDate('2009-06-30')), 2) AS trough_close,
toString(argMinIf(et_date, (close_usd, et_date), et_date BETWEEN toDate('2008-07-01') AND toDate('2009-06-30'))) AS trough_date,
round((minIf(close_usd, et_date BETWEEN toDate('2008-07-01') AND toDate('2009-06-30')) / peak_close_usd - 1) * 100, 1) AS decline_pct,
toString(minIf(et_date, et_date > toDate('2009-03-09') AND close_usd >= peak_close_usd)) AS recovered_date
FROM daily從 2007-10-09 創下的 $156.41 收盤高點,SPY 跌至 2009-03-09 的 $68.07 ——跌幅達 -56.5%,是自1930年代以來最深的一次。同一行數據也包含了長期投資者接下來會追問的數字:重返起點所需的時間。SPY 直到 2013-03-14 才再次收於2007年高點之上——距離低點過了四年,距離高點則過了五年半。這兩個時間段的計算依據,都在下方各自列出。
一日摘要,單行呈現
每個數據背後的精確 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('2009-03-06 00:00:00') AND window_start < toDateTime('2009-03-09 04:00:00')
) AS prior_rth_close,
(
SELECT round(avg(day_shares) / 1e6, 1)
FROM (
SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d, toFloat64(sum(volume)) AS day_shares
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
AND window_start >= toDateTime('2008-12-01 00:00:00') AND window_start < toDateTime('2009-03-09 04:00:00')
GROUP BY d
ORDER BY d DESC
LIMIT 20
)
) AS avg20_shares,
(
SELECT round(avg(day_shares) / 1e6, 1)
FROM (
SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d, toFloat64(sum(volume)) AS day_shares
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
AND window_start >= toDateTime('2008-12-01 00:00:00') AND window_start < toDateTime('2009-03-09 04:00:00')
GROUP BY d
ORDER BY d DESC
LIMIT 60
)
) AS avg60_shares
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(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,
formatDateTime(toTimeZone(argMaxIf(window_start, (toFloat64(high), -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 high_et,
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,
avg20_shares AS avg20_shares_m,
avg60_shares AS avg60_shares_m,
round((toFloat64(sum(volume)) / 1e6 / avg20_shares - 1) * 100, 0) AS vol_vs_20d_pct,
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('2009-03-09 04:00:00') AND window_start < toDateTime('2009-03-09 23:59:00')SPY 開盤價 $67.95 — 較週五收盤 $68.84 出現 -1.3% 的跳空缺口 — 在美東時間 10:13 觸及 $70,尾盤(美東時間 15:17)滑落至 $67.73 的低點,終場收在 $68.07 — 當日 -1.1%。全日波動區間約兩美元。這個世代最重要的收盤價,就在毫無戲劇性波動的一分鐘內悄然誕生。
成交量回答了單純數字無法解釋的問題:357.4 百萬股的 SPY 成交量,究竟算熱絡還是冷清?以 2009 年 3 月來看,算是冷清。此前二十個交易日的 SPY 日均量為 406.3 百萬股 — 相對於該均值,底部成交量僅為 -12% — 而此前六十個交易日的日均量則為 337.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('2009-03-09 04:00:00') AND window_start < toDateTime('2009-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這半小時的路徑修正了一個多數複述時會被抹平的細節:3 月 9 日並非單向滑落。跳空開低後,SPY 在上午中段反彈——10:00 ET 時段收在 $69.49,略低於 10:13 所創下的 $70 日內高點——隨後整個下午回吐漲幅,緩步下滑至 15:17 的 $67.73 低點,並在收盤前小幅彈升。反彈、回落、小彈:一個極其平凡的走勢。沒有瀑布式急殺,沒有恐慌量能訊號,沒有 V 型反轉。將它與 雷曼週一 收在低點的急迫感,或 閃電崩盤 的真空區相比:這完全是第三種型態,一種力竭的盤勢。那年冬天的數個百分點跌幅,都發生在前幾週。底部本身,就是賣方單純彈盡援絕的那一天。
什麼推動了盤勢轉向
週一的數據完全無法解釋週二的走勢——轉折點是跟著新聞週期來的,不是盤面數據。週二開盤前,花旗集團執行長潘偉迪的一份內部備忘錄外洩給媒體;備忘錄指出,該行在2009年1月與2月實現獲利,是自2007年以來表現最佳的兩個月。花旗——這場危機的震央,週一收盤價為$1.05——已有數月未曾出現過任何來自一手來源的利多消息。以下是低點過後五個交易日,盤面所記錄的走勢:
每個數據背後的精確 SQL 語法
WITH daily AS (
SELECT
toDate(toTimeZone(window_start, 'America/New_York')) AS et_date,
argMaxIf(toFloat64(close), window_start, ticker = 'SPY' AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) AS spy_close_raw,
round(argMaxIf(toFloat64(close), window_start, ticker = 'C' AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959), 2) AS citi_close,
round(toFloat64(sumIf(volume, ticker = 'SPY')) / 1e6, 1) AS spy_shares_m
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('SPY', 'C')
AND window_start >= toDateTime('2009-03-06 04:00:00') AND window_start < toDateTime('2009-03-14 00:00:00')
GROUP BY et_date
)
SELECT
toString(d.et_date) AS session,
round(d.spy_close_raw, 2) AS spy_close,
round((d.spy_close_raw / d.prev_close - 1) * 100, 1) AS spy_change_pct,
d.spy_shares_m,
d.citi_close,
t.ten_year_pct
FROM (
SELECT *, lagInFrame(spy_close_raw) OVER (ORDER BY et_date ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev_close
FROM daily
) AS d
LEFT JOIN (
SELECT date, round(toFloat64(yield_10_year), 2) AS ten_year_pct
FROM global_markets.treasury_yields
WHERE date BETWEEN '2009-03-09' AND '2009-03-13'
) AS t ON d.et_date = t.date
WHERE d.et_date >= toDate('2009-03-09')
ORDER BY d.et_date3月10日開高後便一路維持漲勢:SPY收在$72.21,上漲6.1%,成交量401.3萬股——比觸底當天還要大量。花旗收在$1.44。到了週五,SPY來到$76.09,花旗則為$1.78。10年期公債殖利率在同一個週二從2.89%升至2.99%——資金在股市反彈的同時撤出最安全的資產,趨避風險的交易模式逆轉。
必須誠實說明的但書:那個冬天已經出現過好幾次幅度達數個百分點的反彈,最終都失敗了,3月10日當天沒有任何跡象能證明這次有所不同。潘偉迪的備忘錄是歷史學家用來標記轉折點的線索;而盤面所能呈現的——也確實如上所示——是時間點上的巧合。
低點守住了嗎?
底部之所以是底部,是因為市場再也沒有回頭。這張表逐週追蹤 SPY 直到 2009 年 6 月底的走勢——每週最低成交價與最終收盤價,最後一欄則是滾動最低價:
每個數據背後的精確 SQL 語法
WITH daily AS (
SELECT
toDate(toTimeZone(window_start, 'America/New_York')) AS et_date,
minIf(toFloat64(low), (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) AS day_low,
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 day_close
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
AND window_start >= toDateTime('2009-03-10 04:00:00') AND window_start < toDateTime('2009-06-27 00:00:00')
GROUP BY et_date
)
SELECT
week_of,
week_low,
week_close,
round(min(week_low) OVER (), 2) AS lowest_low_after_mar9
FROM (
SELECT
toString(toMonday(et_date)) AS week_of,
round(min(day_low), 2) AS week_low,
round(argMax(day_close, et_date), 2) AS week_close
FROM daily
GROUP BY week_of
)
ORDER BY week_of3 月 9 日之後的十六週內,SPY 的最低成交價是 $69.37——而這個價位出現在脫離低點後的第一週(2009-03-09)。SPY 再也沒有跌破 3 月 9 日的收盤價 $68.07 ,更別提 $67.73 的盤中低點了。沒有重新測試,沒有第二次機會,沒有拉回到原先的水準:到了 2009-05-04 那一週,SPY 收在 $93.04,九週內就比底部高出三分之一。等待確認是有代價的,而這張表精確地說明了這一點。
誰帶領市場從低點回升
處於風暴中心的銀行,也正是反彈的核心。從接近2010年3月9日的底部起算一年:
每個數據背後的精確 SQL 語法
SELECT
ticker,
round(b_close, 2) AS close_mar9_2009,
round(y_close, 2) AS close_mar9_2010,
round((y_close / b_close - 1) * 100, 0) AS pct_1yr,
fin AS financial
FROM (
SELECT
ticker,
argMaxIf(toFloat64(close), window_start, toDate(toTimeZone(window_start, 'America/New_York')) = toDate('2009-03-09') AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) AS b_close,
argMaxIf(toFloat64(close), window_start, toDate(toTimeZone(window_start, 'America/New_York')) = toDate('2010-03-09') AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) AS y_close,
max(ticker IN ('C', 'BAC', 'WFC', 'JPM', 'GS', 'XLF')) AS fin
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('C', 'BAC', 'WFC', 'JPM', 'GS', 'XLF', 'SPY', 'AAPL', 'XOM')
AND ((window_start >= toDateTime('2009-03-09 04:00:00') AND window_start < toDateTime('2009-03-10 04:00:00'))
OR (window_start >= toDateTime('2010-03-09 04:00:00') AND window_start < toDateTime('2010-03-10 04:00:00')))
GROUP BY ticker
)
ORDER BY pct_1yr DESC榜單前列:BAC 上漲 349%,C 上漲 265%(從每股 $1.05 起算),WFC 上漲 190%——這些受創最深的大型金融股,從反映最悲觀預期的價格水準翻了三倍、四倍。榜單上不全是銀行——AAPL 同期回報率為 168%——但這組數據明確顯示,表現最佳的單一個股是金融股。與此同時,大盤(SPY)上漲了 68%,而 XOM,這家在下跌過程中表現最為抗跌的防禦型巨頭,僅上漲了 3%。反彈幾乎完全逆轉了跌勢中的領漲排行。
與其他底部比較
此處的逐筆資料始於 2003 年 9 月,因此 2002 年 10 月的網路泡沫低點不在接收範圍內。與此後最深的三個收盤低點相比,2009 年 3 月的情況如下:
每個數據背後的精確 SQL 語法
WITH daily AS (
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('2009-03-09 04:00:00') AND window_start < toDateTime('2010-03-17 00:00:00'))
OR (window_start >= toDateTime('2011-10-03 04:00:00') AND window_start < toDateTime('2012-10-10 00:00:00'))
OR (window_start >= toDateTime('2018-12-24 04:00:00') AND window_start < toDateTime('2019-12-31 00:00:00'))
OR (window_start >= toDateTime('2020-03-23 04:00:00') AND window_start < toDateTime('2021-03-30 00:00:00')))
GROUP BY et_date
)
SELECT
bottom_session,
round(argMin(close_usd, et_date), 2) AS bottom_close,
round((argMinIf(close_usd, et_date, et_date >= toDate(bottom_session) + 91) / argMin(close_usd, et_date) - 1) * 100, 1) AS plus_3mo_pct,
round((argMinIf(close_usd, et_date, et_date >= toDate(bottom_session) + 365) / argMin(close_usd, et_date) - 1) * 100, 1) AS plus_1yr_pct
FROM (
SELECT
multiIf(et_date >= toDate('2020-03-23'), '2020-03-23',
et_date >= toDate('2018-12-24'), '2018-12-24',
et_date >= toDate('2011-10-03'), '2011-10-03',
'2009-03-09') AS bottom_session,
et_date,
close_usd
FROM daily
)
GROUP BY bottom_session
ORDER BY bottom_session自 2009 年低點起,SPY 在三個月內上漲了 38.5%,一年內上漲了 68.1%——這是當時多數在世投資人所見過最強勁的十二個月,始於危機中最平淡無奇的一天。唯有 2020 年 3 月新冠疫情低點 可與之相提並論,其第一年漲幅為 +75.1%——該轉折點的 2020 年刺激措施驅動的反彈 結構另有專頁說明。2011 年與 2018 年的修正低點——在當時均引發了真正的恐慌——其第一年回報率分別為 31.4% 與 37.1%。這四次底部的共同模式是:跌得越深,第一波反彈就越陡峭,而第一波反彈始終是整個復甦過程中最陡峭的一段。
為何底部只在事後才看得見
誠實的機制:底部是由事後「沒有」發生的事來定義的——沒有再出現更低的低點——這在當下本質上就無法得知。歷來所有被提出的量化「底部訊號」,在 2008 年底一路下跌的過程中都反覆觸發過;而 3 月 9 日當天本身,在所有這些訊號上的表現都平淡無奇——走勢型態普通、成交量低於平均、催化消息直到隔天早上才出現。任何聲稱自己的指標精準命中這一天的人,描述的其實是倖存者偏差,而該指標先前同樣喊過的許多次「底部」,就是最好的證明。
這一天真正教會我們的是:要針對結果的「區間」來配置,而不是針對某個「點位」。從 2009 年 3 月開始表現優異的投資人,絕大多數都是在整個慘澹的冬天按紀律持續買進的人——這正是報酬衡量慣例默默預設的做法——而不是那些抓到像素級完美低點的人。大盤在這項紀律中的角色是校準,而非預言:知道「平常」是什麼樣子,才能避免把一個平靜的星期一,誤認為是那場其實才剛結束的跌勢中,又一個繼續下跌的日子。
2009年3月市場底部常見問答
2008–2009年崩盤的精確底部在哪裡?
收盤低點出現在2009年3月9日星期一:SPY收在$68.07,標普500指數則落在廣為引用的676.53點。盤中著名的「666」指數低點則在前一個交易日,也就是3月6日星期五出現。
股市從2007年到2009年下跌了多少?
SPY以收盤價計算下跌了-56.5%——從2007-10-09的$156.41跌至2009-03-09的$68.07——這是自1930年代以來最嚴重的一次美國股市回檔。
2009年3月10日發生了什麼事?
觸底後的第一個交易日:在前一晚花旗集團內部備忘錄外洩,表明該銀行在一月和二月實現盈利後,SPY上漲了6.1%。花旗集團自身收在$1.44,高於低點時的$1.05。
市場從2009年低點復甦的速度有多快?
第一年的表現堪稱歷史性:SPY從底部收盤價上漲了68.1%。要完全收復整個危機期間的跌幅則耗時更久——首次收盤價回到2007年10月高點之上發生在2013-03-14。
底部形成前有任何預警信號嗎?
3月9日的盤面與前後幾週的交易日並無二致——當天交易平靜,成交量低於其20日均值。這個底部是事後回顧才確立的,因為它從未被跌破:此後十六週的最低成交價甚至一直高於3月9日的收盤價。
以上每個面板都是對歷史交易記錄的儲存、版本化查詢——展開SQL即可查看每項衡量數據。想親身體驗這一天,而不只是閱讀嗎?這是Strasmore Labs交易模擬器中可播放的情境之一。