Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/obr-receipts-importer.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- `import_obr_forecasts.py` now refreshes the OBR receipts growth series that project corporate SDLT and business rates (`yoy_growth.obr.stamp_duty_land_tax.*` and `.business_rates.*`) from a new EFO's receipts tables, with the previous EFO's tables (`--previous-receipts-file`) as the base for outturn growth, and refuses receipts tables from a different or unidentifiable EFO or without an unambiguous pound-billion unit declaration in every selected table in both releases.
55 changes: 53 additions & 2 deletions policyengine_uk/parameters/gov/economic_assumptions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,19 @@ GDP and population assumptions remain supported.
| `petrol_spending_litre_proxy` | Spending growth that preserves road-fuel litres | HMRC + OBR |
| `diesel_spending_litre_proxy` | Same, for diesel | HMRC + OBR |
| `finance_ni.domestic_rates` | Average Northern Ireland domestic rates bill (regional plus district poundage) | DoF rate poundages, LPS rates paid, NI draft Budget 2026-29 |
| `stamp_duty_land_tax.residential` | SDLT receipts from residential property | EFO receipts Table 3.7 |
| `stamp_duty_land_tax.non_residential` | SDLT receipts from non-residential property | EFO receipts Table 3.7 |
| `business_rates.great_britain` | Business rates receipts, England, Scotland and Wales (cash) | EFO receipts, current receipts (cash basis): Table 3.8 in March 2026 |
| `business_rates.northern_ireland` | Northern Ireland business rates receipts | EFO receipts Table 3.2 |

The four receipts series project the corporate SDLT and business rates
statistics (`gov.hmrc.stamp_duty.statistics`,
`gov.hmrc.business_rates.statistics`) from their latest outturn. Each is the
ratio of consecutive published receipts levels, to six decimals: outturn
growth for the EFO's outturn year (its outturn over the year before's outturn
in an earlier EFO), the EFO's forecast years, and after them the
`average_earnings` path. Years before the outturn year are kept, so each
index keeps its base year.

## Time horizons

Expand Down Expand Up @@ -282,8 +295,19 @@ threshold by the same rises, up to the last year of

