Esempio n. 1
0
def calcDepAdjustment(corp):
    """
    Calculates the adjustment factor for assets, depreciation and investment
    corp: indicator for whether corporate or noncorporate data
    """
    # Create Asset object
    policy = Policy()
    asset1 = Asset(policy.parameters_dataframe(), corp)
    asset1.calc_all()
    # Get unscaled depreciation for all years
    totalAnnualDepreciation = asset1.calcDep_allyears()
    # Get IRS data
    depreciation_data = copy.deepcopy(asset1.data.depreciationIRS_data)
    depreciation_data['dep_model'] = totalAnnualDepreciation[40:54]
    if corp:
        depreciation_data['scale'] = (depreciation_data['dep_Ccorp'] /
                                      depreciation_data['dep_model'])
    else:
        depreciation_data['scale'] = (
            (depreciation_data['dep_Scorp'] + depreciation_data['dep_sp'] +
             depreciation_data['dep_partner']) /
            depreciation_data['dep_model'])
    adj_factor = (sum(depreciation_data['scale']) /
                  len(depreciation_data['scale']))
    # depreciation_data.to_csv('depr_data_' + str(corp) + '.csv')
    return adj_factor
def calcIDAdjustment(corp, eta=0.4):
    """
    Calculates the adjustment factors for the corporate and noncorporate
    debt and interest.
    eta: retirement rate of existing debt
    """
    policy = Policy()
    policy_params_df = policy.parameters_dataframe()
    # Create Asset object
    asset = Asset(policy_params_df, corp)
    asset.calc_all()
    # Get asset forecast
    forecast = asset.get_forecast()
    # Create Debt object
    debt = Debt(policy_params_df, forecast, corp=corp)
    debt.calc_all()
    # Get unscaled net interest deduction
    NID_gross = debt.NID[38:54]
    # Get net interest deduction from historical IRS data
    if corp:
        NID_irs = np.array(data1.debt_data_corp['NID_IRS'])[38:54]
    else:
        NID_irs = np.array(data1.debt_data_noncorp['ID_Scorp'][38:54] +
                           data1.debt_data_noncorp['ID_sp'][38:54] +
                           data1.debt_data_noncorp['ID_partner'][38:54])
    NID_scale = sum(NID_irs / NID_gross) / 16.0  # 16 = 54 - 38
    return NID_scale
 def __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
