policyengine-uk 2.40.1__py3-none-any.whl → 2.65.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- policyengine_uk/__init__.py +5 -3
- policyengine_uk/data/__init__.py +1 -0
- policyengine_uk/data/dataset_schema.py +70 -18
- policyengine_uk/data/economic_assumptions.py +36 -10
- policyengine_uk/data/filter_dataset.py +52 -0
- policyengine_uk/dynamics/labour_supply.py +343 -0
- policyengine_uk/dynamics/participation.py +629 -0
- policyengine_uk/dynamics/progression.py +384 -0
- policyengine_uk/microsimulation.py +105 -0
- policyengine_uk/model_api.py +1 -0
- policyengine_uk/parameters/gov/boe/base_rate.yaml +34 -0
- policyengine_uk/parameters/gov/boe/index.yaml +2 -0
- policyengine_uk/parameters/gov/contrib/behavioral_responses/employee_salary_sacrifice_reduction_rate.yaml +14 -0
- policyengine_uk/parameters/gov/contrib/behavioral_responses/salary_sacrifice_broad_base_haircut_rate.yaml +22 -0
- policyengine_uk/parameters/gov/contrib/cec/state_pension_increase.yaml +1 -1
- policyengine_uk/parameters/gov/contrib/ubi_center/carbon_tax.yaml +2 -2
- policyengine_uk/parameters/gov/contrib/ubi_center/land_value_tax.yaml +3 -3
- policyengine_uk/parameters/gov/dcms/bbc/tv_licence/colour.yaml +5 -5
- policyengine_uk/parameters/gov/dfe/education_spending.yaml +1 -1
- policyengine_uk/parameters/gov/dft/rail/fare_index.yaml +32 -0
- policyengine_uk/parameters/gov/dft/rail/prior_law_fare_index.yaml +32 -0
- policyengine_uk/parameters/gov/dft/rail/ridership_index.yaml +30 -0
- policyengine_uk/parameters/gov/dft/spending.yaml +2 -2
- policyengine_uk/parameters/gov/dwp/ESA/income/earn_disregard.yaml +1 -1
- policyengine_uk/parameters/gov/dwp/ESA/income/income_disregard_couple.yaml +1 -1
- policyengine_uk/parameters/gov/dwp/ESA/income/income_disregard_lone_parent.yaml +1 -1
- policyengine_uk/parameters/gov/dwp/ESA/income/income_disregard_single.yaml +1 -1
- policyengine_uk/parameters/gov/dwp/ESA/income/pension_disregard.yaml +1 -1
- policyengine_uk/parameters/gov/dwp/IIDB/maximum.yaml +1 -1
- policyengine_uk/parameters/gov/dwp/JSA/contrib/amount_over_25.yaml +1 -1
- policyengine_uk/parameters/gov/dwp/JSA/contrib/earn_disregard.yaml +1 -1
- policyengine_uk/parameters/gov/dwp/JSA/contrib/pension_disregard.yaml +1 -1
- policyengine_uk/parameters/gov/dwp/JSA/income/amount_18_24.yaml +7 -7
- policyengine_uk/parameters/gov/dwp/JSA/income/amount_over_25.yaml +7 -7
- policyengine_uk/parameters/gov/dwp/JSA/income/income_disregard_couple.yaml +1 -1
- policyengine_uk/parameters/gov/dwp/JSA/income/income_disregard_lone_parent.yaml +1 -1
- policyengine_uk/parameters/gov/dwp/JSA/income/income_disregard_single.yaml +1 -1
- policyengine_uk/parameters/gov/dwp/LHA/shared_accommodation_age_threshold.yaml +12 -0
- policyengine_uk/parameters/gov/dwp/attendance_allowance/higher.yaml +7 -7
- policyengine_uk/parameters/gov/dwp/attendance_allowance/lower.yaml +7 -7
- policyengine_uk/parameters/gov/dwp/benefit_cap.yaml +3 -3
- policyengine_uk/parameters/gov/dwp/carer_premium/couple.yaml +2 -2
- policyengine_uk/parameters/gov/dwp/carer_premium/single.yaml +6 -6
- policyengine_uk/parameters/gov/dwp/carers_allowance/rate.yaml +7 -7
- policyengine_uk/parameters/gov/dwp/disability_premia/disability_couple.yaml +1 -1
- policyengine_uk/parameters/gov/dwp/disability_premia/enhanced_couple.yaml +1 -1
- policyengine_uk/parameters/gov/dwp/disability_premia/enhanced_single.yaml +1 -1
- policyengine_uk/parameters/gov/dwp/disability_premia/severe_couple.yaml +1 -1
- policyengine_uk/parameters/gov/dwp/dla/mobility/higher.yaml +4 -4
- policyengine_uk/parameters/gov/dwp/dla/mobility/lower.yaml +8 -8
- policyengine_uk/parameters/gov/dwp/dla/self_care/higher.yaml +7 -7
- policyengine_uk/parameters/gov/dwp/dla/self_care/lower.yaml +8 -8
- policyengine_uk/parameters/gov/dwp/dla/self_care/middle.yaml +7 -7
- policyengine_uk/parameters/gov/dwp/housing_benefit/allowances/lone_parent/aged.yaml +1 -1
- policyengine_uk/parameters/gov/dwp/housing_benefit/allowances/lone_parent/older.yaml +3 -3
- policyengine_uk/parameters/gov/dwp/housing_benefit/allowances/single/aged.yaml +1 -1
- policyengine_uk/parameters/gov/dwp/housing_benefit/allowances/single/older.yaml +3 -3
- policyengine_uk/parameters/gov/dwp/housing_benefit/means_test/income_disregard/worker.yaml +1 -1
- policyengine_uk/parameters/gov/dwp/housing_benefit/non_dep_deduction/amount.yaml +1 -1
- policyengine_uk/parameters/gov/dwp/housing_benefit/takeup.yaml +7 -7
- policyengine_uk/parameters/gov/dwp/income_support/amounts/amount_16_24.yaml +1 -1
- policyengine_uk/parameters/gov/dwp/income_support/amounts/amount_couples_over_18.yaml +1 -1
- policyengine_uk/parameters/gov/dwp/income_support/means_test/earn_disregard.yaml +1 -1
- policyengine_uk/parameters/gov/dwp/income_support/means_test/income_disregard_couple.yaml +1 -1
- policyengine_uk/parameters/gov/dwp/income_support/means_test/income_disregard_lone_parent.yaml +1 -1
- policyengine_uk/parameters/gov/dwp/income_support/means_test/income_disregard_single.yaml +1 -1
- policyengine_uk/parameters/gov/dwp/income_support/means_test/pension_disregard.yaml +1 -1
- policyengine_uk/parameters/gov/dwp/income_support/takeup.yaml +7 -7
- policyengine_uk/parameters/gov/dwp/pension_credit/guarantee_credit/carer/addition.yaml +4 -4
- policyengine_uk/parameters/gov/dwp/pension_credit/guarantee_credit/minimum_guarantee.yaml +9 -9
- policyengine_uk/parameters/gov/dwp/pension_credit/guarantee_credit/severe_disability/addition.yaml +3 -3
- policyengine_uk/parameters/gov/dwp/pension_credit/savings_credit/threshold.yaml +5 -5
- policyengine_uk/parameters/gov/dwp/pip/daily_living/enhanced.yaml +7 -7
- policyengine_uk/parameters/gov/dwp/pip/daily_living/standard.yaml +8 -8
- policyengine_uk/parameters/gov/dwp/pip/mobility/enhanced.yaml +4 -4
- policyengine_uk/parameters/gov/dwp/pip/mobility/standard.yaml +9 -9
- policyengine_uk/parameters/gov/dwp/sda/maximum.yaml +7 -7
- policyengine_uk/parameters/gov/dwp/state_pension/basic_state_pension/amount.yaml +11 -11
- policyengine_uk/parameters/gov/dwp/state_pension/new_state_pension/amount.yaml +4 -4
- policyengine_uk/parameters/gov/dwp/tax_credits/child_tax_credit/limit/child_count.yaml +10 -1
- policyengine_uk/parameters/gov/dwp/tax_credits/child_tax_credit/takeup.yaml +7 -7
- policyengine_uk/parameters/gov/dwp/tax_credits/working_tax_credit/takeup.yaml +7 -7
- policyengine_uk/parameters/gov/dwp/universal_credit/elements/carer/amount.yaml +3 -3
- policyengine_uk/parameters/gov/dwp/universal_credit/elements/child/amount.yaml +2 -4
- policyengine_uk/parameters/gov/dwp/universal_credit/elements/child/disabled/amount.yaml +2 -4
- policyengine_uk/parameters/gov/dwp/universal_credit/elements/child/first/higher_amount.yaml +6 -8
- policyengine_uk/parameters/gov/dwp/universal_credit/elements/child/limit/child_count.yaml +6 -1
- policyengine_uk/parameters/gov/dwp/universal_credit/elements/child/severely_disabled/amount.yaml +3 -5
- policyengine_uk/parameters/gov/dwp/universal_credit/elements/childcare/cap.yaml +2 -6
- policyengine_uk/parameters/gov/dwp/universal_credit/elements/disabled/amount.yaml +4 -6
- policyengine_uk/parameters/gov/dwp/universal_credit/elements/housing/non_dep_deduction/amount.yaml +4 -1
- policyengine_uk/parameters/gov/dwp/universal_credit/rebalancing/active.yaml +9 -0
- policyengine_uk/parameters/gov/dwp/universal_credit/rebalancing/new_claimant_health_element.yaml +9 -0
- policyengine_uk/parameters/gov/dwp/universal_credit/rebalancing/standard_allowance_uplift.yaml +13 -0
- policyengine_uk/parameters/gov/dwp/universal_credit/standard_allowance/amount.yaml +5 -5
- policyengine_uk/parameters/gov/dwp/winter_fuel_payment/eligibility/taxable_income_test/maximum_taxable_income.yaml +2 -1
- policyengine_uk/parameters/gov/dwp/winter_fuel_payment/eligibility/taxable_income_test/use_maximum_taxable_income.yaml +1 -0
- policyengine_uk/parameters/gov/dynamic/obr_labour_supply_assumptions.yaml +9 -0
- policyengine_uk/parameters/gov/economic_assumptions/create_economic_assumption_indices.py +1 -1
- policyengine_uk/parameters/gov/economic_assumptions/yoy_growth.yaml +522 -153
- policyengine_uk/parameters/gov/hmrc/cgt/additional_rate.yaml +5 -0
- policyengine_uk/parameters/gov/hmrc/cgt/basic_rate.yaml +5 -0
- policyengine_uk/parameters/gov/hmrc/cgt/higher_rate.yaml +4 -0
- policyengine_uk/parameters/gov/hmrc/child_benefit/amount/additional.yaml +6 -6
- policyengine_uk/parameters/gov/hmrc/child_benefit/amount/eldest.yaml +8 -8
- policyengine_uk/parameters/gov/hmrc/child_benefit/takeup/by_age.yaml +1 -1
- policyengine_uk/parameters/gov/hmrc/fuel_duty/calculate_fuel_duty_rates.py +464 -0
- policyengine_uk/parameters/gov/hmrc/fuel_duty/petrol_and_diesel.yaml +86 -10
- policyengine_uk/parameters/gov/hmrc/income_tax/allowances/personal_allowance/amount.yaml +6 -0
- policyengine_uk/parameters/gov/hmrc/income_tax/earned_taxable_income_exclusions.yaml +2 -1
- policyengine_uk/parameters/gov/hmrc/income_tax/income_tax_additions.yaml +1 -0
- policyengine_uk/parameters/gov/hmrc/income_tax/rates/dividends.yaml +12 -0
- policyengine_uk/parameters/gov/hmrc/income_tax/rates/property.yaml +46 -0
- policyengine_uk/parameters/gov/hmrc/income_tax/rates/savings.yaml +46 -0
- policyengine_uk/parameters/gov/hmrc/income_tax/rates/scotland/rates.yaml +2 -2
- policyengine_uk/parameters/gov/hmrc/income_tax/rates/uk.yaml +14 -2
- policyengine_uk/parameters/gov/hmrc/national_insurance/class_1/rates/employee/additional.yaml +4 -6
- policyengine_uk/parameters/gov/hmrc/national_insurance/class_1/rates/employer.yaml +3 -3
- policyengine_uk/parameters/gov/hmrc/national_insurance/class_1/thresholds/secondary_threshold.yaml +14 -4
- policyengine_uk/parameters/gov/hmrc/national_insurance/class_2/flat_rate.yaml +2 -2
- policyengine_uk/parameters/gov/hmrc/national_insurance/salary_sacrifice_pension_cap.yaml +16 -0
- policyengine_uk/parameters/gov/hmrc/student_loans/interest_rates/index.yaml +12 -0
- policyengine_uk/parameters/gov/hmrc/student_loans/interest_rates/plan_1/boe_margin.yaml +11 -0
- policyengine_uk/parameters/gov/hmrc/student_loans/interest_rates/plan_2/additional_rate.yaml +27 -0
- policyengine_uk/parameters/gov/hmrc/student_loans/interest_rates/plan_2/index.yaml +16 -0
- policyengine_uk/parameters/gov/hmrc/student_loans/interest_rates/plan_2/upper_threshold.yaml +48 -0
- policyengine_uk/parameters/gov/hmrc/student_loans/interest_rates/postgraduate_additional_rate.yaml +11 -0
- policyengine_uk/parameters/gov/hmrc/student_loans/postgraduate_repayment_rate.yaml +9 -0
- policyengine_uk/parameters/gov/hmrc/student_loans/repayment_rate.yaml +9 -0
- policyengine_uk/parameters/gov/hmrc/student_loans/thresholds/plan_1.yaml +25 -0
- policyengine_uk/parameters/gov/hmrc/student_loans/thresholds/plan_2.yaml +58 -0
- policyengine_uk/parameters/gov/hmrc/student_loans/thresholds/plan_4.yaml +19 -0
- policyengine_uk/parameters/gov/hmrc/student_loans/thresholds/plan_5.yaml +16 -0
- policyengine_uk/parameters/gov/hmrc/student_loans/thresholds/postgraduate.yaml +21 -0
- policyengine_uk/parameters/gov/hmrc/vat/reduced_rate_share.yaml +3 -3
- policyengine_uk/parameters/gov/indices/private_rent_index.yaml +9 -9
- policyengine_uk/parameters/gov/revenue_scotland/lbtt/non_residential.yaml +2 -2
- policyengine_uk/parameters/gov/revenue_scotland/lbtt/rent.yaml +2 -2
- policyengine_uk/parameters/gov/revenue_scotland/lbtt/residential/first_time_buyer_rate.yaml +2 -2
- policyengine_uk/parameters/gov/revenue_scotland/lbtt/residential/rate.yaml +2 -2
- policyengine_uk/parameters/gov/wra/land_transaction_tax/non_residential.yaml +2 -2
- policyengine_uk/parameters/gov/wra/land_transaction_tax/rent.yaml +2 -2
- policyengine_uk/parameters/gov/wra/land_transaction_tax/residential/higher_rate.yaml +1 -1
- policyengine_uk/parameters/gov/wra/land_transaction_tax/residential/primary.yaml +2 -2
- policyengine_uk/parameters/household/consumption/carbon/consumption.yaml +8 -6
- policyengine_uk/parameters/household/consumption/carbon/intensity.yaml +4 -1
- policyengine_uk/parameters/household/consumption/carbon/production.yaml +12 -7
- policyengine_uk/parameters/household/consumption/carbon/production_by_source.yaml +76 -41
- policyengine_uk/parameters/household/consumption/fuel/prices/petrol.yaml +1 -1
- policyengine_uk/parameters/household/poverty/absolute_poverty_threshold_bhc.yaml +1 -1
- policyengine_uk/reforms/policyengine/adjust_budgets.py +0 -1
- policyengine_uk/scenarios/__init__.py +4 -0
- policyengine_uk/scenarios/pip_reform.py +23 -0
- policyengine_uk/scenarios/reindex_benefit_cap.py +32 -0
- policyengine_uk/scenarios/repeal_two_child_limit.py +10 -0
- policyengine_uk/scenarios/uc_reform.py +50 -0
- policyengine_uk/simulation.py +619 -0
- policyengine_uk/system.py +3 -257
- policyengine_uk/tax_benefit_system.py +141 -0
- policyengine_uk/tests/behavioral_responses/test_labor_supply_responses.yaml +183 -0
- policyengine_uk/tests/microsimulation/reforms_config.yaml +8 -8
- policyengine_uk/tests/microsimulation/test_reform_impacts.py +2 -2
- policyengine_uk/tests/microsimulation/test_salary_sacrifice_cap_reform.py +401 -0
- policyengine_uk/tests/microsimulation/test_validity.py +2 -3
- policyengine_uk/tests/microsimulation/update_reform_impacts.py +104 -40
- policyengine_uk/tests/policy/baseline/contrib/policyengine/employer_ni/employer_ni_fixed_employer_cost_change.yaml +105 -0
- policyengine_uk/tests/policy/baseline/finance/benefit/family/child_benefit.yaml +2 -0
- policyengine_uk/tests/policy/baseline/finance/benefit/family/income_support.yaml +0 -23
- policyengine_uk/tests/policy/baseline/gov/dcms/bbc/tv-licence/tv_licence.yaml +3 -0
- policyengine_uk/tests/policy/baseline/gov/dfe/extended_childcare_entitlement/extended_childcare_entitlement.yaml +17 -17
- policyengine_uk/tests/policy/baseline/gov/dwp/basic_state_pension.yaml +44 -0
- policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/allowances/gift_aid.yaml +71 -0
- policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/allowances/personal_allowance.yaml +161 -0
- policyengine_uk/tests/policy/baseline/gov/hmrc/national_insurance/salary_sacrifice_pension_ni_employee.yaml +107 -0
- policyengine_uk/tests/policy/baseline/gov/hmrc/national_insurance/salary_sacrifice_pension_ni_employer.yaml +95 -0
- policyengine_uk/tests/policy/baseline/gov/hmrc/student_loans/student_loan_interest_rate.yaml +153 -0
- policyengine_uk/tests/policy/baseline/gov/hmrc/student_loans/student_loan_repayment.yaml +130 -0
- policyengine_uk/tests/policy/baseline/household/wealth/vehicle.yaml +27 -0
- policyengine_uk/tests/policy/reforms/nov_2025_budget/income_source_tax_rates.yaml +235 -0
- policyengine_uk/tests/policy/reforms/nov_2025_budget/income_tax_freeze.yaml +83 -0
- policyengine_uk/tests/policy/reforms/parametric/basic_income/basic_income.yaml +1 -0
- policyengine_uk/tests/test_behavioral_responses.py +215 -0
- policyengine_uk/tests/test_fiscal_year_parameters.py +131 -0
- policyengine_uk/utils/__init__.py +1 -0
- policyengine_uk/utils/compare.py +28 -0
- policyengine_uk/utils/create_ahc_deflator.py +169 -0
- policyengine_uk/utils/create_triple_lock.py +1 -1
- policyengine_uk/utils/dependencies.py +259 -0
- policyengine_uk/utils/parameters.py +12 -1
- policyengine_uk/utils/scenario.py +225 -0
- policyengine_uk/utils/solve_private_school_attendance_factor.py +4 -6
- policyengine_uk/variables/contrib/policyengine/education_budget_change.py +0 -1
- policyengine_uk/variables/contrib/policyengine/employer_ni/baseline_employer_cost.py +5 -1
- policyengine_uk/variables/contrib/policyengine/employer_ni/employer_ni_fixed_employer_cost_change.py +23 -23
- policyengine_uk/variables/contrib/policyengine/employer_ni/employer_ni_response_capital_incidence.py +1 -1
- policyengine_uk/variables/contrib/policyengine/employer_ni/employer_ni_response_consumer_incidence.py +1 -1
- policyengine_uk/variables/contrib/policyengine/other_public_spending_budget_change.py +0 -1
- policyengine_uk/variables/gov/dfe/targeted_childcare_entitlement/targeted_childcare_entitlement_eligible.py +0 -1
- policyengine_uk/variables/gov/dft/rail_subsidy_spending.py +16 -1
- policyengine_uk/variables/gov/dft/rail_usage.py +16 -0
- policyengine_uk/variables/gov/dwp/BRMA_LHA_rate.py +7 -2
- policyengine_uk/variables/gov/dwp/LHA_category.py +4 -2
- policyengine_uk/variables/gov/dwp/additional_state_pension.py +4 -2
- policyengine_uk/variables/gov/dwp/basic_state_pension.py +26 -8
- policyengine_uk/variables/gov/dwp/is_CTC_eligible.py +1 -1
- policyengine_uk/variables/gov/dwp/is_benefit_cap_exempt.py +9 -13
- policyengine_uk/variables/gov/dwp/is_benefit_cap_exempt_earnings.py +66 -0
- policyengine_uk/variables/gov/dwp/is_benefit_cap_exempt_health_disability.py +75 -0
- policyengine_uk/variables/gov/dwp/is_benefit_cap_exempt_other.py +66 -0
- policyengine_uk/variables/gov/dwp/winter_fuel_allowance.py +5 -4
- policyengine_uk/variables/gov/gov_tax.py +0 -2
- policyengine_uk/variables/gov/hmrc/household_tax.py +0 -1
- policyengine_uk/variables/gov/hmrc/income_tax/allowances/gift_aid.py +23 -0
- policyengine_uk/variables/gov/hmrc/income_tax/allowances/personal_allowance.py +9 -2
- policyengine_uk/variables/gov/hmrc/income_tax/income_tax_pre_charges.py +1 -0
- policyengine_uk/variables/gov/hmrc/income_tax/liability/property_income_tax.py +75 -0
- policyengine_uk/variables/gov/hmrc/income_tax/liability/savings_income_tax.py +4 -4
- policyengine_uk/variables/gov/hmrc/national_insurance/salary_sacrifice_broad_base_haircut.py +43 -0
- policyengine_uk/variables/gov/hmrc/national_insurance/salary_sacrifice_pension_ni_employee.py +38 -0
- policyengine_uk/variables/gov/hmrc/national_insurance/salary_sacrifice_pension_ni_employer.py +27 -0
- policyengine_uk/variables/gov/hmrc/pensions/pension_contributions_via_salary_sacrifice_adjusted.py +31 -0
- policyengine_uk/variables/gov/hmrc/pensions/salary_sacrifice_returned_to_income.py +41 -0
- policyengine_uk/variables/gov/hmrc/student_loans/__init__.py +2 -0
- policyengine_uk/variables/gov/hmrc/student_loans/plan_1_interest_rate.py +23 -0
- policyengine_uk/variables/gov/hmrc/student_loans/plan_2_interest_rate.py +31 -0
- policyengine_uk/variables/gov/hmrc/student_loans/plan_4_interest_rate.py +22 -0
- policyengine_uk/variables/gov/hmrc/student_loans/plan_5_interest_rate.py +18 -0
- policyengine_uk/variables/gov/hmrc/student_loans/postgraduate_interest_rate.py +23 -0
- policyengine_uk/variables/gov/hmrc/student_loans/student_loan_plan.py +27 -0
- policyengine_uk/variables/gov/hmrc/student_loans/student_loan_repayment.py +91 -0
- policyengine_uk/variables/gov/hmrc/student_loans/student_loan_repayment_rate.py +31 -0
- policyengine_uk/variables/gov/hmrc/would_claim_child_benefit.py +5 -1
- policyengine_uk/variables/household/demographic/benunit/benunit_count_adults.py +11 -0
- policyengine_uk/variables/household/demographic/is_disabled_for_benefits.py +13 -1
- policyengine_uk/variables/household/income/hbai_household_net_income.py +29 -1
- policyengine_uk/variables/household/income/hbai_household_net_income_ahc.py +13 -0
- policyengine_uk/variables/household/income/household_net_income.py +5 -1
- policyengine_uk/variables/household/income/inflation_adjustment.py +24 -0
- policyengine_uk/variables/household/post_tax_income.py +12 -0
- policyengine_uk/variables/household/wealth/num_vehicles.py +9 -0
- policyengine_uk/variables/household/wealth/owns_vehicle.py +17 -0
- policyengine_uk/variables/input/consumption/property/council_tax.py +0 -35
- policyengine_uk/variables/input/consumption/property/employee_pension_contributions.py +8 -1
- policyengine_uk/variables/input/consumption/property/employee_pension_contributions_reported.py +16 -0
- policyengine_uk/variables/input/consumption/property/pension_contributions_via_salary_sacrifice.py +16 -0
- policyengine_uk/variables/input/employment_income.py +2 -0
- policyengine_uk/variables/input/rent.py +0 -40
- policyengine_uk/variables/input/savings_interest_income.py +3 -1
- {policyengine_uk-2.40.1.dist-info → policyengine_uk-2.65.6.dist-info}/METADATA +17 -8
- {policyengine_uk-2.40.1.dist-info → policyengine_uk-2.65.6.dist-info}/RECORD +252 -173
- {policyengine_uk-2.40.1.dist-info → policyengine_uk-2.65.6.dist-info}/WHEEL +1 -1
- policyengine_uk/repo.py +0 -3
- policyengine_uk/tests/policy/baseline/gov/abolitions/abolition_parameters.yaml +0 -250
- policyengine_uk/variables/contrib/policyengine/high_income_incident_tax_change.py +0 -22
- policyengine_uk-2.40.1.data/data/share/openfisca/openfisca-country-template/CHANGELOG.md +0 -2285
- policyengine_uk-2.40.1.data/data/share/openfisca/openfisca-country-template/README.md +0 -37
- policyengine_uk-2.40.1.dist-info/licenses/LICENSE +0 -661
- {policyengine_uk-2.40.1.data/data/share/openfisca/openfisca-country-template → policyengine_uk-2.65.6.dist-info/licenses}/LICENSE +0 -0
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
description: Capital gains tax rate on additional rate taxpayers. This parameter is under active development and reforms including it should not be cited.
|
|
2
2
|
values:
|
|
3
3
|
2015-01-01: 0.2
|
|
4
|
+
2025-04-06: 0.24
|
|
4
5
|
metadata:
|
|
5
6
|
unit: /1
|
|
6
7
|
label: Capital Gains Tax additional rate
|
|
8
|
+
reference:
|
|
9
|
+
- title: Finance Act 2025(7)
|
|
10
|
+
href: https://www.legislation.gov.uk/ukpga/2025/8/section/7
|
|
11
|
+
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
description: Capital gains tax rate on basic rate taxpayers. This parameter is under active development and reforms including it should not be cited.
|
|
2
2
|
values:
|
|
3
3
|
2015-01-01: 0.1
|
|
4
|
+
2025-04-06: 0.18
|
|
4
5
|
metadata:
|
|
5
6
|
unit: /1
|
|
6
7
|
label: Capital Gains Tax basic rate
|
|
8
|
+
reference:
|
|
9
|
+
- title: Finance Act 2025(7)
|
|
10
|
+
href: https://www.legislation.gov.uk/ukpga/2025/8/section/7
|
|
11
|
+
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
description: Capital gains tax rate on higher rate taxpayers. This parameter is under active development and reforms including it should not be cited.
|
|
2
2
|
values:
|
|
3
3
|
2015-01-01: 0.2
|
|
4
|
+
2025-04-06: 0.24
|
|
4
5
|
metadata:
|
|
5
6
|
unit: /1
|
|
6
7
|
label: Capital Gains Tax higher rate
|
|
8
|
+
reference:
|
|
9
|
+
- title: Finance Act 2025(7)
|
|
10
|
+
href: https://www.legislation.gov.uk/ukpga/2025/8/section/7
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
description: Child Benefit amount for each additional child
|
|
2
2
|
values:
|
|
3
3
|
2007-04-09:
|
|
4
|
-
value: 12.
|
|
4
|
+
value: 12.1
|
|
5
5
|
# Legislation.gov.uk amends this amount to £12.55, but
|
|
6
6
|
# the amendment it references directs that it should be
|
|
7
7
|
# amended to £12.10. We use the original amendment.
|
|
@@ -9,12 +9,12 @@ values:
|
|
|
9
9
|
- title: The Child Benefit Up-rating Order 2007(2)(b)
|
|
10
10
|
href: https://www.legislation.gov.uk/uksi/2007/1053/article/2/made
|
|
11
11
|
2009-01-05:
|
|
12
|
-
value: 13.
|
|
12
|
+
value: 13.2
|
|
13
13
|
reference:
|
|
14
14
|
- title: The Child Benefit (Rates) (Amendment) Regulations 2008(3)(b)
|
|
15
15
|
href: https://www.legislation.gov.uk/uksi/2008/3246/regulation/3/made
|
|
16
16
|
2010-04-12:
|
|
17
|
-
value: 13.
|
|
17
|
+
value: 13.4
|
|
18
18
|
reference:
|
|
19
19
|
- title: The Child Benefit Up-rating Order 2010(2)(b)
|
|
20
20
|
href: https://www.legislation.gov.uk/uksi/2010/982/article/2/made
|
|
@@ -24,7 +24,7 @@ values:
|
|
|
24
24
|
- title: The Child Benefit and Tax Credits Up-rating Order 2014(2)(b)
|
|
25
25
|
href: https://www.legislation.gov.uk/uksi/2014/384/article/2/made
|
|
26
26
|
2015-04-06:
|
|
27
|
-
value: 13.
|
|
27
|
+
value: 13.7
|
|
28
28
|
reference:
|
|
29
29
|
- title: The Child Benefit and Tax Credits Up-rating Order 2015(2)(b)
|
|
30
30
|
href: https://www.legislation.gov.uk/uksi/2015/567/article/2/made
|
|
@@ -34,12 +34,12 @@ values:
|
|
|
34
34
|
- title: The Tax Credits, Child Benefit and Guardian’s Allowance Up-rating Regulations 2020(5)(b)
|
|
35
35
|
href: https://www.legislation.gov.uk/uksi/2020/298/regulation/5/made
|
|
36
36
|
2021-04-12:
|
|
37
|
-
value: 14
|
|
37
|
+
value: 14
|
|
38
38
|
reference:
|
|
39
39
|
- title: The Tax Credits, Child Benefit and Guardian’s Allowance Up-rating Regulations 2021(5)(b)
|
|
40
40
|
href: https://www.legislation.gov.uk/uksi/2021/156/regulation/5/made
|
|
41
41
|
2022-04-01: 14.45
|
|
42
|
-
2023-04-01: 15.
|
|
42
|
+
2023-04-01: 15.9
|
|
43
43
|
2024-04-01:
|
|
44
44
|
value: 16.95
|
|
45
45
|
reference:
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
description: Child Benefit amount for the eldest or only child
|
|
2
2
|
values:
|
|
3
3
|
2007-04-09:
|
|
4
|
-
value: 18.
|
|
4
|
+
value: 18.8
|
|
5
5
|
reference:
|
|
6
6
|
- title: The Child Benefit Up-rating Order 2007(2)(a)
|
|
7
7
|
href: https://www.legislation.gov.uk/uksi/2007/1053/article/2/made
|
|
8
8
|
2009-01-05:
|
|
9
|
-
value: 20
|
|
9
|
+
value: 20
|
|
10
10
|
reference:
|
|
11
11
|
- title: The Child Benefit (Rates) (Amendment) Regulations 2008(3)(a)
|
|
12
12
|
href: https://www.legislation.gov.uk/uksi/2008/3246/regulation/3/made
|
|
13
13
|
2010-04-12:
|
|
14
|
-
value: 20.
|
|
14
|
+
value: 20.3
|
|
15
15
|
reference:
|
|
16
16
|
- title: The Child Benefit Up-rating Order 2010(2)(a)
|
|
17
17
|
href: https://www.legislation.gov.uk/uksi/2010/982/article/2/made
|
|
18
18
|
2014-04-07:
|
|
19
|
-
value: 20.
|
|
19
|
+
value: 20.5
|
|
20
20
|
reference:
|
|
21
21
|
- title: The Child Benefit and Tax Credits Up-rating Order 2014(2)(a)
|
|
22
22
|
href: https://www.legislation.gov.uk/uksi/2014/384/article/2/made
|
|
23
23
|
2015-04-06:
|
|
24
|
-
value: 20.
|
|
24
|
+
value: 20.7
|
|
25
25
|
reference:
|
|
26
26
|
- title: The Child Benefit and Tax Credits Up-rating Order 2015(2)(a)
|
|
27
27
|
href: https://www.legislation.gov.uk/uksi/2015/567/article/2/made
|
|
@@ -35,10 +35,10 @@ values:
|
|
|
35
35
|
reference:
|
|
36
36
|
- title: The Tax Credits, Child Benefit and Guardian’s Allowance Up-rating Regulations 2021(5)(a)
|
|
37
37
|
href: https://www.legislation.gov.uk/uksi/2021/156/regulation/5/made
|
|
38
|
-
2022-04-01: 21.
|
|
39
|
-
2023-04-01: 24
|
|
38
|
+
2022-04-01: 21.8
|
|
39
|
+
2023-04-01: 24
|
|
40
40
|
2024-04-01:
|
|
41
|
-
value: 25.
|
|
41
|
+
value: 25.6
|
|
42
42
|
reference:
|
|
43
43
|
- title: Benefits Uprating 2024/25 | Commons Library Briefing
|
|
44
44
|
href: https://researchbriefings.files.parliament.uk/documents/CBP-9872/CBP-9872.pdf
|
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Calculates calendar year average fuel duty rates and updates petrol_and_diesel.yaml.
|
|
3
|
+
|
|
4
|
+
Reads base rates from petrol_and_diesel.yaml and RPI forecasts from yoy_growth.yaml,
|
|
5
|
+
then computes weighted averages accounting for the staggered 5p cut reversal and
|
|
6
|
+
RPI uprating from April 2027.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
python calculate_fuel_duty_rates.py # Print calculations only
|
|
10
|
+
python calculate_fuel_duty_rates.py --update # Update the YAML file
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import argparse
|
|
14
|
+
import re
|
|
15
|
+
from datetime import date
|
|
16
|
+
from calendar import isleap
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
import yaml
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# Years to calculate rates for
|
|
23
|
+
CALCULATION_YEARS = range(2026, 2031)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def get_repo_root() -> Path:
|
|
27
|
+
"""Find the repository root by looking for policyengine_uk directory."""
|
|
28
|
+
current = Path(__file__).resolve()
|
|
29
|
+
while current != current.parent:
|
|
30
|
+
if (current / "policyengine_uk").is_dir():
|
|
31
|
+
return current
|
|
32
|
+
current = current.parent
|
|
33
|
+
raise RuntimeError("Could not find repository root")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_fuel_duty_yaml_path() -> Path:
|
|
37
|
+
"""Get the path to the fuel duty YAML file."""
|
|
38
|
+
repo_root = get_repo_root()
|
|
39
|
+
return (
|
|
40
|
+
repo_root
|
|
41
|
+
/ "policyengine_uk/parameters/gov/hmrc/fuel_duty/petrol_and_diesel.yaml"
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def load_fuel_duty_rates() -> dict:
|
|
46
|
+
"""Load fuel duty rates from the YAML parameter file."""
|
|
47
|
+
yaml_path = get_fuel_duty_yaml_path()
|
|
48
|
+
with open(yaml_path) as f:
|
|
49
|
+
return yaml.safe_load(f)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def load_rpi_forecasts() -> dict:
|
|
53
|
+
"""Load RPI year-on-year growth forecasts from economic assumptions."""
|
|
54
|
+
repo_root = get_repo_root()
|
|
55
|
+
yaml_path = (
|
|
56
|
+
repo_root
|
|
57
|
+
/ "policyengine_uk/parameters/gov/economic_assumptions/yoy_growth.yaml"
|
|
58
|
+
)
|
|
59
|
+
with open(yaml_path) as f:
|
|
60
|
+
data = yaml.safe_load(f)
|
|
61
|
+
|
|
62
|
+
# Extract RPI values and convert to percentage format
|
|
63
|
+
rpi_values = data["obr"]["rpi"]["values"]
|
|
64
|
+
rpi_forecasts = {}
|
|
65
|
+
for date_key, value in rpi_values.items():
|
|
66
|
+
# Handle both string and datetime.date keys from YAML
|
|
67
|
+
if hasattr(date_key, "year"):
|
|
68
|
+
year = date_key.year
|
|
69
|
+
else:
|
|
70
|
+
year = int(str(date_key).split("-")[0])
|
|
71
|
+
# Convert from decimal (0.0371) to percentage (3.71)
|
|
72
|
+
rpi_forecasts[year] = value * 100
|
|
73
|
+
return rpi_forecasts
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def get_value_for_date(values: dict, target_date: str) -> float:
|
|
77
|
+
"""
|
|
78
|
+
Get the value for a specific date from a YAML values dict.
|
|
79
|
+
Handles both string and datetime.date keys.
|
|
80
|
+
"""
|
|
81
|
+
for date_key, value in values.items():
|
|
82
|
+
# Normalize date key to string for comparison
|
|
83
|
+
if hasattr(date_key, "strftime"):
|
|
84
|
+
key_str = date_key.strftime("%Y-%m-%d")
|
|
85
|
+
else:
|
|
86
|
+
key_str = str(date_key)
|
|
87
|
+
|
|
88
|
+
if key_str == target_date:
|
|
89
|
+
# Value might be a dict with 'value' key or a direct number
|
|
90
|
+
if isinstance(value, dict):
|
|
91
|
+
return value["value"]
|
|
92
|
+
return value
|
|
93
|
+
return None
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def get_base_rate_with_cut(fuel_duty_data: dict) -> float:
|
|
97
|
+
"""
|
|
98
|
+
Get the base fuel duty rate with the 5p cut still in place.
|
|
99
|
+
This is the rate at 2022-03-23 (when the 5p cut was introduced).
|
|
100
|
+
Returns rate in pence.
|
|
101
|
+
"""
|
|
102
|
+
values = fuel_duty_data["values"]
|
|
103
|
+
# The 5p cut rate is at 2022-03-23
|
|
104
|
+
rate = get_value_for_date(values, "2022-03-23")
|
|
105
|
+
if rate is None:
|
|
106
|
+
raise ValueError("Could not find 2022-03-23 fuel duty rate")
|
|
107
|
+
# Convert from GBP to pence
|
|
108
|
+
return rate * 100
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def get_pre_cut_rate(fuel_duty_data: dict) -> float:
|
|
112
|
+
"""
|
|
113
|
+
Get the fuel duty rate before the 5p cut (the rate to restore to).
|
|
114
|
+
This is the rate at 2021-01-01 (57.95p).
|
|
115
|
+
Returns rate in pence.
|
|
116
|
+
"""
|
|
117
|
+
values = fuel_duty_data["values"]
|
|
118
|
+
rate = get_value_for_date(values, "2021-01-01")
|
|
119
|
+
if rate is None:
|
|
120
|
+
raise ValueError("Could not find 2021-01-01 fuel duty rate")
|
|
121
|
+
return rate * 100
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
# Staggered reversal schedule (date, cumulative increase in pence)
|
|
125
|
+
REVERSAL_SCHEDULE = [
|
|
126
|
+
(date(2026, 9, 1), 1.0), # +1p
|
|
127
|
+
(date(2026, 12, 1), 3.0), # +2p more (total +3p)
|
|
128
|
+
(date(2027, 3, 1), 5.0), # +2p more (total +5p, full reversal)
|
|
129
|
+
]
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def get_rate_on_date(
|
|
133
|
+
d: date,
|
|
134
|
+
base_rate_with_cut: float,
|
|
135
|
+
pre_cut_rate: float,
|
|
136
|
+
rpi_forecasts: dict,
|
|
137
|
+
) -> float:
|
|
138
|
+
"""Get the fuel duty rate (in pence) on a specific date."""
|
|
139
|
+
# Start with the base rate (with 5p cut still in place)
|
|
140
|
+
rate = base_rate_with_cut
|
|
141
|
+
|
|
142
|
+
# Apply staggered reversal
|
|
143
|
+
for reversal_date, increase in REVERSAL_SCHEDULE:
|
|
144
|
+
if d >= reversal_date:
|
|
145
|
+
rate = base_rate_with_cut + increase
|
|
146
|
+
|
|
147
|
+
# Apply RPI uprating from April 2027
|
|
148
|
+
if d >= date(2027, 4, 1):
|
|
149
|
+
# Rate after full reversal (pre-cut rate)
|
|
150
|
+
rate = pre_cut_rate
|
|
151
|
+
|
|
152
|
+
# Apply cumulative RPI uprating
|
|
153
|
+
for year in sorted(rpi_forecasts.keys()):
|
|
154
|
+
if year < 2026:
|
|
155
|
+
continue # Only apply forecasts from 2026 onwards
|
|
156
|
+
uprating_date = date(year + 1, 4, 1)
|
|
157
|
+
if d >= uprating_date:
|
|
158
|
+
rpi = rpi_forecasts[year]
|
|
159
|
+
rate = rate * (1 + rpi / 100)
|
|
160
|
+
|
|
161
|
+
return round(rate, 2)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def days_in_year(year: int) -> int:
|
|
165
|
+
"""Return number of days in a year."""
|
|
166
|
+
return 366 if isleap(year) else 365
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def calculate_annual_average(
|
|
170
|
+
year: int,
|
|
171
|
+
base_rate_with_cut: float,
|
|
172
|
+
pre_cut_rate: float,
|
|
173
|
+
rpi_forecasts: dict,
|
|
174
|
+
) -> float:
|
|
175
|
+
"""Calculate the weighted average fuel duty rate for a calendar year."""
|
|
176
|
+
total_days = days_in_year(year)
|
|
177
|
+
|
|
178
|
+
# Calculate daily rates and sum them
|
|
179
|
+
total_rate = 0.0
|
|
180
|
+
for month in range(1, 13):
|
|
181
|
+
for day in range(1, 32):
|
|
182
|
+
try:
|
|
183
|
+
d = date(year, month, day)
|
|
184
|
+
total_rate += get_rate_on_date(
|
|
185
|
+
d, base_rate_with_cut, pre_cut_rate, rpi_forecasts
|
|
186
|
+
)
|
|
187
|
+
except ValueError:
|
|
188
|
+
# Invalid date (e.g., Feb 30)
|
|
189
|
+
continue
|
|
190
|
+
|
|
191
|
+
average = total_rate / total_days
|
|
192
|
+
return round(average, 2)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def format_as_pounds(pence: float) -> str:
|
|
196
|
+
"""Convert pence to pounds string format for YAML."""
|
|
197
|
+
return f"{pence / 100:.4f}"
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def generate_year_breakdown(
|
|
201
|
+
year: int,
|
|
202
|
+
base_rate_with_cut: float,
|
|
203
|
+
pre_cut_rate: float,
|
|
204
|
+
rpi_forecasts: dict,
|
|
205
|
+
) -> list:
|
|
206
|
+
"""Generate period breakdown for a year, returns list of (start, end, rate, days)."""
|
|
207
|
+
current_rate = None
|
|
208
|
+
period_start = None
|
|
209
|
+
periods = []
|
|
210
|
+
|
|
211
|
+
for month in range(1, 13):
|
|
212
|
+
for day in range(1, 32):
|
|
213
|
+
try:
|
|
214
|
+
d = date(year, month, day)
|
|
215
|
+
rate = get_rate_on_date(
|
|
216
|
+
d, base_rate_with_cut, pre_cut_rate, rpi_forecasts
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
if rate != current_rate:
|
|
220
|
+
if current_rate is not None:
|
|
221
|
+
days = (prev_date - period_start).days + 1
|
|
222
|
+
periods.append(
|
|
223
|
+
(period_start, prev_date, current_rate, days)
|
|
224
|
+
)
|
|
225
|
+
current_rate = rate
|
|
226
|
+
period_start = d
|
|
227
|
+
prev_date = d
|
|
228
|
+
except ValueError:
|
|
229
|
+
continue
|
|
230
|
+
|
|
231
|
+
# Add final period
|
|
232
|
+
if current_rate is not None:
|
|
233
|
+
days = (prev_date - period_start).days + 1
|
|
234
|
+
periods.append((period_start, prev_date, current_rate, days))
|
|
235
|
+
|
|
236
|
+
return periods
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def generate_note_for_year(
|
|
240
|
+
year: int,
|
|
241
|
+
avg_pence: float,
|
|
242
|
+
base_rate_with_cut: float,
|
|
243
|
+
pre_cut_rate: float,
|
|
244
|
+
rpi_forecasts: dict,
|
|
245
|
+
) -> str:
|
|
246
|
+
"""Generate the note text for a year's YAML entry."""
|
|
247
|
+
periods = generate_year_breakdown(
|
|
248
|
+
year, base_rate_with_cut, pre_cut_rate, rpi_forecasts
|
|
249
|
+
)
|
|
250
|
+
total_days = days_in_year(year)
|
|
251
|
+
year_type = "leap year" if isleap(year) else ""
|
|
252
|
+
|
|
253
|
+
lines = []
|
|
254
|
+
if year_type:
|
|
255
|
+
lines.append(f"Calendar year {year} average ({year_type}):")
|
|
256
|
+
else:
|
|
257
|
+
lines.append(f"Calendar year {year} average:")
|
|
258
|
+
|
|
259
|
+
for start, end, rate, days in periods:
|
|
260
|
+
lines.append(
|
|
261
|
+
f"- {start.strftime('%b %d')} - {end.strftime('%b %d')} "
|
|
262
|
+
f"({days} days): {rate:.2f}p"
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
# Add formula
|
|
266
|
+
formula_parts = [f"{rate:.2f}p * {days}" for _, _, rate, days in periods]
|
|
267
|
+
lines.append(
|
|
268
|
+
f"({' + '.join(formula_parts)}) / {total_days} = {avg_pence:.2f}p"
|
|
269
|
+
)
|
|
270
|
+
lines.append("Generated by calculate_fuel_duty_rates.py")
|
|
271
|
+
|
|
272
|
+
return "\n".join(lines)
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def update_yaml_file(
|
|
276
|
+
calculated_rates: dict,
|
|
277
|
+
rpi_forecasts: dict,
|
|
278
|
+
base_rate_with_cut: float,
|
|
279
|
+
pre_cut_rate: float,
|
|
280
|
+
) -> None:
|
|
281
|
+
"""Update the petrol_and_diesel.yaml file with calculated rates."""
|
|
282
|
+
yaml_path = get_fuel_duty_yaml_path()
|
|
283
|
+
|
|
284
|
+
# Read the current file content
|
|
285
|
+
with open(yaml_path, "r") as f:
|
|
286
|
+
content = f.read()
|
|
287
|
+
|
|
288
|
+
# For each year, update or add the entry
|
|
289
|
+
for year, avg_pence in calculated_rates.items():
|
|
290
|
+
date_str = f"{year}-01-01"
|
|
291
|
+
value_pounds = avg_pence / 100
|
|
292
|
+
|
|
293
|
+
# Generate the note
|
|
294
|
+
note = generate_note_for_year(
|
|
295
|
+
year, avg_pence, base_rate_with_cut, pre_cut_rate, rpi_forecasts
|
|
296
|
+
)
|
|
297
|
+
# Indent note lines for YAML
|
|
298
|
+
note_yaml = note.replace("\n", "\n ")
|
|
299
|
+
|
|
300
|
+
# Pattern to match existing entry for this year
|
|
301
|
+
# Matches from the date line until the next date or metadata section
|
|
302
|
+
pattern = (
|
|
303
|
+
rf"( {date_str}:.*?)(?=\n \d{{4}}-\d{{2}}-\d{{2}}:|\nmetadata:)"
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
# New entry text
|
|
307
|
+
new_entry = f""" {date_str}:
|
|
308
|
+
value: {value_pounds:.4f}
|
|
309
|
+
metadata:
|
|
310
|
+
reference:
|
|
311
|
+
- title: OBR Economic and Fiscal Outlook November 2025
|
|
312
|
+
href: https://obr.uk/efo/economic-and-fiscal-outlook-november-2025/
|
|
313
|
+
note: |
|
|
314
|
+
{note_yaml}"""
|
|
315
|
+
|
|
316
|
+
# Try to replace existing entry
|
|
317
|
+
if re.search(pattern, content, re.DOTALL):
|
|
318
|
+
content = re.sub(pattern, new_entry, content, flags=re.DOTALL)
|
|
319
|
+
else:
|
|
320
|
+
# Entry doesn't exist, need to add it before metadata section
|
|
321
|
+
# Find the metadata section and insert before it
|
|
322
|
+
metadata_match = re.search(r"\nmetadata:", content)
|
|
323
|
+
if metadata_match:
|
|
324
|
+
insert_pos = metadata_match.start()
|
|
325
|
+
content = (
|
|
326
|
+
content[:insert_pos]
|
|
327
|
+
+ "\n"
|
|
328
|
+
+ new_entry
|
|
329
|
+
+ content[insert_pos:]
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
# Write the updated content back
|
|
333
|
+
with open(yaml_path, "w") as f:
|
|
334
|
+
f.write(content)
|
|
335
|
+
|
|
336
|
+
print(f"Updated {yaml_path}")
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def print_calculations(
|
|
340
|
+
base_rate_with_cut: float,
|
|
341
|
+
pre_cut_rate: float,
|
|
342
|
+
rpi_forecasts: dict,
|
|
343
|
+
calculated_rates: dict,
|
|
344
|
+
) -> None:
|
|
345
|
+
"""Print calculation details to stdout."""
|
|
346
|
+
print("Loading data from repository files...")
|
|
347
|
+
print(f" Base rate with 5p cut (2022-03-23): {base_rate_with_cut:.2f}p")
|
|
348
|
+
print(f" Pre-cut rate (2021-01-01): {pre_cut_rate:.2f}p")
|
|
349
|
+
print()
|
|
350
|
+
|
|
351
|
+
print(
|
|
352
|
+
"RPI forecasts from yoy_growth.yaml (applied in April of next year):"
|
|
353
|
+
)
|
|
354
|
+
for year in CALCULATION_YEARS:
|
|
355
|
+
rpi = rpi_forecasts.get(year, 0)
|
|
356
|
+
print(f" {year}: {rpi:.2f}%")
|
|
357
|
+
print()
|
|
358
|
+
|
|
359
|
+
print("=" * 60)
|
|
360
|
+
print("Fuel Duty Rate Calculations")
|
|
361
|
+
print("=" * 60)
|
|
362
|
+
print()
|
|
363
|
+
|
|
364
|
+
# Show the rate schedule
|
|
365
|
+
print("Rate Schedule (actual policy dates):")
|
|
366
|
+
print("-" * 40)
|
|
367
|
+
key_dates = [
|
|
368
|
+
date(2026, 1, 1),
|
|
369
|
+
date(2026, 9, 1),
|
|
370
|
+
date(2026, 12, 1),
|
|
371
|
+
date(2027, 3, 1),
|
|
372
|
+
date(2027, 4, 1),
|
|
373
|
+
date(2028, 4, 1),
|
|
374
|
+
date(2029, 4, 1),
|
|
375
|
+
date(2030, 4, 1),
|
|
376
|
+
]
|
|
377
|
+
for d in key_dates:
|
|
378
|
+
rate = get_rate_on_date(
|
|
379
|
+
d, base_rate_with_cut, pre_cut_rate, rpi_forecasts
|
|
380
|
+
)
|
|
381
|
+
print(f" {d}: {rate:.2f}p ({format_as_pounds(rate)} GBP)")
|
|
382
|
+
|
|
383
|
+
print()
|
|
384
|
+
print("Calendar Year Averages (for YAML parameter file):")
|
|
385
|
+
print("-" * 40)
|
|
386
|
+
|
|
387
|
+
for year in CALCULATION_YEARS:
|
|
388
|
+
avg = calculated_rates[year]
|
|
389
|
+
print(f" {year}-01-01:")
|
|
390
|
+
print(f" value: {format_as_pounds(avg)}")
|
|
391
|
+
print(f" # Average rate: {avg:.2f}p")
|
|
392
|
+
print()
|
|
393
|
+
|
|
394
|
+
# Show detailed breakdown for each year
|
|
395
|
+
print()
|
|
396
|
+
print("Detailed Breakdown:")
|
|
397
|
+
print("=" * 60)
|
|
398
|
+
|
|
399
|
+
for year in CALCULATION_YEARS:
|
|
400
|
+
year_type = "leap year" if isleap(year) else "regular year"
|
|
401
|
+
print(f"\n{year} ({year_type}):")
|
|
402
|
+
print("-" * 40)
|
|
403
|
+
|
|
404
|
+
periods = generate_year_breakdown(
|
|
405
|
+
year, base_rate_with_cut, pre_cut_rate, rpi_forecasts
|
|
406
|
+
)
|
|
407
|
+
total_days = days_in_year(year)
|
|
408
|
+
weighted_sum = 0.0
|
|
409
|
+
|
|
410
|
+
for start, end, rate, days in periods:
|
|
411
|
+
weighted_sum += rate * days
|
|
412
|
+
print(
|
|
413
|
+
f" {start.strftime('%b %d')} - {end.strftime('%b %d')}: "
|
|
414
|
+
f"{days:3d} days @ {rate:.2f}p"
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
avg = weighted_sum / total_days
|
|
418
|
+
print(f" Average: {avg:.2f}p ({format_as_pounds(avg)} GBP)")
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
def main():
|
|
422
|
+
parser = argparse.ArgumentParser(
|
|
423
|
+
description="Calculate fuel duty rates based on Autumn Budget 2025 policy."
|
|
424
|
+
)
|
|
425
|
+
parser.add_argument(
|
|
426
|
+
"--update",
|
|
427
|
+
action="store_true",
|
|
428
|
+
help="Update the petrol_and_diesel.yaml file with calculated rates",
|
|
429
|
+
)
|
|
430
|
+
args = parser.parse_args()
|
|
431
|
+
|
|
432
|
+
# Load data from repository files
|
|
433
|
+
fuel_duty_data = load_fuel_duty_rates()
|
|
434
|
+
rpi_forecasts = load_rpi_forecasts()
|
|
435
|
+
|
|
436
|
+
base_rate_with_cut = get_base_rate_with_cut(fuel_duty_data)
|
|
437
|
+
pre_cut_rate = get_pre_cut_rate(fuel_duty_data)
|
|
438
|
+
|
|
439
|
+
# Calculate rates for each year
|
|
440
|
+
calculated_rates = {}
|
|
441
|
+
for year in CALCULATION_YEARS:
|
|
442
|
+
avg = calculate_annual_average(
|
|
443
|
+
year, base_rate_with_cut, pre_cut_rate, rpi_forecasts
|
|
444
|
+
)
|
|
445
|
+
calculated_rates[year] = avg
|
|
446
|
+
|
|
447
|
+
# Print calculations
|
|
448
|
+
print_calculations(
|
|
449
|
+
base_rate_with_cut, pre_cut_rate, rpi_forecasts, calculated_rates
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
# Update YAML file if requested
|
|
453
|
+
if args.update:
|
|
454
|
+
print()
|
|
455
|
+
print("=" * 60)
|
|
456
|
+
print("Updating YAML file...")
|
|
457
|
+
print("=" * 60)
|
|
458
|
+
update_yaml_file(
|
|
459
|
+
calculated_rates, rpi_forecasts, base_rate_with_cut, pre_cut_rate
|
|
460
|
+
)
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
if __name__ == "__main__":
|
|
464
|
+
main()
|