Skip to content

Commit

Permalink
Merge pull request #2734 from martinholmer/add-tcja-docs
Browse files Browse the repository at this point in the history
  • Loading branch information
jdebacker authored Apr 13, 2024
2 parents a9a071f + c4cb4f8 commit ea93c7a
Show file tree
Hide file tree
Showing 7 changed files with 373 additions and 0 deletions.
1 change: 1 addition & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ comment:
ignore:
- "setup.py"
- "ppp.py"
- "extend_tcja.py"
1 change: 1 addition & 0 deletions docs/_toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ parts:
- file: recipes/recipe04_pandas
- file: recipes/recipe05
- file: recipes/recipe06
- file: usage/tcja_after_2025
- caption: About
chapters:
- file: about/history
Expand Down
133 changes: 133 additions & 0 deletions docs/usage/tcja_after_2025.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
TCJA after 2025
===============

Many provisions of the TCJA are temporary and are scheduled to end
after 2025 under current-law policy. Tax policy parameters that are
associated with expiring provisions and that are not inflation indexed
will revert to their 2017 values in 2026. Tax policy parameters that
are associated with expiring provisions and that are inflation indexed
will revert to their 2017 values indexed to 2026 using a chained CPI-U
inflation factor. For a list of the ending TCJA provisions, see this
Congressional Research Service document: [Reference Table: Expiring
Provisions in the "Tax Cuts and Jobs Act" (TCJA, P.L. 115-97)](
https://crsreports.congress.gov/product/pdf/R/R47846), which is dated
November 21, 2023.

This document describes how to use the PSLmodels Tax-Calculator
command-line interface
[tc](https://taxcalc.pslmodels.org/guide/cli.html) with any compatible
input dataset to analyze the post-2025 effects of alternatives to
current-law policy (which calls for all temporary TCJA provisions to
expire). Compatible input datasets include:

* the older `cps.csv` file included in the Tax-Calculator package

* the older `puf.csv` file generated in the PSLmodels
[taxdata](https://github.com/PSLmodels/taxdata) repository and
available only to those with access to the 2011 IRS/SOI PUF

* several newer CSV-formatted input files created in the PSLmodels
[tax-microdata](https://github.com/PSLmodels/tax-microdata-benchmarking)
repository that are based on the 2015 IRS/SOI PUF and on recent CPS
data, and are available only to those with access to the 2015
IRS/SOI PUF

Before reading the rest of this document, be sure you understand how
to use the Tax-Calculator command-line tool
[tc](https://taxcalc.pslmodels.org/guide/cli.html), particularly the
`--baseline` and `--reform` command-line options. (For complete and
up-to-date `tc` documentation, enter `tc --help` at the command
prompt.) Omitting the `--baseline` option means the baseline policy
is current-law policy. Omitting the `--reform` option means the
reform policy is current-law policy. The `--tables` option produces
tables comparing taxes under the baseline policy to taxes under the
reform policy by income decile and in aggregate.

The `--baseline` option is not commonly used, but it can be very
helpful in analyzing reforms that take effect beginning in 2026. Such
a reform could be analyzed relative to current-law policy (that is,
with temporary TCJA provisions expiring after 2025) by omitting the
`--baseline` option. But if such a reform were to be analyzed
relative to extending all the temporary TCJA provisions beyond 2025,
then the `--baseline ext.json` option would need to be used. The
[`ext.json`](../../taxcalc/reforms/ext.json) file contains the 2026
tax policy reform provisions that would extend TCJA's temporary
provisions beyond 2025. Before using this `ext.json` reform file, be
sure to read how it is generated at the end of this document.

Here are some concrete examples of using the `tc` tool to analyze a
reform of interest to you that begins in 2026. The examples assume
you have named your reform file `x.json` and that you are using one
of the compatible input datasets describe above. The examples will
call the input dataset `z.csv`.

To analyze your reform relative to current-law policy (which means
temporary TCJA provisions have expired beginning in 2026), you would
execute this command:

```
tc z.csv 2026 --exact --tables --reform x.json
```

The tables would be in the `z-26-#-x-#-tab.text` output file generated
by this `tc` run. If you want to do custom tabulations of the micro
output data, use the `--dump`, `--dvars`, and `--sqldb` options as
explained by the `tc --help` documentation.

To analyze your reform relative to a reform that extends all TCJA
temporary provisions beyond 2025, you would execute this command:

```
tc z.csv 2026 --exact --tables --baseline ext.json --reform x.json
```

The tables would be in the `z-26-ext-x-#-tab.text` output file
generated by this `tc` run.

Also, remember that you can simulate a _compound reform_ using the
following syntax:

```
tc z.csv 2026 --exact --tables --baseline ext.json --reform x.json+y.json
```

where `y.json` contains a reform with additional provisions not
included in your `x.json` reform file. The resulting table output
would be in a file named `z-26-ext-x+y-#-tab.text`.

And finally, you might consider creating a reform file called
`end.json` that contains just the two characters `{}`. This is a null
reform, which is equivalent to current-law policy, that could be used
as follows:

```
tc z.csv 2026 --exact --tables --baseline end.json --reform x.json
```

The resulting table output would be named `z-26-end-x-#-tab.text` and
have the same tabular output as the `z-26-#-x-#-tab.text` file. Some
people may prefer `end` to `#` as a way of naming current-law policy
in the context of discussing TCJA-related reforms.


**How is the `ext.json` file generated?**

The short answer is by using the
[`extend_tcja.py`](../../extend_tcja.py) script.

Reading the `extend_tcja.py` script will provide details on how the
values in the `ext.json` file are generated.

It is important to bear in mind that the `extend_tcja.py` script will
generate a different `ext.json` file whenever the CBO economic
projection (incorporated in the Tax-Calculator `growfactors.csv` file)
change or whenever new historical values of policy parameters are
added to the `policy_current_law.json` file thereby changing the
`Policy.LAST_KNOWN_YEAR`.

The 3.5.3 version of Tax-Calculator incorporates the February 2024 CBO
economic projection and contains historical tax policy parameter values
through 2022. Future versions of Tax-Calculator that use historical
policy parameter values for 2023 and 2024 or use the February 2025 CBO
economic projection will cause the `extend_tcja.py` script to generate
somewhat different 2026 parameter values in the `ext.json` file.
143 changes: 143 additions & 0 deletions extend_tcja.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
"""
This script generates a JSON reform file, which could be called
extend_tcja.json, that can serve as an alternative baseline to
current-law policy (which ends TCJA temporary provisions after 2025).
USAGE: (taxcalc-dev) ~% python extend_tcja.py
IMPORTANT NOTE: be sure to remove the trailing comma after the last item
in the reform JSON object generated by this script.
"""

import sys
import numpy
import taxcalc

TCJA_CATEGORY = None # set to None to generate all TCJA temporary provisions
TCJA_PARAMETERS = {
# category 1 ...
"II_rt1": {"indexed": False, "category": 1},
"II_brk1": {"indexed": True, "category": 1},
"PT_rt1": {"indexed": False, "category": 1},
"PT_brk1": {"indexed": True, "category": 1},
"II_rt2": {"indexed": False, "category": 1},
"II_brk2": {"indexed": True, "category": 1},
"PT_rt2": {"indexed": False, "category": 1},
"PT_brk2": {"indexed": True, "category": 1},
"II_rt3": {"indexed": False, "category": 1},
"II_brk3": {"indexed": True, "category": 1},
"PT_rt3": {"indexed": False, "category": 1},
"PT_brk3": {"indexed": True, "category": 1},
"II_rt4": {"indexed": False, "category": 1},
"II_brk4": {"indexed": True, "category": 1},
"PT_rt4": {"indexed": False, "category": 1},
"PT_brk4": {"indexed": True, "category": 1},
"II_rt5": {"indexed": False, "category": 1},
"II_brk5": {"indexed": True, "category": 1},
"PT_rt5": {"indexed": False, "category": 1},
"PT_brk5": {"indexed": True, "category": 1},
"II_rt6": {"indexed": False, "category": 1},
"II_brk6": {"indexed": True, "category": 1},
"PT_rt6": {"indexed": False, "category": 1},
"PT_brk6": {"indexed": True, "category": 1},
"II_rt7": {"indexed": False, "category": 1},
"II_brk7": {"indexed": True, "category": 1},
"PT_rt7": {"indexed": False, "category": 1},
"PT_brk7": {"indexed": True, "category": 1},
# category 2 ...
"CTC_c": {"indexed": False, "category": 2},
"ACTC_c": {"indexed": False, "category": 2},
"ODC_c": {"indexed": False, "category": 2},
"CTC_ps": {"indexed": False, "category": 2},
"ACTC_Income_thd": {"indexed": False, "category": 2},
# category 3 ...
"AMT_em": {"indexed": True, "category": 3},
"AMT_em_ps": {"indexed": True, "category": 3},
"AMT_em_pe": {"indexed": True, "category": 3},
# category 4 ...
"STD": {"indexed": True, "category": 4},
# category 5 ...
"ID_AllTaxes_c": {"indexed": False, "category": 5},
"ID_Charity_crt_all": {"indexed": False, "category": 5},
"ID_Casualty_hc": {"indexed": False, "category": 5},
"ID_Miscellaneous_hc": {"indexed": False, "category": 5},
"ID_ps": {"indexed": True, "category": 5},
"ID_prt": {"indexed": False, "category": 5},
"ID_crt": {"indexed": False, "category": 5},
# category 6 ...
"II_em": {"indexed": True, "category": 6},
"II_em_ps": {"indexed": True, "category": 6},
# category 7 ...
"PT_qbid_rt": {"indexed": False, "category": 7},
"PT_qbid_taxinc_thd": {"indexed": True, "category": 7},
"PT_qbid_taxinc_gap": {"indexed": False, "category": 7},
"PT_qbid_w2_wages_rt": {"indexed": False, "category": 7},
"PT_qbid_alt_w2_wages_rt": {"indexed": False, "category": 7},
"PT_qbid_alt_property_rt": {"indexed": False, "category": 7},
# category 8 ...
"ALD_BusinessLosses_c": {"indexed": True, "category": 8},
"ALD_DomesticProduction_hc": {"indexed": False, "category": 8},
}


def main():
"""
High-level script logic.
"""
# calculate 2025-to-2026 parameters indexing factor
pol = taxcalc.Policy()
pirates = pol.inflation_rates()
ifactor = 1.0 + pirates[2025-taxcalc.Policy.JSON_START_YEAR]
# specify extend-TCJA-beyond-2025 reform
# ... get 2025 parameter values
pol.set_year(2025)
pdata = dict(pol.items())
# ... write reform header comments
print( '// REFORM TO EXTEND TEMPORARY TCJA PROVISIONS BEYOND 2025')
print(f'// USING TAX-CALCULATOR {taxcalc.__version__}')
print(f'// WITH 2025-to-2026 INDEXING FACTOR = {ifactor:.6f}')
if TCJA_CATEGORY:
print(f'// ONLY TCJA PROVISIONS IN CATEGORY {TCJA_CATEGORY}')
print('{')
# ... set 2026 nonreverted values for the parameters set to revert
for pname, pinfo in TCJA_PARAMETERS.items():
if TCJA_CATEGORY and pinfo['category'] != TCJA_CATEGORY:
continue # skip this parameter
if pinfo['indexed']:
pval = pdata[pname][0] * ifactor
if isinstance(pval, numpy.ndarray):
# handle vector parameter
pval = numpy.minimum(9e99, pval.round(2))
sys.stdout.write(f' "{pname}": ')
sys.stdout.write('{"2026": ')
sys.stdout.write(f'{pval.tolist()}')
sys.stdout.write('},\n')
else:
# handle scalar parameter
pval = min(9e99, pval)
sys.stdout.write(f' "{pname}": ')
sys.stdout.write('{"2026": ')
sys.stdout.write(f'{pval*ifactor:.2f}')
sys.stdout.write('},\n')
else: # if parameter is not indexed
pval = pdata[pname][0]
if isinstance(pval, numpy.ndarray):
# handle vector parameter
pval = numpy.minimum(9e99, pval.round(2))
sys.stdout.write(f' "{pname}": ')
sys.stdout.write('{"2026": ')
sys.stdout.write(f'{pval.tolist()}')
sys.stdout.write('},\n')
else:
# handle scalar parameter
sys.stdout.write(f' "{pname}": ')
sys.stdout.write('{"2026": ')
sys.stdout.write(f'{pval:.2f}')
sys.stdout.write('},\n')
print('}')
return 0
# end main function code


if __name__ == '__main__':
sys.exit(main())
59 changes: 59 additions & 0 deletions taxcalc/reforms/ext.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// REFORM TO EXTEND TEMPORARY TCJA PROVISIONS BEYOND 2025
// USING TAX-CALCULATOR 3.5.3
// WITH 2025-to-2026 INDEXING FACTOR = 1.022000
{
"II_rt1": {"2026": 0.10},
"II_brk1": {"2026": [12170.98, 24341.94, 12170.98, 17353.27, 24341.94]},
"PT_rt1": {"2026": 0.10},
"PT_brk1": {"2026": [12170.98, 24341.94, 12170.98, 17353.27, 24341.94]},
"II_rt2": {"2026": 0.12},
"II_brk2": {"2026": [49483.44, 98966.89, 49483.44, 66214.83, 98966.89]},
"PT_rt2": {"2026": 0.12},
"PT_brk2": {"2026": [49483.44, 98966.89, 49483.44, 66214.83, 98966.89]},
"II_rt3": {"2026": 0.22},
"II_brk3": {"2026": [105511.38, 211022.75, 105511.38, 105481.77, 211022.75]},
"PT_rt3": {"2026": 0.22},
"PT_brk3": {"2026": [105511.38, 211022.75, 105511.38, 105481.77, 211022.75]},
"II_rt4": {"2026": 0.24},
"II_brk4": {"2026": [201428.14, 402856.25, 201428.14, 201428.14, 402856.25]},
"PT_rt4": {"2026": 0.24},
"PT_brk4": {"2026": [201428.14, 402856.25, 201428.14, 201428.14, 402856.25]},
"II_rt5": {"2026": 0.32},
"II_brk5": {"2026": [255797.72, 511595.46, 255797.72, 255797.72, 511595.46]},
"PT_rt5": {"2026": 0.32},
"PT_brk5": {"2026": [255797.72, 511595.46, 255797.72, 255797.72, 511595.46]},
"II_rt6": {"2026": 0.35},
"II_brk6": {"2026": [639523.94, 767393.2, 383696.6, 639523.94, 767393.2]},
"PT_rt6": {"2026": 0.35},
"PT_brk6": {"2026": [639523.94, 767393.2, 383696.6, 639523.94, 767393.2]},
"II_rt7": {"2026": 0.37},
"II_brk7": {"2026": [9e+99, 9e+99, 9e+99, 9e+99, 9e+99]},
"PT_rt7": {"2026": 0.37},
"PT_brk7": {"2026": [9e+99, 9e+99, 9e+99, 9e+99, 9e+99]},
"CTC_c": {"2026": 2000.00},
"ACTC_c": {"2026": 1600.00},
"ODC_c": {"2026": 500.00},
"CTC_ps": {"2026": [200000.0, 400000.0, 200000.0, 200000.0, 400000.0]},
"ACTC_Income_thd": {"2026": 2500.00},
"AMT_em": {"2026": [89905.29, 139892.17, 69946.08, 89905.29, 139892.17]},
"AMT_em_ps": {"2026": [639523.94, 1279047.88, 639523.94, 639523.94, 1279047.88]},
"AMT_em_pe": {"2026": 939533.04},
"STD": {"2026": [15339.57, 30679.14, 15339.57, 22979.74, 30679.14]},
"ID_AllTaxes_c": {"2026": [10000.0, 10000.0, 5000.0, 10000.0, 10000.0]},
"ID_Charity_crt_all": {"2026": 0.60},
"ID_Casualty_hc": {"2026": 1.00},
"ID_Miscellaneous_hc": {"2026": 1.00},
"ID_ps": {"2026": [9e+99, 9e+99, 9e+99, 9e+99, 9e+99]},
"ID_prt": {"2026": 0.00},
"ID_crt": {"2026": 1.00},
"II_em": {"2026": 0.00},
"II_em_ps": {"2026": [9e+99, 9e+99, 9e+99, 9e+99, 9e+99]},
"PT_qbid_rt": {"2026": 0.20},
"PT_qbid_taxinc_thd": {"2026": [201428.14, 402856.25, 201428.14, 201428.14, 402856.25]},
"PT_qbid_taxinc_gap": {"2026": [50000.0, 100000.0, 50000.0, 50000.0, 100000.0]},
"PT_qbid_w2_wages_rt": {"2026": 0.50},
"PT_qbid_alt_w2_wages_rt": {"2026": 0.25},
"PT_qbid_alt_property_rt": {"2026": 0.03},
"ALD_BusinessLosses_c": {"2026": [319821.19, 639642.39, 319821.19, 319821.19, 639642.39]},
"ALD_DomesticProduction_hc": {"2026": 1.00}
}
Loading

0 comments on commit ea93c7a

Please sign in to comment.