Skip to content

Commit

Permalink
Harris capital gains tax reform
Browse files Browse the repository at this point in the history
Fixes #5203
  • Loading branch information
PavelMakarchuk committed Oct 14, 2024
1 parent 0051378 commit 029423d
Show file tree
Hide file tree
Showing 7 changed files with 450 additions and 0 deletions.
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:
- Harris capital gains tax reform.
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
description: Harris proposed to tax capital gains at the following rates.
rates:
description: Long term capital gain and qualified dividends (regular/non-AMT) rate
1:
2013-01-01: 0
2:
2013-01-01: 0.15
3:
2013-01-01: 0.2
4:
2013-01-01: 0.28
metadata:
unit: /1
thresholds:
description: Top thresholds of long-term capital gains and qualified dividends (regular/non-AMT) tax brackets
metadata:
unit: currency-USD
period: year
reference:
- title: 2024 IRS data release
href: https://www.irs.gov/pub/irs-drop/rp-23-34.pdf#page=8
- title: 2023 IRS data release
href: https://www.irs.gov/pub/irs-drop/rp-22-38.pdf#page=8
- title: 2022 IRS data release
href: https://www.irs.gov/pub/irs-drop/rp-21-45.pdf#page=8
- title: 2021 IRS data release
href: https://www.irs.gov/pub/irs-drop/rp-20-45.pdf#page=8
- title: 2020 IRS data release
href: https://www.irs.gov/pub/irs-drop/rp-19-44.pdf#page=8
- title: 2019 IRS data release
href: https://www.irs.gov/pub/irs-drop/rp-18-57.pdf#page=8
- title: Internal Revenue Code §1(j)(5)(B)
# IRC defines amounts as of 2018.
# Defines COLA with rounded up to the nearest multiple of $50.
href: https://www.law.cornell.edu/uscode/text/26/1#j_5_B
1:
HEAD_OF_HOUSEHOLD:
values:
2013-01-01: 48_600
2014-01-01: 49_400
2015-01-01: 50_200
2016-01-01: 50_400
2017-01-01: 50_800
2018-01-01: 51_700
2019-01-01: 52_750
2020-01-01: 53_600
2021-01-01: 54_100
2022-01-01: 55_800
2023-01-01: 59_750
2024-01-01: 63_000
JOINT:
values:
2013-01-01: 72_500
2014-01-01: 73_800
2015-01-01: 74_900
2016-01-01: 75_300
2017-01-01: 75_900
2018-01-01: 77_200
2019-01-01: 78_750
2020-01-01: 80_000
2021-01-01: 80_800
2022-01-01: 83_350
2023-01-01: 89_250
2024-01-01: 94_050
SEPARATE:
values:
2013-01-01: 36_250
2014-01-01: 36_900
2015-01-01: 37_450
2016-01-01: 37_650
2017-01-01: 37_950
2018-01-01: 38_600
2019-01-01: 39_375
2020-01-01: 40_000
2021-01-01: 40_400
2022-01-01: 41_675
2023-01-01: 44_625
2024-01-01: 47_025
SINGLE:
values:
2013-01-01: 36_250
2014-01-01: 36_900
2015-01-01: 37_450
2016-01-01: 37_650
2017-01-01: 37_950
2018-01-01: 38_600
2019-01-01: 39_375
2020-01-01: 40_000
2021-01-01: 40_400
2022-01-01: 41_675
2023-01-01: 44_625
2024-01-01: 47_025
SURVIVING_SPOUSE:
values:
2013-01-01: 72_500
2014-01-01: 73_800
2015-01-01: 74_900
2016-01-01: 75_300
2017-01-01: 75_900
2018-01-01: 77_200
2019-01-01: 78_750
2020-01-01: 80_000
2021-01-01: 80_800
2022-01-01: 83_350
2023-01-01: 89_250
2024-01-01: 94_050
2:
HEAD_OF_HOUSEHOLD:
values:
2013-01-01: 425_000
2014-01-01: 432_200
2015-01-01: 439_000
2016-01-01: 441_000
2017-01-01: 444_550
2018-01-01: 452_400
2019-01-01: 461_700
2020-01-01: 469_050
2021-01-01: 473_750
2022-01-01: 488_500
2023-01-01: 523_050
2024-01-01: 551_350
JOINT:
values:
2013-01-01: 450_000
2014-01-01: 457_600
2015-01-01: 464_850
2016-01-01: 466_950
2017-01-01: 470_700
2018-01-01: 479_000
2019-01-01: 488_850
2020-01-01: 496_600
2021-01-01: 501_600
2022-01-01: 517_200
2023-01-01: 553_850
2024-01-01: 583_750
SEPARATE:
values:
2013-01-01: 225_000
2014-01-01: 228_800
2015-01-01: 232_425
2016-01-01: 233_475
2017-01-01: 235_350
2018-01-01: 239_500
2019-01-01: 244_425
2020-01-01: 248_300
2021-01-01: 250_800
2022-01-01: 258_600
2023-01-01: 276_900
2024-01-01: 291_850
SINGLE:
values:
2013-01-01: 400_000
2014-01-01: 406_750
2015-01-01: 413_200
2016-01-01: 415_050
2017-01-01: 418_400
2018-01-01: 425_800
2019-01-01: 434_550
2020-01-01: 441_450
2021-01-01: 445_850
2022-01-01: 459_750
2023-01-01: 492_300
2024-01-01: 518_900
SURVIVING_SPOUSE:
values:
2013-01-01: 450_000
2014-01-01: 457_600
2015-01-01: 464_850
2016-01-01: 466_950
2017-01-01: 470_700
2018-01-01: 479_000
2019-01-01: 488_850
2020-01-01: 496_600
2021-01-01: 501_600
2022-01-01: 517_200
2023-01-01: 553_850
2024-01-01: 583_750

