FOMC · reaction function

Ordered logit on 36 years of decisions · point-in-time data · walk-forward scored

10/19/2026, 11:39:33 AM

Frozen snapshot. The engine does not run on this host. These are the numbers cli.py produced on 10/18/2026, 5:15:31 PM, not a live read.

Incoming data since then is not in this page, and the futures read below is that day's pricing, not today's.

calibrated to
2.2pp
mean gap, said vs happened · 233 meetings
vs. fed funds futures, on moves
−17.3pp
65.8% called, 6.9% false alarms · 83.1% priced, 5.3% false alarms · n=65 moves
walk-forward window
233meetings
1997-08-19 → 2026-09-16

Next meeting 2026-10-28

10 days away

headline · fed funds futures

hold 84.0%

14 days out, the futures strip called direction on 88.4% of 164 meetings against the model's 86.6% (3 more right).

The two disagree: the model says hike, the market prices hold.

model

cut50+0.0%
cut250.0%
hold18.3%
hike2579.3%
hike50+2.4%
P(cut) 0.0%P(hold) 18.3%P(hike) 81.7%
current target (upper)4.00%
expected move+21.3 bp
implied target4.21%

Read the probability, not the argmax. The expected move is the distribution's mean in basis points, not a prediction that the Fed will move by that amount — the Committee only chooses in 25bp steps.

fed funds futures · headline

cut0.0%
hold84.0%
hike16.0%
priced move+4.0 bp
call (±12.5bp band)hold

CME ZQ strip through the FedWatch arithmetic, the same number the scorecard grades. Options (Atlanta Fed) put P(hike) at 93.0% and P(cut) at 2.1%, but over the nearest option window, not this meeting.

Direction called, walk-forward, by days before the meeting opens, on the meetings the strip reached that day. Recall on moves and false alarms on holds read together.
days outnmodelmarketmoves m / mktfalse alarm m / mkt
119684.7%90.8%64.6% / 83.1%5.3% / 5.3%
718784.0%95.7%62.3% / 95.1%5.6% / 4.0%
14 ← now16486.6%88.4%62.0% / 86.0%2.6% / 10.5%
2113284.8%87.1%57.9% / 81.6%4.3% / 10.6%
2813085.4%86.2%55.6% / 91.7%3.2% / 16.0%
426783.6%83.6%50.0% / 77.8%4.1% / 14.3%

CME watch — the priced path

reading the fed funds futures strip across the next eight meetings…

walk-forward record

233 meetings, 1997-08-19 → 2026-09-16. Refit at every step on prior meetings only — scaler, imputation medians, cutpoints and coefficients, so no fit ever saw its own test row. Headline accuracy is meaningless on its own: the Fed held 68.7% of these meetings, so that is the floor, not the bar. Every figure below is read straight out of the engine's scorecard — this page does not recompute any of it.

On the meetings that matter, the engine loses to what was already priced.
Across the 65 meetings where the Fed moved and the futures strip reached (of 73 in all) , the fed funds futures called direction 83.1% of the time against this model's 65.8% — a gap of −17.3pp. And unlike the yield-spread proxy it does not buy that recall with false alarms: 5.3% of holds against the model's 6.9%. It is better on both axes at once. Treat the distribution as a structured read on why pressure sits where it does, not as an edge over the market.
Direction accuracy for the model and each baseline, over all scored meetings, over the subset where the Fed moved, and the false-alarm rate on the meetings where it held.
direction called byscored onall meetingswhen it movedfalse alarms on holds
this model23384.5%65.8%6.9%
always say hold23368.7%0.0%0.0%
repeat the last action23379.0%65.8%15.0%
market-implied (1y - funds proxy)23366.1%91.8%best45.6%
market-implied (fed funds futures)19690.8%best83.1%5.3%
model edge vs. best baseline−6.3pp−26.0ppread across, not down

The "when it moved" column is recall and the column beside it is what that recall cost. A caller can buy the first with the second, which is exactly what the 1y-minus-funds proxy does. Coverage differs by row: the fed funds futures strip cannot price every meeting, and those meetings are left out of its denominator rather than scored against the Treasury proxy under its name. On the 196 meetings it does reach, every caller scores this model: 64.6% / 5.3% · always say hold: 0.0% / 0.0% · repeat the last action: 66.2% / 11.5% · market-implied (1y - funds proxy): 90.8% / 45.8% · market-implied (fed funds futures): 83.1% / 5.3% (moves / false alarms).