Esempio n. 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()
Esempio n. 5
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)
Esempio n. 6
0
class BtaxMini():
    """
    Constructor for the BtaxMini class. This class functions similarly to
    the B-Tax model, with several modifications, such as the use of different
    equations and allowing for nonconstant tax rates, as well as producing
    somewhat different final measures. 
    
    Parameters
    ----------
    btax_params: DataFrame of regular tax parameters
    
    Returns
    -------
    DataFrame of user cost of capital and EATR for each year and asset type
    """
    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()

    def make_tdict_c(self, start_year):
        """
        Produces a dictionary of tax rates and changes to those rates,
        for use when calculating rho and EATR, for corporations.
        Assumes no changes after 2027.
        """
        assert start_year >= 2017
        assert type(start_year) == int
        if start_year >= 2027:
            tdict = {'0': self.btax_params['tau_c'][10]}
        else:
            tdict = {'0': self.btax_params['tau_c'][start_year - 2014]}
            for i in range(start_year - 2016,
                           len(self.btax_params['year']) - 3):
                if self.btax_params['tau_c'][
                        i + 3] != self.btax_params['tau_c'][i + 2]:
                    tdict[str(i - (start_year -
                                   2017))] = self.btax_params['tau_c'][i + 3]
        return tdict

    def make_tdict_nc(self, start_year):
        """
        Produces a dictionary of tax rates and changes to those rates,
        for use when calculating rho and EATR, for noncorporate businesses.
        Assumes no changes after 2027.
        """
        assert start_year >= 2017
        assert type(start_year) == int
        if start_year >= 2027:
            tdict = {'0': self.btax_params['tau_nc'][13]}
        else:
            tdict = {'0': self.btax_params['tau_nc'][start_year - 2014]}
            for i in range(start_year - 2016,
                           len(self.btax_params['year']) - 3):
                tdict[str(i - (start_year -
                               2017))] = self.btax_params['tau_nc'][i + 3]
        return tdict

    def get_econ_params_oneyear(self, year):
        """
        Extracts the economic parameters to use for calculations in each year.
        """
        r_d = self.econ_params['r_d'][year - 2014]
        r_e_c = self.econ_params['r_e_c'][year - 2014]
        r_e_nc = self.econ_params['r_e_nc'][year - 2014]
        pi = self.econ_params['pi'][year - 2014]
        f_c = self.econ_params['f_c'][year - 2014]
        f_nc = self.econ_params['f_nc'][year - 2014]
        r_c = f_c * r_d + (1 - f_c) * r_e_c
        r_nc = f_nc * r_d + (1 - f_nc) * r_e_nc
        return (r_c, r_nc, r_d, pi, f_c, f_nc)

    def calc_frac_ded(self, year):
        """
        Calculates the fraction of interest deductible for the given year,
        for corporate and noncorporate.
        """
        # Extract the corporate interest haircuts
        hc_nid_c = np.array(self.btax_params['netIntPaid_corp_hc'])[year -
                                                                    2014]
        hc_id_new_year_c = np.array(
            self.btax_params['newIntPaid_corp_hcyear'])[year - 2014]
        hc_id_new_c = np.array(self.btax_params['newIntPaid_corp_hc'])[year -
                                                                       2014]
        # Find haircut for corporations
        fracdedc = 1.0 - hc_nid_c
        if year >= hc_id_new_year_c:
            fracdedc = min(fracdedc, 1.0 - hc_id_new_c)
        hc_id_new_year_nc = np.array(
            self.btax_params['newIntPaid_noncorp_hcyear'])[year - 2014]
        hc_id_new_nc = np.array(
            self.btax_params['newIntPaid_noncorp_hc'])[year - 2014]
        # Find haircut for noncorporate businesses
        if year < hc_id_new_year_nc:
            # If not subject to haircut
            fracdedn = 1.0
        else:
            # If subject to haircut
            fracdedn = 1.0 - hc_id_new_nc
        return (fracdedc, fracdedn)

    def calc_I(self, delta, r, a, b):
        """
        Calculates present value of income occuring during the period [a,b]
            delta: depreciation rate
            r: discount rate
        Note: this is based on unit incone amount
        """
        if r + delta == 0:
            I = b - a
        else:
            I = (1 / (r + delta) * np.exp(-(r + delta) * a) *
                 (1 - np.exp(-(r + delta) * (b - a))))
        return I

    def calc_Ilist(self, delta, r, length=50):
        """
        Calculates present value of income unit over lifetime
            delta: depreciation rate
            r: discount rate
            length: number of periods to use
        """
        # Calculate for first (half) year
        I0 = self.calc_I(delta, r, 0, 0.5)
        Ilist = [I0]
        for j in range(1, length - 1):
            Ilist.append(self.calc_I(delta, r, j - 0.5, j + 0.5))
        # Calculate from final period to infinity
        Ilist.append(self.calc_I(delta, r, length - 1 - 0.5, 9e99))
        return Ilist

    def calc_F(self, f, r, i, delta, fracded, a, b):
        """
        Calculates present value of interest deduction during period [a,b]
            f: ratio of debt to assets
            r: discount rate
            i: interest rate on debt
            delta: depreciation rate
            fracded: fraction of interest paid deductible
        """
        F = (f * i / (r + delta) * fracded * np.exp(-(r + delta) * a) *
             (1 - np.exp(-(r + delta) * (b - a))))
        return F

    def calc_Flist(self, f, r, i, delta, fracded, length=50):
        """
        Calculates present value of interest deduction over lifetime
            f: ratio of debt to assets
            r: discount rate
            i: interest rate on debt
            delta: depreciation rate
            fracded: fraction of interest paid deductible
            length: number of periods to use
        """
        # Calcuate for first (half) year
        Flist = [self.calc_F(f, r, i, delta, fracded, 0, 0.5)]
        for j in range(1, length - 1):
            Flist.append(self.calc_F(f, r, i, delta, fracded, j - 0.5,
                                     j + 0.5))
        # Calculate from final period to infinity
        Flist.append(
            self.calc_F(f, r, i, delta, fracded, length - 1 - 0.5, 9e99))
        return Flist

    def calc_Dlist_exp(self, length=50):
        """
        Calculates depreciation deduction vector for expensing
        Note: by default, this is 1 for the first period and 0 thereafter
        """
        Dlist = np.zeros(length)
        Dlist[0] = 1
        return Dlist

    def calc_D_econ(self, delta, r, a, b):
        """
        Calculates PV of depreciation deduction during [a,b] using economic
        depreciation method. 
            delta: depreciation rate
            r: discount rate
        """
        if r + delta == 0:
            D = delta * (b - a)
        else:
            D = (delta / (r + delta) * np.exp(-(r + delta) * a) *
                 (1 - np.exp(-(r + delta) * (b - a))))
        return D

    def calc_Dlist_econ(self, delta, r, bonus, length=50):
        """
        Calculates present value of depreciation deductions over lifetime
        for economic depreciation. 
            delta: depreciation rate
            r: discount rate
            bonus: bonus depreciation rate
        """
        # Calculate for fist (half) year
        Dlist = [bonus + (1 - bonus) * self.calc_D_econ(delta, r, 0, 0.5)]
        for j in range(1, length - 1):
            Dlist.append(
                (1 - bonus) * self.calc_D_econ(delta, r, j - 0.5, j + 0.5))
        # Calculate from last period to infinity
        Dlist.append(
            (1 - bonus) * self.calc_D_econ(delta, r, length - 1 - 0.5, 9e99))
        return Dlist

    def calc_D_dbsl(self, N, L, r, pi, a, b):
        """
        Calculates PV of depreciation deductions during [a,b] for declining
        balance and straight-line depreciation.
            N: exponential depreciation:
                2 for double-declining balance
                1.5 for 150% declining balance
                1 for straight-line
            L: tax life
            r: discount rate
            pi: inflation rate
        """
        # Ensure N is not an int
        N = N * 1.0
        # Switching point
        t1 = L * (1 - 1 / N)
        # End of tax life
        t2 = L
        if b <= t1:
            # If entirely subject to exponential depreciation
            D = (N / L / (r + pi + N / L) * np.exp(-(r + pi + N / L) * a) *
                 (1 - np.exp(-(r + pi + N / L) * (b - a))))
        elif b <= t2:
            if a < t1:
                # If period splits exponential and straight-line depreciation
                Ddb = (N / L / (r + pi + N / L) *
                       np.exp(-(r + pi + N / L) * a) *
                       (1 - np.exp(-(r + pi + N / L) * (t1 - a))))
                if r + pi == 0:
                    # Special case of zero nominal discount rate
                    Dsl = np.exp(1 - N) * (b - t1) / (t2 - t1)
                else:
                    Dsl = (N / L / (r + pi) * np.exp(1 - N) *
                           np.exp(-(r + pi) * t1) * (1 - np.exp(-(r + pi) *
                                                                (b - t1))))
                D = Ddb + Dsl
            else:
                # If entirely subject to straight-line depreciation
                if r + pi == 0:
                    D = np.exp(1 - N) * (b - a) / (t2 - t1)
                else:
                    D = (N / L / (r + pi) * np.exp(1 - N) *
                         np.exp(-(r + pi) * a) * (1 - np.exp(-(r + pi) *
                                                             (b - a))))
        else:
            # end of period occurs after tax life ends
            if a < t2:
                # If tax life ends during period
                if r + pi == 0:
                    D = np.exp(1 - N) * (t2 - a) / (t2 - t1)
                else:
                    D = (N / L / (r + pi) * np.exp(1 - N) *
                         np.exp(-(r + pi) * a) * (1 - np.exp(-(r + pi) *
                                                             (t2 - a))))
            else:
                # If period occurs entirely after tax life has ended
                D = 0
        return D

    def calc_Dlist_dbsl(self, N, L, bonus, r, pi, length=50):
        """
        Calculates present value of depreciation deductions over lifetime
        for declining balance and straight-line depreciation.
            N: exponential depreciation:
                2 for double-declining balance
                1.5 for 150% declining balance
                1 for straight-line
            L: tax life
            r: discount rate
            pi: inflation rate
            length: number of periods to use
        """
        Dlist = [bonus + (1 - bonus) * self.calc_D_dbsl(N, L, r, pi, 0, 0.5)]
        for j in range(1, length):
            Dlist.append(
                (1 - bonus) * self.calc_D_dbsl(N, L, r, pi, j - 0.5, j + 0.5))
        return Dlist

    def calc_Dlist(self, method, life, delta, r, pi, bonus, length=50):
        """
        Calculates present value of depreciation deductions over lifetime.
            method: depreciation method to use
            life: tax life
            delta: depreciation rate
            r: discount rate
            pi: inflation rate
            bonus: bonus depreciation rate
            length: number of periods to use
        """
        # Check that methods are acceptable
        assert method in [
            'DB 200%', 'DB 150%', 'SL', 'Economic', 'Expensing', 'None'
        ]
        # Check bonus depreciation rates
        assert bonus >= 0 and bonus <= 1
        if type(length) != int:
            length = int(length)
        if method == 'DB 200%':
            # Double-declining (200%) balance depreciation
            Dlist = self.calc_Dlist_dbsl(2, life, bonus, r, pi, length)
        elif method == 'DB 150%':
            # 150% declining balance depreciation
            Dlist = self.calc_Dlist_dbsl(1.5, life, bonus, r, pi, length)
        elif method == 'SL':
            # Straight-line depreciation
            Dlist = self.calc_Dlist_dbsl(1.0, life, bonus, r, pi, length)
        elif method == 'Economic':
            # Economic depreciation
            Dlist = self.calc_Dlist_econ(delta, r, bonus, length)
        elif method == 'Expensing':
            # Expensing
            Dlist = self.calc_Dlist_exp(length)
        else:
            # No depreciation
            Dlist = np.zeros(length)
        return Dlist

    def calc_Tlist(self, tdict, length=50):
        """
        Builds list of statutory tax rates for each period in lifetime
            tdict: dictionary of tax rates and when they become effective
                tdict may not be empty
                tdict must contain at least one key of '0'
                tdict keys must be as nonnegative integers
            length: number of periods to use
        """
        assert len(tdict) > 0
        # changelist is the period when the tax rate changes
        changelist = []
        for key in tdict:
            changelist.append(int(key))
        changelist.sort()
        # ratelist is list of tax rates
        ratelist = []
        for chg in changelist:
            ratelist.append(tdict[str(chg)])
        numrates = len(ratelist)
        rateind = 0
        # Get initial tax rate
        Tlist = [tdict[str(changelist[0])]]
        for j in range(1, length):
            if rateind + 1 == numrates:
                # If at end of tax rate changes
                Tlist.append(ratelist[rateind])
            else:
                if j < changelist[rateind + 1]:
                    # If between tax rate changes
                    Tlist.append(ratelist[rateind])
                else:
                    # If tax rate change occurs this year
                    rateind = rateind + 1
                    Tlist.append(ratelist[rateind])
        return Tlist

    def calc_rho(self,
                 r,
                 pi,
                 delta,
                 method,
                 life,
                 bonus,
                 f,
                 rd,
                 fracded,
                 tdict,
                 length=50):
        """
        Calculates the cost of capital
            r: discount rate
            pi: inflation rate
            delta: depreciation rate
            method: depreciation method
            life: tax life
            bonus: bonus depreciation rate
            f: debt to asset ratio
            rd: interest rate on debt
            fracded: fraction of interest paid deductible
            tdict: dict of tax rates and changes
            length: number of periods to use
        """
        # Get tax rates for all periods
        Tlist = np.asarray(self.calc_Tlist(tdict, length))
        # Get income rates for all periods
        Nlist = np.asarray(self.calc_Ilist(delta, r, length))
        # Get depreciation deductions for all periods
        Dlist = np.asarray(
            self.calc_Dlist(method, life, delta, r, pi, bonus, length))
        # Get interest deductions for all periods
        Flist = np.asarray(self.calc_Flist(f, r, rd, delta, fracded, length))
        # Present value of tax shield from depreciation
        A = sum(Dlist * Tlist)
        # Present value of tax shield from interest deduction
        F = sum(Flist * Tlist)
        # Present value of gross income net-of-tax rate
        N = sum(Nlist * (1 - Tlist))
        rho = (1 - A - F) / N - delta
        return rho

    def calc_rho_inv(self, r, pi, inv_method, hold, tdict):
        """
        Calculates the cost of capital for inventories
            r: discount rate
            pi: inflation rate
            inv_method: inventory accounting method
            hold: holding period for inventories
            tdict: dict of tax rates and changes
        """
        # Acceptable inventory methods
        assert inv_method in ['FIFO', 'LIFO', 'Expensing', 'Mix']
        tau = tdict['0']
        # Cost of capital with expensing
        rho_exp = r
        # Cost of capital using LIFO
        rho_lifo = (1 / hold * np.log((np.exp(
            (r + pi) * hold) - tau) / (1 - tau)) - pi)
        # Cost of capital using FIFO
        rho_fifo = 1 / hold * np.log((np.exp(r * hold) - tau) / (1 - tau))
        if inv_method == 'FIFO':
            rho_inv = rho_fifo
        elif inv_method == 'LIFO':
            rho_inv = rho_lifo
        elif inv_method == 'Expensing':
            rho_inv = rho_exp
        else:
            # Mix of 50% FIFO and 50% LIFO
            rho_inv = 0.5 * (rho_fifo + rho_lifo)
        return rho_inv

    def calc_eatr(self,
                  p,
                  r,
                  pi,
                  delta,
                  method,
                  life,
                  bonus,
                  f,
                  rd,
                  fracded,
                  tdict,
                  length=50):
        """
        Calculates the effective average tax rate on investment
            p: financial income rate
            r: discount rate
            pi: inflation rate
            delta: depreciation rate
            method: depreciation method
            life: tax life
            bonus: bonus depreciation rate
            f: debt to asset ratio
            rd: interest rate on debt
            fracded: fraction of interest paid deductible
            tdict: dict of tax rates and changes
            length: number of periods to use
        """
        # Calculate the cost of capital
        coc = self.calc_rho(r, pi, delta, method, life, bonus, f, rd, fracded,
                            tdict, length)
        # Check that the financial income rate exceess the cost of capital
        assert p >= coc
        # Rent in the absence of tax
        Rstar = (p - r) / (r + delta)
        # Income stream
        P = p / (r + delta)
        Tlist = np.asarray(self.calc_Tlist(tdict, length))
        Nlist = np.asarray(self.calc_Ilist(delta, r, length))
        Dlist = np.asarray(
            self.calc_Dlist(method, life, delta, r, pi, bonus, length))
        Flist = np.asarray(self.calc_Flist(f, r, rd, delta, fracded, length))
        A = sum(Dlist * Tlist)
        F = sum(Flist * Tlist)
        N = sum(Nlist * (1 - Tlist))
        # Calculate after-tax rent
        R = -(1 - A - F) + (p + delta) * N
        eatr = (Rstar - R) / P
        return eatr

    def calc_usercost(self,
                      r,
                      pi,
                      delta,
                      method,
                      life,
                      bonus,
                      f,
                      rd,
                      fracded,
                      tdict,
                      length=50):
        """
        Calculates the cost of capital
            r: discount rate
            pi: inflation rate
            delta: depreciation rate
            method: depreciation method
            life: tax life
            bonus: bonus depreciation rate
            f: debt to asset ratio
            rd: interest rate on debt
            fracded: fraction of interest paid deductible
            tdict: dict of tax rates and changes
            length: number of periods to use
        """
        # Calculate the cost of capital
        coc = self.calc_rho(r, pi, delta, method, life, bonus, f, rd, fracded,
                            tdict, length)
        ucoc = coc + delta
        return ucoc

    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

    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
