Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add INITIAL non-dom status #882

Merged
merged 5 commits into from
Jun 28, 2024
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
4 changes: 4 additions & 0 deletions changelog_entry.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- bump: minor
changes:
added:
- Non-dom status switch.
Binary file added enhanced_frs_brmas.csv.gz
Binary file not shown.
2 changes: 1 addition & 1 deletion policyengine_uk/data/datasets/frs/enhanced_frs.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ class EnhancedFRS(Dataset):
data_format = Dataset.TIME_PERIOD_ARRAYS
num_years = 7
time_period = 2021
count_copies = 4
count_copies = 9
url = "release://policyengine/non-public-microdata/uk-2024-march-efo/enhanced_frs.h5"

def generate(self):
Expand Down
Binary file modified policyengine_uk/data/gov/enhanced_frs_brmas.csv.gz
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
description: Whether individuals can claim non-domiciled status for tax purposes.
values:
2000-01-01: true
metadata:
unit: bool
label: allow non-domiciled tax status
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
description: Proportion of non-domiciled people by income band.
brackets:
- threshold:
2022-01-01: 0
amount:
2022-01-01: 0 # Actually 0.03 but 0 to be safe
- threshold:
2022-01-01: 100_000
amount:
2022-01-01: 0.052
- threshold:
2022-01-01: 200_000
amount:
2022-01-01: 0.134
- threshold:
2022-01-01: 500_000
amount:
2022-01-01: 0.211
- threshold:
2022-01-01: 1_000_000
amount:
2022-01-01: 0.268
- threshold:
2022-01-01: 2_000_000
amount:
2022-01-01: 0.344
- threshold:
2022-01-01: 5_000_000
amount:
2022-01-01: 0.414
- threshold:
2022-01-01: 10_000_000
amount:
2022-01-01: 0.4

metadata:
label: proportion of non-domiciled individuals by income band
type: single_amount
threshold_unit: currency-GBP
amount_unit: /1
reference:
- title: CAGE Policy Briefing no. 36
href: https://warwick.ac.uk/fac/soc/economics/research/centres/cage/manage/publications/bn36.2022.pdf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
description: Total number of non-domiciled people.
values:
2022-01-01: 238_000
metadata:
unit: person
label: total non-domiciled individuals
reference:
- title: CAGE Policy Briefing no. 36
href: https://warwick.ac.uk/fac/soc/economics/research/centres/cage/manage/publications/bn36.2022.pdf
4 changes: 4 additions & 0 deletions policyengine_uk/variables/gov/hmrc/income_tax/relief.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,10 @@ def formula(person, period, parameters):
"taxable_dividend_income",
"taxable_miscellaneous_income",
]
if not parameters(
period
).gov.hmrc.income_tax.reliefs.non_domiciled_status:
COMPONENTS.append("worldwide_income")
if parameters(
period
).gov.contrib.ubi_center.basic_income.interactions.include_in_taxable_income:
Expand Down
57 changes: 57 additions & 0 deletions policyengine_uk/variables/household/income/worldwide_income.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from policyengine_uk.model_api import *


class is_non_domiciled(Variable):
label = "non-domiciled"
documentation = "Whether the person is non-domiciled for tax purposes."
entity = Person
definition_period = YEAR
value_type = bool

def formula(person, period, parameters):
if not hasattr(person.simulation, "dataset"):
return 0
if person.simulation.dataset.name != "enhanced_frs":
return 0
total_income = person("total_income", period)
non_dom = parameters(period).gov.simulation.non_domiciled_status
weight = person("person_weight", period)

thresholds = non_dom.proportion_by_income.thresholds
shares_of_non_doms = non_dom.proportion_by_income.amounts
probabilities = np.zeros_like(total_income)
ADJUSTMENT_FACTOR = 1e3
for i in range(len(thresholds)):
lower = thresholds[i]
upper = thresholds[i + 1] if i + 1 < len(thresholds) else np.inf
in_range = (total_income >= lower) & (total_income < upper)
total_population = weight[in_range].sum()
percent_non_dom = where(
total_population == 0,
0,
shares_of_non_doms[i] / total_population,
)
probability = 1 - (1 - percent_non_dom) ** ADJUSTMENT_FACTOR
probabilities[in_range] = probability

return random(person) < probabilities


class worldwide_income(Variable):
label = "worldwide income"
documentation = "Income not taxed due to non-domiciled status."
entity = Person
definition_period = YEAR
value_type = float
unit = GBP

def formula(person, period, parameters):
ADJUSTMENT_FACTOR = 2.7 # Gets 3.2bn from abolishing non-dom status
total_income = person("total_income", period)
is_non_dom = person("is_non_domiciled", period)

return where(
is_non_dom,
total_income * ADJUSTMENT_FACTOR,
0,
)
Loading