예제 #1
0
 def __init__(self,
              btax_refdict,
              iit_refdict,
              btax_basedict={},
              iit_basedict={},
              elast_dict=None,
              investor_data='puf.csv'):
     # Set default policy parameters for later use
     self.btax_defaults = Data().btax_defaults
     # Create the baseline and reform parameter storing forms
     self.btax_params_base = self.update_btax_params(btax_basedict)
     self.btax_params_ref = self.update_btax_params(btax_refdict)
     # Create Investors
     self.investor_base = Investor(iit_basedict, investor_data)
     self.investor_ref = Investor(iit_refdict, investor_data)
     # Create Corporations
     self.corp_base = Corporation(self.btax_params_base)
     self.corp_ref = Corporation(self.btax_params_ref)
     # Create PassThroughs
     self.passthru_base = PassThrough(self.btax_params_base)
     self.passthru_ref = PassThrough(self.btax_params_ref)
     # Save the elasticity dictionary
     if elast_dict is not None:
         self.check_elast_dict(elast_dict)
         self.elast_dict = elast_dict
     else:
         self.elast_dict = Data().elast_defaults
예제 #2
0
 def __init__(self, btax_params, corp=True, data=None, response=None):
     # Create an associated Data object
     if isinstance(data, Data):
         self.data = data
     else:
         self.data = Data()
     # Check inputs
     if isinstance(corp, bool):
         self.corp = corp
     else:
         raise ValueError('corp must be True or False')
     if response is None or isinstance(response, pd.DataFrame):
         self.response = response
     else:
         raise ValueError('response must be DataFrame or None')
     if corp:
         self.adjustments = {
             'bonus': 0.60290131,
             'sec179': 0.016687178,
             'overall': self.data.adjfactor_dep_corp,
             'rescalar': self.data.rescale_corp
         }
     else:
         self.adjustments = {
             'bonus': 0.453683778,
             'sec179': 0.17299506,
             'overall': self.data.adjfactor_dep_noncorp,
             'rescalar': self.data.rescale_noncorp
         }
     if isinstance(btax_params, pd.DataFrame):
         self.btax_params = btax_params
     else:
         raise ValueError('btax_params must be DataFrame')
예제 #3
0
 def calc_tauE(mtrdict, incdict, year):
     """
     Calculate the effective marginal tax rate on equity income in year.
     """
     # Retained earnings rate
     m = 0.44
     # Nominal expected return to equity
     iyr = year - START_YEAR
     E = (Data().econ_defaults['r_e_c'][iyr] +
          Data().econ_defaults['pi'][iyr])
     # shares of cg in short-term, long-term, and held until death
     omega_scg = 0.034
     omega_lcg = 0.496
     omega_xcg = 1 - omega_scg - omega_lcg
     # shares of corp equity in taxable, deferred and nontaxable form
     alpha_ft = 0.572
     alpha_td = 0.039
     alpha_nt = 0.389
     # holding period for equity
     h_scg = 0.5
     h_lcg = 8.0
     h_td = 8.0
     # Get MTRs
     mtr_d = mtrdict['e00650']
     mtr_scg = mtrdict['p22250']
     mtr_lcg = mtrdict['p23250']
     mtr_td = mtrdict['e01700']
     # Get income measures
     inc_d = incdict['div']
     inc_scg = np.where(incdict['stcg'] >= 0, incdict['stcg'], 0)
     inc_lcg = np.where(incdict['ltcg'] >= 0, incdict['ltcg'], 0)
     inc_td = incdict['definc']
     posti = (incdict['taxinc'] > 0.)
     wgt = incdict['wgt']
     # MTR on dividend income
     tau_d = sum(mtr_d * inc_d * posti * wgt) / sum(inc_d * posti * wgt)
     # accrual effective mtr on stcg
     tau_scg1 = (sum(mtr_scg * inc_scg * posti * wgt) /
                 sum(inc_scg * posti * wgt))
     tau_scg = (1 -
                (np.log(np.exp(m * E * h_scg) * (1 - tau_scg1) + tau_scg1) /
                 (m * E * h_scg)))
     # accrual effective mtr on ltcg
     tau_lcg1 = (sum(mtr_lcg * inc_lcg * posti * wgt) /
                 sum(inc_lcg * posti * wgt))
     tau_lcg = (1 -
                (np.log(np.exp(m * E * h_lcg) * (1 - tau_lcg1) + tau_lcg1) /
                 (m * E * h_lcg)))
     # mtr on capital gains held until death
     tau_xcg = 0.0
     tau_cg = (omega_scg * tau_scg + omega_lcg * tau_lcg +
               omega_xcg * tau_xcg)
     tau_ft = (1 - m) * tau_d + m * tau_cg
     tau_td1 = (sum(mtr_td * inc_td * posti * wgt) /
                sum(inc_td * posti * wgt))
     tau_td = (1 - (np.log(np.exp(E * h_td) * (1 - tau_td1) + tau_td1) /
                    (E * h_td)))
     tau_e = alpha_ft * tau_ft + alpha_td * tau_td + alpha_nt * 0.0
     return tau_e
예제 #4
0
 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()
예제 #5
0
 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
예제 #6
0
 def _calc_investment_response(self, btax_params_base, btax_params_ref):
     """
     Calculates percent change in investment & marginal product of capital,
     for each asset type, for each year, corporate and noncorporate.
     firstyear: when the firm behavioral response takes effect
     """
     # Read in the underlying functions for the investment response
     maindata = copy.deepcopy(Data().taxdep_info_gross('pre2017'))
     maindata.drop(['L_gds', 'L_ads', 'Method'], axis=1, inplace=True)
     # Extract relevant response parameters
     firstyear = self.elasticities['first_year_response']
     elast_c = self.elasticities['inv_usercost_c']
     elast_nc = self.elasticities['inv_usercost_nc']
     selast_c = self.elasticities['inv_eatr_c']
     selast_nc = self.elasticities['inv_eatr_nc']
     mne_share_c = self.elasticities['mne_share_c']
     mne_share_nc = self.elasticities['mne_share_nc']
     # No responses for years before first_year_response
     for year in range(START_YEAR, firstyear):
         ystr = str(year)
         maindata['deltaIc' + ystr] = 0.
         maindata['deltaInc' + ystr] = 0.
         maindata['MPKc' + ystr] = 0.
         maindata['MPKnc' + ystr] = 0.
     # Calculate cost of capital and EATR for every year for baseline
     btaxmini_base = BtaxMini(btax_params_base)
     years = range(firstyear, END_YEAR + 1)
     results_base = btaxmini_base.run_btax_mini(years)
     # Calculate cost of capital and EATR for every year for reform
     btaxmini_ref = BtaxMini(btax_params_ref)
     results_ref = btaxmini_ref.run_btax_mini(years)
     # Compare results to produce the responses
     for year in years:
         ystr = str(year)
         maindata['deltaIc' + ystr] = (
             ((results_ref['u_c' + ystr] / results_base['u_c' + ystr] - 1) *
              elast_c +
              (results_ref['eatr_c' + ystr] - results_base['eatr_c' + ystr])
              * selast_c * mne_share_c))
         maindata['deltaInc' + ystr] = (
             ((results_ref['u_nc' + ystr] / results_base['u_nc' + ystr] - 1)
              * elast_nc +
              (results_ref['eatr_nc' + ystr] -
               results_base['eatr_nc' + ystr]) * selast_nc * mne_share_nc))
         maindata['MPKc' + ystr] = (results_ref['u_c' + ystr] +
                                    results_base['u_c' + ystr]) / 2.0
         maindata['MPKnc' + ystr] = (results_ref['u_nc' + ystr] +
                                     results_base['u_nc' + ystr]) / 2.0
     # Save the responses
     self.investment_response = copy.deepcopy(maindata)
예제 #7
0
 def calc_inv_response(self):
     """
     Calculates the percent change in investment & marginal product of capital,
     for each asset type, for each year, corporate and noncorporate.
     firstyear: when the firm behavioral response takes effect
     """
     # Read in the underlying functions for the investment response
     maindata = copy.deepcopy(Data().assets_data())
     maindata.drop(['assets_c', 'assets_nc'], axis=1, inplace=True)
     # Extract relevant response parameters
     firstyear = self.elast_dict['first_year_response']
     elast_c = self.elast_dict['inv_usercost_c']
     elast_nc = self.elast_dict['inv_usercost_nc']
     selast_c = self.elast_dict['inv_eatr_c']
     selast_nc = self.elast_dict['inv_eatr_nc']
     mne_share_c = self.elast_dict['mne_share_c']
     mne_share_nc = self.elast_dict['mne_share_nc']
     # No responses for years before first_year_response
     for year in range(2014, firstyear):
         maindata['deltaIc' + str(year)] = 0.
         maindata['deltaInc' + str(year)] = 0.
         maindata['MPKc' + str(year)] = 0.
         maindata['MPKnc' + str(year)] = 0.
     # Calculate cost of capital and EATR for every year for baseline
     Btax_base = BtaxMini(self.btax_params_base)
     results_base = Btax_base.run_btax_mini(range(firstyear, 2028))
     # Calculate cost of capital and EATR for every year for reform
     Btax_ref = BtaxMini(self.btax_params_ref)
     results_ref = Btax_ref.run_btax_mini(range(firstyear, 2028))
     # Compare results to produce the responses
     for year in range(firstyear, 2028):
         maindata['deltaIc' + str(year)] = (
             (results_ref['u_c' + str(year)] /
              results_base['u_c' + str(year)] - 1) * elast_c +
             (results_ref['eatr_c' + str(year)] -
              results_base['eatr_c' + str(year)]) * selast_c * mne_share_c)
         maindata['deltaInc' + str(year)] = (
             (results_ref['u_nc' + str(year)] /
              results_base['u_nc' + str(year)] - 1) * elast_nc +
             (results_ref['eatr_nc' + str(year)] -
              results_base['eatr_nc' + str(year)]) * selast_nc *
             mne_share_nc)
         maindata['MPKc' +
                  str(year)] = (results_ref['u_c' + str(year)] +
                                results_base['u_c' + str(year)]) / 2.0
         maindata['MPKnc' +
                  str(year)] = (results_ref['u_nc' + str(year)] +
                                results_base['u_nc' + str(year)]) / 2.0
     # Save the responses
     self.investment_response = copy.deepcopy(maindata)
예제 #8
0
 def __init__(self, btax_params, data=None):
     # 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
     if isinstance(data, Data):
         self.data = data
     else:
         self.data = Data()
     # Extract baseline forecast for earnings and action
     self.cfc_data = copy.deepcopy(self.data.cfc_data)
     self.cfc_data.set_index('Unnamed: 0', inplace=True)
     # Generate earnings
     self.create_earnings()
예제 #9
0
 def __init__(self, btax_params, data=None):
     # Store policy parameter object
     if isinstance(btax_params, pd.DataFrame):
         self.btax_params = btax_params
     else:
         raise ValueError('btax_params must be DataFrame')
     # Create Data object
     if data is None:
         self.data = Data()
     elif isinstance(data, Data):
         self.data = data
     else:
         raise ValueError('data must be a Data object')
     # Extract baseline forecast for earnings and action
     self.dmne_data = copy.deepcopy(self.data.dmne_data)
     # Create affiliated CFC
     self.cfc = CFC(self.btax_params)
     # For initial creation, set includes_response to False
     self.includes_response = False
예제 #10
0
 def __init__(self,
              btax_params,
              asset_forecast,
              data=None,
              response=None,
              eta=0.4,
              corp=True):
     # Create an associated Data object
     if isinstance(data, Data):
         self.data = data
     else:
         self.data = Data()
     if isinstance(corp, bool):
         self.corp = corp
     else:
         raise ValueError('corp must be True or False')
     if isinstance(btax_params, pd.DataFrame):
         self.btax_params = btax_params
     else:
         raise ValueError('btax_params must be DataFrame')
     if response is not None:
         if len(response) == 14:
             self.response = response
         else:
             raise ValueError('Wrong response')
     else:
         self.response = np.zeros(14)
     if corp:
         self.delta = np.array(
             self.data.econ_defaults['f_c']) * (1 + self.response)
     else:
         self.delta = np.array(
             self.data.econ_defaults['f_nc']) * (1 + self.response)
     if len(asset_forecast) == 14:
         self.asset_forecast = asset_forecast
     else:
         raise ValueError('Wrong length for asset forecast')
     if eta >= 0 and eta <= 1:
         self.eta = eta
     else:
         raise ValueError('Value of eta inappropriate')
예제 #11
0
 def run_btax_mini(self, yearlist):
     """
     Runs the code to compute the user cost and EATR
     for each asset type for each year in yearlist.
     """
     basedata = copy.deepcopy(Data().assets_data())
     for year in yearlist:
         # Get calculations for each year
         results_oneyear = self.calc_oneyear(year)
         # Rename to include the year calculated
         results_oneyear.rename(columns={
             'uc_c': 'u_c' + str(year),
             'uc_nc': 'u_nc' + str(year),
             'eatr_c': 'eatr_c' + str(year),
             'eatr_nc': 'eatr_nc' + str(year)
         },
                                inplace=True)
         # Merge year's results into combined DataFrame
         basedata = basedata.merge(right=results_oneyear,
                                   how='outer',
                                   on='Asset')
     basedata.drop(['assets_c', 'assets_nc'], axis=1, inplace=True)
     return basedata
예제 #12
0
 def _calc_repatriation_response(self, btax_params_base, btax_params_ref):
     """
     Calculates the change in the repatriation rate of current CFC
     after-tax profits. The parameter used is the semi-elasticity of repatriations
     with respect to the tax penalty from repatriating. The response is
     only used for repatriations from current profits, as repatriations
     from accumulated profits are too complicated to model explicity
     and not relevant following the 2017 tax act.
     Note that although the set-up for this may seem odd, it is designed to
     ensure that no policy change results in to repatriation response,
     regardless of the semielasticity used. The appropriate value for the
     semi-elasticity is -10.66536949, which is consistent with the
     repatriation rate as of 2014.
     """
     # Get foreign tax rate
     ftax = Data().cfc_data.loc[0, 'taxrt']
     # Get domestic tax rate
     dtax_base = np.asarray(btax_params_base['tau_c'])
     dtax_ref = np.asarray(btax_params_ref['tau_c'])
     # Get foreign dividend inclusion rate for CFCs
     divrt_base = np.asarray(btax_params_base['foreign_dividend_inclusion'])
     divrt_ref = np.asarray(btax_params_ref['foreign_dividend_inclusion'])
     penalty_base = np.maximum(dtax_base - ftax, 0.) * divrt_base
     penalty_ref = np.maximum(dtax_ref - ftax, 0.) * divrt_ref
     # Compute change in repatriation rate
     reprate_ch1 = (penalty_ref -
                    penalty_base) * self.elasticities['reprate_inc']
     reprate_ch = np.zeros(NUM_YEARS)
     for i in range(NUM_YEARS):
         if i + 2014 >= self.elasticities['first_year_response']:
             reprate_ch[i] = reprate_ch1[i]
     repat_response = pd.DataFrame({
         'year': range(START_YEAR, END_YEAR + 1),
         'reprate_e': reprate_ch,
         'reprate_a': np.zeros(NUM_YEARS)
     })
     self.repatriation_response = repat_response
예제 #13
0
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)
예제 #14
0
class Asset():
    """
    Constructor for the Asset class.
    This class includes several objects related to assets and depreciation:
        For internal class use:
            investment_history:
                array of investment amounts
                asset type (95) x year investment made (68)
            capital_history:
                array of asset amounts
                asset type (95) x years in the budget window (NUM_YEARS)
            system_history:
                array of depreciation systems (GDS or ADS)
                asset type (95) x year investment made (68)
            method_history:
                array of depreciation methods (DB, Economics, etc.)
                asset type (95) x year investment made (68)
            life_history:
                array of tax lives (see LIVES list)
                asset type (95) and year investment made (68) given system
            bonus_history:
                array of effective bonus depreciation rates
                asset type (95) x year investment made (68)
            ccr_data:
                DataFrame of asset amounts and economic depreciation rates
                asset type (95), 2017 only
            capital_path:
                DataFrame of asset information totals in the budget window

    Parameters:
        corp: True for corporate, False for noncorporate
        btax_params: dict of business tax policy parameters
        response: DataFrame of investment responses
    """
    def __init__(self,
                 btax_params,
                 corp=True,
                 data=None,
                 response=None,
                 industry='ALL'):
        # Create an associated Data object
        if isinstance(data, Data):
            self.data = data
        else:
            self.data = Data()
        # Check inputs
        if isinstance(corp, bool):
            self.corp = corp
        else:
            raise ValueError('corp must be True or False')
        if response is None or isinstance(response, pd.DataFrame):
            self.response = response
        else:
            raise ValueError('response must be DataFrame or None')
        if corp:
            self.adjustments = {
                'bonus': 0.60290131,
                'sec179': 0.016687178,
                'rescalar': self.data.rescale_corp
            }
        else:
            self.adjustments = {
                'bonus': 0.453683778,
                'sec179': 0.17299506,
                'rescalar': self.data.rescale_noncorp
            }
        if isinstance(btax_params, pd.DataFrame):
            self.btax_params = btax_params
        else:
            raise ValueError('btax_params must be DataFrame')
        self.industry = industry

    def update_response(self, response):
        """
        Updates the response DataFrame.
        Note: The response is the investment response DataFrame, not a
              Response object.
        """
        assert isinstance(response, pd.DataFrame)
        self.response = response

    def build_inv_matrix(self):
        """
        Builds investment array by asset type and by year made
        """
        # Get historical investment for 1960-2014
        if self.corp:
            investment_dfg = copy.deepcopy(self.data.investment_corp)
        else:
            investment_dfg = copy.deepcopy(self.data.investment_noncorp)
        investment_df = investment_dfg.loc[investment_dfg.industry ==
                                           self.industry, :]
        investment_df.drop(['industry'], axis=1, inplace=True)
        investment_df.reset_index(drop=True, inplace=True)
        # Extend investment using NGDP (growth factors from CBO forecast)
        inv2014 = np.asarray(investment_df.loc[:, str(START_YEAR)])
        for year in range(START_YEAR + 1, END_YEAR + 1):
            gfact1 = (
                self.data.gfactors.loc[year - START_YEAR + 1, 'fi_nonres'] /
                self.data.gfactors.loc[1, 'fi_nonres'])
            gfact2 = (self.data.gfactors.loc[year - START_YEAR + 1, 'fi_res'] /
                      self.data.gfactors.loc[1, 'fi_res'])
            investment_df.loc[:, str(year)] = inv2014 * gfact1
            # Use residential investment gfactor for residential inv
            investment_df.loc[91:, str(year)] = inv2014[91:] * gfact2
        # Update investment matrix to include investment responses
        if self.response is not None:
            if self.corp:
                deltaIkey = 'deltaIc'
            else:
                deltaIkey = 'deltaInc'
            for year in range(START_YEAR, END_YEAR + 1):
                deltaI = np.asarray(self.response[deltaIkey + str(year)])
                investment_df.loc[:, str(year)] = (
                    investment_df.loc[:, str(year)] * (1. + deltaI))
        self.investment_history = investment_df

    def build_deprLaw_matrices(self):
        """
        Builds the arrays for tax depreciation laws
        """
        def taxdep_final(depr_methods, depr_bonuses, depr_file):
            """
            Constructs the DataFrame of information for tax depreciation.
            Only relevant for years beginning with START_YEAR.
            Returns a DataFrame with:
                depreciation method,
                tax depreciation life,
                true depreciation rate,
                bonus depreciation rate.
            """
            taxdep = copy.deepcopy(self.data.taxdep_info_gross(depr_file))
            system = np.asarray(taxdep['System'])
            life = np.asarray(taxdep['L_gds'])
            # Determine depreciation systems for each asset class (by GDS life)
            for cl, method in depr_methods.items():
                system[life == cl] = method
            # Determine tax life
            L_ads = np.asarray(taxdep['L_ads'])
            Llist = np.asarray(taxdep['L_gds'])
            Llist[system == 'ADS'] = L_ads[system == 'ADS']
            Llist[system == 'None'] = 9e99
            taxdep['L'] = Llist
            # Determine depreciation method. Default is GDS method
            method = np.asarray(taxdep['Method'])
            for i in range(len(method)):
                if system[i] == 'ADS':
                    method[i] = np.asarray(taxdep['ADS method'])[i]
                elif system[i] == 'Economic':
                    method[i] = 'Economic'
                elif system[i] == 'None':
                    method[i] = 'None'
                elif system[i] == 'Expensing':
                    method[i] = 'Expensing'
                elif system[i] != 'GDS':
                    asset1 = np.asarray(taxdep['Asset'])[i]
                    raise ValueError('Must specify depreciation system for ' +
                                     asset1 + '. Cannot use ' + str(system[i]))
            taxdep['Method'] = method
            # Detemine bonus depreciation rate
            bonus = np.zeros(len(taxdep))
            for cl, cl_bonus in depr_bonuses.items():
                bonus[life == cl] = cl_bonus
            taxdep['bonus'] = bonus
            taxdep.drop(['L_gds', 'L_ads', 'Class life'], axis=1, inplace=True)
            return taxdep

        def taxdep_preset():
            """
            Constructs the DataFrame of information for tax depreciation.
            Only relevant for years before START_YEAR.
            Returns a DataFrame with:
                depreciation method,
                tax depreciation life,
                true depreciation rate,
                bonus depreciation rate.
            """
            taxdep = copy.deepcopy(self.data.taxdep_info_gross('pre2017'))
            taxdep['L'] = taxdep['L_gds']
            life = np.asarray(taxdep['L_gds'])
            bonus = np.zeros(len(life))
            for y in [3, 5, 7, 10, 15, 20, 25, 27.5, 39]:
                s = "bonus{}".format(y if y != 27.5 else 27)
                bonus[life == y] = self.data.bonus_data[s][year -
                                                           HISTORY_START]
            taxdep['bonus'] = bonus
            taxdep.drop(['L_gds', 'L_ads', 'Class life'], axis=1, inplace=True)
            return taxdep

        def get_btax_params_oneyear(btax_params, year):
            """
            Extracts tax depreciation parameters and
            calls the functions to build the tax depreciation
            DataFrames.
            """
            if year >= START_YEAR:
                year = min(year, END_YEAR)
                iyr = year - START_YEAR
                depr_methods = {}
                depr_bonuses = {}
                for y in [3, 5, 7, 10, 15, 20, 25, 27.5, 39]:
                    s = "depr_{}yr_".format(y if y != 27.5 else 275)
                    depr_methods[y] = btax_params[s + 'method'][iyr]
                    depr_bonuses[y] = btax_params[s + 'bonus'][iyr]
                depr_file = btax_params.loc[year - START_YEAR, 'depr_file']
                taxdep = taxdep_final(depr_methods, depr_bonuses, depr_file)
            else:
                taxdep = taxdep_preset()
            return taxdep

        """
        Create arrays and store depreciation rules in them
        """
        length1 = END_YEAR - HISTORY_START + 1
        method_history = [[]] * length1
        life_history = np.zeros((95, length1))
        bonus_history = np.zeros((95, length1))
        for year in range(HISTORY_START, END_YEAR + 1):
            iyr = year - HISTORY_START
            params_oneyear = get_btax_params_oneyear(self.btax_params, year)
            method_history[iyr] = params_oneyear['Method']
            life_history[:, iyr] = params_oneyear['L']
            bonus_history[:, iyr] = params_oneyear['bonus']
        self.method_history = method_history
        self.life_history = life_history
        self.bonus_history = bonus_history

    def calcDep_oneyear(self, year):
        """
        Calculates total depreciation deductions taken in the year.
        """
        def depreciationDeduction(year_investment, year_deduction, method, L,
                                  delta, bonus):
            """
            Computes the nominal depreciation deduction taken on any
            unit investment in any year with any depreciation method and life.
            Parameters:
                year_investment: year the investment is made
                year_deduction: year the CCR deduction is taken
                method: method of CCR (DB 200%, DB 150%, SL, Expensing, None)
                L: class life for DB or SL depreciation (MACRS)
                delta: economic depreciation rate
                bonus: bonus depreciation rate
            """
            assert method in [
                'DB 200%', 'DB 150%', 'SL', 'Expensing', 'Economic', 'None'
            ]
            # No depreciation
            if method == 'None':
                deduction = 0
            # Expensing
            elif method == 'Expensing':
                if year_deduction == year_investment:
                    deduction = 1.0
                else:
                    deduction = 0
            # Economic depreciation
            elif method == 'Economic':
                yded = year_deduction
                pi_temp = (self.data.investmentGfactors_data['pce'][yded + 1] /
                           self.data.investmentGfactors_data['pce'][yded])
                if pi_temp == np.exp(delta):
                    annual_change = 1.0
                else:
                    if year_deduction == year_investment:
                        annual_change = ((
                            (pi_temp * np.exp(delta / 2))**0.5 - 1) /
                                         (np.log(pi_temp - delta)))
                    else:
                        annual_change = ((pi_temp * np.exp(delta) - 1) /
                                         (np.log(pi_temp) - delta))

                if year_deduction < year_investment:
                    sval = 0
                    deduction = 0
                elif year_deduction == year_investment:
                    sval = 1.0
                    deduction = (bonus +
                                 (1 - bonus) * delta * sval * annual_change)
                else:
                    sval = (
                        np.exp(-delta * (year_deduction - year_investment)) *
                        self.data.investmentGfactors_data['pce']
                        [year_deduction] / 2.0 /
                        (self.data.investmentGfactors_data['pce']
                         [year_investment] + self.data.
                         investmentGfactors_data['pce'][year_investment + 1]))
                    deduction = (1 - bonus) * delta * sval * annual_change
            else:
                if method == 'DB 200%':
                    N = 2
                elif method == 'DB 150%':
                    N = 1.5
                elif method == 'SL':
                    N = 1

            # DB or SL depreciation, half-year convention
                t0 = year_investment + 0.5
                t1 = t0 + L * (1 - 1 / N)
                s1 = year_deduction
                s2 = s1 + 1
                if year_deduction < year_investment:
                    deduction = 0
                elif year_deduction > year_investment + L:
                    deduction = 0
                elif year_deduction == year_investment:
                    deduction = (bonus + (1 - bonus) *
                                 (1 - np.exp(-N / L * 0.5)))
                elif s2 <= t1:
                    deduction = ((1 - bonus) *
                                 (np.exp(-N / L *
                                         (s1 - t0)) - np.exp(-N / L *
                                                             (s2 - t0))))
                elif s1 >= t1 and s1 <= t0 + L and s2 > t0 + L:
                    deduction = ((1 - bonus) * (N / L * np.exp(1 - N) *
                                                (s2 - s1) * 0.5))
                elif s1 >= t1 and s2 <= t0 + L:
                    deduction = ((1 - bonus) * (N / L * np.exp(1 - N) *
                                                (s2 - s1)))
                elif s1 < t1 and s2 > t1:
                    deduction = ((1 - bonus) *
                                 (np.exp(-N / L *
                                         (s1 - t0)) - np.exp(-N / L *
                                                             (t1 - t0)) +
                                  N / L * np.exp(1 - N) * (s2 - t1)))
            return deduction

        """
        Calculate depreciation deductions for each year
        """
        unitDep_arr = np.zeros((95, END_YEAR - HISTORY_START + 1))
        depr_file = self.btax_params.loc[year - START_YEAR, 'depr_file']
        delta = np.asarray(self.data.taxdep_info_gross(depr_file)['delta'])
        for i in range(95):
            # Iterate over asset types
            for j in range(END_YEAR - HISTORY_START + 1):
                # Iterate over investment years
                bonus1 = min(
                    (self.bonus_history[i, j] * self.adjustments['bonus'] +
                     self.adjustments['sec179']), 1.0)
                unitDep_arr[i, j] = depreciationDeduction(
                    j, year - HISTORY_START, self.method_history[j][i],
                    self.life_history[i, j], delta[i], bonus1)
        inv_hist = copy.deepcopy(self.investment_history)
        inv_hist.drop(['asset_code'], axis=1, inplace=True)
        inv_hist2 = inv_hist.to_numpy()
        Dep_arr = inv_hist2 * unitDep_arr
        # Apply the haircut on undepreciated basis
        iyr = year - START_YEAR
        if year < START_YEAR:
            # Use no haircut for years before calculator
            hc_undep_year = 0
            hc_undep = 0.
        else:
            if self.corp:
                hc_undep_year = np.array(
                    self.btax_params['undepBasis_corp_hcyear'])[iyr]
                hc_undep = np.array(
                    self.btax_params['undepBasis_corp_hc'])[iyr]
            else:
                hc_undep_year = np.array(
                    self.btax_params['undepBasis_noncorp_hcyear'])[iyr]
                hc_undep = np.array(
                    self.btax_params['undepBasis_noncorp_hc'])[iyr]
        if year >= hc_undep_year:
            for j in range(END_YEAR - HISTORY_START + 1):
                if j < hc_undep_year:
                    Dep_arr[:, j] = Dep_arr[:, j] * (1 - hc_undep)
        # Asset types included in tax depreciation or not
        other_assets = [68, 69, 70]  # Software
        other_assets.extend(range(71, 86))  # Add R&D categories
        depr_assets = list(range(0, 68))  # Tangible assets
        depr_assets.extend(range(86, 95))  # Add artistic originals
        depr_assets.append(93)  # Add residential
        # Tax depreciation deduction
        depded = Dep_arr[depr_assets, :].sum().sum()
        # Other CCR deduction
        otherded = Dep_arr[other_assets, :].sum().sum()
        return [depded, otherded]

    def calcDep_allyears(self):
        """
        Calculates total depreciation deductions taken for all years
        1960-2035.
        """
        dep_deductions = np.zeros(END_YEAR + 1 - HISTORY_START)
        for year in range(HISTORY_START, END_YEAR + 1):
            dep_deductions[year -
                           HISTORY_START] = self.calcDep_oneyear(year)[0]
        return dep_deductions

    def calcDep_budget(self):
        """
        Calculates total depreciation deductions taken for START_ to END_YEAR.
        """
        dep_deductions = np.zeros(NUM_YEARS)
        other_deductions = np.zeros(NUM_YEARS)
        for iyr in range(0, NUM_YEARS):
            year = iyr + START_YEAR
            [depded, otherded] = self.calcDep_oneyear(year)
            dep_deductions[iyr] = depded
            other_deductions[iyr] = otherded
        return dep_deductions

    def build_capital_history(self):
        """
        Builds capital history array using investment_history and capital_df
        """
        # Get historical capital stock
        if self.corp:
            capital_dfg = copy.deepcopy(self.data.capital_corp)
        else:
            capital_dfg = copy.deepcopy(self.data.capital_noncorp)
        capital_df1 = capital_dfg[capital_dfg.industry == self.industry]
        capital_df1.drop(['industry'], axis=1, inplace=True)
        capital_df1.reset_index(drop=True, inplace=True)
        capital_df1.rename(columns={'asset_code': 'Code'}, inplace=True)
        capital_df2 = capital_df1.merge(right=self.data.econ_depr_df(),
                                        how='outer',
                                        on='Code')
        trueDep_df = copy.deepcopy(self.data.econ_depr_df())
        pcelist = np.asarray(self.data.investmentGfactors_data['pce'])
        for year in range(START_YEAR, END_YEAR + 1):
            trueDep_df[str(
                year)] = capital_df2[str(year)] * trueDep_df['delta']
            capital_df2[str(year + 1)] = (
                (capital_df2[str(year)] - trueDep_df[str(year)] +
                 self.investment_history[str(year)]) *
                pcelist[year - HISTORY_START + 1] /
                pcelist[year - HISTORY_START])
        self.capital_history = capital_df2
        self.trueDep = trueDep_df

    def build_capital_path(self):
        """
        Builds the DataFrame of asset amount, investment and depreciation
        totals for each year in the budget window.
        """
        # Sum across assets and put into new dataset
        Kstock_total = np.zeros(NUM_YEARS)
        trueDep_total = np.zeros(NUM_YEARS)
        inv_total = np.zeros(NUM_YEARS)
        Mdep_total = np.zeros(NUM_YEARS)
        Oded_total = np.zeros(NUM_YEARS)
        for year in range(START_YEAR, END_YEAR + 1):
            iyr = year - START_YEAR
            adjfactor = self.adjustments['rescalar'][iyr]
            Kstock_total[iyr] = sum(
                self.capital_history[str(year)]) * adjfactor
            trueDep_total[iyr] = sum(self.trueDep[str(year)]) * adjfactor
            inv_total[iyr] = sum(
                self.investment_history[str(year)]) * adjfactor
            [depded, otherded] = self.calcDep_oneyear(year)
            Mdep_total[iyr] = depded * adjfactor
            Oded_total[iyr] = otherded * adjfactor
        cap_result = pd.DataFrame({
            'year': range(START_YEAR, END_YEAR + 1),
            'Kstock': Kstock_total,
            'Investment': inv_total,
            'trueDep': trueDep_total,
            'taxDep': Mdep_total,
            'otherCCR': Oded_total
        })
        self.capital_path = cap_result

    def calc_all(self):
        """
        Executes all calculations for Asset object.
        """
        self.build_inv_matrix()
        self.build_deprLaw_matrices()
        self.build_capital_history()
        self.build_capital_path()
        return None

    def get_forecast(self):
        """
        Returns an array of the capital stock for [START_YEAR, END_YEAR]
        """
        forecast = np.array(self.capital_path['Kstock'])
        return forecast

    def get_taxdep(self):
        """
        Returns an array of tax depreciation deductions for
        [START_YEAR, END_YEAR]
        """
        taxdep = np.array(self.capital_path['taxDep'])
        return taxdep

    def get_investment(self):
        """
        Returns an array of total investment for [START_YEAR, END_YEAR]
        """
        inv1 = np.array(self.capital_path['Investment'])
        return inv1

    def get_truedep(self):
        """
        Returns an array of true depreciation for [START_YEAR, END_YEAR]
        """
        truedep = np.array(self.capital_path['trueDep'])
        return truedep
