Exemple de calcul de l’impôt fédéral

Importation du package

import srd

Initialisation d’un ménage

On doit d’abord initialiser un ménage. Ici nous supposerons un couple avec deux membres ayant tous les deux 45 ans et des revenus de travail de 50 000$ et 25 000$, respectivement.

jean = srd.Person(age=45,earn=50e3)
pauline = srd.Person(age=45,earn=25e3)

On les insère dans un ménage vivant au Québec.

hh = srd.Hhold(jean,pauline,prov='qc')

On peut voir le profil de chacun des membres du ménage en utilisant vars():

vars(jean)
{'age': 45,
'male': True,
'inc_earn': 50000.0,
'inc_self_earn': 0,
'inc_work_month': [4166.666666666667,
4166.666666666667,
4166.666666666667,
4166.666666666667,
4166.666666666667,
4166.666666666667,
4166.666666666667,
4166.666666666667,
4166.666666666667,
4166.666666666667,
4166.666666666667,
4166.666666666667],
'prev_inc_work': 50000.0,
'inc_rpp': 0,
'inc_cpp': 0,
'net_cap_gains': 0,
'prev_cap_losses': 0,
'cap_gains_exempt': 0,
'inc_othtax': 0,
'inc_othntax': 0,
'div_elig': 0,
'div_other_can': 0,
'inc_rrsp': 0,
'con_rrsp': 0,
'con_non_rrsp': 0,
'con_rpp': 0,
'union_dues': 0,
'donation': 0,
'gift': 0,
'years_can': 27,
'disabled': False,
'widow': False,
'med_exp': 0,
'ndays_chcare_k1': 0,
'ndays_chcare_k2': 0,
'asset': 0,
'months_crb': 0,
'months_ei': 0,
'oas_years_post': 0,
'months_cesb': 0,
'months_cerb': 0,
'pub_drug_insurance': False,
'tax_shield': False,
'student': False,
'essential_worker': False,
'emp_temp_constraints': False,
'hours_month': None,
'dep_senior': False,
'home_support_cost': 0,
'pension_split': 0,
'pension_split_qc': 0,
'pension_deduction': 0,
'pension_deduction_qc': 0,
'inc_oas': 0,
'inc_gis': 0,
'rent': 0,
'prop_tax': 0,
'inc_ei': 0,
'inc_sa': 0,
'allow_couple': 0,
'allow_surv': 0,
'inc_cerb': 0,
'inc_cesb': 0,
'inc_crb': 0,
'inc_iprew': 0,
'covid': None,
'after_tax_inc': None,
'disp_inc': None,
'fed_return': None,
'prov_return': None,
'payroll': None,
'prov_contrib': None,
'max_split': 0.0}

Calcul de l’impôt fédéral

On doit d’abord créer un formulaire d’impôt pour une année en particulier.

from srd import federal
fed_form = federal.form(2022)

On peut voir les différents paramètres du système fiscal en utilisant encore vars():

