model 03 · frb-us · US · hosted
Test US monetary and fiscal shocks.
Trace how a funds-rate or fiscal shock affects US output, inflation, and unemployment quarter by quarter using the April 2026 baseline.
The US counterpart to the OBR emulator.
This reimplements the large-scale macroeconometric model the Federal
Reserve Board has used for policy analysis and forecasting since 1996. The
Board publishes the whole thing — the equation system as
model.xml, the LONGBASE historical and
projection database, the model documentation, and a reference Python
solver called pyfrbus — in the public domain. What it does
not publish is a modern, readable, dependency-light implementation you
can drop into a research stack.
This is that: a from-scratch build on numpy, scipy and sympy under Python 3.10+, parsing the Board's own model file rather than re-specifying it. It carries 284 endogenous variables and their equations, classified into behavioural and identity blocks exactly as the Board's file declares them, and solves them as one simultaneous system per quarter.
In the suite it plays the role for the United States that the OBR emulator plays for the United Kingdom: reproducing the estimated equation system an official institution actually relies on, rather than deriving behaviour from first principles the way the overlapping-generations model does. The two diverge on one point that shapes everything below: the OBR emulator has a bridge from statute, and this one does not.
Parse, add-factor, solve by Newton.
| stage | what it does |
|---|---|
| Parse | Reads the Board's model.xml directly: variables, equations, per-equation coefficients, and the endogenous / exogenous classification for the VAR-expectations ("standard") equation set. Nothing is re-typed or re-specified. |
| Load | Loads LONGBASE.TXT — the April 2026 vintage — into a pandas frame on a quarterly PeriodIndex. |
Add-factor (init_trac) |
Sets each equation's tracking residual so that solving the model reproduces the database exactly. This is the Fed's own device, used the Fed's own way — the direct analogue of the OBR emulator's anchoring. |
| Solve | A per-period damped Newton iteration on the full simultaneous system, with an analytic sparse Jacobian — differentiated symbolically with sympy, factorised with scipy.sparse.linalg.splu. Defaults are xtol=1e-8, rtol=5e-4. |
| Shock & compare | A shock is an addition to an equation's error term — rffintay_aerr for the policy rule, for instance. Solve shocked and baseline paths over the same window and read the difference. |
The reference implementation decomposes each period into recursive and simultaneous blocks; this one solves the whole period at once. Both approaches solve the same F(x) = 0, which is why the two agree to solver tolerance rather than to some negotiated threshold — see how far to trust it below.
Ask the server, or install it.
The quickest route is the hosted MCP server,
where three tools reach this model:
frbus_list_variables (the shockable levers, with their
units), frbus_shock (solve and return impulse responses),
and frbus_summary (vintage and validation provenance).
A solve takes about 3 seconds cold and well under a second
warm — the fastest member of the suite. The same three are on
the CLI:
pe-macro frbus-variables
pe-macro frbus-shock --var rffintay_aerr --shock 1.0
pe-macro frbus-summary
Two traps. Shock sizes are per-lever and not
interchangeable: rffintay_aerr is in percentage points
(1.0 = a 100bp tightening), but the spending levers such as
egfe_aerr are in log points of quarterly
growth, not billions of dollars — a dollar-sized number there
diverges the solver. And each policy rule reads its own
add-error, so rffintay_aerr works only under
inertial_taylor; asking for it under
taylor is rejected with a pointer to
rfftay_aerr rather than silently returning all-zero
responses.
frbus_shock takes a policy_rule, and the
choice is usually the economic point of the exercise:
inertial_taylor (the default, the LONGBASE rule and the
one the validation numbers use), taylor, or
fixed_funds_rate, which holds the funds rate on its
baseline path so there is no endogenous monetary offset. A four-quarter
federal-purchases shock of 0.01 log points peaks higher on real GDP
with the funds rate fixed than under the inertial rule — and the
price-level response is larger still without the monetary offset.
For the full 284-variable model, the Board's own demo scripts, or anything the three tools do not expose, install the package. It is separate from the rest of the suite, with its own Python API. The Board's raw materials are vendored unmodified in the repository, so there is no data-download step, but you do clone rather than pip-install from an index.
git clone https://github.com/PolicyEngine/us-frb-model
cd us-frb-model
uv venv && uv pip install -e ".[dev]"import pandas as pd
from frbus import Frbus, load_data
data = load_data("vendor/data_only_package/LONGBASE.TXT")
model = Frbus("vendor/pyfrbus_package/models/model.xml")
start, end = pd.Period("2026Q1"), pd.Period("2030Q4")
# the fiscal-policy configuration the Board's own demos use
data.loc[start:end, "dfpdbt"] = 0
data.loc[start:end, "dfpsrp"] = 1
# add-factor the model so the baseline reproduces LONGBASE exactly
with_adds = model.init_trac(start, end, data)
# 100bp monetary policy shock in the first quarter
with_adds.loc[start, "rffintay_aerr"] += 1
sim = model.solve(start, end, with_adds)
print((sim.loc[start:end, "xgdp"] / with_adds.loc[start:end, "xgdp"] - 1) * 100)
a runnable copy of exactly this is
examples/monetary_policy_shock.py. The API surface mirrors
the essentials of pyfrbus's Frbus class:
Frbus(path), .init_trac(),
.solve(), .exogenize() — so the Board's own
demo scripts port across with minimal change.
| code | variable | role |
|---|---|---|
rffintay_aerr | Taylor-rule policy-rate error term | shock instrument — +1 for a 100bp tightening |
dfpdbt / dfpsrp | Fiscal policy switches | exogenous — set the debt / surplus closure |
xgdp | Real GDP | endogenous — headline output |
lur | Unemployment rate | endogenous — rate, pp |
picxfe | Core PCE inflation | endogenous — rate, pp |
rff | Federal funds rate | endogenous under the rule, pp |
US monetary and fiscal shocks, quarter by quarter.
The model's designed job is the dynamic response of the US economy to a policy impulse. A 100bp funds-rate tightening in 2026Q1 moves the policy rate +1.000pp on impact, pushes real GDP to a trough of −0.55% in 2027Q4, raises unemployment by a peak +0.26pp, and takes core inflation down 0.034pp at its trough — signs, magnitudes and timing consistent with the simulation properties in the Board's own frb-us documentation.
Fiscal impulses land in the published cross-model ranges. A government-purchases shock worth 1% of GDP gives a year-one multiplier of 0.72 under the inertial Taylor rule, inside the 0.7–1.0 no-accommodation range in Coenen et al. (2012); holding the funds rate fixed, the year-two multiplier is 0.99. A personal tax cut worth 1% of GDP ex ante gives 0.22 rising to 0.32 over years one and two, inside both the 0.2–0.4 cross-model range and CBO's central estimate of about 0.3.
Machine precision on the baseline; the Fed's own noise floor on shocks.
This is a replication with a published anchor, and it is the sharpest-tested member of the suite — because for once the ground truth is exact rather than statistical. Three invariants carry the weight, and all are enforced in continuous integration — including four like-for-like scenarios gated against vendor-generated references.
The last figure is the one that frames the other three. The Board's
two releases ship a byte-identical model.xml and
LONGBASE and differ only in how the Newton routine reuses its LU
factorisation — yet they disagree with each other by
1.3×10−8, as much as this
implementation disagrees with either. Agreement here therefore sits at
the reference implementation's own numerical noise, not at a tolerance
anyone chose. All three residuals concentrate in the same near-zero
expectational-gap series (wpsn, zgap05).
| test | what it checks | result |
|---|---|---|
| Tracking invariant | After init_trac, solving the baseline must reproduce LONGBASE for all 284 endogenous variables over 2026Q1–2030Q4. |
Max absolute error 5.6e−17 — machine precision, against a 1e−8 gate. The Board's own pyfrbus 1.1.1 reproduces LONGBASE to 1.1e−8 on the same test. |
| Cross-validation | An identical 100bp rffintay_aerr shock run in both implementations, compared across all 284 variables and all 20 quarters. |
6.0e−9 against pyfrbus 1.0.0 and 1.4e−8 against 1.1.1 — where the two Board releases differ from each other by 1.3e−8. |
| Simulation properties | A 100bp tightening must move the right things in the right direction by the right order of magnitude. | rff +1.000pp on impact, GDP trough −0.55%, unemployment peak +0.26pp, core inflation trough −0.034pp — consistent with the Board's documented VAR-expectations properties. |
The committed reference stays pinned to pyfrbus 1.0.0 so the gate has a fixed anchor; the 1.1.1 comparison is a recorded cross-check. CI does not merely re-check a committed CSV — a dedicated job re-runs the Board's pyfrbus from source in a throwaway environment and gates against that freshly generated solution, and a weekly scheduled run repeats the whole suite across Python 3.10–3.12 so dependency drift surfaces without a pull request. Full tables in VALIDATION.md, the working paper, and validation.
This is an independent implementation built from the Federal Reserve Board's published model equations and data. It is not produced, maintained, or endorsed by the Federal Reserve, and its results should not be presented as official Federal Reserve estimates.
What is absent, and what is merely local.
| limit | detail |
|---|---|
| VAR expectations only | The model-consistent-expectations (MCE) equation variants are not implemented — Frbus(path, mce=...) raises NotImplementedError. Anything that turns on agents anticipating announced future policy, forward guidance most obviously, is out of scope. |
No mcontrol |
The reference implementation's trajectory-targeting routine is out of scope. Stochastic simulation is implemented — stochsim_bands() produces seeded residual-bootstrap percentile bands — but the hosted frbus_shock path still returns a single deterministic projection, so bands are not available through the MCP surface. |
| Hosted, but only as raw shocks | The hosted tools and their pe-macro mirrors expose one lever, one shock size, a policy rule and a headline set of responses — not the full 284-variable model. Anything beyond that (the Board's demo scripts, exogenize, arbitrary variable sets) still means installing the package and using its Python API. |
| No PolicyEngine reform bridge | Reforms enter as shocks to model variables, not as statute. There is no equivalent of the OBR emulator's static-costing bridge from a PolicyEngine reform dict — score_reform refuses model="frbus" outright and points at frbus_shock — so US reform scoring stops at pe-microsim's static answer. Hosting the model did not change this. |
| Approximate published comparisons | The 100bp funds-rate responses in the Board's 2014 FEDS Note are read off charts, so those comparisons are approximate by nature: our output-gap trough of −0.50pp against the Note's roughly −0.4pp reflects vintage and shock-design differences, and is not claimed as a match. |
| Vintage | The April 2026 model.xml and LONGBASE as published by the Board. Later Board vintages have not been adopted. |