예제 #15
0
 def calc_oneyear(self, year):
     """
     In the given year, calculates EATR and user cost of capital for each
     asset type.
     """
     # Check that year has acceptable value
     assert year in range(2017, 2028)
     # Extract economic parameters
     [r_c, r_nc, r_d, pi, f_c, f_nc] = self.get_econ_params_oneyear(year)
     # Extract tax depreciation information
     Method = self.asset_c.method_history[year - 1960]
     Life = self.asset_c.life_history[:, year - 1960]
     Bonus = self.asset_c.bonus_history[:, year - 1960]
     # Make tax rate dictionaries
     tdict_c = self.make_tdict_c(year)
     tdict_nc = self.make_tdict_nc(year)
     # Create base DataFrame and get depreciation rates
     asset_data = copy.deepcopy(Data().assets_data())
     Delta = np.array(Data().econ_depr_df()['delta'])
     # Get deductible fractions of interest paid
     (fracded_c, fracded_nc) = self.calc_frac_ded(year)
     # Get inventory method
     inv_method = self.btax_params['inventory_method'][year - 2014]
     assets = np.asarray(asset_data['Asset'])
     uc_c = np.zeros(len(assets))
     uc_nc = np.zeros(len(assets))
     eatr_c = np.zeros(len(assets))
     eatr_nc = np.zeros(len(assets))
     for j in range(len(asset_data)):
         uc_c[j] = self.calc_usercost(r_c, pi, Delta[j], Method[j], Life[j],
                                      Bonus[j], f_c, r_d, fracded_c,
                                      tdict_c, 50)
         uc_nc[j] = self.calc_usercost(r_nc, pi, Delta[j], Method[j],
                                       Life[j], Bonus[j], f_nc, r_d,
                                       fracded_nc, tdict_nc, 50)
         eatr_c[j] = self.calc_eatr(0.2,
                                    r_c,
                                    pi,
                                    Delta[j],
                                    Method[j],
                                    Life[j],
                                    Bonus[j],
                                    f_c,
                                    r_d,
                                    fracded_c,
                                    tdict_c,
                                    length=50)
         eatr_nc[j] = self.calc_eatr(0.2,
                                     r_nc,
                                     pi,
                                     Delta[j],
                                     Method[j],
                                     Life[j],
                                     Bonus[j],
                                     f_nc,
                                     r_d,
                                     fracded_nc,
                                     tdict_nc,
                                     length=50)
     # Special cost of capital calculations for inventories
     uc_c[assets == 'Inventories'] = self.calc_rho_inv(
         r_c, pi, inv_method, 0.5, tdict_c)
     uc_nc[assets == 'Inventories'] = self.calc_rho_inv(
         r_nc, pi, inv_method, 0.5, tdict_nc)
     # EATR for inventories and land with no supernormal returns
     eatr_c[assets == 'Inventories'] = (uc_c[assets == 'Inventories'] -
                                        r_c) / uc_c[assets == 'Inventories']
     eatr_nc[assets ==
             'Inventories'] = (uc_nc[assets == 'Inventories'] -
                               r_nc) / uc_nc[assets == 'Inventories']
     eatr_c[assets == 'Land'] = (uc_c[assets == 'Land'] -
                                 r_c) / uc_c[assets == 'Land']
     eatr_nc[assets == 'Land'] = (uc_nc[assets == 'Land'] -
                                  r_nc) / uc_nc[assets == 'Land']
     # Save the results to the main DataFrame
     asset_data['uc_c'] = uc_c
     asset_data['uc_nc'] = uc_nc
     asset_data['eatr_c'] = eatr_c
     asset_data['eatr_nc'] = eatr_nc
     asset_data.drop(['assets_c', 'assets_nc'], axis=1, inplace=True)
     return asset_data
