Skip to content

Fix MTR calculation to use hbai_household_net_income#64

Closed
nwoodruff-co wants to merge 8 commits intomainfrom
fix-mtr-net-income-hbai
Closed

Fix MTR calculation to use hbai_household_net_income#64
nwoodruff-co wants to merge 8 commits intomainfrom
fix-mtr-net-income-hbai

Conversation

@nwoodruff-co
Copy link
Copy Markdown
Collaborator

Summary

  • Core fix: MTR perturbation now uses hbai_household_net_income (projected from household to person level) instead of total_income - income_tax. The old approach missed NI, UC taper, and all benefit interactions — systematically understating marginal rates for lower-income households and producing wrong reform ETRs/MTRs.
  • How it works: for each £1 perturbation (labour income or capital income), we compare hbai_household_net_income before and after via map_to_entity(..., how="project"). This captures the full tax-benefit wedge.
  • Minor cleanup: removed unused BW variable and a redundant frac_payroll assignment in calibrate(); fixed years[i] formatting in run_oguk.py to handle fiscal-year string labels (e.g. "2026-27").

Test plan

  • Run examples/run_oguk.py ss — verify steady state converges and reform direction is economically sensible (higher IT → lower GDP, not higher)
  • Run examples/run_oguk.py tpi — verify transition path converges and tax revenue impact is positive
  • Check CI passes

- Fix map_transition_to_real_world: use period-0 anchor scale factor so
  baseline levels carry the full growth path rather than collapsing to a
  flat constant each period
- Add scripts/run_tpi_and_export.py: runs SS+TPI for baseline and a 1pp
  basic rate reform, exports results to tpi_results.xlsx with optional
  pre-2026 ONS/OBR historical rows (light yellow) prepended to the
  baseline sheet
- Add scripts/tpi_charts_plotly.py: single-page 2×3 chart showing five
  variables as % of GDP and GDP in £bn; baseline = OBR Nov 2025 EFO
  outturn + forecast; reform = OBR baseline × TPI % change from model;
  dashed reform line only, grey dotted boundary at outturn/forecast split
Extend chart baseline back to 2000-01 by fetching ONS YBHA/NPQS/ABJQ
calendar-year series and converting to fiscal years via the existing
_fy_from_calendar() helper. OBR table 1.4/1.2 data takes priority from
2008-09 onwards; ONS rows are only prepended for earlier years.

Also extend hardcoded _fy_tax_revenue() back to 2000-01 using HMRC
outturn data, and update x-axis range to use HIST_START_FY constant.
- Recalibrate adjustment_factor_for_cit_receipts from 0.309 → 1.1785 to
  match UK CT/GDP ~3.3% (was underestimating at 0.8% using US default)
- Add run_ct_and_export.py: SS+TPI for baseline (cit=0.27) and reform
  (cit=0.28), exports 3-sheet xlsx with historical actuals + model output
- Add ct_charts_plotly.py: 6-panel interactive Plotly charts mapping model
  % changes onto OBR outturn/forecast baseline
- Add ct_tpi_results.xlsx and rendered HTML charts
- Add ct_reexport.py (interim correction script, now superseded)

Dynamic GE estimate: CT +1pp raises ~£2.3-2.6bn/yr tax revenue vs HMRC
static RR of £3.6-4.0bn, with ~£2bn/yr investment drag and £0.5-0.8bn
GDP cost in OBR window.
Previously, marginal tax rates were computed by comparing
total_income - income_tax before and after a £1 perturbation.
This missed NI, UC taper, and benefit interactions — all of
which affect the true net income change faced by a household.

Switch to hbai_household_net_income (the HBAI poverty measure
of disposable income), broadcast from household to person level
via map_to_entity(..., how="project"). This captures the full
tax-benefit wedge including NI, UC, and other means-tested
interactions, giving accurate ETR and MTR estimates for the
Gouveia-Strauss tax function estimation.

Also remove stale dead-code lines (unused BW variable, a
redundant frac_payroll assignment, and two inline comments)
and fix years[i] formatting in run_oguk.py to handle
fiscal-year string labels.
@nwoodruff-co
Copy link
Copy Markdown
Collaborator Author

Changes folded into #63 (obr-grounded-tpi-charts) via cherry-pick.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants