model 02 — OBR macroeconometric model · obr-macro · UK · hosted

UK fiscal reform, quarter by quarter.

Run selected UK tax and spending scenarios and trace GDP, consumption, and investment over 3–5 years against the March 2026 EFO baseline. Borrowing is not yet returned by the PolicyEngine Macro adapter.

methodology

Transpile, solve, swap the closure.

The pipeline in six steps: the OBR's published EViews equation listing is rewritten in Python, initialised from official data, solved quarter by quarter until the equations agree, anchored so the baseline reproduces the published EFO, shocked against an identical baseline so the difference is the policy effect — and joined to the PolicyEngine microsimulation, which supplies the static costing the shock comes from.

1

Transpile the published listing

From EViews source to open Python EViews listing dlog(X) X(-1) @elem error-correction terms needs an EViews licence transpiler line by line Python expressions log(X) - log(X[-1]) indexed array reads compiled once per solve no licence needed the published listing in open code — 372 parse, ~79 skipped at solve
click to expand

From EViews to Python

The OBR publishes its full equation listing, but as EViews source that few can run. The transpiler rewrites every EViews line — dlog(), @elem, lags like X(-1), error-correction terms — into an equivalent Python expression, compiled once per solve.

What comes out

The result is the published listing in open code, runnable without an EViews licence. All 372 equations parse, but it is not a complete working copy of the OBR’s model: about 79 are skipped at solve time because inputs they need are not published, some headline variables pass through at their published values rather than being computed, and business investment uses an equation the OBR had commented out of its listing, reconstructed here.

translation
growth rates
\(\mathrm{dlog}(X) \;\rightarrow\; \log X_t - \log X_{t-1}\)
lags & elements
\(X_{t-1}\), @elem → indexed array reads
2

Initialise from official data

Where the starting values come from OBR detailed forecast tables March 2026 EFO vendored ONS snapshot 355 series, ships in the package model history: 199 of 261 unprinted endogenous variables matched by ONS code fiscal and financial sub-blocks get real balancing data
click to expand

Loading history

History loads from the OBR's detailed forecast tables. Of the 261 endogenous variables the listing referenced but the outlook did not print, 199 had ONS series codes; a vendored 355-series ONS snapshot supplies them.

Why it matters

That snapshot ships inside the package — there is no download step — and it gives the circular fiscal and financial sub-blocks real balancing data rather than guessed starting values.

data sources
forecast tables
OBR detailed forecast tables, March 2026 EFO
ONS snapshot
355 vendored series; 199 of 261 unprinted variables matched
3

Solve by Gauss–Seidel iteration

Simultaneous within a quarter, sequential across quarters within a quarter cycle through the equations update each in turn repeat to convergence converged Q1 Q2 Q3 … quarters solve sequentially forward 12-quarter anchored solve: ~30–40 s single-threaded; a reform run is two solves
click to expand

Simultaneous within a quarter

The equations depend on each other, so each quarter is solved simultaneously: cycle through the equations, update, repeat to convergence. Quarters then solve sequentially forward.

Runtime

A twelve-quarter anchored solve takes roughly 30–40 seconds single-threaded; a reform run is two such solves.

solver
within quarter
cycle → update → repeat to convergence
across quarters
sequential forward solve
4

Anchor to the published EFO

Add-factors pull the baseline onto the published EFO fit window 2024Q1–2025Q4 add-factors EFO raw fit add-factors hold constant, project to 2027Q4 to 2031Q1
click to expand

Add-factors, the OBR's own device

Add-factors — the residuals reconciling each behavioural equation to data — are set so the baseline reproduces the published EFO. This is the OBR's own device, used the OBR's own way.

Forecasting with held add-factors

For forecasting rather than one-off shocks, the emulator fits add-factors over a base window of 2024Q1–2025Q4, holds them constant, and projects to 2027Q4, with exogenous inputs extrapolated (seasonal cash series at their trailing annual mean). Scenario solves run twelve quarters, 2025Q1–2027Q4.

Horizon limits

The anchored horizon extends to 2031Q1, where GDP is reproduced to 0.67%. Anchored unemployment (LFSUR) is unreliable beyond 2027Q4, drifting to 0.9% against the EFO's 4.1% by 2031Q1.

anchoring
add-factor window
fit 2024Q1–2025Q4, hold constant, project to 2027Q4
scenario solves
12 quarters, 2025Q1–2027Q4
anchored horizon
to 2031Q1; GDP reproduced to 0.67%
5

Swap the closure, shock, compare

Two identical solves; the difference is the policy effect closure swap GDPM endogenised DINV held at EFO shocked baseline policy effect shock applied reported result = shocked path − baseline path identical structure isolates the policy from the forecast
click to expand

Closure swap

In the OBR file GDP (GDPM) is an exogenous input and inventories (DINV) are already the residual that closes the expenditure identity. For a shock the emulator removes the DINV equation, holds DINV at its EFO path, and adds a GDP identity so that GDPM is endogenous — output responds to the policy instead of being fixed.

Shock against an identical baseline

The emulator solves shocked and baseline paths with identical structure and reports the difference, isolating the policy effect from the underlying forecast.

closure and shock
closure swap
DINV equation removed and held at EFO; GDP identity added, GDPM endogenous
policy effect
\(X_t^{\text{shocked}} - X_t^{\text{baseline}}\), identical structure
6

Score a costed reform through the microsimulation bridge

Static costing in, second-round effects out pe-microsim static costing, £bn/yr who pays, how much HHDI_ADDFACTOR minus the costing ×1000 ÷ 4 → £m/qtr, held obr-macro HHDI → CONS → GDPM quarterly, vs baseline 1p on the basic rate: £6.46bn in → GDP falls, building to ~0.34× the revenue by quarter 12 close to the OBR's published 0.3 for income tax — read the scale, not single quarters
click to expand

Static costing in, second-round effects out

The suite's flagship join. PolicyEngine's microsimulation costs a statutory reform year by year — who pays and how much — and score_reform(country="uk", reform=..., model="obr") hands this model the bill: each year's costing enters as HHDI_ADDFACTOR, minus the annual £bn spread flat across its four quarters (×1000 ÷ 4 → £m/qtr), held as an add-factor on household disposable income.

What the emulator computes

Lower income moves consumption through the published consumption equation, and consumption moves GDP under the demand closure — the second round, quarter by quarter, against the anchored baseline of step 4. The anchoring add-factors are held fixed in both the baseline and the shocked run, so they cancel in the difference. 1p on the basic rate from April 2026: £6.46bn static in 2026, and a GDP fall building from about 0.15× the revenue raised in the first year to roughly 0.34× by the twelfth quarter. Individual quarters are not reliable — no quarter of the solve converges to tolerance.

Where the bridge stops

This route's implied multiplier is about 0.34 by the twelfth quarter, against the OBR's published 0.3 for income tax and NICs — the ~1-by-construction problem belongs to the spending lever (CGG, exactly 1.0000 against the OBR's 0.6), not to this one. Corporation tax is refused — not household-borne in the microsim, and the direct TCPRO closure converges only slowly (a 12-quarter run reaches ~40% of its plateau). UK only; no US bridge exists. Every join in the suite → /models#compose.

the bridge
injection
HHDI_ADDFACTOR = −(annual costing) × 1000 ÷ 4, £m/qtr, held
transmission
HHDI → RHHDI → CONS → GDPM
command
pe-macro score --country uk --reform '{…}' --model obr