exact size, all meetings
82.4%
vs 68.7% for always-hold
exact size, on moves
58.9%
vs 0.0% for always-hold · n=73
false alarms on holds
6.9%
called a move when it held · n=160
mean |error|
6.8 bp
log loss 0.494 · Brier 0.263

calibration — is the distribution trustworthy?

Read this before any single forecast. Each point is a bucket of meetings the model assigned a similar P(move); the diagonal is perfect calibration. A point above the line means the Fed moved more often than the model said, below means it moved less. Scored walk-forward over 233 meetings.

perfectly calibrated0-20%: model said 7.3%, it happened 8.5% (n=141)20-40%: model said 28.3%, it happened 28.6% (n=21)40-60%: model said 51.2%, it happened 60.0% (n=20)60-80%: model said 71.0%, it happened 66.7% (n=12)80-100%: model said 92.9%, it happened 89.7% (n=39)00252550507575100100model said P(move) %it happened %
calibration error (n-weighted)
2.2pp
mean gap between what it said and what happened
worst bucket
8.8pp
in the 40-60% bucket — an average can hide one broken bin
Calibration of the predicted probability of a policy move, by bucket.
model saidnpredictedhappenedgap
0-20%1417.3%8.5%+1.2pp
20-40%2128.3%28.6%+0.3pp
40-60%2051.2%60.0%+8.8pp
60-80%1271.0%66.7%−4.3pp
80-100%3992.9%89.7%−3.1pp

Buckets are the engine's own, from models/backtest.json. A bucket holding a handful of meetings is noise — read n before reading its gap.

conditional path — pressure already in the data

This is not a rate-path forecast. Do not quote it as one.
Every meeting past the first is scored on today's data — a read on how much pressure is already in the data, not a call on the terminal rate.
running the reaction function across the next five meetings…

what is driving this meeting

Exact arithmetic, not an approximation: each contribution is βj · zj, the fitted coefficient times the standardised feature value, in latent policy-pressure units. They sum to the latent score the cutpoints are applied to, so this decomposition IS the forecast rather than a story told about it.

pushing toward tightening

featurevalueβ·z
mkt_3m0.36+1.17
ff_p_cut0.02+0.85
mkt_1y0.59+0.74
mortgage_chg_6m0.86+0.73
last_dir1.00+0.73
breakeven_5y2.35+0.64

pushing toward easing

featurevalueβ·z
sentiment51.70−0.46
vacancy_ratio1.00−0.35
ff_p_hike0.93−0.33
months_supply8.50−0.30
months_since_move1.28−0.19
hpi_yoy1.87−0.12

the fitted reaction function

One signed coefficient per feature, biggest first — the thing a desk would actually argue with. The latent is policy pressure, so a positive β means a higher value of that feature pushes toward tightening. These are L2-penalised and fitted on standardised columns, so they are comparable to each other in size but are not elasticities, and a feature correlated with three others will have its weight split across them.

  • ff_exp_move_bp+1.412
  • mkt_3m+0.794
  • breakeven_5y+0.789
  • mkt_1y+0.765
  • chg_12m+0.712
  • mkt_2y+0.674
  • last_dir+0.565
  • credit_chg−0.520
  • mortgage_chg_6m+0.474
  • newsales_yoy−0.462
  • vacancy_ratio−0.411
  • ff_p_cut−0.368
  • nfci+0.339
  • months_since_move+0.330
  • slope_10y2y−0.321
  • claims_yoy+0.301
  • hpi_yoy+0.282
  • level−0.249
← pushes toward easingpushes toward tightening →

recent decisions

The most recent policy decisions, derived from the FRED target series.
2026-09-16+25bphike253.75% → 4.00%
2026-07-290bphold3.75% → 3.75%
2026-06-170bphold3.75% → 3.75%
2026-04-290bphold3.75% → 3.75%
2026-03-180bphold3.75% → 3.75%
2026-01-280bphold3.75% → 3.75%
2025-12-10-25bpcut254.00% → 3.75%
2025-10-29-25bpcut254.25% → 4.00%
2025-09-17-25bpcut254.50% → 4.25%
2025-07-300bphold4.50% → 4.50%
2025-06-180bphold4.50% → 4.50%
2025-05-070bphold4.50% → 4.50%
2025-03-190bphold4.50% → 4.50%
2025-01-290bphold4.50% → 4.50%