예제 #16
0
 def __init__(self, btax_params):
     self.econ_params = copy.deepcopy(Data().econ_defaults)
     self.btax_params = btax_params
     self.asset_c = Asset(btax_params, corp=True)
     self.asset_c.build_deprLaw_matrices()
예제 #17
0
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
We need to produce the following objects:
    adjfactors.csv
    pass-through shares
"""
import copy
import numpy as np
import pandas as pd
import scipy.optimize
from biztax.data import Data
from biztax.asset import Asset
from biztax.debt import Debt
from biztax.policy import Policy

# Specify single Data object (for convenience)
data1 = Data()
"""
Section 1. Calculation of the adjustment parameters
"""


def calcAMTparams2():
    """
    Calculates the adjustment factors for the AMT and PYMTC
    """
    # Grab historical data
    hist_data = copy.deepcopy(data1.historical_combined)
    taxinc = np.array(hist_data['taxinc'])
    amt = np.array(hist_data['amt'])
    stock13 = 26.0
    A13 = 4.196871
예제 #19
0
class Asset():
    """
    Constructor for the Asset class. 
    This class includes several objects related to assets and depreciation:
        For internal class use:
            investment_history: 
                array of investment amounts
                asset type (96) x year investment made (75)
            capital_history:
                array of asset amounts
                asset type (96) x years in the budget window (14)
            system_history:
                array of depreciation systems (GDS or ADS)
                asset type (96) x year investment made (75)
            method_history:
                array of depreciation methods (DB, Economics, etc.)
                asset type (96) x year investment made (75)
            life_history:
                array of tax lives (see LIVES list)
                asset type (96) and year investment made (75) given system
            bonus_history:
                array of effective bonus depreciation rates
                asset type (96) x year investment made (75)
            ccr_data:
                DataFrame of asset amounts and economic depreciation rates
                asset type (96), 2017 only
            capital_path:
                DataFrame of asset information totals in the budget window
        
    Parameters:
        corp: True for corporate, False for noncorporate
        btax_params: dict of business tax policy parameters
        response: DataFrame of investment responses
        
    """
    def __init__(self, btax_params, corp=True, data=None, response=None):
        # Create an associated Data object
        if isinstance(data, Data):
            self.data = data
        else:
            self.data = Data()
        # Check inputs
        if isinstance(corp, bool):
            self.corp = corp
        else:
            raise ValueError('corp must be True or False')
        if response is None or isinstance(response, pd.DataFrame):
            self.response = response
        else:
            raise ValueError('response must be DataFrame or None')
        if corp:
            self.adjustments = {
                'bonus': 0.60290131,
                'sec179': 0.016687178,
                'overall': self.data.adjfactor_dep_corp,
                'rescalar': self.data.rescale_corp
            }
        else:
            self.adjustments = {
                'bonus': 0.453683778,
                'sec179': 0.17299506,
                'overall': self.data.adjfactor_dep_noncorp,
                'rescalar': self.data.rescale_noncorp
            }
        if isinstance(btax_params, pd.DataFrame):
            self.btax_params = btax_params
        else:
            raise ValueError('btax_params must be DataFrame')

    def update_response(self, response):
        """
        Updates the response DataFrame.
        Note: The response is the investment response DataFrame, not a 
              Response object.
        """
        assert isinstance(response, pd.DataFrame)
        self.response = response

    def get_ccr_data(self):
        assets2017 = copy.deepcopy(self.data.assets_data())
        ccrdata = assets2017.merge(right=self.data.econ_depr_df(),
                                   how='outer',
                                   on='Asset')
        self.ccr_data = ccrdata

    def build_inv_matrix(self):
        """
        Builds investment array by asset type and by year made
        """
        inv_mat1 = np.zeros((96, 75))
        # Build historical portion
        for j in range(57):
            if self.corp:
                inv_mat1[:, j] = (
                    self.data.investmentrate_data['i' + str(j + 1960)] *
                    self.data.investmentshare_data['c_share'][j])
            else:
                inv_mat1[:, j] = (
                    self.data.investmentrate_data['i' + str(j + 1960)] *
                    (1 - self.data.investmentshare_data['c_share'][j]))
        # Extend investment using NGDP (growth factors from CBO forecast)
        for j in range(57, 75):
            inv_mat1[:, j] = (inv_mat1[:, 56] *
                              self.data.investmentGfactors_data['ngdp'][j] /
                              self.data.investmentGfactors_data['ngdp'][56])
        # Investment forecast for 2017
        if self.corp:
            inv2017 = np.asarray(
                self.ccr_data['assets_c'] *
                (self.data.investmentGfactors_data['ngdp'][57] /
                 self.data.investmentGfactors_data['ngdp'][56] - 1 +
                 self.ccr_data['delta']))
        else:
            inv2017 = np.asarray(
                self.ccr_data['assets_nc'] *
                (self.data.investmentGfactors_data['ngdp'][57] /
                 self.data.investmentGfactors_data['ngdp'][56] - 1 +
                 self.ccr_data['delta']))
        # Rescale to match B-Tax data for 2017
        inv_mat2 = np.zeros((96, 75))
        l1 = list(range(96))
        l1.remove(32)  # exclude land
        for j in range(75):
            for i in l1:
                inv_mat2[i, j] = inv_mat1[i, j] * inv2017[i] / inv_mat1[i, 57]
        # Update investment matrix to include investment responses
        inv_mat3 = copy.deepcopy(inv_mat2)
        if self.response is not None:
            if self.corp:
                deltaIkey = 'deltaIc'
            else:
                deltaIkey = 'deltaInc'
            for i in range(96):
                for j in range(57, 68):
                    deltaI = self.response[deltaIkey +
                                           str(j + 1960)].tolist()[i]
                    inv_mat3[i, j] = inv_mat2[i, j] * (1 + deltaI)
        self.investment_history = inv_mat3

    def build_deprLaw_matrices(self):
        """
        Builds the arrays for tax depreciation laws
        """
        def taxdep_final(depr_methods, depr_bonuses):
            """
            Constructs the DataFrame of information for tax depreciation.
            Only relevant for years beginning with 2014.
            Returns a DataFrame with:
                depreciation method,
                tax depreciation life,
                true depreciation rate,
                bonus depreciation rate.
            """
            taxdep = copy.deepcopy(self.data.taxdep_info_gross())
            system = np.empty(len(taxdep), dtype='S10')
            class_life = np.asarray(taxdep['GDS Class Life'])
            # Determine depreciation systems for each asset type
            for cl, method in depr_methods.items():
                system[class_life == cl] = method
            # Determine tax life
            L_ads = np.asarray(taxdep['L_ads'])
            Llist = np.asarray(taxdep['L_gds'])
            Llist[system == 'ADS'] = L_ads[system == 'ADS']
            Llist[system == 'None'] = 100
            taxdep['L'] = Llist
            # Determine depreciation method. Default is GDS method
            method = np.asarray(taxdep['Method'])
            method[system == 'ADS'] = 'SL'
            method[system == 'Economic'] = 'Economic'
            method[system == 'None'] = 'None'
            taxdep['Method'] = method
            # Detemine bonus depreciation rate
            bonus = np.zeros(len(taxdep))
            for cl, cl_bonus in depr_bonuses.items():
                bonus[class_life == cl] = cl_bonus
            taxdep['bonus'] = bonus
            taxdep.drop(['L_gds', 'L_ads', 'GDS Class Life'],
                        axis=1,
                        inplace=True)
            return taxdep

        def taxdep_preset(year):
            """
            Constructs the DataFrame of information for tax depreciation.
            Only relevant for years before 2014.
            Returns a DataFrame with:
                depreciation method,
                tax depreciation life,
                true depreciation rate,
                bonus depreciation rate.
            """
            taxdep = copy.deepcopy(self.data.taxdep_info_gross())
            taxdep['L'] = taxdep['L_gds']
            class_life = np.asarray(taxdep['GDS Class Life'])
            bonus = np.zeros(len(class_life))
            for y in [3, 5, 7, 10, 15, 20, 25, 27.5, 39]:
                s = "bonus{}".format(y if y != 27.5 else 27)
                bonus[class_life == y] = self.data.bonus_data[s][year - 1960]
            taxdep['bonus'] = bonus
            taxdep.drop(['L_gds', 'L_ads', 'GDS Class Life'],
                        axis=1,
                        inplace=True)
            return taxdep

        def get_btax_params_oneyear(btax_params, year):
            """
            Extracts tax depreciation parameters and
            calls the functions to build the tax depreciation
            DataFrames.
            """
            if year >= 2014:
                year = min(year, 2027)
                depr_methods = {}
                depr_bonuses = {}
                for y in [3, 5, 7, 10, 15, 20, 25, 27.5, 39]:
                    s = "depr_{}yr_".format(y if y != 27.5 else 275)
                    depr_methods[y] = btax_params[s + 'method'][year - 2014]
                    depr_bonuses[y] = btax_params[s + 'bonus'][year - 2014]
                taxdep = taxdep_final(depr_methods, depr_bonuses)
            else:
                taxdep = taxdep_preset(year)
            return taxdep

        """
        Create arrays and store depreciation rules in them
        """
        method_history = [[]] * 75
        life_history = np.zeros((96, 75))
        bonus_history = np.zeros((96, 75))
        for year in range(1960, 2035):
            params_oneyear = get_btax_params_oneyear(self.btax_params, year)
            method_history[year - 1960] = params_oneyear['Method']
            life_history[:, year - 1960] = params_oneyear['L']
            bonus_history[:, year - 1960] = params_oneyear['bonus']
        self.method_history = method_history
        self.life_history = life_history
        self.bonus_history = bonus_history

    def calcDep_oneyear(self, year):
        """
        Calculates total depreciation deductions taken in the year.
        """
        def depreciationDeduction(year_investment, year_deduction, method, L,
                                  delta, bonus):
            """
            Computes the nominal depreciation deduction taken on any
            unit investment in any year with any depreciation method and life.
            Parameters:
                year_investment: year the investment is made
                year_deduction: year the CCR deduction is taken
                method: method of CCR (DB 200%, DB 150%, SL, Expensing, None)
                L: class life for DB or SL depreciation (MACRS)
                delta: economic depreciation rate
                bonus: bonus depreciation rate
            """
            assert method in [
                'DB 200%', 'DB 150%', 'SL', 'Expensing', 'Economic', 'None'
            ]
            # No depreciation
            if method == 'None':
                deduction = 0
            # Expensing
            elif method == 'Expensing':
                if year_deduction == year_investment:
                    deduction = 1.0
                else:
                    deduction = 0
            # Economic depreciation
            elif method == 'Economic':
                pi_temp = (
                    self.data.investmentGfactors_data['pce'][year_deduction +
                                                             1] /
                    self.data.investmentGfactors_data['pce'][year_deduction])
                if pi_temp == np.exp(delta):
                    annual_change = 1.0
                else:
                    if year_deduction == year_investment:
                        annual_change = ((
                            (pi_temp * np.exp(delta / 2))**0.5 - 1) /
                                         (np.log(pi_temp - delta)))
                    else:
                        annual_change = ((pi_temp * np.exp(delta) - 1) /
                                         (np.log(pi_temp) - delta))

                if year_deduction < year_investment:
                    sval = 0
                    deduction = 0
                elif year_deduction == year_investment:
                    sval = 1.0
                    deduction = bonus + (1 -
                                         bonus) * delta * sval * annual_change
                else:
                    sval = (
                        np.exp(-delta * (year_deduction - year_investment)) *
                        self.data.investmentGfactors_data['pce']
                        [year_deduction] / 2.0 /
                        (self.data.investmentGfactors_data['pce']
                         [year_investment] + self.data.
                         investmentGfactors_data['pce'][year_investment + 1]))
                    deduction = (1 - bonus) * delta * sval * annual_change
            else:
                if method == 'DB 200%':
                    N = 2
                elif method == 'DB 150%':
                    N = 1.5
                elif method == 'SL':
                    N = 1

            # DB or SL depreciation, half-year convention
                t0 = year_investment + 0.5
                t1 = t0 + L * (1 - 1 / N)
                s1 = year_deduction
                s2 = s1 + 1
                if year_deduction < year_investment:
                    deduction = 0
                elif year_deduction > year_investment + L:
                    deduction = 0
                elif year_deduction == year_investment:
                    deduction = bonus + (1 - bonus) * (1 -
                                                       np.exp(-N / L * 0.5))
                elif s2 <= t1:
                    deduction = ((1 - bonus) *
                                 (np.exp(-N / L *
                                         (s1 - t0)) - np.exp(-N / L *
                                                             (s2 - t0))))
                elif s1 >= t1 and s1 <= t0 + L and s2 > t0 + L:
                    deduction = (1 - bonus) * (N / L * np.exp(1 - N) *
                                               (s2 - s1) * 0.5)
                elif s1 >= t1 and s2 <= t0 + L:
                    deduction = (1 - bonus) * (N / L * np.exp(1 - N) *
                                               (s2 - s1))
                elif s1 < t1 and s2 > t1:
                    deduction = ((1 - bonus) *
                                 (np.exp(-N / L *
                                         (s1 - t0)) - np.exp(-N / L *
                                                             (t1 - t0)) +
                                  N / L * np.exp(1 - N) * (s2 - t1)))
            return deduction

        """
        Calculate depreciation deductions for each year
        """
        unitDep_arr = np.zeros((96, 75))
        for i in range(96):
            # Iterate over asset types
            for j in range(75):
                # Iterate over investment years
                bonus1 = min(
                    self.bonus_history[i, j] * self.adjustments['bonus'] +
                    self.adjustments['sec179'], 1.0)
                unitDep_arr[i, j] = depreciationDeduction(
                    j, year - 1960, self.method_history[j][i],
                    self.life_history[i, j], self.ccr_data['delta'][i], bonus1)
        Dep_arr = self.investment_history * unitDep_arr
        # Apply the haircut on undepreciated basis
        if self.corp:
            hc_undep_year = np.array(
                self.btax_params['undepBasis_corp_hcyear'])[year - 2014]
            hc_undep = np.array(self.btax_params['undepBasis_corp_hc'])[year -
                                                                        2014]
        else:
            hc_undep_year = np.array(
                self.btax_params['undepBasis_noncorp_hcyear'])[year - 2014]
            hc_undep = np.array(
                self.btax_params['undepBasis_noncorp_hc'])[year - 2014]
        if year >= hc_undep_year:
            for j in range(75):
                if j < hc_undep_year:
                    Dep_arr[:, j] = Dep_arr[:, j] * (1 - hc_undep)
        # Calculate the total deduction
        total_depded = Dep_arr.sum().sum()
        return total_depded

    def calcDep_allyears(self):
        """
        Calculates total depreciation deductions taken for all years
        1960-2035. 
        """
        dep_deductions = np.zeros(75)
        for year in range(1960, 2035):
            dep_deductions[year - 1960] = self.calcDep_oneyear(year)
        return dep_deductions

    def calcDep_budget(self):
        """
        Calculates total depreciation deductions taken for 2014 - 2027. 
        """
        dep_deductions = np.zeros(14)
        for year in range(2014, 2028):
            dep_deductions[year - 2014] = self.calcDep_oneyear(year)
        return dep_deductions

    def build_capital_history(self):
        """
        Builds capital history array using investment_history and ccr_data
        """
        Kstock = np.zeros((96, 15))
        trueDep = np.zeros((96, 14))
        pcelist = np.asarray(self.data.investmentGfactors_data['pce'])
        deltalist = np.asarray(self.ccr_data['delta'])
        for i in range(96):
            # Starting by assigning 2017 data from B-Tax
            if self.corp:
                Kstock[i, 3] = np.asarray(self.ccr_data['assets_c'])[i]
            else:
                Kstock[i, 3] = np.asarray(self.ccr_data['assets_nc'])[i]
            # Using 2017 asset totals, apply retroactively
            for j in [56, 55, 54]:
                Kstock[i, j - 54] = (
                    (Kstock[i, j - 53] * pcelist[j] / pcelist[j + 1] -
                     self.investment_history[i, j]) / (1 - deltalist[i]))
                trueDep[i, j - 54] = Kstock[i, j - 54] * deltalist[i]
            # Using 2017 asset totals, apply to future
            for j in range(57, 68):
                trueDep[i, j - 54] = Kstock[i, j - 54] * deltalist[i]
                Kstock[i, j - 53] = (
                    (Kstock[i, j - 54] + self.investment_history[i, j] -
                     trueDep[i, j - 54]) * pcelist[j + 1] / pcelist[j])
        self.capital_history = Kstock
        self.trueDep = trueDep

    def build_capital_path(self):
        """
        Builds the DataFrame of asset amount, investment and depreciation
        totals for each year in the budget window.
        """
        # Sum across assets and put into new dataset
        Kstock_total = np.zeros(14)
        fixedK_total = np.zeros(14)
        trueDep_total = np.zeros(14)
        inv_total = np.zeros(14)
        fixedInv_total = np.zeros(14)
        Mdep_total = np.zeros(14)
        for j in range(14):
            adjfactor = self.adjustments['overall'] * self.adjustments[
                'rescalar'][j]
            Kstock_total[j] = sum(self.capital_history[:, j]) * adjfactor
            fixedK_total[j] = (
                (sum(self.capital_history[:, j]) -
                 self.capital_history[31, j] - self.capital_history[32, j]) *
                adjfactor)
            trueDep_total[j] = sum(self.trueDep[:, j]) * adjfactor
            inv_total[j] = (sum(self.investment_history[:, j + 54]) *
                            adjfactor)
            fixedInv_total[j] = ((sum(self.investment_history[:, j + 54]) -
                                  self.investment_history[31, j + 54]) *
                                 adjfactor)
            Mdep_total[j] = self.calcDep_oneyear(j + 2014) * adjfactor
        cap_result = pd.DataFrame({
            'year': range(2014, 2028),
            'Kstock': Kstock_total,
            'Investment': inv_total,
            'FixedInv': fixedInv_total,
            'trueDep': trueDep_total,
            'taxDep': Mdep_total,
            'FixedK': fixedK_total
        })
        self.capital_path = cap_result

    def calc_all(self):
        """
        Executes all calculations for Asset object.
        """
        self.get_ccr_data()
        self.build_inv_matrix()
        self.build_deprLaw_matrices()
        self.build_capital_history()
        self.build_capital_path()
        return None

    def get_forecast(self):
        """
        Returns an array of the capital stock for 2014-2027
        """
        forecast = np.array(self.capital_path['Kstock'])
        return forecast

    def get_taxdep(self):
        """
        Returns an array of tax depreciation deductions for 2014-2027
        """
        taxdep = np.array(self.capital_path['taxDep'])
        return taxdep

    def get_investment(self):
        """
        Returns an array of total investment for 2014-2027
        """
        inv1 = np.array(self.capital_path['Investment'])
        return inv1

    def get_truedep(self):
        """
        Returns an array of true depreciation for 2014-2027
        """
        truedep = np.array(self.capital_path['trueDep'])
        return truedep
예제 #20
0
 def calc_oneyear(self, year):
     """
     In the given year, calculates EATR and user cost of capital for each
     asset type.
     """
     # Check that year has acceptable value
     assert year in range(2017, END_YEAR + 1)
     # Extract economic parameters
     [r_c, r_nc, r_d, pi, f_c, f_nc] = self.get_econ_params_oneyear(year)
     # Extract tax depreciation information
     iyr = year - 1960
     Method = self.asset_c.method_history[iyr]
     Life = self.asset_c.life_history[:, iyr]
     Bonus = self.asset_c.bonus_history[:, iyr]
     # Make tax rate dictionaries
     tdict_c = self.make_tdict_c(year)
     tdict_nc = self.make_tdict_nc(year)
     # Create base DataFrame and get depreciation rates
     asset_data = copy.deepcopy(Data().taxdep_info_gross('pre2017'))
     asset_data.drop(['L_gds', 'L_ads', 'Method'], axis=1, inplace=True)
     Delta = np.array(asset_data['delta'])
     # Get deductible fractions of interest paid
     (fracded_c, fracded_nc) = self.calc_frac_ded(year)
     # Get inventory method
     assets = np.asarray(asset_data['Asset'])
     uc_c = np.zeros(len(assets))
     uc_nc = np.zeros(len(assets))
     eatr_c = np.zeros(len(assets))
     eatr_nc = np.zeros(len(assets))
     for j in range(len(asset_data)):
         uc_c[j] = self.calc_usercost(r_c, pi, Delta[j], Method[j], Life[j],
                                      Bonus[j], f_c, r_d, fracded_c,
                                      tdict_c, 50)
         uc_nc[j] = self.calc_usercost(r_nc, pi, Delta[j], Method[j],
                                       Life[j], Bonus[j], f_nc, r_d,
                                       fracded_nc, tdict_nc, 50)
         eatr_c[j] = self.calc_eatr(0.2,
                                    r_c,
                                    pi,
                                    Delta[j],
                                    Method[j],
                                    Life[j],
                                    Bonus[j],
                                    f_c,
                                    r_d,
                                    fracded_c,
                                    tdict_c,
                                    length=50)
         eatr_nc[j] = self.calc_eatr(0.2,
                                     r_nc,
                                     pi,
                                     Delta[j],
                                     Method[j],
                                     Life[j],
                                     Bonus[j],
                                     f_nc,
                                     r_d,
                                     fracded_nc,
                                     tdict_nc,
                                     length=50)
     # Save the results to the main DataFrame
     asset_data['uc_c'] = uc_c
     asset_data['uc_nc'] = uc_nc
     asset_data['eatr_c'] = eatr_c
     asset_data['eatr_nc'] = eatr_nc
     return asset_data
예제 #21
0
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()
예제 #22
0
 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