3:
HEAD_OF_HOUSEHOLD:
values:
2013-01-01: 1_000_000
JOINT:
values:
2013-01-01: 1_000_000
SEPARATE:
values:
2013-01-01: 1_000_000
SINGLE:
values:
2013-01-01: 1_000_000
SURVIVING_SPOUSE:
values:
2013-01-01: 1_000_000
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
description: Senator harris has proposed an additional, increased capital gains tax bracket, which comes into effect if this is true.
metadata:
unit: bool
period: year
label: Harris ciptal gains tax reform in effect
reference:
- title: Remarks by Vice President Harris at a Campaign Event| North Hampton, NH
href: https://www.whitehouse.gov/briefing-room/speeches-remarks/2024/09/04/remarks-by-vice-president-harris-at-a-campaign-event-north-hampton-nh/

values:
0000-01-01: false
3 changes: 3 additions & 0 deletions policyengine_us/reforms/harris/capital_gains/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .harris_capital_gains import (
create_harris_capital_gains_reform,
)
144 changes: 144 additions & 0 deletions policyengine_us/reforms/harris/capital_gains/harris_capital_gains.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
from policyengine_us.model_api import *


def create_harris_capital_gains() -> Reform:
class capital_gains_tax(Variable):
value_type = float
entity = TaxUnit
label = "Maximum income tax after capital gains tax"
unit = USD
definition_period = YEAR

def formula(tax_unit, period, parameters):
net_cg = tax_unit("net_capital_gain", period)
taxable_income = tax_unit("taxable_income", period)
adjusted_net_cg = min_(
tax_unit("adjusted_net_capital_gain", period),
taxable_income,
) # ANCG is referred to in all cases as ANCG or taxable income if less.

cg = parameters(period).gov.irs.capital_gains

p_ref = parameters(period).gov.contrib.harris.capital_gains

excluded_cg = tax_unit(
"capital_gains_excluded_from_taxable_income", period
)
non_cg_taxable_income = max_(0, taxable_income - excluded_cg)
income_less_ancg = max_(0, taxable_income - adjusted_net_cg)

filing_status = tax_unit("filing_status", period)