1. Replace the 2025-2030 block in each series with values from the new EFO
detailed forecast tables (note the EFO release month in the header comment).
The importer converts annual economy growth percentages to decimal rates
and rounds them to four decimal places. Review the economy-series diff
deliberately when running a full CLI import: with the real March 2026
economy workbook, the existing extraction changes cumulative 2030 indices
relative to the stored series by RPI −0.0880%, CPI −0.0584%, average
earnings −0.0585% and house prices +0.0194%. Receipts-only rendering can
reproduce the committed YAML byte for byte; a full import also refreshes
these economy series.
2. Recompute the 2031-2073 convergence path so the first long-run year
continues smoothly from the new last forecast year (no jump).
continues smoothly from the new last forecast year (no jump). If the new
EFO forecasts a year that a series has no entry for, add that entry first:
the importer only replaces existing entries, and stops naming the series
and year it cannot update.
3. Nothing needs regenerating: `create_economic_assumption_indices` rebuilds
the cumulative `indices` parameters from these series whenever the
tax-benefit system processes its parameters (`tax_benefit_system.py`).
Expand All @@ -293,9 +317,36 @@ threshold by the same rises, up to the last year of
`yoy_growth.yaml`; pass the receipts tables with `--receipts-file` or
`--receipts-url` so September CPI uses the OBR's September forecast. If
you edit `yoy_growth.yaml` by hand instead, rerun it with `--gaps-only`.
6. If the new EFO runs past `PROJECTION_END_YEAR`, move it on (see
6. Refresh the receipts series (`stamp_duty_land_tax.*`,
`business_rates.*`). The importer does this in the same run when it also
gets the receipts tables of the EFO whose outturn year is one earlier
(March 2025 for March 2026), with `--previous-receipts-file` or
`--previous-receipts-url`; their outturn is the base for the outturn
year's growth. It finds each line by table title and row label, so table
renumbering does not matter, and reads only that table's rows. It takes
each workbook's release from its contents sheet, or else its file name or
URL, and refuses receipts tables from another EFO or of unknown release.
Every selected table in both releases must declare `£ billion` in its
header (`£bn` and `£ bn` are also accepted, ignoring case and whitespace).
Other units, including `£m`, and missing or ambiguous declarations stop
the import before any file is written, so different cash magnitudes
cannot be combined across releases.
Then update the published levels in
`policyengine_uk/tests/test_corporate_receipts_statistics.py`
(`OBR_RECEIPTS_BN`), which pin the series to the OBR's tables. Pass
`--skip-receipts-growth` only to leave them on the previous EFO.
7. If the new EFO runs past `PROJECTION_END_YEAR`, move it on (see
[Dataset projection horizon](#dataset-projection-horizon)).

For example, for March 2026:

```bash
uv run python -m policyengine_uk.utils.import_obr_forecasts \
--file economy_tables_march_2026.xlsx \
--receipts-file receipts_tables_march_2026.xlsx \
--previous-receipts-file receipts_tables_march_2025.xlsx
```

The EFO refresh does not touch `finance_ni.domestic_rates`; OBR does not
publish a Northern Ireland domestic rates bill series (see below).

Expand Down
25 changes: 14 additions & 11 deletions policyengine_uk/parameters/gov/economic_assumptions/yoy_growth.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -713,19 +713,22 @@ obr:
href: https://obr.uk/efo/economic-and-fiscal-outlook-march-2026/

# Receipts used to project the statistics behind corporate incidence.
# Each is the OBR's growth in a receipts line: 2024 is outturn growth
# (2024-25 outturn in the March 2026 EFO over 2023-24 outturn in the March
# 2025 EFO), 2025-2030 the March 2026 EFO forecast, and 2031 onwards the
# average_earnings long-run path (the OBR forecasts receipts only to
# 2030-31). Values are ratios of the published levels, to six decimals.
# The 2024 value never enters a projection: indices start at 1.0 in a
# series' first year, so it only anchors the index at 2024, where the
# Each is the OBR's growth in a receipts line, the ratio of consecutive
# published levels to six decimals. The latest EFO supplies outturn growth
# for its outturn year (its outturn over the previous year's outturn in an
# earlier EFO) and growth for each forecast year. After the OBR's receipts
# forecast, each series follows the average_earnings long-run path. The
# comments in each series name the EFOs and tables behind its values.
# policyengine_uk/utils/import_obr_forecasts.py rewrites these series from
# a new EFO's receipts tables and keeps the years before its outturn year.
# The first value, 2024, never enters a projection: indices start at 1.0
# in a series' first year, so it only anchors the index at 2024, where the
# statistics with 2024-25 as their latest outturn are uprated from.
stamp_duty_land_tax:
residential:
description: Growth in stamp duty land tax receipts from residential property (England and Northern Ireland).
values:
# Outturn (2024-25 over 2023-24), Table 3.7 "SDLT from residential property"
# Outturn (2024-25 over 2023-24) from OBR EFO March 2026 over March 2025, receipts Table 3.7 "SDLT from residential property"
2024-01-01: 0.211202
# Forecast (2025-2030) from OBR EFO March 2026, receipts Table 3.7
2025-01-01: 0.1302
Expand All @@ -752,7 +755,7 @@ obr:
non_residential:
description: Growth in stamp duty land tax receipts from non-residential property (England and Northern Ireland).
values:
# Outturn (2024-25 over 2023-24), Table 3.7 "SDLT from non-residential property"
# Outturn (2024-25 over 2023-24) from OBR EFO March 2026 over March 2025, receipts Table 3.7 "SDLT from non-residential property"
2024-01-01: 0.151067
# Forecast (2025-2030) from OBR EFO March 2026, receipts Table 3.7
2025-01-01: 0.048515
Expand Down Expand Up @@ -780,7 +783,7 @@ obr:
great_britain:
description: Growth in business rates receipts in England, Scotland and Wales (the OBR "Business rates" line, cash basis).
values:
# Outturn (2024-25 over 2023-24), Table 3.8 (March 2025: Table 3.9) "Business rates"
# Outturn (2024-25 over 2023-24) from OBR EFO March 2026 over March 2025, receipts Table 3.8 (March 2025: Table 3.9) "Business rates"
2024-01-01: 0.093818
# Forecast (2025-2030) from OBR EFO March 2026, receipts Table 3.8
2025-01-01: 0.051739
Expand All @@ -807,7 +810,7 @@ obr:
northern_ireland:
description: Growth in Northern Ireland business rates receipts (the OBR "Northern Ireland business rates" line in other taxes).
values:
# Outturn (2024-25 over 2023-24), Table 3.2 "Northern Ireland business rates"
# Outturn (2024-25 over 2023-24) from OBR EFO March 2026 over March 2025, receipts Table 3.2 "Northern Ireland business rates"
2024-01-01: 0.032513
# Forecast (2025-2030) from OBR EFO March 2026, receipts Table 3.2
2025-01-01: 0.032388
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ revenue:
- title: MHCLG, National non-domestic rates collected by councils in England 2025 to 2026, Table 1 "Non-domestic rating income from rates retention scheme" (2021-22 to 2025-26; 2025-26 provisional)
href: https://www.gov.uk/government/statistics/national-non-domestic-rates-collected-by-councils-in-england-2025-to-2026
- title: MHCLG, NNDR3 2019 to 2020 local authority data, November 2025 update, Datasheet1 "nndrincome", England
href: https://www.gov.uk/government/statistics/national-non-domestic-rates-collected-by-councils-in-england-2019-to-2020
href: https://www.gov.uk/government/statistics/national-non-domestic-rates-collected-by-councils-in-england-2019-to-2020-provisional-data
- title: MHCLG, NNDR3 2020 to 2021 consolidated data, November 2025 update, "nndrincome", England
href: https://www.gov.uk/government/statistics/national-non-domestic-rates-collected-by-councils-in-england-2020-to-2021
ENGLAND_CENTRAL_LIST:
Expand Down
22 changes: 22 additions & 0 deletions policyengine_uk/tests/fixtures/obr_receipts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Real OBR receipts table fixtures

These parser fixtures retain the original worksheet XML for Contents, Other
taxes (3.2), Property transactions taxes: receipts by sector (3.7), and Current
receipts (on a cash basis: 3.9 in 2025, 3.8 in 2026), plus the original shared
strings. Only the workbook's sheet list and relationships were reduced to those
entries. The published unit cells, fiscal-year headers, markers, row labels and
numeric cells are unchanged. These are minimal archives for the importer's XLSX
reader, rather than complete Excel documents with styles and charts.

Sources: OBR [March 2025 EFO](https://obr.uk/efo/economic-and-fiscal-outlook-march-2025/)
and [March 2026 EFO](https://obr.uk/efo/economic-and-fiscal-outlook-march-2026/),
receipts detailed forecast tables. The original files used for extraction are
`obr_efo_march_2025_receipts.xlsx` and `obr_efo_march_2026_receipts.xlsx`.
Their SHA-256 hashes are:

- March 2025: `6b20e05e93c50e3ccae1d3111fd84b8fa326b75c38c8ab055fad694648c75905`
- March 2026: `f65b6cb7f96931d4abd85940794eb60f6f65afca8bbf16c74a4548bf92766a28`

Tests mutate the unit cell and selected receipt levels inside these real tables;
the unchanged control must reproduce the committed YAML byte for byte. No test
downloads a workbook or depends on a developer's local source directory.
Binary file not shown.
Binary file not shown.
Loading
Loading