Esempio n. 7
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()
class CorpTaxReturn():
    """
    Constructor for the CorpTaxReturn object. 
    This class includes objects relevant to the calculation of 
    corporate income tax liability:
        assets: an associated Asset object
        debts: an associated debt object
        combined_return: a DataFrame with tax calculations for each year
    
    Parameters:
        btax_params: dict of business tax policy parameters
        assets: Asset object for the corporation
        debts: Debt object for the corporation
        earnings: list or array of earnings for each year in the budget window
    """
    
    def __init__(self, btax_params, earnings,
                 data=None, assets=None, debts=None):
        # Create an associated Data object
        if isinstance(data, Data):
            self.data = data
        else:
            self.data = Data()
        if isinstance(btax_params, pd.DataFrame):
            self.btax_params = btax_params
        else:
            raise ValueError('btax_params must be DataFrame')
        if assets is not None:
            if isinstance(assets, Asset):
                self.assets = assets
            else:
                raise ValueError('assets must be Asset object')
        else:
            self.assets = Asset(btax_params)
            self.assets.calc_all()
        if debts is not None:
            if isinstance(debts, Debt):
                self.debts = debts
            else:
                raise ValueError('debts must be Debt object')
        else:
            assets_forecast = self.assets.get_forecast()
            self.debts = Debt(btax_params, assets_forecast)
            self.debts.calc_all()
        # Use earnings to create DataFrame for results
        assert len(earnings) == 14
        combined = pd.DataFrame({'year': range(2014,2028), 'ebitda': earnings})
        # Add tax depreciation and net interest deductions
        combined['taxDep'] = self.assets.get_taxdep()
        combined['nid'] = self.debts.get_nid()
        self.combined_return = combined
    
    def update_assets(self, assets):
        """
        Updates the Asset object associated with the tax return.
        """
        if isinstance(assets, Asset):
            self.assets = assets
        else:
            raise ValueError('assets must be Asset object')
    
    def update_debts(self, debts):
        """
        Updates the Debt object associated with the tax return.
        """
        if isinstance(debts, Debt):
            self.debts = debts
        else:
            raise ValueError('debts must be Debt object')
    
    def update_earnings(self, earnings):
        """
        Updates the earnings DataFrame associated with the tax return.
        """
        assert len(earnings) == 14
        self.combined_return['ebitda'] = earnings
    
    def calcSec199(self):
        """
        Calculates section 199 deduction.
        """
        # Extract relevant parmeters
        s199_hclist = np.array(self.btax_params['sec199_hc'])
        profit = np.asarray(self.data.gfactors['profit_d'])
        sec199_res = np.zeros(14)
        sec199_2013 = np.asarray(self.data.historical_taxdata['sec199'])[-1]
        for i in range(14):
            sec199_res[i] = profit[i+1] / profit[0] * sec199_2013 * (1 - s199_hclist[i])
        self.combined_return['sec199'] = sec199_res
    
    def calcInitialTax(self):
        """
        Calculates taxable income and tax before credits.
        """
        self.combined_return['taxinc'] = (self.combined_return['ebitda'] -
                                          self.combined_return['taxDep'] -
                                          self.combined_return['nid'] -
                                          self.combined_return['sec199'])
        self.combined_return['tau'] = self.btax_params['tau_c']
        self.combined_return['taxbc'] = (self.combined_return['taxinc'] *
                                         self.combined_return['tau'])
    
    def calcFTC(self):
        """
        Calculates foreign tax credit for 2014-2027.
        """
        hclist = np.array(self.btax_params['ftc_hc'])
        def calcWAvgTaxRate(year):
            """
            Calculates the weighted average statutory corporate tax rate
            in all OECD countries in a given year.
            """
            assert year in range(1995, 2028)
            year = min(year, 2016)
            gdp_list = np.asarray(self.data.ftc_gdp_data[str(year)])
            taxrate_list = np.asarray(self.data.ftc_taxrates_data[str(year)])
            # remove observations with missing data
            taxrate_list2 = np.where(np.isnan(taxrate_list), 0, taxrate_list)
            gdp_list2 = np.where(np.isnan(taxrate_list), 0, gdp_list)
            avgrate = sum(taxrate_list2 * gdp_list2) / sum(gdp_list2)
            return avgrate
        # Get foreign profits forecast
        profits = np.asarray(self.data.ftc_other_data['C_total'][19:])
        profits_d = np.asarray(self.data.ftc_other_data['C_domestic'][19:])
        tax_f = np.zeros(14)
        for i in range(14):
            tax_f[i] = calcWAvgTaxRate(i + 2014)
        ftc_final = ((profits - profits_d) * tax_f / 100. *
                     self.data.adjfactor_ftc_corp *
                     (1 - hclist)) * self.data.rescale_corp
        self.combined_return['ftc'] = ftc_final
    
    def calcAMT(self):
        """
        Calculates the AMT revenue and PYMTC for 2014-2027
        pymtc_status: 0 for no change, 1 for repeal, 2 for refundable
        """
        # Get relevant tax information
        taxinc = np.array(self.combined_return['taxinc'])
        amt_rates = np.array(self.btax_params['tau_amt'])
        ctax_rates = np.array(self.btax_params['tau_c'])
        pymtc_status = np.array(self.btax_params['pymtc_status'])
        # Check values for PYMTC status
        for x in pymtc_status:
            assert x in [0, 1, 2]
        # Create empty arrays for AMT, PYMTC, and stocks (by status)
        A = np.zeros(14)
        P = np.zeros(14)
        stockA = np.zeros(15)
        stockN = np.zeros(15)
        stockA[0] = ((self.data.trans_amt1 * self.data.userate_pymtc + self.data.trans_amt2 *
                      (1 - self.data.userate_pymtc)) / (1 - self.data.trans_amt1) * self.data.stock2014)
        stockN[0] = self.data.stock2014 - stockN[0]
        stockN[0] = (1 - self.data.trans_amt1) / (1 - self.data.trans_amt1 + self.data.trans_amt1 *
                                                  self.data.userate_pymtc + self.data.trans_amt2 *
                                                  (1 - self.data.userate_pymtc)) * self.data.stock2014
        stockA[0] = self.data.stock2014 - stockN[0]
        for i in range(14):
            # Calculate AMT
            if amt_rates[i] == 0.:
                # If no AMT
                A[i] = 0.
                frac_amt = 0.
            elif ctax_rates[i] <= amt_rates[i]:
                # If AMT rate exceeds regular rate (all subject to AMT)
                A[i] = ((amt_rates[i] - ctax_rates[i] + amt_rates[i] / self.data.param_amt) *
                        taxinc[i])
                frac_amt = 0.999
            else:
                A[i] = (amt_rates[i] / self.data.param_amt *
                        np.exp(-self.data.param_amt * (ctax_rates[i] / amt_rates[i] - 1)) *
                        taxinc[i])
                frac_amt = np.exp(-self.data.param_amt * (ctax_rates[i] / amt_rates[i] - 1))
            # Adjust transition params for change in AMT frequency
            alpha = max(0.0, min(1.0, self.data.trans_amt1 * (frac_amt / self.data.amt_frac)**0.5))
            beta = (1 - alpha) * frac_amt / (1 - frac_amt)
            if pymtc_status[i] == 0:
                # No change from baseline
                userate = self.data.userate_pymtc
            elif pymtc_status[i] == 1:
                # PYMTC repealed
                userate = 0.0
            else:
                # PYMTC made fully refundable
                userate = 1.0
            P[i] = userate * stockN[i]
            stockA[i+1] = (alpha * (stockA[i] + A[i]) +
                           beta * (stockN[i] - P[i]))
            stockN[i+1] = ((1 - alpha) * (stockA[i] + A[i]) +
                           (1 - beta) * (stockN[i] - P[i]))
        # Rescale for any cross-sector shifting
        amt_final = A * self.data.rescale_corp
        pymtc_final = P * self.data.rescale_corp
        self.combined_return['amt'] = amt_final
        self.combined_return['pymtc'] = pymtc_final
    
    def calcTax(self):
        """
        Calculates final tax liability.
        """
        # Calculate general business credits
        profit = np.asarray(self.data.gfactors['profit_d'])
        gbc_2013 = np.asarray(self.data.historical_taxdata['gbc'])[-1]
        gbc_res = profit[1:] / profit[0] * gbc_2013
        self.combined_return['gbc'] = gbc_res
        # Calculate final tax liability
        self.combined_return['taxrev'] = (self.combined_return['taxbc'] +
                                          self.combined_return['amt'] -
                                          self.combined_return['ftc'] -
                                          self.combined_return['pymtc'] -
                                          self.combined_return['gbc'])
    
    def calc_all(self):
        """
        Executes all tax calculations.
        """
        self.calcSec199()
        self.calcInitialTax()
        self.calcFTC()
        self.calcAMT()
        self.calcTax()
    
    def getReturn(self):
        """
        Returns the tax return information
        """
        combined_result = copy.deepcopy(self.combined_return)
        return combined_result
    
    def get_tax(self):
        """
        Returns the total tax liability.
        """
        tax1 = np.array(self.combined_return['taxrev'])
        return tax1
 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
