def calcIDAdjustment(corp, eta=0.4): """ Calculates the adjustment factors for the corporate and noncorporate debt and interest. eta: retirement rate of existing debt """ policy = Policy() policy_params_df = policy.parameters_dataframe() # Create Asset object asset = Asset(policy_params_df, corp) asset.calc_all() # Get asset forecast forecast = asset.get_forecast() # Create Debt object debt = Debt(policy_params_df, forecast, corp=corp) debt.calc_all() # Get unscaled net interest deduction NID_gross = debt.NID[38:54] # Get net interest deduction from historical IRS data if corp: NID_irs = np.array(data1.debt_data_corp['NID_IRS'])[38:54] else: NID_irs = np.array(data1.debt_data_noncorp['ID_Scorp'][38:54] + data1.debt_data_noncorp['ID_sp'][38:54] + data1.debt_data_noncorp['ID_partner'][38:54]) NID_scale = sum(NID_irs / NID_gross) / 16.0 # 16 = 54 - 38 return NID_scale
def calcIDAdjustment(corp, eta=0.4): """ Calculates the adjustment factors for the corporate and noncorporate debt and interest. eta: retirement rate of existing debt """ data = Data() policy = Policy() policy_params_df = policy.parameters_dataframe() # Create Asset object asset = Asset(policy_params_df, corp) asset.calc_all() # Get asset forecast forecast = asset.get_forecast() # Create Debt object debt = Debt(policy_params_df, forecast, corp=corp) debt.calc_all() # Get unscaled interest incomes and expenses intpaid_model = debt.int_expense[40:54] intinc_model = debt.int_income[40:54] muniinc_model = debt.muni_income[40:54] if corp: # Exclude anomalous results for 2007 paid_scale = (sum(intpaid[:7] / intpaid_model[:7]) + sum(intpaid[8:] / intpaid_model[8:])) / 13. inc_scale = (sum(taxint[:7] / intinc_model[:7]) + sum(taxint[8:] / intinc_model[8:])) / 13. muni_scale = (sum(ntaxint[:7] / muniinc_model[:7]) + sum(ntaxint[8:] / muniinc_model[8:]))/ 13. scales = [paid_scale, inc_scale, muni_scale] else: ID_irs = np.array(data.debt_data_noncorp['ID_Scorp'][40:54] + data.debt_data_noncorp['ID_sp'][40:54] + data.debt_data_noncorp['ID_partner'][40:54]) scales = sum(ID_irs / intpaid_model) / 14. assets14 = forecast[0] return (scales, assets14, intpaid_model, intinc_model, muniinc_model)
class CorpTaxReturn(): """ Constructor for the CorpTaxReturn object. This class includes objects relevant to the calculation of corporate income tax liability: assets: an associated Asset object debts: an associated debt object combined_return: a DataFrame with tax calculations for each year Parameters: btax_params: dict of business tax policy parameters assets: Asset object for the corporation debts: Debt object for the corporation earnings: list or array of earnings for each year in the budget window """ def __init__(self, btax_params, earnings, data=None, assets=None, debts=None): # Create an associated Data object if isinstance(data, Data): self.data = data else: self.data = Data() if isinstance(btax_params, pd.DataFrame): self.btax_params = btax_params else: raise ValueError('btax_params must be DataFrame') if assets is not None: if isinstance(assets, Asset): self.assets = assets else: raise ValueError('assets must be Asset object') else: self.assets = Asset(btax_params) self.assets.calc_all() if debts is not None: if isinstance(debts, Debt): self.debts = debts else: raise ValueError('debts must be Debt object') else: assets_forecast = self.assets.get_forecast() self.debts = Debt(btax_params, assets_forecast) self.debts.calc_all() # Use earnings to create DataFrame for results assert len(earnings) == 14 combined = pd.DataFrame({'year': range(2014,2028), 'ebitda': earnings}) # Add tax depreciation and net interest deductions combined['taxDep'] = self.assets.get_taxdep() combined['nid'] = self.debts.get_nid() self.combined_return = combined def update_assets(self, assets): """ Updates the Asset object associated with the tax return. """ if isinstance(assets, Asset): self.assets = assets else: raise ValueError('assets must be Asset object') def update_debts(self, debts): """ Updates the Debt object associated with the tax return. """ if isinstance(debts, Debt): self.debts = debts else: raise ValueError('debts must be Debt object') def update_earnings(self, earnings): """ Updates the earnings DataFrame associated with the tax return. """ assert len(earnings) == 14 self.combined_return['ebitda'] = earnings def calcSec199(self): """ Calculates section 199 deduction. """ # Extract relevant parmeters s199_hclist = np.array(self.btax_params['sec199_hc']) profit = np.asarray(self.data.gfactors['profit_d']) sec199_res = np.zeros(14) sec199_2013 = np.asarray(self.data.historical_taxdata['sec199'])[-1] for i in range(14): sec199_res[i] = profit[i+1] / profit[0] * sec199_2013 * (1 - s199_hclist[i]) self.combined_return['sec199'] = sec199_res def calcInitialTax(self): """ Calculates taxable income and tax before credits. """ self.combined_return['taxinc'] = (self.combined_return['ebitda'] - self.combined_return['taxDep'] - self.combined_return['nid'] - self.combined_return['sec199']) self.combined_return['tau'] = self.btax_params['tau_c'] self.combined_return['taxbc'] = (self.combined_return['taxinc'] * self.combined_return['tau']) def calcFTC(self): """ Calculates foreign tax credit for 2014-2027. """ hclist = np.array(self.btax_params['ftc_hc']) def calcWAvgTaxRate(year): """ Calculates the weighted average statutory corporate tax rate in all OECD countries in a given year. """ assert year in range(1995, 2028) year = min(year, 2016) gdp_list = np.asarray(self.data.ftc_gdp_data[str(year)]) taxrate_list = np.asarray(self.data.ftc_taxrates_data[str(year)]) # remove observations with missing data taxrate_list2 = np.where(np.isnan(taxrate_list), 0, taxrate_list) gdp_list2 = np.where(np.isnan(taxrate_list), 0, gdp_list) avgrate = sum(taxrate_list2 * gdp_list2) / sum(gdp_list2) return avgrate # Get foreign profits forecast profits = np.asarray(self.data.ftc_other_data['C_total'][19:]) profits_d = np.asarray(self.data.ftc_other_data['C_domestic'][19:]) tax_f = np.zeros(14) for i in range(14): tax_f[i] = calcWAvgTaxRate(i + 2014) ftc_final = ((profits - profits_d) * tax_f / 100. * self.data.adjfactor_ftc_corp * (1 - hclist)) * self.data.rescale_corp self.combined_return['ftc'] = ftc_final def calcAMT(self): """ Calculates the AMT revenue and PYMTC for 2014-2027 pymtc_status: 0 for no change, 1 for repeal, 2 for refundable """ # Get relevant tax information taxinc = np.array(self.combined_return['taxinc']) amt_rates = np.array(self.btax_params['tau_amt']) ctax_rates = np.array(self.btax_params['tau_c']) pymtc_status = np.array(self.btax_params['pymtc_status']) # Check values for PYMTC status for x in pymtc_status: assert x in [0, 1, 2] # Create empty arrays for AMT, PYMTC, and stocks (by status) A = np.zeros(14) P = np.zeros(14) stockA = np.zeros(15) stockN = np.zeros(15) stockA[0] = ((self.data.trans_amt1 * self.data.userate_pymtc + self.data.trans_amt2 * (1 - self.data.userate_pymtc)) / (1 - self.data.trans_amt1) * self.data.stock2014) stockN[0] = self.data.stock2014 - stockN[0] stockN[0] = (1 - self.data.trans_amt1) / (1 - self.data.trans_amt1 + self.data.trans_amt1 * self.data.userate_pymtc + self.data.trans_amt2 * (1 - self.data.userate_pymtc)) * self.data.stock2014 stockA[0] = self.data.stock2014 - stockN[0] for i in range(14): # Calculate AMT if amt_rates[i] == 0.: # If no AMT A[i] = 0. frac_amt = 0. elif ctax_rates[i] <= amt_rates[i]: # If AMT rate exceeds regular rate (all subject to AMT) A[i] = ((amt_rates[i] - ctax_rates[i] + amt_rates[i] / self.data.param_amt) * taxinc[i]) frac_amt = 0.999 else: A[i] = (amt_rates[i] / self.data.param_amt * np.exp(-self.data.param_amt * (ctax_rates[i] / amt_rates[i] - 1)) * taxinc[i]) frac_amt = np.exp(-self.data.param_amt * (ctax_rates[i] / amt_rates[i] - 1)) # Adjust transition params for change in AMT frequency alpha = max(0.0, min(1.0, self.data.trans_amt1 * (frac_amt / self.data.amt_frac)**0.5)) beta = (1 - alpha) * frac_amt / (1 - frac_amt) if pymtc_status[i] == 0: # No change from baseline userate = self.data.userate_pymtc elif pymtc_status[i] == 1: # PYMTC repealed userate = 0.0 else: # PYMTC made fully refundable userate = 1.0 P[i] = userate * stockN[i] stockA[i+1] = (alpha * (stockA[i] + A[i]) + beta * (stockN[i] - P[i])) stockN[i+1] = ((1 - alpha) * (stockA[i] + A[i]) + (1 - beta) * (stockN[i] - P[i])) # Rescale for any cross-sector shifting amt_final = A * self.data.rescale_corp pymtc_final = P * self.data.rescale_corp self.combined_return['amt'] = amt_final self.combined_return['pymtc'] = pymtc_final def calcTax(self): """ Calculates final tax liability. """ # Calculate general business credits profit = np.asarray(self.data.gfactors['profit_d']) gbc_2013 = np.asarray(self.data.historical_taxdata['gbc'])[-1] gbc_res = profit[1:] / profit[0] * gbc_2013 self.combined_return['gbc'] = gbc_res # Calculate final tax liability self.combined_return['taxrev'] = (self.combined_return['taxbc'] + self.combined_return['amt'] - self.combined_return['ftc'] - self.combined_return['pymtc'] - self.combined_return['gbc']) def calc_all(self): """ Executes all tax calculations. """ self.calcSec199() self.calcInitialTax() self.calcFTC() self.calcAMT() self.calcTax() def getReturn(self): """ Returns the tax return information """ combined_result = copy.deepcopy(self.combined_return) return combined_result def get_tax(self): """ Returns the total tax liability. """ tax1 = np.array(self.combined_return['taxrev']) return tax1
class CorpTaxReturn(): """ Constructor for the CorpTaxReturn object. This class includes objects relevant to the calculation of corporate income tax liability: assets: an associated Asset object debts: an associated debt object combined_return: a DataFrame with tax calculations for each year Parameters: btax_params: dict of business tax policy parameters assets: Asset object for the corporation debts: Debt object for the corporation earnings: list or array of earnings for each year in the budget window """ def __init__(self, btax_params, revenues, deductions, credit, dmne=None, data=None, assets=None, debts=None): # Create an associated Data object if isinstance(data, Data): self.data = data else: self.data = Data() if isinstance(btax_params, pd.DataFrame): self.btax_params = btax_params else: raise ValueError('btax_params must be DataFrame') if isinstance(revenues, pd.DataFrame): self.revenues = copy.deepcopy(revenues) else: raise ValueError('revenues must be in DataFrame') if isinstance(deductions, pd.DataFrame): self.deductions = copy.deepcopy(deductions) else: raise ValueError('deductions must be in DataFrame') if isinstance(credit, pd.DataFrame): self.credits = copy.deepcopy(credit) else: raise ValueError('credits must be in DataFrame') if dmne is None: # Note: Don't do this in general self.dmne = DomesticMNE(self.btax_params) self.dmne.calc_all() elif isinstance(dmne, DomesticMNE): self.dmne = dmne else: raise ValueError('dmne must be a DomesticMNE object') if assets is not None: if isinstance(assets, Asset): self.assets = assets else: raise ValueError('assets must be Asset object') else: self.assets = Asset(btax_params) self.assets.calc_all() if debts is not None: if isinstance(debts, Debt): self.debts = debts else: raise ValueError('debts must be Debt object') else: assets_forecast = self.assets.get_forecast() self.debts = Debt(btax_params, assets_forecast) self.debts.calc_all() # Prepare unmodeled components of tax return self.revenues['capgains'] = ( self.revenues['capgains'] * (1. - self.btax_params['capgains_corp_hc'])) self.revenues['domestic_divs'] = ( self.revenues['domestic_divs'] * self.btax_params['domestic_dividend_inclusion']) self.revenues['total'] = (self.revenues['receipts'] + self.revenues['rent'] + self.revenues['royalties'] + self.revenues['capgains'] + self.revenues['domestic_divs'] + self.revenues['other'] + self.dmne.dmne_results['foreign_taxinc']) self.deductions['charity'] = (self.deductions['charity'] * (1. - self.btax_params['charity_hc'])) self.deductions['statelocaltax'] = ( self.deductions['statelocaltax'] * (1. - self.btax_params['statelocaltax_hc'])) self.deductions['total'] = ( self.deductions['cogs'] + self.deductions['execcomp'] + self.deductions['wages'] + self.deductions['repairs'] + self.deductions['baddebt'] + self.deductions['rent'] + self.deductions['statelocaltax'] + self.deductions['charity'] + self.deductions['amortization'] + self.deductions['depletion'] + self.deductions['advertising'] + self.deductions['pensions'] + self.deductions['benefits'] + self.deductions['other']) combined = pd.DataFrame({ 'year': range(START_YEAR, END_YEAR + 1), 'ebitda': (self.revenues['total'] - self.deductions['total']) }) # Add tax depreciation combined['taxDep'] = self.assets.get_taxdep() self.combined_return = combined def update_assets(self, assets): """ Updates the Asset object associated with the tax return. """ if isinstance(assets, Asset): self.assets = assets else: raise ValueError('assets must be Asset object') def update_debts(self, debts): """ Updates the Debt object associated with the tax return. """ if isinstance(debts, Debt): self.debts = debts else: raise ValueError('debts must be Debt object') def update_earnings(self, dearnings): """ Updates the earnings DataFrame associated with the tax return. """ assert len(dearnings) == NUM_YEARS fearnings = np.asarray(self.dmne.dmne_results['foreign_taxinc']) self.combined_return['ebitda'] = dearnings + fearnings def calcInterestDeduction(self): """ Computes interest deduction. """ # Compute adjusted taxable income adjTaxInc = np.maximum( self.combined_return['ebitda'] - self.revenues['capgains'] - self.combined_return['taxDep'] + self.btax_params['adjustedTaxInc_def'] * (self.combined_return['taxDep'] + self.deductions['amortization'] + self.deductions['depletion']), 0.0001) # Section 163(j) deduction limitation deductible_int = ( adjTaxInc * self.btax_params['adjustedTaxInc_limit'] + self.debts.get_intInc()) intded0 = self.debts.get_intDed() intded1 = np.zeros(NUM_YEARS) for i in range(NUM_YEARS): if i > 0: # Add disallowed interest as carryforward from prior year intded0[i] = intded0[i] + intded0[i - 1] - intded1[i - 1] intded1[i] = min(deductible_int[i], intded0[i]) # Apply interest haircuts intTaxInc = (self.debts.get_intInc() * (1. - self.btax_params['intIncome_corp_hc']) + self.debts.get_muniInc() * (1. - self.btax_params['muniIntIncome_corp_hc'])) intTaxDed = intded1 * (1. - self.btax_params['intPaid_corp_hc']) # Compute net interest deduction self.combined_return['nid'] = intTaxDed - intTaxInc # Assign fraction of interest deductible to Debt object fracded = intTaxDed / (self.debts.get_intPaid() + 0.000001) self.btax_params['fracded_c'] = fracded def calcInitialTax(self): """ Calculates taxable income and tax before credits. """ netinc1 = (self.combined_return['ebitda'] - self.combined_return['taxDep'] - self.combined_return['nid']) self.combined_return['sec199'] = (netinc1 * self.deductions['sec199share'] * self.btax_params['sec199_rt']) netinc2 = netinc1 - self.combined_return['sec199'] self.combined_return['taxinc'] = np.maximum(netinc2, 0.) self.combined_return['tau'] = self.btax_params['tau_c'] self.combined_return['taxbc'] = (self.combined_return['taxinc'] * self.combined_return['tau']) def calcFTC(self): """ Gets foreign tax credit from DomesticMNE """ self.combined_return['ftc'] = self.dmne.dmne_results['ftc'] def calcAMT(self): """ Calculates the AMT revenue and PYMTC for [START_YEAR, END_YEAR] """ # Overall transition rates and parameters trans_amt0 = self.data.trans_amt0 trans_amt1 = self.data.trans_amt1 userate = self.data.userate_pymtc amt2013 = self.data.corp_tax2013.loc[40, 'ALL'] # Get relevant tax information taxinc = np.array(self.combined_return['taxinc']) amt_rates = np.array(self.btax_params['tau_amt']) ctax_rates = np.array(self.btax_params['tau_c']) pymtc_hc = np.array(self.btax_params['pymtc_hc']) pymtc_refund = np.array(self.btax_params['pymtc_refund']) # Create empty arrays for AMT, PYMTC, and stocks (by status) A = np.zeros(NUM_YEARS) P = np.zeros(NUM_YEARS) stock0 = np.zeros(NUM_YEARS + 1) stock1 = np.zeros(NUM_YEARS + 1) # Set initial stocks using steady-state equations stock0[0] = amt2013 / userate stock1[0] = amt2013 * (trans_amt1 / (1. - trans_amt1) + (1. - userate) / userate * (1. - trans_amt0) / (1. - trans_amt1)) for iyr in range(NUM_YEARS): # Calculate AMT if amt_rates[iyr] == 0.: # If no AMT A[iyr] = 0. frac_amt = 0. # Update transition rate parameters pi0 = 1. pi1 = 0. elif ctax_rates[iyr] <= amt_rates[iyr]: # If AMT rate exceeds regular rate (all subject to AMT) A[iyr] = ((amt_rates[iyr] - ctax_rates[iyr] + amt_rates[iyr] / self.data.param_amt) * taxinc[iyr]) frac_amt = 0.999 # Update transition rate parameters pi0 = 0. pi1 = 1. else: A[iyr] = (amt_rates[iyr] / self.data.param_amt * np.exp(-self.data.param_amt * (ctax_rates[iyr] / amt_rates[iyr] - 1)) * taxinc[iyr]) # Compute new fraction subject to AMT frac_amt = np.exp(-self.data.param_amt * (ctax_rates[iyr] / amt_rates[iyr] - 1)) # Adjust transition params for change in AMT frequency pi1 = max( min( self.data.trans_amt1 * (frac_amt / self.data.amt_frac)**0.5, 1.), 0.) pi0 = max(min(1. - frac_amt * (1 - pi1) / (1 - frac_amt), 1.), 0.) # Compute PYMTC P[iyr] = ((pymtc_refund[iyr] * stock0[iyr] + (1. - pymtc_refund[iyr]) * stock0[iyr] * userate) * (1. - pymtc_hc[iyr])) # Update credits carried forward stock0[iyr + 1] = ((stock1[iyr] + A[iyr]) * (1. - pi1) + (stock0[iyr] - P[iyr]) * pi0) stock1[iyr + 1] = ((stock1[iyr] + A[iyr]) * pi1 + (stock0[iyr] - P[iyr]) * (1. - pi0)) # Rescale for any cross-sector shifting amt_final = A * self.data.rescale_corp pymtc_final = P * self.data.rescale_corp self.combined_return['amt'] = amt_final self.combined_return['pymtc'] = pymtc_final def calcTax(self): """ Calculates final tax liability. """ self.combined_return['gbc'] = self.credits['gbc'] # Calculate final tax liability taxliab1 = (self.combined_return['taxbc'] + self.combined_return['amt'] - self.combined_return['ftc'] - self.combined_return['pymtc'] - self.combined_return['gbc']) self.combined_return['taxrev'] = np.maximum(taxliab1, 0.) def calc_all(self): """ Executes all tax calculations. """ self.calcInterestDeduction() self.calcInitialTax() self.calcFTC() self.calcAMT() self.calcTax() def getReturn(self): """ Returns the tax return information """ combined_result = copy.deepcopy(self.combined_return) return combined_result def get_tax(self): """ Returns the total tax liability. """ tax = np.array(self.combined_return['taxrev']) return tax
assets14 = forecast[0] return (scales, assets14, intpaid_model, intinc_model, muniinc_model) (scales_corp, ast_c_14, intpaid_model, intinc_model, muniinc_model) = calcIDAdjustment(True) (scale_ncorp, ast_nc_14, _, _, _) = calcIDAdjustment(False) print(scales_corp) print(scale_ncorp) newdebt = copy.deepcopy(debt2) newdebt['L_c'] = debt2['L_c'] * scales_corp[0] newdebt['L_nc'] = debt2['L_nc'] * scale_ncorp newdebt['At_c'] = debt2['At_c'] * scales_corp[1] newdebt['An_c'] = debt2['An_c'] * scales_corp[2] newdebt.to_csv(OUTPUT_PATH + 'debt_history.csv') pol1 = Policy() # Create Asset object asset = Asset(pol1.parameters_dataframe(), True) asset.calc_all() # Create Debt object debt = Debt(pol1.parameters_dataframe(), asset.get_forecast(), corp=True) debt.calc_all() df1 = pd.DataFrame({'inc_mod': intinc_model * scales_corp[1], 'paid_mod': intpaid_model * scales_corp[0], 'muni_mod': muniinc_model * scales_corp[2], 'inc_irs': taxint, 'paid_irs': intpaid, 'muni_irs': ntaxint}) df1.to_csv('debt_fit.csv')
class PassThrough(): """ Constructor for the PassThrough class. This contains the calculation of pass-through business income. All other components of pass-through taxation occur through Tax-Calculator. For now, a PassThrough object contains 6 different business entities: sole proprietorship, positive net income sole proprietorship, negative net income S corporation, positive net income S corporation, negative net income partnership, positive net income partnership, negative net income Therefore, the process for modeling the pass-through sector evolves in two stages. The first, like for the Corporation class, produces a single Asset object, Debt object and earnings for the pass-through sector. Once these are calculated, they are split between each of the 6 entities. The results from these will later be used by the Investor class to distribute the changes in business income to individuals in Tax-Calculator. The following functions apply to the sector as a whole: create_asset() create_earnings() create_debt() real_activity() """ def __init__(self, btax_params): # Store policy parameter objects if isinstance(btax_params, pd.DataFrame): self.btax_params = btax_params else: raise ValueError('btax_params must be DataFrame') # Create Data object self.data = Data() # Create Asset object and calculate self.asset = Asset(self.btax_params, corp=False, data=self.data) self.asset.calc_all() # Create earnings forecast self.create_earnings() def create_earnings(self): """ Creates the initial forecast for earnings. Static only. """ # Get initial EBITDA for 2014, for those in net income positions sp_posinc2014 = np.array(self.data.sp_data['netinc'])[-1] part_posinc2014 = np.array(self.data.partner_data['netinc_total'])[-1] scorp_posinc2014 = np.array(self.data.Scorp_data['netinc_total'])[-1] # Get initial EBITDA for 2014, for those in net loss positions sp_neginc2014 = -np.array(self.data.sp_data['netloss'])[-1] part_neginc2014 = -np.array(self.data.partner_data['netloss_total'])[-1] scorp_neginc2014 = -np.array(self.data.Scorp_data['netloss_total'])[-1] # Get growth factor for noncorporate business income and apply it gfact_propinc = np.array(self.data.gfactors['propinc_nonfarm'])[1:] sp_posinc = sp_posinc2014 / gfact_propinc[0] * gfact_propinc part_posinc = part_posinc2014 / gfact_propinc[0] * gfact_propinc scorp_posinc = scorp_posinc2014 / gfact_propinc[0] * gfact_propinc sp_neginc = sp_neginc2014 / gfact_propinc[0] * gfact_propinc part_neginc = part_neginc2014 / gfact_propinc[0] * gfact_propinc scorp_neginc = scorp_neginc2014 / gfact_propinc[0] * gfact_propinc # Aggregate and save EBITDAs total_inc = (sp_posinc + sp_neginc + part_posinc + part_neginc + scorp_posinc + scorp_neginc) earnings_result = pd.DataFrame({'year': range(2014,2028), 'total': total_inc, 'SchC_pos': sp_posinc, 'SchC_neg': sp_neginc, 'partner_pos': part_posinc, 'partner_neg': part_neginc, 'Scorp_pos': scorp_posinc, 'Scorp_neg': scorp_neginc}) self.earnings = earnings_result def create_debt(self): """ Creates the Debt object for the pass-through sector. Note: create_asset must have already been called """ self.debt = Debt(self.btax_params, self.asset.get_forecast(), data=self.data, corp=False) self.debt.calc_all() def real_activity(self): """ Produces a DataFrame of the pass-through sector's real activity. Real measures are: Capital stock Investment Depreciation (economic) Debt Interest paid Earnings Net income Cash flow Note that unlike for a corporation, the final real activity measures (net income and cash flow) are pre-tax, as these would be passed to units in Tax-Calculator. """ real_results = pd.DataFrame({'year': range(2014,2028), 'Earnings': self.earnings['total']}) real_results['Kstock'] = self.asset.get_forecast() real_results['Inv'] = self.asset.get_investment() real_results['Depr'] = self.asset.get_truedep() real_results['Debt'] = self.debt.get_debt() real_results['NIP'] = self.debt.get_nip() real_results['NetInc'] = real_results['Earnings'] - real_results['Depr'] - real_results['NIP'] real_results['CashFlow'] = real_results['Earnings'] - real_results['Inv'] self.real_results = real_results def calc_schC(self): """ Calculates net income for sole proprietorships """ SchC_results = pd.DataFrame({'year': range(2014,2028)}) # Update earnings SchC_results['ebitda_pos'] = self.earnings['SchC_pos'] SchC_results['ebitda_neg'] = self.earnings['SchC_neg'] # Update tax depreciation SchC_results['dep_pos'] = (self.asset.get_taxdep() * self.data.depshare_sp_posinc) SchC_results['dep_neg'] = (self.asset.get_taxdep() * self.data.depshare_sp_neginc) # Update interest deduction SchC_results['intded_pos'] = (self.debt.get_nid() * self.data.intshare_sp_posinc) SchC_results['intded_neg'] = (self.debt.get_nid() * self.data.intshare_sp_neginc) # Update business net income SchC_results['netinc_pos'] = SchC_results['ebitda_pos'] - SchC_results['dep_pos'] - SchC_results['intded_pos'] SchC_results['netinc_neg'] = SchC_results['ebitda_neg'] - SchC_results['dep_neg'] - SchC_results['intded_neg'] self.SchC_results = SchC_results def calc_partner(self): """ Calculates net income for partnerships """ partner_results = pd.DataFrame({'year': range(2014,2028)}) # Update earnings partner_results['ebitda_pos'] = self.earnings['partner_pos'] partner_results['ebitda_neg'] = self.earnings['partner_neg'] # Update tax depreciation partner_results['dep_pos'] = (self.asset.get_taxdep() * self.data.depshare_partner_posinc) partner_results['dep_neg'] = (self.asset.get_taxdep() * self.data.depshare_partner_neginc) # Update interest deduction partner_results['intded_pos'] = (self.debt.get_nid() * self.data.intshare_partner_posinc) partner_results['intded_neg'] = (self.debt.get_nid() * self.data.intshare_partner_neginc) # Update business net income partner_results['netinc_pos'] = partner_results['ebitda_pos'] - partner_results['dep_pos'] - partner_results['intded_pos'] partner_results['netinc_neg'] = partner_results['ebitda_neg'] - partner_results['dep_neg'] - partner_results['intded_neg'] self.partner_results = partner_results def calc_Scorp(self): """ Calculates net income for S corporations """ Scorp_results = pd.DataFrame({'year': range(2014,2028)}) # Update earnings Scorp_results['ebitda_pos'] = self.earnings['Scorp_pos'] Scorp_results['ebitda_neg'] = self.earnings['Scorp_neg'] # Update tax depreciation Scorp_results['dep_pos'] = (self.asset.get_taxdep() * self.data.depshare_scorp_posinc) Scorp_results['dep_neg'] = (self.asset.get_taxdep() * self.data.depshare_scorp_neginc) # Update interest deduction Scorp_results['intded_pos'] = (self.debt.get_nid() * self.data.intshare_scorp_posinc) Scorp_results['intded_neg'] = (self.debt.get_nid() * self.data.intshare_scorp_neginc) # Update business net income Scorp_results['netinc_pos'] = Scorp_results['ebitda_pos'] - Scorp_results['dep_pos'] - Scorp_results['intded_pos'] Scorp_results['netinc_neg'] = Scorp_results['ebitda_neg'] - Scorp_results['dep_neg'] - Scorp_results['intded_neg'] self.Scorp_results = Scorp_results def calc_netinc(self): """ Runs all calculations for each entity and saves the net income results. """ self.calc_schC() self.calc_partner() self.calc_Scorp() netinc_results = pd.DataFrame({'year': range(2014,2028)}) netinc_results['SchC_pos'] = self.SchC_results['netinc_pos'] netinc_results['SchC_neg'] = self.SchC_results['netinc_neg'] netinc_results['partner_pos'] = self.SchC_results['netinc_pos'] netinc_results['partner_neg'] = self.SchC_results['netinc_neg'] netinc_results['Scorp_pos'] = self.SchC_results['netinc_pos'] netinc_results['Scorp_neg'] = self.SchC_results['netinc_neg'] self.netinc_results = netinc_results def calc_static(self): """ Runs the static calculations """ self.create_debt() self.real_activity() self.calc_netinc() def update_legal(self, responses): """ Updates the rescale_corp and rescale_noncorp associated with each Data associated with each object. """ self.data.update_rescaling(responses.rescale_corp, responses.rescale_noncorp) self.asset.data.update_rescaling(responses.rescale_corp, responses.rescale_noncorp) def update_investment(self, responses): """ Updates the Asset object to include investment response. """ # First, save the capital stock by asset type and year (for earnings) self.old_capital_history = copy.deepcopy(self.asset.capital_history) self.asset.update_response(responses.investment_response) self.asset.calc_all() def update_earnings(self, responses): """ Recalculates earnings using the old capital stock by asset type, the new capital stock by asset type (based on the investment response), and the marginal product of capital. """ Kstock_base = copy.deepcopy(self.old_capital_history) Kstock_ref = copy.deepcopy(self.asset.capital_history) deltaK = Kstock_ref - Kstock_base changeEarnings = np.zeros((96, 14)) for j in range(14): # for each year mpk = np.array(responses.investment_response['MPKnc' + str(j + 2014)]) for i in range(96): # by asset changeEarnings[i,j] = deltaK[i,j] * mpk[i] * self.data.adjfactor_dep_noncorp deltaE = np.zeros(14) for j in range(14): deltaE[j] = changeEarnings[:, j].sum() earnings_old = np.array(self.earnings['total']) ebitda_chgfactor = (earnings_old + deltaE) * self.data.rescale_noncorp / earnings_old keylist = list(self.earnings) for key in keylist: self.earnings[key] = self.earnings[key] * ebitda_chgfactor def update_debt(self, responses): """ Replaces the Debt object to use the new asset forecast and Data """ pctch_delta = np.array(responses.debt_response['pchDelta_corp']) self.debt = Debt(self.btax_params, self.asset.get_forecast(), data=self.data, response=pctch_delta, corp=False) self.debt.calc_all() def apply_responses(self, responses): """ Updates Data, Asset, earnings, and Debt to include responses. """ assert isinstance(responses, Response) self.update_legal(responses) self.update_investment(responses) self.update_earnings(responses) self.update_debt(responses) self.real_activity() self.calc_netinc()
class Corporation(): """ Constructor for the Corporation class. This contains both the real and tax information relevant to the corporate income tax. """ def __init__(self, btax_params): # Store policy parameter objects if isinstance(btax_params, pd.DataFrame): self.btax_params = btax_params else: raise ValueError('btax_params must be DataFrame') # Create Data object self.data = Data() # Create Asset object and calculate self.asset = Asset(self.btax_params, corp=True, data=self.data) self.asset.calc_all() # Create DomesticMNE object self.dmne = DomesticMNE(self.btax_params) self.dmne.calc_all() # Create earnings forecast self.create_earnings() def create_debt(self): """ Creates the Debt object for the Corporation. Note: create_asset must have already been called """ self.debt = Debt(self.btax_params, self.asset.get_forecast(), data=self.data, corp=True) self.debt.calc_all() def create_earnings(self): """ Creates the initial forecast for earnings. Static only. """ # Grab forecasts of profit growth earnings_forecast = np.asarray(self.data.gfactors['profit']) gfacts = earnings_forecast[1:] / earnings_forecast[0] # 2013 values for non-modeled revenues taxitems = np.array(self.data.corp_tax2013['ALL']) receipts = taxitems[4] * gfacts rent_inc = taxitems[7] * gfacts royalties = taxitems[8] * gfacts capgains = (taxitems[9] + taxitems[10] + taxitems[11] - taxitems[32]) * gfacts domestic_divs = taxitems[12] * gfacts other_recs = taxitems[14] * gfacts # 2013 values for non-modeled deductions and credits cogs = taxitems[16] * gfacts execcomp = taxitems[17] * gfacts wages = taxitems[18] * gfacts repairs = taxitems[19] * gfacts baddebt = taxitems[20] * gfacts rent_paid = taxitems[21] * gfacts statelocaltax = taxitems[22] * gfacts charity = taxitems[24] * gfacts amortization = taxitems[25] * gfacts depletion = taxitems[27] * gfacts advertising = taxitems[28] * gfacts pensions = taxitems[29] * gfacts benefits = taxitems[30] * gfacts sec199_base = taxitems[31] * gfacts other_ded = taxitems[33] * gfacts gbc = taxitems[42] * gfacts # Save unodeled tax items self.revenues = pd.DataFrame({ 'year': range(START_YEAR, END_YEAR + 1), 'receipts': receipts, 'rent': rent_inc, 'royalties': royalties, 'capgains': capgains, 'domestic_divs': domestic_divs, 'other': other_recs }) self.deductions = pd.DataFrame({ 'year': range(START_YEAR, END_YEAR + 1), 'cogs': cogs, 'execcomp': execcomp, 'wages': wages, 'repairs': repairs, 'baddebt': baddebt, 'rent': rent_paid, 'statelocaltax': statelocaltax, 'charity': charity, 'amortization': amortization, 'depletion': depletion, 'advertising': advertising, 'pensions': pensions, 'benefits': benefits, 'sec199share': sec199_base, 'other': other_ded }) self.credits = pd.DataFrame({ 'year': range(START_YEAR, END_YEAR + 1), 'gbc': gbc }) def file_taxes(self): """ Creates the CorpTaxReturn object. """ self.taxreturn = CorpTaxReturn(self.btax_params, self.revenues, self.deductions, self.credits, dmne=self.dmne, data=self.data, assets=self.asset, debts=self.debt) self.taxreturn.calc_all() def real_activity(self): """ Produces a DataFrame of the corporation's real activity. Real measures are: Capital stock Investment Depreciation (economic) Net debt Net interest paid Earnings Tax liability Net income Cash flow """ real_results = pd.DataFrame({'year': range(START_YEAR, END_YEAR + 1)}) real_results['Earnings'] = ( self.revenues['receipts'] + self.revenues['rent'] + self.revenues['royalties'] + self.revenues['capgains'] + self.revenues['domestic_divs'] + self.revenues['other'] - self.deductions['cogs'] - self.deductions['execcomp'] - self.deductions['wages'] - self.deductions['repairs'] - self.deductions['baddebt'] - self.deductions['rent'] - self.deductions['charity'] - self.deductions['depletion'] - self.deductions['advertising'] - self.deductions['pensions'] - self.deductions['benefits'] - self.deductions['other'] + self.dmne.dmne_results['foreign_directinc'] + self.dmne.dmne_results['foreign_indirectinc']) real_results['Kstock'] = self.asset.get_forecast() real_results['Inv'] = self.asset.get_investment() real_results['Depr'] = self.asset.get_truedep() real_results['Debt'] = self.debt.get_debt() real_results['NIP'] = self.debt.get_nip() real_results['Tax'] = self.taxreturn.get_tax() real_results['NetInc'] = (real_results['Earnings'] - real_results['Depr'] - real_results['NIP'] - real_results['Tax'] - self.dmne.dmne_results['foreign_tax'] - self.deductions['statelocaltax']) real_results['CashFlow'] = (real_results['Earnings'] - real_results['Inv'] - real_results['Tax'] - self.dmne.dmne_results['foreign_tax'] - self.deductions['statelocaltax']) self.real_results = real_results def calc_static(self): """ Runs the static calculations. """ self.create_debt() self.file_taxes() self.real_activity() def update_legal(self, responses): """ Updates the rescale_corp and rescale_noncorp associated with each Data associated with each object. """ self.data.update_rescaling(responses.rescale_corp, responses.rescale_noncorp) self.asset.data.update_rescaling(responses.rescale_corp, responses.rescale_noncorp) def update_investment(self, responses): """ Updates the Asset object to include investment response. """ # First, save the capital stock by asset type and year (for earnings) self.old_capital_history = copy.deepcopy(self.asset.capital_history) self.asset.update_response(responses.investment_response) self.asset.calc_all() def update_repatriation(self, responses): """ Updates the DomesticMNE object to include the repatriation response. Also updates profits to reflect this response. """ # First, save current foreign earnings self.dmne.update_profits(responses.repatriation_response, responses.shifting_response) self.dmne.calc_all() def update_earnings(self, responses): """ Recalculates earnings using the old capital stock by asset type, the new capital stock by asset type (based on the investment response), and the marginal product of capital. """ Kstock_base = copy.deepcopy(self.old_capital_history) Kstock_ref = copy.deepcopy(self.asset.capital_history) changeEarnings = np.zeros((95, NUM_YEARS)) for iyr in range(NUM_YEARS): # for each year ystr = str(iyr + START_YEAR) mpk = np.array(responses.investment_response['MPKc' + ystr]) for i in range(95): # by asset changeEarnings[i, iyr] = (Kstock_ref[ystr][i] - Kstock_base[ystr][i]) * mpk[i] deltaE = np.zeros(NUM_YEARS) for iyr in range(NUM_YEARS): deltaE[iyr] = changeEarnings[:, iyr].sum() # Update new earnings self.revenues['receipts'] = self.revenues['receipts'] + deltaE def update_debt(self, responses): """ Replaces the Debt object to use the new asset forecast and Data """ pctch_delta = np.array(responses.debt_response['pchDelta_corp']) self.debt = Debt(self.btax_params, self.asset.get_forecast(), data=self.data, response=pctch_delta, corp=True) self.debt.calc_all() def apply_responses(self, responses): """ Updates Data, Asset, earnings, Debt and CorpTaxReturn to include responses. Then calc_all() for each object. """ assert isinstance(responses, Response) self.update_legal(responses) self.update_investment(responses) self.update_repatriation(responses) self.update_earnings(responses) self.update_debt(responses) self.file_taxes() self.real_activity() def get_netinc(self): """ Returns an array of the corporation's net income (after-tax). """ netinc = np.array(self.real_results['NetInc']) return netinc def get_taxrev(self): """ Returns an array of the corporation's tax liability. """ taxrev = np.array(self.real_results['Tax']) return taxrev