Stock Returns After the First Fed Rate Hike
S&P 500 returns 1, 3, 6 and 12 months after the first Fed rate hike of the 2004, 2015 and 2022 cycles, from daily SPY closes, plus what the yield curve did.
What do stocks do after the first Fed rate hike? Measured on SPY, the exchange-traded fund that tracks the S&P 500, the year following the first hike of each of the last three tightening cycles (June 2004, December 2015 and March 2022) opened with a soft patch: three months after each of those hikes, SPY closed below its hike-day price. Twelve months out the record splits, higher after the 2004 and 2015 hikes and lower after 2022. Every figure below is computed from daily closes, and the FOMC statement that dates each hike is linked so the anchor can be checked.
What counts as the first Fed rate hike of a cycle?
The Federal Open Market Committee (FOMC) sets a target for the federal funds rate, the overnight rate at which banks lend reserves to one another. A hiking cycle begins at the first meeting that raises the target after a run of cuts or holds. That meeting is the first hike, and the statement it releases that afternoon is the anchor date. Three first hikes fall inside the daily price history this post queries:
- June 30, 2004. The target moved from 1.00% to 1.25% (FOMC statement). Sixteen more quarter-point steps followed, 17 in all, ending at 5.25% in June 2006.
- December 16, 2015. The target range moved from 0–0.25% to 0.25–0.50% (FOMC statement). Eight more hikes followed through December 2018, ending at 2.25–2.50%.
- March 16, 2022. The target range moved from 0–0.25% to 0.25–0.50% (FOMC statement). Ten more hikes followed through July 2023, ending at 5.25–5.50%.
Two earlier first hikes, February 4, 1994 and June 30, 1999, are left to the published literature. No return for them appears on this page: none is computed here, and a number that cannot be rerun cannot be checked.
How did the S&P 500 perform after the first Fed rate hike?
The method is plain. The base price is SPY's close on hike day, the first close that includes the decision. Each horizon is a calendar offset from that date (one, three, six and twelve months), and the price used is the last close on or before the target date, so a weekend or holiday never pushes a horizon forward. Returns are price returns; SPY's quarterly dividends are not added back.
| cycle | fwd_1m_pct | fwd_3m_pct | fwd_6m_pct | fwd_12m_pct |
|---|---|---|---|---|
| Jun 30, 2004 | -3.2 | -2.4 | 5.8 | 4.1 |
| Dec 16, 2015 | -9.7 | -2.3 | 0.2 | 8.2 |
| Mar 16, 2022 | 0.5 | -15.8 | -11.5 | -9.1 |
The exact SQL behind every number
WITH px AS
(
SELECT
date,
toFloat64(close) AS px_close,
multiIf(date <= '2005-06-30', toDate('2004-06-30'),
date <= '2016-12-16', toDate('2015-12-16'),
toDate('2022-03-16')) AS hike_date
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND ((date >= '2004-06-30' AND date <= '2005-06-30')
OR (date >= '2015-12-16' AND date <= '2016-12-16')
OR (date >= '2022-03-16' AND date <= '2023-03-16'))
)
SELECT
formatDateTime(hike_date, '%b %e, %Y') AS cycle,
round(100 * (argMaxIf(px_close, date, date <= addMonths(hike_date, 1)) / argMin(px_close, date) - 1), 1) AS fwd_1m_pct,
round(100 * (argMaxIf(px_close, date, date <= addMonths(hike_date, 3)) / argMin(px_close, date) - 1), 1) AS fwd_3m_pct,
round(100 * (argMaxIf(px_close, date, date <= addMonths(hike_date, 6)) / argMin(px_close, date) - 1), 1) AS fwd_6m_pct,
round(100 * (argMaxIf(px_close, date, date <= addMonths(hike_date, 12)) / argMin(px_close, date) - 1), 1) AS fwd_12m_pct
FROM px
GROUP BY hike_date
ORDER BY hike_dateThe one-month column disagrees with itself: the Jun 30, 2004 hike was followed by -3.2%, Dec 16, 2015 by -9.7%, and Mar 16, 2022 by 0.5%. The three-month column is the one that lines up: -2.4%, -2.3% and -15.8%, and none of the three is positive. By six months the 2004 path had turned to 5.8%, 2015 sat close to flat at 0.2%, and 2022 read -11.5%. At twelve months the figures were 4.1%, 8.2% and -9.1%: two cycles above the hike-day close, the 2022 cycle below it.
Three cycles are three observations. They record what happened, and a sample that small carries no weight as a forecast. The value of the table is that every cell can be rerun from the daily closes instead of being taken on faith from a chart in a research note.
What did the path look like in the year after the hike?
A four-horizon table hides everything between the horizons. The panel below aligns the three cycles on hike day (week 0) and tracks SPY's percentage distance from the hike-day close at the end of each of the following 52 weeks, so the three shapes sit on one chart.
| wk_after_hike | cycle_2004_pct | cycle_2015_pct | cycle_2022_pct |
|---|---|---|---|
| 0 | 0 | 0 | 0 |
| 1 | -2 | -1 | 1.9 |
| 2 | -2.6 | -1 | 5.3 |
| 3 | -4.3 | -4.4 | 2.5 |
| 4 | -3.9 | -9.2 | 1.8 |
| 5 | -3.8 | -10.8 | 2.1 |
| 6 | -5.6 | -9.6 | -4.2 |
| 7 | -3.9 | -8 | -1.5 |
| 8 | -3 | -10.9 | -9.8 |
| 9 | -2.8 | -7.3 | -10 |
| 10 | -1.7 | -7.1 | -8.8 |
| 11 | -1.5 | -4.3 | -6 |
| 12 | -2.6 | -4.2 | -5.6 |
| 13 | -2.3 | -2.3 | -13 |
| 14 | 0.1 | -2.3 | -14.1 |
| 15 | -2.6 | -1 | -12.7 |
| 16 | -3.5 | -0.8 | -12 |
| 17 | -1.4 | 0 | -13 |
| 18 | 0.4 | 1 | -9.4 |
| 19 | 2.1 | 0.6 | -7.9 |
The exact SQL behind every number
WITH
px AS
(
SELECT
date,
toFloat64(close) AS px_close,
multiIf(date <= '2005-06-30', toDate('2004-06-30'),
date <= '2016-12-16', toDate('2015-12-16'),
toDate('2022-03-16')) AS hike_date
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND ((date >= '2004-06-30' AND date <= '2005-06-30')
OR (date >= '2015-12-16' AND date <= '2016-12-16')
OR (date >= '2022-03-16' AND date <= '2023-03-16'))
),
base AS
(
SELECT hike_date, argMin(px_close, date) AS hike_close
FROM px
GROUP BY hike_date
),
weekly AS
(
SELECT
p.hike_date AS hk,
intDiv(dateDiff('day', p.hike_date, p.date) + 6, 7) AS wk,
argMax(p.px_close, p.date) / any(b.hike_close) AS ratio
FROM px AS p
INNER JOIN base AS b ON p.hike_date = b.hike_date
GROUP BY hk, wk
)
SELECT
wk AS wk_after_hike,
round(100 * (maxIf(ratio, toYear(hk) = 2004) - 1), 1) AS cycle_2004_pct,
round(100 * (maxIf(ratio, toYear(hk) = 2015) - 1), 1) AS cycle_2015_pct,
round(100 * (maxIf(ratio, toYear(hk) = 2022) - 1), 1) AS cycle_2022_pct
FROM weekly
WHERE wk <= 52
GROUP BY wk
ORDER BY wkEach line starts at 0% by construction. The 2015 line drops fastest: by week 8 it stood at -10.9% from the hike-day close, then climbed through most of the remaining year to finish at 8.6%. The 2004 line dipped through the summer, recovered into the winter and finished at 4.6%. The 2022 line spent its first few weeks above zero, slid through the spring and summer, read -9.4% at the halfway mark and ended the year at -10.6%.
How deep were the pullbacks after the first hike?
A twelve-month return can flatter a path that was uncomfortable to hold. This panel takes the lowest and highest close in the twelve months after each hike and measures both against the hike-day close.
| cycle | low_vs_hike_pct | low_on | high_vs_hike_pct | high_on |
|---|---|---|---|---|
| Jun 30, 2004 | -6.7 | Aug 6, 2004 | 7.2 | Mar 7, 2005 |
| Dec 16, 2015 | -12.1 | Feb 11, 2016 | 9.5 | Dec 13, 2016 |
| Mar 16, 2022 | -18.1 | Oct 12, 2022 | 6 | Mar 29, 2022 |
The exact SQL behind every number
WITH px AS
(
SELECT
date,
toFloat64(close) AS px_close,
multiIf(date <= '2005-06-30', toDate('2004-06-30'),
date <= '2016-12-16', toDate('2015-12-16'),
toDate('2022-03-16')) AS hike_date
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND ((date >= '2004-06-30' AND date <= '2005-06-30')
OR (date >= '2015-12-16' AND date <= '2016-12-16')
OR (date >= '2022-03-16' AND date <= '2023-03-16'))
)
SELECT
formatDateTime(hike_date, '%b %e, %Y') AS cycle,
round(100 * (min(px_close) / argMin(px_close, date) - 1), 1) AS low_vs_hike_pct,
formatDateTime(argMin(date, px_close), '%b %e, %Y') AS low_on,
round(100 * (max(px_close) / argMin(px_close, date) - 1), 1) AS high_vs_hike_pct,
formatDateTime(argMax(date, px_close), '%b %e, %Y') AS high_on
FROM px
GROUP BY hike_date
ORDER BY hike_dateThe low arrived at a different point in each cycle: Aug 6, 2004 after the 2004 hike, Feb 11, 2016 after 2015 and Oct 12, 2022 after 2022, at -6.7%, -12.1% and -18.1% from the hike-day close. The highs ran 7.2% on Mar 7, 2005, 9.5% on Dec 13, 2016 and 6% on Mar 29, 2022. Set beside the weekly paths, the 2022 high sits inside the first few weeks and the low in the autumn; the 2015 cycle runs the other way, low inside the first two months and high in the final week of the window.
What did the yield curve do after the first hike?
The 2-year Treasury yield tracks the expected path of the policy rate over the next two years, so it moves with the hiking cycle itself. The 10-year yield prices growth and inflation expectations across a decade and moves less per hike. The difference between them, the 2s10s spread (10-year yield minus 2-year yield), is the standard read on the curve's slope: positive is the normal upward slope, negative is an inverted curve. This panel takes the spread on each hike day and twelve months later.
| cycle | spread_at_hike_bps | spread_12m_later_bps | change_bps |
|---|---|---|---|
| Jun 30, 2004 | 192 | 28 | -164 |
| Dec 16, 2015 | 128 | 132 | 4 |
| Mar 16, 2022 | 24 | -58 | -82 |
The exact SQL behind every number
WITH ty AS
(
SELECT
date,
toFloat64(yield_10_year) - toFloat64(yield_2_year) AS spread_pp,
multiIf(date <= '2005-06-30', toDate('2004-06-30'),
date <= '2016-12-16', toDate('2015-12-16'),
toDate('2022-03-16')) AS hike_date
FROM global_markets.treasury_yields
WHERE ((date >= '2004-06-23' AND date <= '2005-06-30')
OR (date >= '2015-12-09' AND date <= '2016-12-16')
OR (date >= '2022-03-09' AND date <= '2023-03-16'))
AND yield_10_year > 0
AND yield_2_year > 0
)
SELECT
formatDateTime(hike_date, '%b %e, %Y') AS cycle,
toInt32(round(100 * argMaxIf(spread_pp, date, date <= hike_date))) AS spread_at_hike_bps,
toInt32(round(100 * argMaxIf(spread_pp, date, date <= addMonths(hike_date, 12)))) AS spread_12m_later_bps,
toInt32(round(100 * (argMaxIf(spread_pp, date, date <= addMonths(hike_date, 12))
- argMaxIf(spread_pp, date, date <= hike_date)))) AS change_bps
FROM ty
GROUP BY hike_date
HAVING countIf(date <= hike_date) > 0
ORDER BY hike_dateAt the hike, 2s10s stood at 192 basis points in 2004, 128 in 2015 and 24 in 2022 (a basis point is one hundredth of a percentage point). Twelve months later the readings were 28, 132 and -58. The 2004 and 2022 curves flattened, the spread moving -164 and -82 basis points; the 2015 spread moved 4 basis points, close to unchanged. Only the 2022 cycle had an inverted curve at the twelve-month mark. The curve's path through this year is charted in the Treasury curve in H1 2026, and what followed past inversions once the curve steepened back is in what happens when the yield curve un-inverts.
Where does the current cycle fit?
As of September 2026 the question readers bring to this history is whether, and when, the next first hike arrives. That is a question for the fed funds futures curve rather than for a history post: how markets price Fed rate odds reads the futures strip meeting by meeting, and the macro picture entering H2 2026 lays out the inflation and labor data the committee weighs. Nothing on this page asserts what the FOMC decided at any 2026 meeting. The three cycles above are the product; the current one is the context a reader carries into them.
FAQ
What happens to the stock market after the first Fed rate hike?
In the three cycles measured here (2004, 2015 and 2022), SPY closed below its hike-day price three months after the first hike every time: -2.4%, -2.3% and -15.8%. Twelve months out it was higher after the 2004 and 2015 hikes and lower after 2022. Three cycles are a small sample and describe the past only.
Do stocks always fall when the Fed starts raising rates?
No. One month after the first hike the three cycles disagree, at -3.2%, -9.7% and 0.5%, and a year later two of the three sat above the hike-day close. What all three shared was a pullback inside the first twelve months; the 2022 low sat -18.1% from the hike-day close.
When was the first Fed rate hike of the last cycle?
March 16, 2022, when the FOMC raised the target range from 0–0.25% to 0.25–0.50%. The two first hikes before that came on December 16, 2015 and June 30, 2004. The ones before those, June 1999 and February 1994, fall outside the price history this page computes from.
Does the yield curve invert after the first Fed hike?
Not automatically. Over the twelve months after the first hike, the 2s10s spread flattened in 2004 and 2022 and was little changed in 2015, and only in 2022 did it sit below zero a year on. Inversion has preceded past recessions; what happened once past curves steepened back is covered in the un-inversion post linked above.
Every panel above carries the SQL that produced it; expand one to see how the return was measured. To run the same forward-return math from any other FOMC date, ask the question in plain English on the Strasmore terminal.
Data notes
- SPY daily closes stand in for the S&P 500. Returns are price returns; dividends are excluded.
- The base is the hike-day close. Horizons are calendar offsets; the price is the last close on or before the target date.
- In the weekly path, week k is the last close within the seven days ending k weeks after hike day, and week 0 is hike day itself.
- 2s10s is the 10-year yield minus the 2-year yield, in basis points, using the last observation on or before each date.
- Hike dates come from the FOMC statements linked above. No cycle before 2004 is computed.