import sympy as sp
import matplotlib
%matplotlib notebook
from ipywidgets import *
# matplotlib.rc('lines', linewidth=2, color='g')
matplotlib.rcParams['axes.grid'] = True
AGI Federal Tax Brackets | Definitions |
---|---|
|
AGI, GI, deductions = sp.symbols('AGI GI deductions')
AGI = GI - deductions
STANDARD_DEDUCTION=12400
tax_fed=sp.Piecewise((0, AGI<0),
(0.10*AGI, AGI<=9875),
(987.50 + 0.12*(AGI-9875), AGI<=40125),
(4617.50 + 0.22*(AGI-40125), AGI<=85525),
(14605.5 + 0.24*(AGI-85525), AGI<=163000),
(33271.5 + 0.32*(AGI-163300),AGI<=207350),
(47367.5 + 0.35*(AGI-207350),AGI<=518400),
(156235 + 0.37*(AGI-518401),True))
tax_fed
sp.plotting.plot(tax_fed.subs(deductions,STANDARD_DEDUCTION), (GI, 0, 500000),
title='Gross Income vs. Federal Income Tax Owed', ylabel='Fed Tax owed($)', xlabel='GI($)', line_color='blue')
print("NOTE: Single salaried employee taking the standard deduction")
sp.plotting.plot(tax_fed.subs(deductions,STANDARD_DEDUCTION)/GI, (GI, 0, 500000),
title='% of GI payed to Federal Income Taxes', ylabel='%', xlabel='GI($)', line_color='blue')
print("NOTE: Single salaried employee taking the standard deduction")
ss_tax = sp.Piecewise((0.062*GI, GI<137700),
(8537.4, True))
medicare_tax = sp.Piecewise( (0.0145*GI, GI<200000),
((0.0145+0.009)*GI, True))
tax_FICA = ss_tax + medicare_tax
tax_FICA
sp.plotting.plot(tax_FICA, (GI, 0, 500000),
title='FICA Tax vs Gross Income', ylabel='FICA Tax ($)', xlabel='GI($)', line_color='darkblue')
print("NOTE: Single salaried employee taking the standard deduction. No deductions can be made on FICA(?)")
fed_and_FICA = tax_fed + tax_FICA
sp.plotting.plot(fed_and_FICA.subs(deductions,STANDARD_DEDUCTION), (GI, 0, 500000),
title='Fed + FICA Tax vs Gross Income', ylabel='Taxes owed($)', xlabel='GI($)', line_color='royalblue')
print("NOTE: Single salaried employee taking the standard deduction")
plot4=sp.plotting.plot(fed_and_FICA.subs(deductions,STANDARD_DEDUCTION)/GI, (GI, 0, 500000),
title='% of GI paid to Fed + FICA', ylabel='% of GI', xlabel='GI($)', line_color='royalblue')
print("NOTE: Single salaried employee taking the standard deduction")
x = sp.symbols('x')
MAX_SALARY = 500000
post_tax_income = GI - fed_and_FICA.subs(deductions,STANDARD_DEDUCTION)
post_tax_plot=sp.plotting.plot(post_tax_income, (GI, 0, MAX_SALARY),
title='Gross & Take Home Pay', ylabel='Pay($)', xlabel='GI($)', line_color='royalblue', show=False)
no_fed_tax_plot = sp.plotting.plot(x, (x, 0, MAX_SALARY), line_color="teal", show=False)
post_tax_plot.append(no_fed_tax_plot[0])
post_tax_plot.show()
print("NOTE: Single salaried employee taking the standard deduction. Does not account for state tax")
(still single tax payer taking standard deduction)
state_tax_ny=sp.Piecewise((0, AGI<0),
(000.00 + 0.0400*(AGI-00.00), AGI<=8500),
(340.00 + 0.0450*(AGI-8500), AGI<=11700),
(484.50 + 0.0525*(AGI-11700), AGI<=13900),
(599.50 + 0.0590*(AGI-13900), AGI<=21400),
(1042.0 + 0.0621*(AGI-21400), AGI<=80650),
(4721.43 + 0.0649*(AGI-80650), AGI<=215400),
(13466.7 + 0.0685*(AGI-215400),AGI<1077550),
(72523.98+ 0.0882*(AGI-1077550), True))
state_tax_ca=sp.Piecewise((0, AGI<0),
(000.00 + 0.0100*(AGI-00.00), AGI<=8809),
(88.090 + 0.0200*(AGI-8809), AGI<=20883),
(329.57 + 0.0400*(AGI-20883), AGI<=32960),
(812.65 + 0.0600*(AGI-32960), AGI<=45753),
(1580.23 + 0.0800*(AGI-45753), AGI<=57824),
(2545.91 + 0.0930*(AGI-57824), AGI<=295373),
(24637.97 + 0.0103*(AGI-295373),AGI<=354445),
(30722.38 + 0.0113*(AGI-354445),AGI<=590742),
(57423.94 + 0.0123*(AGI-590742),AGI<=1000000),
(107762.68+ 0.0133*(AGI-1000000), True))
MAX_SALARY = 500000
ca_plot = sp.plotting.plot(state_tax_ca.subs(deductions, STANDARD_DEDUCTION), (GI, 0, MAX_SALARY),
title='State Income Tax Owed', ylabel='State Tax($)', xlabel='GI($)', line_color='red', show=False)
ny_plot = sp.plotting.plot(state_tax_ny.subs(deductions, STANDARD_DEDUCTION), (GI, 0, MAX_SALARY),
title='State Income Tax Owed', ylabel='State Tax($)', xlabel='GI($)', line_color='green', show=False)
ca_plot.append(ny_plot[0])
ca_plot.show()
tax_liability_ca = state_tax_ca + fed_and_FICA
tax_liability_ny = state_tax_ny + fed_and_FICA
tot_tax = sp.plotting.plot(
tax_liability_ca.subs(deductions, STANDARD_DEDUCTION),
tax_liability_ny.subs(deductions, STANDARD_DEDUCTION),
(GI, 0, MAX_SALARY), title='GI vs. Total Tax Liability', ylabel='%', xlabel='AGI($)', show=False)
tot_tax[0].line_color = 'red'
tot_tax.show()
tot_perc_plot = sp.plotting.plot(
tax_liability_ca.subs(deductions, STANDARD_DEDUCTION)/GI,
tax_liability_ny.subs(deductions, STANDARD_DEDUCTION)/GI,
(GI, 0, MAX_SALARY), title='% of GI owed in Taxes', ylabel='%', xlabel='GI($)', show=False)
tot_perc_plot[0].line_color = 'red'
tot_perc_plot.show()
The graph above shows the decreasing value of earned income as it reaches a ~40% asymptote. Here are a few notable benchmarks for this given scenario:
This suggests that any investment that increases our gross income should be normalized when compared to an investment that gets taxed at a different rate. For example, and index fund that returns 7% annually vs a long term capital gain that returns 5% anually would become 0.7*(1-0.27)
vs 0.5*(1-0.15)
because long term capital gains get taxed at 15%*. The after tax normalized comparison would be 5.11% vs 4.25% if our earned income is 100k
At 250k earned income normalizing the same investments above we have: 0.7*(1-0.36)
vs 0.5*(1*0.15)
or 4.48% vs 4.25%. As you can see, as earned income gross, its become increasingly beneficial to seek sources of income that are
*in 2020, if making between 40,001 to $441,450
In order to reduce our tax liability we can try and change the character of our income. Above, we analyzed ordinary income (wages, salaries, commisions, bonuses, etc). Long term capital gains (assets held for more than a year) are usually taxed at a lower rate
Another way to reduce tax liability is to increase our deductions to an amount greater than STANDARD_DEDUCTION
so that it becomes advantageous to itemize instead. Popular tax deductions are:
apy = 0.03892
home_price = 538000
down_payment_perc = 0.20
loan_len_years = 30
avg_ny_prop_tax = 0.01973
# M = P[r(1+r)^n/((1+r)^n)-1)]
monthly_mortgage_payment = (home_price - home_price*down_payment_perc)*( (apy/12)*(1+apy/12)**(loan_len_years*12)/( (1+apy/12)**(loan_len_years*12) -1))
tax_deduction_estiamte = round(monthly_mortgage_payment,3)*12 + home_price*avg_ny_prop_tax
print("mortgage payment: ${}, property tax: ${}".format(round(monthly_mortgage_payment*12,2), home_price*avg_ny_prop_tax))
print("Guesstimated deductible amount ${}".format(tax_deduction_estiamte))