vars(fed_form)
{'div_elig_factor': 1.38,
'div_other_can_factor': 1.15,
'div_elig_cred_rate': 0.150198,
'div_other_can_cred_rate': 0.090313,
'cap_gains_rate': 0.5,
'qpip_deduc_rate': 0.43786,
'basic_amount_poor': 14398.0,
'basic_amount_rich': 12719.0,
'age_cred_amount': 7898.0,
'min_age_cred': 65,
'age_cred_exempt': 39826.0,
'age_cred_claw_rate': 0.15,
'empl_cred_max': 1287.0,
'pension_cred_amount': 2000.0,
'pension_cred_min_age_split': 65,
'disability_cred_amount': 8870.0,
'med_exp_nr_cred_max_age': 18,
'med_exp_nr_cred_max_claw': 2479.0,
'med_exp_nr_cred_rate': 0.03,
'donation_frac_net': 0.75,
'donation_low_cut': 200.0,
'donation_high_cut': 216511.0,
'donation_low_rate': 0.15,
'donation_med_rate': 0.29,
'donation_high_rate': 0.33,
'rate_non_ref_tax_cred': 0.15,
'rate_abatment_qc': 0.165,
'ccb_young': 6997.0,
'ccb_old': 5903.0,
'ccb_max_num_ch': 4,
'ccb_cutoff_1': 32797.0,
'ccb_cutoff_2': 71060.0,
'ccb_rate_1_1ch': 0.07,
'ccb_rate_1_2ch': 0.135,
'ccb_rate_1_3ch': 0.19,
'ccb_rate_1_4ch': 0.23,
'ccb_rate_2_1ch': 0.032,
'ccb_rate_2_2ch': 0.057,
'ccb_rate_2_3ch': 0.08,
'ccb_rate_2_4ch': 0.095,
'med_exp_rate': 0.25,
'med_exp_claw_rate': 0.05,
'med_exp_claw_cutoff': 29129.0,
'med_exp_max': 1316.0,
'med_exp_min_work_inc': 3841.0,
'gst_cred_claw_rate': 0.05,
'gst_cred_claw_cutoff': 39826.0,
'gst_cred_base': 459.0,
'gst_cred_other': 241.5,
'gst_cred_rate': 0.02,
'gst_cred_base_amount': 9919.0,
'gst_covid_single': 400.0,
'gst_covid_couple': 600.0,
'chcare_young': 8000.0,
'chcare_old': 5000.0,
'chcare_rate_inc': 0.66666,
'ei_max_net_inc': 70375.0,
'ei_rate_repay': 0.3,
'ded_qpp_rate': 0.052632,
'ded_qpp_exempt': 3500,
'ded_qpp_claw_rate': 0.03,
'nrtc_spouse_dis': 2357,
'dep_disa_amount': 2985,
'base_single': 2400,
'base_couple': 3600,
'rate_single_dep': 0.2,
'rate': 0.373,
'rate_couple_dep': 0.239,
'max_single': 3277.92,
'max_single_dep': 1757.59,
'max_couple': 5120.45,
'max_couple_dep': 3280.93,
'exempt_single': 12683.06,
'exempt_single_dep': 12700.5,
'exempt_couple': 19457.77,
'exempt_couple_dep': 19508.32,
'exempt_second_earner': 14000,
'claw_rate': 0.2,
'dis_base': 1200,
'dis_max': 738.31,
'dis_rate_single': 0.4,
'dis_rate_couple': 0.2,
'dis_exempt_single': 29072.64,
'dis_exempt_single_dep': 21488.47,
'dis_exempt_couple': 45060.02,
'dis_exempt_couple_dep': 35912.95,
'dis_claw_rate': 0.2,
'dis_couple_claw_rate': 0.1,
'l_brackets': [0.0, 50197.0, 100392.0, 155625.0, 221708.0],
'l_rates': [0.15, 0.205, 0.26, 0.29, 0.33],
'l_constant': [0.0, 7530.0, 17820.0, 32180.0, 51344.0],
'witb_params': {'on': {'base_single': 3000,
'base_couple': 3000,
'rate_single_dep': 0.27,
'rate': 0.27,
'rate_couple_dep': 0.27,
'max_single': 1428.48,
'max_single_dep': 1428.48,
'max_couple': 2460.67,
'max_couple_dep': 2460.67,
'exempt_single': 23494.66,
'exempt_single_dep': 26805.25,
'exempt_couple': 26805.25,
'exempt_couple_dep': 26805.25,
'claw_rate': 0.12,
'dis_base': 1150,
'dis_max': 737.28,
'dis_rate_single': 0.27,
'dis_rate_couple': 0.27,
'dis_exempt_single': 33017.86,
'dis_exempt_single_dep': 43209.73,
'dis_exempt_couple': 43209.73,
'dis_exempt_couple_dep': 43209.73,
'dis_claw_rate': 0.15,
'dis_couple_claw_rate': 0.075},
'qc': {'base_single': 2400,
'base_couple': 3600,
'rate_single_dep': 0.2,
'rate': 0.373,
'rate_couple_dep': 0.239,
'max_single': 3277.92,
'max_single_dep': 1757.59,
'max_couple': 5120.45,
'max_couple_dep': 3280.93,
'exempt_single': 12683.06,
'exempt_single_dep': 12700.5,
'exempt_couple': 19457.77,
'exempt_couple_dep': 19508.32,
'exempt_second_earner': 14000,
'claw_rate': 0.2,
'dis_base': 1200,
'dis_max': 738.31,
'dis_rate_single': 0.4,
'dis_rate_couple': 0.2,
'dis_exempt_single': 29072.64,
'dis_exempt_single_dep': 21488.47,
'dis_exempt_couple': 45060.02,
'dis_exempt_couple_dep': 35912.95,
'dis_claw_rate': 0.2,
'dis_couple_claw_rate': 0.1}}}

