March 9 2009 bottom tape quiet Monday wey end bear
March 9, 2009 na di exact bottom of di crisis. Di tape show quiet Monday wey no get drama. See how generational lows dey look up close.
March 9, 2009 na one of di most important dates for modern market history: e be di closing low of di financial crisis — -56.5% below di October 2007 peak — and di first day of bull market wey run for more dan ten years. Di history books dey quote di index levels from dat Monday: 676.53 for S&P 500, 6,547 for Dow. Di receipts wey dey below dey use SPY, di S&P 500 ETF, wey im minute-by-minute tape dis database dey store since 2003. And dis na di uncomfortable truth wey dat tape keep: nothing about di session announce am. No capitulation crescendo, no reversal fireworks — na quiet, grinding red Monday wey just happen to be di last one. Every number na stored query; expand any panel for di SQL.
Di road go down
Di wahala come small-small, and di dates matter to understand everitin wey dey follow. Dem sell Bear Stearns give JPMorgan for March 2008. Lehman Brothers file for bankruptcy on Monday, September 15, 2008 — one session wey get im own page for here. Congress pass TARP, di $700 billion bank-rescue fund, on October 3. Dem expand AIG government rescue two times. Citigroup collect im second federal backstop for November. One winter rally fade, and by late February 2009 di averages don break dia November lows and continue to dey fall. One row squeeze dat seventeen-month run:
The exact SQL behind every number
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 dailyFrom one closing peak of $156.41 on 2007-10-09, SPY fall reach $68.07 on 2009-03-09 — na -56.5% decline, di deepest since di 1930s. Di same row carry di number wey long-term investors dey ask about next: di round trip. SPY no close above im 2007 peak again until 2013-03-14 — four years after di low, five and a half after di top. Both halves of dat arithmetic get dia own receipts for down.
Di day, for one row
The exact SQL behind every number
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 open for $67.95 — na -1.3% gap down from Friday own $68.84 close — e touch $70 by 10:13 ET, e drop go $67.73 low late for di day (15:17 ET), and e close for $68.07 — -1.1% for di day. Di whole session range na about two dollars. Di most important closing print for one generation show face without any single dramatic minute.
Volume dey answer one question wey di raw number alone no fit answer: di 357.4 million shares, e loud or e quiet? For March 2009, e quiet. Di last twenty sessions don dey average 406.3 million SPY shares per day — di bottom print -12% relative to dat average — and di last sixty dey average 337.9 million. Capitulation talk dey yarn say generational lows dey show for climactic, record-setting turnover. Di most famous bottom of di modern era trade less pass ordinary day for im own month.
How the session waka
The exact SQL behind every number
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_timeThe half-hour path correct one detail wey plenty retellings dey flatten: March 9 no be one-way slide. After the gap down, SPY rally through mid-morning — the 10:00 ET bucket close for $69.49, just under the $70 day high wey dem print for 10:13 — then e spend the afternoon dey give am back, e dey drift down go the $67.73 low for 15:17 and bounce small enter the close. Rally, fade, small bounce: na ordinary shape. No waterfall, no panic volume signature, no v-bottom. Compare am with Lehman Monday own wey be close-on-the-low urgency or the flash crash own air pocket: this one na different species entirely, the exhausted tape. The multi-percent crashes of that winter don already happen for the weeks wey pass. The bottom itself na the day wey sellers just run out.
Wetin turn di tape
Di data wey come out for Monday no fit explain Tuesday — di turn show face with di news cycle, no be di tape. Before Tuesday market open, one internal memo from Citigroup oga patapata Vikram Pandit leak go press: di bank, e talk say, don make profit for January and February 2009, e best two-month run since 2007. Citigroup — di center of di crisis, wey dey trade for $1.05 as Monday market close — never produce any primary-source good news for months. Na wetin di tape record for di five sessions wey follow di low be dis:
The exact SQL behind every number
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_dateMarch 10 open higher and e no gree give am back: SPY close for $72.21, e go up 6.1%, on 401.3 million shares — volume wey heavy pass di bottom day sef. Citigroup close for $1.44. By Friday, SPY stand for $76.09 and Citigroup for $1.78. Di 10-year Treasury yield rise from 2.89% go 2.99% for dat same Tuesday — money dey comot from di safest asset as equity dey rally, di flight-to-quality trade dey run for reverse.
Di honest caveat: several multi-percent rallies don already come and fail dat winter, and nothing for March 10 certify dis one as different. Di Pandit memo na di marker wey historians dey attach to di turn; wetin di tape fit show — and e show am, for up so — na di coincidence of timing.
Di low hold?
Bottom na bottom only if market no go back. Dis panel dey track SPY week by week till di end of June 2009 — di lowest trade and final close for each week, plus di running minimum for di last column:
The exact SQL behind every number
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_ofDi lowest wey SPY trade for di sixteen weeks after March 9 na $69.37 — and dat print show for di first week after di low (2009-03-09). SPY never trade below im March 9 close of $68.07 again, talk less of di $67.73 intraday low. No retest happen, no second chance, no pullback to di old level: by di week of 2009-05-04 SPY don close at $93.04, wey be one-third above di bottom inside nine weeks. To dey wait for confirmation get price, and di panel state am exactly.
Who lead di year from di low
Di banks wey dey di center of di wahala na im still dey di center of di comeback. One year from di bottom wey close to March 9, 2010:
The exact SQL behind every number
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 DESCDi top of di board: BAC dey +349%, C dey +265% (from $1.05 per share), WFC dey +190% — di big financials wey suffer pass, dem triple and quadruple from prices wey don already assume di worst. Di board no be only banks — AAPL return 168% for dat same year — but di panel tight argument na say di single best performer na financial. Meanwhile di broad market (SPY) gain 68%, and XOM, di defensive giant wey hold up well-well on di way down, gain just 3%. Di rebound turn di decline leaderboard upside down.
How e compare with oda bottoms
Di minute tape for here start for September 2003, so di October 2002 dot-com low no dey inside di range wey we fit see. Against di three deepest closing lows since dat time, March 2009 look like dis:
The exact SQL behind every number
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_sessionFrom di 2009 bottom, SPY gain 38.5% for three months and 68.1% for one year — na di strongest twelve months wey most investors wey dey alive don ever see, and e start for di day wey look most ordinary for di whole crisis. Na only di March 2020 COVID low dey di same class, with +75.1% for im first year — a turn wey im 2020 stimulus rally anatomy get im own page. Di 2011 and 2018 correction lows — wey be genuine panics for dat moment — return 31.4% and 37.1% for dia first years. Di pattern across all four: di deeper di hole, di steeper di first leg out, and di first leg na always di steepest of di whole move.
Why pesin fit only see bottom wen e don pass
Di honest mechanics: dem dey define bottom by wetin no happen afta — no lower low — wey be sey for real time, by design, e no fit know. Every quantitative "bottom signal" wey dem don ever propose fire plenty times as market dey fall go down for late 2008; di March 9 session score no special for any of dem — ordinary shape, volume wey no reach average, news catalyst wey only show di next morning. Anybody wey claim say dia indicator call dis day dey describe survivorship, and di many oda "bottoms" wey e also call before na di receipt for dat.
Wetin di day really teach: position for range of outcomes instead of points. Di investors wey do well from March 2009 na, mostly, dose wey bin dey buy through di whole miserable winter on schedule — di approach wey return-measurement conventions quietly assume — no be dose wey find di pixel-perfect low. Di tape role for dat discipline na calibration, no be prophecy: to sabi wetin ordinary look like na im dey stop quiet Monday from being mistaken for one more day of fall wey, for fact, just end.
March 2009 bottom FAQ
Wetin be di exact bottom of di 2008-2009 crash?
Di closing low show for Monday, March 9, 2009: SPY na $68.07, di S&P 500 index for im widely cited 676.53. Di famous intraday "666" for di index don show one session before, for di prior Friday, March 6.
How much di stock market fall from 2007 to 2009?
SPY fall -56.5% on a closing basis — from $156.41 on 2007-10-09 to $68.07 on 2009-03-09 — na di deepest US equity drawdown since di 1930s.
Wetin happen on March 10, 2009?
Di first session after di bottom: SPY rise 6.1% following di overnight leak of a Citigroup internal memo wey talk say di bank don make profit for January and February. Citigroup sef close at $1.44, up from $1.05 at di low.
How fast di market recover from di 2009 bottom?
Di first year na historic: SPY gain 68.1% from di bottom close. To recover di entire crisis drawdown take much longer — di first close back above di October 2007 peak come on 2013-03-14.
Any signal show di bottom in advance?
Nothing for di tape distinguish March 9 from di weeks around am — di session quiet and volume run below im own 20-day average. Di bottom become bottom retroactively, by never being undercut: di lowest trade of di following sixteen weeks stay above even di March 9 close.
Every panel above na stored, versioned query over di historical tape — expand di SQL to see each measurement. You wan feel dis day instead of reading am? E be one of di playable scenarios for di Strasmore Labs trading simulator.