Esempio n. 10
0
class CorpTaxReturn():
    """
    Constructor for the CorpTaxReturn object.
    This class includes objects relevant to the calculation of
    corporate income tax liability:
        assets: an associated Asset object
        debts: an associated debt object
        combined_return: a DataFrame with tax calculations for each year

    Parameters:
        btax_params: dict of business tax policy parameters
        assets: Asset object for the corporation
        debts: Debt object for the corporation
        earnings: list or array of earnings for each year in the budget window
    """
    def __init__(self,
                 btax_params,
                 revenues,
                 deductions,
                 credit,
                 dmne=None,
                 data=None,
                 assets=None,
                 debts=None):
        # Create an associated Data object
        if isinstance(data, Data):
            self.data = data
        else:
            self.data = Data()
        if isinstance(btax_params, pd.DataFrame):
            self.btax_params = btax_params
        else:
            raise ValueError('btax_params must be DataFrame')
        if isinstance(revenues, pd.DataFrame):
            self.revenues = copy.deepcopy(revenues)
        else:
            raise ValueError('revenues must be in DataFrame')
        if isinstance(deductions, pd.DataFrame):
            self.deductions = copy.deepcopy(deductions)
        else:
            raise ValueError('deductions must be in DataFrame')
        if isinstance(credit, pd.DataFrame):
            self.credits = copy.deepcopy(credit)
        else:
            raise ValueError('credits must be in DataFrame')
        if dmne is None:
            # Note: Don't do this in general
            self.dmne = DomesticMNE(self.btax_params)
            self.dmne.calc_all()
        elif isinstance(dmne, DomesticMNE):
            self.dmne = dmne
        else:
            raise ValueError('dmne must be a DomesticMNE object')
        if assets is not None:
            if isinstance(assets, Asset):
                self.assets = assets
            else:
                raise ValueError('assets must be Asset object')
        else:
            self.assets = Asset(btax_params)
            self.assets.calc_all()
        if debts is not None:
            if isinstance(debts, Debt):
                self.debts = debts
            else:
                raise ValueError('debts must be Debt object')
        else:
            assets_forecast = self.assets.get_forecast()
            self.debts = Debt(btax_params, assets_forecast)
            self.debts.calc_all()
        # Prepare unmodeled components of tax return
        self.revenues['capgains'] = (
            self.revenues['capgains'] *
            (1. - self.btax_params['capgains_corp_hc']))
        self.revenues['domestic_divs'] = (
            self.revenues['domestic_divs'] *
            self.btax_params['domestic_dividend_inclusion'])
        self.revenues['total'] = (self.revenues['receipts'] +
                                  self.revenues['rent'] +
                                  self.revenues['royalties'] +
                                  self.revenues['capgains'] +
                                  self.revenues['domestic_divs'] +
                                  self.revenues['other'] +
                                  self.dmne.dmne_results['foreign_taxinc'])
        self.deductions['charity'] = (self.deductions['charity'] *
                                      (1. - self.btax_params['charity_hc']))
        self.deductions['statelocaltax'] = (
            self.deductions['statelocaltax'] *
            (1. - self.btax_params['statelocaltax_hc']))
        self.deductions['total'] = (
            self.deductions['cogs'] + self.deductions['execcomp'] +
            self.deductions['wages'] + self.deductions['repairs'] +
            self.deductions['baddebt'] + self.deductions['rent'] +
            self.deductions['statelocaltax'] + self.deductions['charity'] +
            self.deductions['amortization'] + self.deductions['depletion'] +
            self.deductions['advertising'] + self.deductions['pensions'] +
            self.deductions['benefits'] + self.deductions['other'])
        combined = pd.DataFrame({
            'year':
            range(START_YEAR, END_YEAR + 1),
            'ebitda': (self.revenues['total'] - self.deductions['total'])
        })
        # Add tax depreciation
        combined['taxDep'] = self.assets.get_taxdep()
        self.combined_return = combined

    def update_assets(self, assets):
        """
        Updates the Asset object associated with the tax return.
        """
        if isinstance(assets, Asset):
            self.assets = assets
        else:
            raise ValueError('assets must be Asset object')

    def update_debts(self, debts):
        """
        Updates the Debt object associated with the tax return.
        """
        if isinstance(debts, Debt):
            self.debts = debts
        else:
            raise ValueError('debts must be Debt object')

    def update_earnings(self, dearnings):
        """
        Updates the earnings DataFrame associated with the tax return.
        """
        assert len(dearnings) == NUM_YEARS
        fearnings = np.asarray(self.dmne.dmne_results['foreign_taxinc'])
        self.combined_return['ebitda'] = dearnings + fearnings

    def calcInterestDeduction(self):
        """
        Computes interest deduction.
        """
        # Compute adjusted taxable income
        adjTaxInc = np.maximum(
            self.combined_return['ebitda'] - self.revenues['capgains'] -
            self.combined_return['taxDep'] +
            self.btax_params['adjustedTaxInc_def'] *
            (self.combined_return['taxDep'] + self.deductions['amortization'] +
             self.deductions['depletion']), 0.0001)
        # Section 163(j) deduction limitation
        deductible_int = (
            adjTaxInc * self.btax_params['adjustedTaxInc_limit'] +
            self.debts.get_intInc())
        intded0 = self.debts.get_intDed()
        intded1 = np.zeros(NUM_YEARS)
        for i in range(NUM_YEARS):
            if i > 0:
                # Add disallowed interest as carryforward from prior year
                intded0[i] = intded0[i] + intded0[i - 1] - intded1[i - 1]
            intded1[i] = min(deductible_int[i], intded0[i])
        # Apply interest haircuts
        intTaxInc = (self.debts.get_intInc() *
                     (1. - self.btax_params['intIncome_corp_hc']) +
                     self.debts.get_muniInc() *
                     (1. - self.btax_params['muniIntIncome_corp_hc']))
        intTaxDed = intded1 * (1. - self.btax_params['intPaid_corp_hc'])
        # Compute net interest deduction
        self.combined_return['nid'] = intTaxDed - intTaxInc
        # Assign fraction of interest deductible to Debt object
        fracded = intTaxDed / (self.debts.get_intPaid() + 0.000001)
        self.btax_params['fracded_c'] = fracded

    def calcInitialTax(self):
        """
        Calculates taxable income and tax before credits.
        """
        netinc1 = (self.combined_return['ebitda'] -
                   self.combined_return['taxDep'] -
                   self.combined_return['nid'])
        self.combined_return['sec199'] = (netinc1 *
                                          self.deductions['sec199share'] *
                                          self.btax_params['sec199_rt'])
        netinc2 = netinc1 - self.combined_return['sec199']
        self.combined_return['taxinc'] = np.maximum(netinc2, 0.)
        self.combined_return['tau'] = self.btax_params['tau_c']
        self.combined_return['taxbc'] = (self.combined_return['taxinc'] *
                                         self.combined_return['tau'])

    def calcFTC(self):
        """
        Gets foreign tax credit from DomesticMNE
        """
        self.combined_return['ftc'] = self.dmne.dmne_results['ftc']

    def calcAMT(self):
        """
        Calculates the AMT revenue and PYMTC for [START_YEAR, END_YEAR]
        """
        # Overall transition rates and parameters
        trans_amt0 = self.data.trans_amt0
        trans_amt1 = self.data.trans_amt1
        userate = self.data.userate_pymtc
        amt2013 = self.data.corp_tax2013.loc[40, 'ALL']
        # Get relevant tax information
        taxinc = np.array(self.combined_return['taxinc'])
        amt_rates = np.array(self.btax_params['tau_amt'])
        ctax_rates = np.array(self.btax_params['tau_c'])
        pymtc_hc = np.array(self.btax_params['pymtc_hc'])
        pymtc_refund = np.array(self.btax_params['pymtc_refund'])
        # Create empty arrays for AMT, PYMTC, and stocks (by status)
        A = np.zeros(NUM_YEARS)
        P = np.zeros(NUM_YEARS)
        stock0 = np.zeros(NUM_YEARS + 1)
        stock1 = np.zeros(NUM_YEARS + 1)
        # Set initial stocks using steady-state equations
        stock0[0] = amt2013 / userate
        stock1[0] = amt2013 * (trans_amt1 / (1. - trans_amt1) +
                               (1. - userate) / userate * (1. - trans_amt0) /
                               (1. - trans_amt1))
        for iyr in range(NUM_YEARS):
            # Calculate AMT
            if amt_rates[iyr] == 0.:
                # If no AMT
                A[iyr] = 0.
                frac_amt = 0.
                # Update transition rate parameters
                pi0 = 1.
                pi1 = 0.
            elif ctax_rates[iyr] <= amt_rates[iyr]:
                # If AMT rate exceeds regular rate (all subject to AMT)
                A[iyr] = ((amt_rates[iyr] - ctax_rates[iyr] +
                           amt_rates[iyr] / self.data.param_amt) * taxinc[iyr])
                frac_amt = 0.999
                # Update transition rate parameters
                pi0 = 0.
                pi1 = 1.
            else:
                A[iyr] = (amt_rates[iyr] / self.data.param_amt *
                          np.exp(-self.data.param_amt *
                                 (ctax_rates[iyr] / amt_rates[iyr] - 1)) *
                          taxinc[iyr])
                # Compute new fraction subject to AMT
                frac_amt = np.exp(-self.data.param_amt *
                                  (ctax_rates[iyr] / amt_rates[iyr] - 1))
                # Adjust transition params for change in AMT frequency
                pi1 = max(
                    min(
                        self.data.trans_amt1 *
                        (frac_amt / self.data.amt_frac)**0.5, 1.), 0.)
                pi0 = max(min(1. - frac_amt * (1 - pi1) / (1 - frac_amt), 1.),
                          0.)
            # Compute PYMTC
            P[iyr] = ((pymtc_refund[iyr] * stock0[iyr] +
                       (1. - pymtc_refund[iyr]) * stock0[iyr] * userate) *
                      (1. - pymtc_hc[iyr]))
            # Update credits carried forward
            stock0[iyr + 1] = ((stock1[iyr] + A[iyr]) * (1. - pi1) +
                               (stock0[iyr] - P[iyr]) * pi0)
            stock1[iyr + 1] = ((stock1[iyr] + A[iyr]) * pi1 +
                               (stock0[iyr] - P[iyr]) * (1. - pi0))
        # Rescale for any cross-sector shifting
        amt_final = A * self.data.rescale_corp
        pymtc_final = P * self.data.rescale_corp
        self.combined_return['amt'] = amt_final
        self.combined_return['pymtc'] = pymtc_final

    def calcTax(self):
        """
        Calculates final tax liability.
        """
        self.combined_return['gbc'] = self.credits['gbc']
        # Calculate final tax liability
        taxliab1 = (self.combined_return['taxbc'] +
                    self.combined_return['amt'] - self.combined_return['ftc'] -
                    self.combined_return['pymtc'] -
                    self.combined_return['gbc'])
        self.combined_return['taxrev'] = np.maximum(taxliab1, 0.)

    def calc_all(self):
        """
        Executes all tax calculations.
        """
        self.calcInterestDeduction()
        self.calcInitialTax()
        self.calcFTC()
        self.calcAMT()
        self.calcTax()

    def getReturn(self):
        """
        Returns the tax return information
        """
        combined_result = copy.deepcopy(self.combined_return)
        return combined_result

    def get_tax(self):
        """
        Returns the total tax liability.
        """
        tax = np.array(self.combined_return['taxrev'])
        return tax