On remplit le formulaire d’impôt à l’aide de la fonction tax().

from srd import tax
tax_form = tax(2022)
tax_form.compute(hh)

On peut visualiser un formulaire d’impôt sommaire qui est rattaché à chaque personne:

jean.fed_return
{'gross_income': 50000.0,
'deductions_gross_inc': 348.75,
'net_income': 49651.25,
'deductions_net_inc': 0.0,
'taxable_income': 49651.25,
'gross_tax_liability': 7447.6875,
'non_refund_credits': 2856.45,
'refund_credits': 757.5541875,
'net_tax_liability': 3833.6833125000003}
pauline.fed_return
{'gross_income': 25000.0,
'deductions_gross_inc': 161.25,
'net_income': 24838.75,
'deductions_net_inc': 0.0,
'taxable_income': 24838.75,
'gross_tax_liability': 3725.8125,
'non_refund_credits': 2590.4249999999997,
'refund_credits': 187.33893750000004,
'net_tax_liability': 948.0485625000002}

On peut ajouter des enfants au ménage à l’aide de la fonction add_dependent().

emma = srd.Dependent(age=4, child_care=2000, med_exp=500)
alex = srd.Dependent(age=14, school=4000)
hh.add_dependent(emma,alex)

On peut ensuite calculer le nouveau formulaire d’impôt pour les deux adultes de la famille.

tax_form.compute(hh)
jean.fed_return
{'gross_income': 50000.0,
'deductions_gross_inc': 348.75,
'net_income': 49651.25,
'deductions_net_inc': 0.0,
'taxable_income': 49651.25,
'gross_tax_liability': 7447.6875,
'non_refund_credits': 2856.45,
'refund_credits': 4584.0466875,
'net_tax_liability': 7.190812499999993}
pauline.fed_return
{'gross_income': 25000.0,
'deductions_gross_inc': 2161.25,
'net_income': 22838.75,
'deductions_net_inc': 0.0,
'taxable_income': 22838.75,
'gross_tax_liability': 3425.8125,
'non_refund_credits': 2590.4249999999997,
'refund_credits': 3964.3314375,
'net_tax_liability': -3128.9439374999997}

On peut voir les différents attributs du ménage en utilisant encore vars():

vars(hh)
{'sp': [<srd.actors.Person at 0x2ce1bbd19d0>,
<srd.actors.Person at 0x2ce1b369610>],
'couple': True,
'prev_fam_net_inc_prov': None,
'prov': 'qc',
'dep': [<srd.actors.Dependent at 0x2ce1c23f460>,
<srd.actors.Dependent at 0x2ce1c23f0d0>],
'nkids_0_6': 1,
'nkids_7_16': 1,
'nkids_0_17': 2,
'nkids_0_18': 2,
'n_adults_in_hh': 2,
'elig_split': False,
'sa_elig_asset': True,
'nkids_0_5': 1,
'nkids_6_17': 1}

Expériences

On peut faire des expériences assez complexes. Une première consisterait par exemple à regarder l’impôt fédéral payé si on augmente les revenus de travail par petites tranches.

import numpy as np
from matplotlib import pyplot as plt

earns = np.linspace(10e3,200e3,100)
atrs = []
for earn in earns:
    jean = srd.Person(age=45,earn=earn)
    hh = srd.Hhold(jean, prov='qc')
    tax_form.compute(hh)
    atrs.append(jean.fed_return['net_tax_liability']/jean.fed_return['gross_income'])

plt.figure()
plt.plot(earns,atrs)
plt.xlabel('niveau de revenu de travail')
plt.ylabel('taux moyen imposition effectif')
plt.show()
_images/output_ex1.png

On peut aussi faire une expérience dans laquelle on change un paramètre du système d’imposition. Supposons par exemple qu’on augmente le montant de base:

base = np.linspace(1.0,1.5,10)
atrs = []
bases = []
jean.inc_earn = 50e3
base_amount = tax_form.federal.basic_amount_poor
for b in base:
    tax_form.federal.basic_amount_poor = base_amount * b
    bases.append(tax_form.federal.basic_amount_poor)
    tax_form.compute(hh)
    atrs.append(jean.fed_return['net_tax_liability']/jean.fed_return['gross_income'])

plt.figure()
plt.plot(bases,atrs)
plt.xlabel('montant de base')
plt.ylabel('taux moyen imposition effectif')
plt.show()
_images/output_ex2.png