first_threshold = p_ref.brackets.thresholds["1"][filing_status]
second_threshold = p_ref.brackets.thresholds["2"][filing_status]
third_threshold = p_ref.brackets.thresholds["3"][filing_status]

income_ordinarily_under_second_rate = clip(
taxable_income, 0, first_threshold
)
cg_in_first_bracket = max_(
0, income_ordinarily_under_second_rate - income_less_ancg
)

income_ordinarily_under_third_rate = clip(
taxable_income, 0, second_threshold
)
cg_in_second_bracket = min_(
max_(0, adjusted_net_cg - cg_in_first_bracket),
max_(
0,
income_ordinarily_under_third_rate
- (non_cg_taxable_income + cg_in_first_bracket),
),
)
income_ordinarily_under_fourth_rate = clip(
taxable_income, 0, third_threshold
)

cg_in_third_bracket = min_(
max_(
0,
adjusted_net_cg
- cg_in_first_bracket
- cg_in_second_bracket,
),
max_(
0,
income_ordinarily_under_fourth_rate
- (
non_cg_taxable_income
+ cg_in_first_bracket
+ cg_in_second_bracket
),
),
)

cg_in_fourth_bracket = max_(
adjusted_net_cg
- cg_in_first_bracket
- cg_in_second_bracket
- cg_in_third_bracket,
0,
)

main_cg_tax = (
cg_in_first_bracket * p_ref.brackets.rates["1"]
+ cg_in_second_bracket * p_ref.brackets.rates["2"]
+ cg_in_third_bracket * p_ref.brackets.rates["3"]
+ cg_in_fourth_bracket * p_ref.brackets.rates["4"]
)

unrecaptured_s_1250_gain = tax_unit(
"unrecaptured_section_1250_gain", period
)
qualified_dividends = add(
tax_unit, period, ["qualified_dividend_income"]
)
max_taxable_unrecaptured_gain = min_(
unrecaptured_s_1250_gain,
max_(0, net_cg - qualified_dividends),
)
unrecaptured_gain_deduction = max_(
non_cg_taxable_income + net_cg - taxable_income,
0,
)
taxable_unrecaptured_gain = max_(
max_taxable_unrecaptured_gain - unrecaptured_gain_deduction,
0,
)

unrecaptured_gain_tax = (
cg.unrecaptured_s_1250_rate * taxable_unrecaptured_gain
)

remaining_cg_tax = (
tax_unit("capital_gains_28_percent_rate_gain", period)
* cg.other_cg_rate
)

return main_cg_tax + unrecaptured_gain_tax + remaining_cg_tax

class reform(Reform):
def apply(self):
self.update_variable(capital_gains_tax)

return reform


def create_harris_capital_gains_reform(
parameters, period, bypass: bool = False
):
if bypass:
return create_harris_capital_gains()

p = parameters(period).gov.contrib.harris.capital_gains

if p.in_effect:
return create_harris_capital_gains()
else:
return None


harris_capital_gains = create_harris_capital_gains_reform(
None, None, bypass=True
)
7 changes: 7 additions & 0 deletions policyengine_us/reforms/reforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@
from .treasury.repeal_dependent_exemptions import (
create_repeal_dependent_exemptions_reform,
)
from .harris.capital_gains import (
create_harris_capital_gains_reform,
)

from policyengine_core.reforms import Reform
import warnings
Expand Down Expand Up @@ -120,6 +123,9 @@ def create_structural_reforms_from_parameters(parameters, period):
repeal_dependent_exemptions = create_repeal_dependent_exemptions_reform(
parameters, period
)
harris_capital_gains = create_harris_capital_gains_reform(
parameters, period
)

reforms = [
afa_reform,
Expand All @@ -146,6 +152,7 @@ def create_structural_reforms_from_parameters(parameters, period):
family_security_act_2024_ctc,
family_security_act_2024_eitc,
repeal_dependent_exemptions,
harris_capital_gains,
]
reforms = tuple(filter(lambda x: x is not None, reforms))

Expand Down
Loading

0 comments on commit 029423d

Please sign in to comment.