Esempio n. 11
0
    assets14 = forecast[0]
    return (scales, assets14, intpaid_model, intinc_model, muniinc_model)

(scales_corp, ast_c_14, intpaid_model, intinc_model, muniinc_model) = calcIDAdjustment(True)
(scale_ncorp, ast_nc_14, _, _, _) = calcIDAdjustment(False)
print(scales_corp)
print(scale_ncorp)

newdebt = copy.deepcopy(debt2)
newdebt['L_c'] = debt2['L_c'] * scales_corp[0]
newdebt['L_nc'] = debt2['L_nc'] * scale_ncorp
newdebt['At_c'] = debt2['At_c'] * scales_corp[1]
newdebt['An_c'] = debt2['An_c'] * scales_corp[2]
newdebt.to_csv(OUTPUT_PATH + 'debt_history.csv')


pol1 = Policy()
# Create Asset object
asset = Asset(pol1.parameters_dataframe(), True)
asset.calc_all()
# Create Debt object
debt = Debt(pol1.parameters_dataframe(), asset.get_forecast(), corp=True)
debt.calc_all()

df1 = pd.DataFrame({'inc_mod': intinc_model * scales_corp[1],
                    'paid_mod': intpaid_model * scales_corp[0],
                    'muni_mod': muniinc_model * scales_corp[2],
                    'inc_irs': taxint, 'paid_irs': intpaid, 'muni_irs': ntaxint})
df1.to_csv('debt_fit.csv')

Esempio n. 12
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()
Esempio n. 13
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