Source code for ccc.calcfunctions

import numpy as np
import pandas as pd
from ccc.constants import TAX_METHODS
from ccc.utils import str_modified

pd.set_option("future.no_silent_downcasting", True)

ENFORCE_CHECKS = True


[docs] def update_depr_methods(df, p, dp): """ Updates depreciation methods per changes from defaults that are specified by user. Args: df (Pandas DataFrame): assets by type and tax treatment p (CCC Specifications object): CCC parameters dp (CCC DepreciationParams object): asset-specific depreciation parameters Returns: df (Pandas DataFrame): assets by type and tax treatment with updated tax depreciation methods """ # update tax_deprec_rates based on user defined parameters # create dataframe with depreciation policy parameters deprec_df = pd.DataFrame(dp.asset) # split out value into two columns deprec_df = deprec_df.join( pd.DataFrame(deprec_df.pop("value").values.tolist()) ) # drop information duplicated in asset dataframe deprec_df.drop( columns=["asset_name", "minor_asset_group", "major_asset_group"], inplace=True, ) # merge depreciation policy parameters to asset dataframe df.drop(columns=deprec_df.keys(), inplace=True, errors="ignore") df = df.merge( deprec_df, how="left", left_on="bea_asset_code", right_on="BEA_code" ) # add bonus depreciation to tax deprec parameters dataframe # ** UPDATE THIS - maybe including bonus in new asset deprec JSON** df["bonus"] = df["GDS_life"].apply(str_modified) df.replace({"bonus": p.bonus_deprec}, inplace=True) # make bonus float format df["bonus"] = df["bonus"].astype(float) # Compute b df["b"] = df["method"] df.replace({"b": TAX_METHODS}, regex=True, inplace=True) df.loc[df["system"] == "ADS", "Y"] = df.loc[ df["system"] == "ADS", "ADS_life" ] df.loc[df["system"] == "GDS", "Y"] = df.loc[ df["system"] == "GDS", "GDS_life" ] return df
[docs] def dbsl(Y, b, bonus, r): r""" Makes the calculation for the declining balance with a switch to straight line (DBSL) method of depreciation. .. math:: z = \frac{\beta}{\beta+r}\left[1-e^{-(\beta+r)Y^{*}}\right]+ \frac{e^{-\beta Y^{*}}}{(Y-Y^{*})r} \left[e^{-rY^{*}}-e^{-rY}\right] Args: Y (array_like): asset life in years b (array_like): scale of declining balance (e.g., b=2 means double declining balance) bonus (array_like): rate of bonus depreciation r (scalar): discount rate Returns: z (array_like): net present value of depreciation deductions for $1 of investment """ beta = b / Y Y_star = Y * (1 - (1 / b)) z = bonus + ( (1 - bonus) * ( ((beta / (beta + r)) * (1 - np.exp(-1 * (beta + r) * Y_star))) + ( (np.exp(-1 * beta * Y_star) / ((Y - Y_star) * r)) * (np.exp(-1 * r * Y_star) - np.exp(-1 * r * Y)) ) ) ) return z
[docs] def sl(Y, bonus, r): r""" Makes the calculation for straight line (SL) method of depreciation. .. math:: z = \frac{1 - e^{-rY}}{Yr} Args: Y (array_like): asset life in years bonus (array_like): rate of bonus depreciation r (scalar): discount rate Returns: z (array_like): net present value of depreciation deductions for $1 of investment """ z = bonus + ((1 - bonus) * ((1 - np.exp(-1 * r * Y)) / (r * Y))) return z
[docs] def econ(delta, bonus, r, pi): r""" Makes the calculation for the NPV of depreciation deductions using economic depreciation rates. .. math:: z = \frac{\delta}{(\delta + r - \pi)} Args: delta (array_like): rate of economic depreciation bonus (array_like): rate of bonus depreciation r (scalar): discount rate pi (scalar): inflation rate Returns: z (array_like): net present value of depreciation deductions for $1 of investment """ z = bonus + ((1 - bonus) * (delta / (delta + r - pi))) return z
[docs] def npv_tax_depr(df, r, pi, land_expensing): """ Depending on the method of depreciation, makes calls to either the straight line or declining balance calculations. Args: df (Pandas DataFrame): assets by type and tax treatment r (scalar): discount rate pi (scalar): inflation rate land_expensing (scalar): rate of expensing on land Returns: z (Pandas series): NPV of depreciation deductions for all asset types and tax treatments """ idx = (df["method"] == "DB 200%") | (df["method"] == "DB 150%") df.loc[idx, "z"] = dbsl( df.loc[idx, "Y"], df.loc[idx, "b"], df.loc[idx, "bonus"], r ) idx = df["method"] == "SL" df.loc[idx, "z"] = sl(df.loc[idx, "Y"], df.loc[idx, "bonus"], r) idx = df["method"] == "Economic" df.loc[idx, "z"] = econ(df.loc[idx, "delta"], df.loc[idx, "bonus"], r, pi) idx = df["method"] == "Expensing" df.loc[idx, "z"] = 1.0 idx = df["asset_name"] == "Land" df.loc[idx, "z"] = np.squeeze(land_expensing) idx = df["asset_name"] == "Inventories" df.loc[idx, "z"] = 0.0 # not sure why I have to do this with changes z = df["z"] return z
[docs] def eq_coc(delta, z, w, u, inv_tax_credit, pi, r): r""" Compute the cost of capital .. math:: \rho = \frac{(r-\pi+\delta)}{1-u}(1-uz)+w-\delta Args: delta (array_like): rate of economic depreciation z (array_like): net present value of depreciation deductions for $1 of investment w (scalar): property tax rate u (scalar): statutory marginal tax rate for the first layer of income taxes inv_tax_credit (scalar): investment tax credit rate pi (scalar): inflation rate r (scalar): discount rate Returns: rho (array_like): the cost of capital """ rho = ( ((r - pi + delta) / (1 - u)) * (1 - inv_tax_credit - u * z) + w - delta ) return rho
[docs] def eq_coc_inventory(u, phi, Y_v, pi, r): r""" Compute the cost of capital for inventories .. math:: \rho = \phi \rho_{FIFO} + (1-\phi)\rho_{LIFO} Args: u (scalar): statutory marginal tax rate for the first layer of income taxes phi (scalar): fraction of inventories that use FIFO accounting Y_v (scalar): average number of year inventories are held pi (scalar): inflation rate r (scalar): discount rate Returns: rho (scalar): cost of capital for inventories """ rho_FIFO = ((1 / Y_v) * np.log((np.exp(r * Y_v) - u) / (1 - u))) - pi rho_LIFO = (1 / Y_v) * np.log((np.exp((r - pi) * Y_v) - u) / (1 - u)) rho = phi * rho_FIFO + (1 - phi) * rho_LIFO return rho
[docs] def eq_ucc(rho, delta): r""" Compute the user cost of capital .. math:: ucc = \rho + \delta Args: rho (array_like): cost of capital delta (array_like): rate of economic depreciation Returns: ucc (array_like): the user cost of capital """ ucc = rho + delta return ucc
[docs] def eq_metr(rho, r_prime, pi): r""" Compute the marginal effective tax rate (METR) .. math:: metr = \frac{\rho - (r^{'}-\pi)}{\rho} Args: rho (array_like): cost of capital r_prime (array_like): after-tax rate of return pi (scalar): inflation rate Returns: metr (array_like): METR """ metr = (rho - (r_prime - pi)) / rho return metr
[docs] def eq_mettr(rho, s): r""" Compute the marginal effective total tax rate (METTR) .. math:: mettr = \frac{\rho - s}{\rho} Args: rho (array_like): cost of capital s (array_like): after-tax return on savings Returns: mettr (array_like): METTR """ mettr = (rho - s) / rho return mettr
[docs] def eq_tax_wedge(rho, s): r""" Compute the tax wedge .. math:: wedge = \rho - s Args: rho (array_like): cost of capital s (array_like): after-tax return on savings Returns: wedge (array_like): tax wedge """ wedge = rho - s return wedge
[docs] def eq_eatr(rho, metr, p, u): r""" Compute the effective average tax rate (EATR). .. math:: eatr = \left(\frac{p - rho}{p}\right)u + \left(\frac{\rho}{p}\right)metr Args: rho (array_like): cost of capital metr (array_like): marginal effective tax rate p (scalar): profit rate u (scalar): statutory marginal tax rate for the first layer of income taxes Returns: eatr (array_like): EATR """ eatr = ((p - rho) / p) * u + (rho / p) * metr return eatr