From c73d20d51fe87c3c817bce3b842b5574c54e7617 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Wed, 20 May 2026 10:01:08 -0400 Subject: [PATCH] Use road fuel volumes for fuel spending uprating --- changelog.d/fuel-volume-uprating.md | 1 + docs/book/assumptions/growthfactors.md | 12 +++- policyengine_uk/data/uprating_indices.yaml | 5 +- .../gov/economic_assumptions/yoy_growth.yaml | 71 +++++++++++++++++++ .../tests/test_road_fuel_volume_uprating.py | 57 +++++++++++++++ .../input/consumption/diesel_spending.py | 2 +- .../input/consumption/petrol_spending.py | 2 +- 7 files changed, 145 insertions(+), 5 deletions(-) create mode 100644 changelog.d/fuel-volume-uprating.md create mode 100644 policyengine_uk/tests/test_road_fuel_volume_uprating.py diff --git a/changelog.d/fuel-volume-uprating.md b/changelog.d/fuel-volume-uprating.md new file mode 100644 index 000000000..45b40278e --- /dev/null +++ b/changelog.d/fuel-volume-uprating.md @@ -0,0 +1 @@ +- Uprate petrol and diesel spending with HMRC/OBR road-fuel volume growth rather than CPI when projecting single-year datasets. diff --git a/docs/book/assumptions/growthfactors.md b/docs/book/assumptions/growthfactors.md index 81c17f738..746f3a1da 100644 --- a/docs/book/assumptions/growthfactors.md +++ b/docs/book/assumptions/growthfactors.md @@ -17,7 +17,17 @@ We use the OBR's CPI projections to drive most benefit and consumption variables We apply CPI to these variables: - All reported benefits– `carers_allowance_reported`, `child_benefit_reported`, `child_tax_credit_reported`, `esa_contrib_reported`, `esa_income_reported`, `housing_benefit_reported`, `iidb_reported`, `incapacity_benefit_reported`, `income_support_reported`, `jsa_contrib_reported`, `jsa_income_reported`, `maternity_allowance_reported`, `pension_credit_reported`, `sda_reported`, `state_pension_reported`, `universal_credit_reported`, `winter_fuel_allowance_reported`, `working_tax_credit_reported` - All consumption categories– `alcohol_and_tobacco_consumption`, `clothing_and_footwear_consumption`, `communication_consumption`, `domestic_energy_consumption`, `education_consumption`, `food_and_non_alcoholic_beverages_consumption`, `health_consumption`, `household_furnishings_consumption`, `housing_water_and_electricity_consumption`, `miscellaneous_consumption`, `recreation_consumption`, `restaurants_and_hotels_consumption`, `transport_consumption` -- Other variables– `afcs_reported`, `bsp_reported`, `childcare_expenses`, `diesel_spending`, `free_school_fruit_veg`, `free_school_meals`, `free_school_milk`, `maintenance_expenses`, `petrol_spending`, `statutory_maternity_pay`, `statutory_paternity_pay`, `statutory_sick_pay`, `state_pension` +- Other variables– `afcs_reported`, `bsp_reported`, `childcare_expenses`, `free_school_fruit_veg`, `free_school_meals`, `free_school_milk`, `maintenance_expenses`, `statutory_maternity_pay`, `statutory_paternity_pay`, `statutory_sick_pay`, `state_pension` + +## Road fuel volume + +We use HMRC road-fuel clearances and OBR-implied forecast volumes for petrol and diesel spending, because PolicyEngine converts these spending fields into litres by dividing by pump prices. + +| Fiscal year | 2022 | 2023 | 2024 | 2025 | 2026 | 2027 | 2028 | 2029 | +|-------------|------|------|------|------|------|------|------|------| +| Growth rate | 6.3% | -0.6% | -0.1% | -2.0% | -1.4% | -2.4% | -2.7% | -3.7% | + +We apply this to: `diesel_spending`, `petrol_spending` ## Average earnings diff --git a/policyengine_uk/data/uprating_indices.yaml b/policyengine_uk/data/uprating_indices.yaml index f7b197231..a8a0b887b 100644 --- a/policyengine_uk/data/uprating_indices.yaml +++ b/policyengine_uk/data/uprating_indices.yaml @@ -15,7 +15,6 @@ gov.economic_assumptions.yoy_growth.obr.consumer_price_index: - childcare_expenses - clothing_and_footwear_consumption - communication_consumption -- diesel_spending - domestic_energy_consumption - education_consumption - esa_contrib_reported @@ -37,7 +36,6 @@ gov.economic_assumptions.yoy_growth.obr.consumer_price_index: - maternity_allowance_reported - miscellaneous_consumption - pension_credit_reported -- petrol_spending - recreation_consumption - restaurants_and_hotels_consumption - sda_reported @@ -50,6 +48,9 @@ gov.economic_assumptions.yoy_growth.obr.consumer_price_index: - universal_credit_reported - winter_fuel_allowance_reported - working_tax_credit_reported +gov.economic_assumptions.yoy_growth.obr.road_fuel_volume: +- diesel_spending +- petrol_spending gov.economic_assumptions.yoy_growth.obr.mortgage_interest: - mortgage_interest_repayment gov.economic_assumptions.yoy_growth.obr.per_capita.gdp: diff --git a/policyengine_uk/parameters/gov/economic_assumptions/yoy_growth.yaml b/policyengine_uk/parameters/gov/economic_assumptions/yoy_growth.yaml index 210ebb20a..459c9ba4a 100644 --- a/policyengine_uk/parameters/gov/economic_assumptions/yoy_growth.yaml +++ b/policyengine_uk/parameters/gov/economic_assumptions/yoy_growth.yaml @@ -251,6 +251,77 @@ obr: - title: Bank of England inflation target (2031+ assumes 2% target) href: https://www.bankofengland.co.uk/monetary-policy/inflation + road_fuel_volume: + description: UK road-fuel petrol and diesel clearances year-on-year growth. + values: + # HMRC Hydrocarbon Oils Bulletin Table 2a: petrol plus diesel clearances. + 2021-01-01: 0.24418262350052777 + 2022-01-01: 0.06256523245735934 + 2023-01-01: -0.005727524527185501 + 2024-01-01: -0.0012858149728238732 + # OBR March 2026 fuel-duty receipts forecast, net of non-road fuel + # receipts, divided by fiscal-year average petrol/diesel duty rates. + 2025-01-01: -0.019907019324541197 + 2026-01-01: -0.01438967286340953 + 2027-01-01: -0.02416859220902523 + 2028-01-01: -0.02700230120226388 + 2029-01-01: -0.037280775640417985 + 2030-01-01: -0.052236910509542045 + # Hold the final OBR forecast volume flat after 2030-31. + 2031-01-01: 0.0 + 2032-01-01: 0.0 + 2033-01-01: 0.0 + 2034-01-01: 0.0 + 2035-01-01: 0.0 + 2036-01-01: 0.0 + 2037-01-01: 0.0 + 2038-01-01: 0.0 + 2039-01-01: 0.0 + 2040-01-01: 0.0 + 2041-01-01: 0.0 + 2042-01-01: 0.0 + 2043-01-01: 0.0 + 2044-01-01: 0.0 + 2045-01-01: 0.0 + 2046-01-01: 0.0 + 2047-01-01: 0.0 + 2048-01-01: 0.0 + 2049-01-01: 0.0 + 2050-01-01: 0.0 + 2051-01-01: 0.0 + 2052-01-01: 0.0 + 2053-01-01: 0.0 + 2054-01-01: 0.0 + 2055-01-01: 0.0 + 2056-01-01: 0.0 + 2057-01-01: 0.0 + 2058-01-01: 0.0 + 2059-01-01: 0.0 + 2060-01-01: 0.0 + 2061-01-01: 0.0 + 2062-01-01: 0.0 + 2063-01-01: 0.0 + 2064-01-01: 0.0 + 2065-01-01: 0.0 + 2066-01-01: 0.0 + 2067-01-01: 0.0 + 2068-01-01: 0.0 + 2069-01-01: 0.0 + 2070-01-01: 0.0 + 2071-01-01: 0.0 + 2072-01-01: 0.0 + 2073-01-01: 0.0 + metadata: + unit: /1 + label: Road fuel volume growth + reference: + - title: HMRC Hydrocarbon Oils Bulletin + href: https://www.gov.uk/government/statistics/hydrocarbon-oils-bulletin + - title: OBR EFO March 2026 (fuel-duty receipts forecast) + href: https://obr.uk/efo/economic-and-fiscal-outlook-march-2026/ + - title: OBR fuel-duty supplementary release, receipts by vehicle type + href: https://obr.uk/docs/dlm_uploads/Fuel-duty-supplementary-release_receipts-by-vehicle-type.pdf + consumer_price_index_ahc: description: Consumer price index year-on-year growth, modified to remove housing costs. values: diff --git a/policyengine_uk/tests/test_road_fuel_volume_uprating.py b/policyengine_uk/tests/test_road_fuel_volume_uprating.py new file mode 100644 index 000000000..04d877ccf --- /dev/null +++ b/policyengine_uk/tests/test_road_fuel_volume_uprating.py @@ -0,0 +1,57 @@ +import pandas as pd +import pytest + +from policyengine_uk.data.dataset_schema import UKSingleYearDataset +from policyengine_uk.data.economic_assumptions import extend_single_year_dataset +from policyengine_uk.system import system + + +def test_petrol_and_diesel_spending_use_road_fuel_volume_not_cpi(): + parameters = system.parameters + road_fuel_volume = ( + parameters.gov.economic_assumptions.yoy_growth.obr.road_fuel_volume + ) + cpi = parameters.gov.economic_assumptions.yoy_growth.obr.consumer_price_index + + assert road_fuel_volume(2027) < 0 + assert cpi(2027) > 0 + + dataset = UKSingleYearDataset( + person=pd.DataFrame( + { + "person_id": [1], + "person_benunit_id": [1], + "person_household_id": [1], + "age": [40], + } + ), + benunit=pd.DataFrame({"benunit_id": [1]}), + household=pd.DataFrame( + { + "household_id": [1], + "region": ["LONDON"], + "tenure_type": ["OWNED_OUTRIGHT"], + "council_tax": [1_500.0], + "rent": [0.0], + "petrol_spending": [1_000.0], + "diesel_spending": [2_000.0], + } + ), + fiscal_year=2026, + ) + + extended = extend_single_year_dataset( + dataset, + tax_benefit_system_parameters=parameters, + end_year=2027, + ) + household_2027 = extended[2027].household + + assert household_2027["petrol_spending"].iloc[0] == pytest.approx( + 1_000 * (1 + road_fuel_volume(2027)) + ) + assert household_2027["diesel_spending"].iloc[0] == pytest.approx( + 2_000 * (1 + road_fuel_volume(2027)) + ) + assert household_2027["petrol_spending"].iloc[0] < 1_000 + assert household_2027["diesel_spending"].iloc[0] < 2_000 diff --git a/policyengine_uk/variables/input/consumption/diesel_spending.py b/policyengine_uk/variables/input/consumption/diesel_spending.py index ea3756b45..e4b816840 100644 --- a/policyengine_uk/variables/input/consumption/diesel_spending.py +++ b/policyengine_uk/variables/input/consumption/diesel_spending.py @@ -10,4 +10,4 @@ class diesel_spending(Variable): value_type = float unit = GBP quantity_type = FLOW - uprating = "gov.economic_assumptions.indices.obr.consumer_price_index" + uprating = "gov.economic_assumptions.indices.obr.road_fuel_volume" diff --git a/policyengine_uk/variables/input/consumption/petrol_spending.py b/policyengine_uk/variables/input/consumption/petrol_spending.py index 49debd62f..bd099183e 100644 --- a/policyengine_uk/variables/input/consumption/petrol_spending.py +++ b/policyengine_uk/variables/input/consumption/petrol_spending.py @@ -10,4 +10,4 @@ class petrol_spending(Variable): value_type = float unit = GBP quantity_type = FLOW - uprating = "gov.economic_assumptions.indices.obr.consumer_price_index" + uprating = "gov.economic_assumptions.indices.obr.road_fuel_volume"