Cost basis is the tax-accounting value assigned to an investment. It sets the reference point for taxable gains or losses when the investment is sold: a lower basis produces a larger gain at the same sale price, while a higher basis produces a smaller gain or a larger loss. In portfolio projections, basis is therefore separate from current value and expected return. section 8.1 section 14.1.1
Treat cost basis as a state variable for each asset. A taxable-account model can begin with both a starting value and an initial basis, alongside return, payout, capital-gains tax rate, ordinary-income tax rate, and turnover. When holdings are sold and reinvested, the model assumes the average-cost method for tax purposes, so basis must remain part of the asset record rather than being inferred from value alone. section 8.1
Tax-loss harvesting lowers basis
Suppose an ETF bought for $100,000 falls to $95,000. Selling it realizes a $5,000 loss; at a 20% tax rate, that loss can offset $1,000 of current tax. Reinvesting the $95,000 proceeds in a similar ETF preserves roughly the same exposure, but the replacement position has a $95,000 basis. If it later sells for $150,000, the realized gain is $55,000 and tax is $11,000 at 20%, versus a $50,000 gain and $10,000 tax had the original ETF been held. The benefit is deferring the $1,000 payment, not eliminating it. section 14.1.1
The value of a lower basis depends on timing. Realizing a loss can free cash from a current tax bill, while the reduced basis creates a future tax liability. With the future tax rate held constant, the economic benefit of the deferral depends on how long the later payment is postponed and the discount rate used to value that future payment. section 14.1.1
Listing 8.1 Defining the Asset() class
class Asset():
def __init__(self, avg_ret=0.08, payout_rate=0.0, tax_rate_payout=0.2, #1
tax_rate_cap_gains=0.2, tax_rate_ord_inc=0.35,
turnover_rate=0, starting_value=500000, cost_basis=500000):
self.avg_ret = avg_ret
self.payout_rate = payout_rate
self.tax_rate_payout = tax_rate_payout
self.tax_rate_cap_gains = tax_rate_cap_gains
self.tax_rate_ord_inc = tax_rate_ord_inc
self.turnover_rate = turnover_rate
self.starting_value = starting_value
self.cost_basis = cost_basis
def IRA_value(self, horizon=30):
pretax_value = self.starting_value * (1+self.avg_ret)**horizon
aftertax_value = pretax_value * (1-self.tax_rate_ord_inc)
return aftertax_value
def Taxable_value(self, horizon=30):
curr_cost_basis = self.cost_basis
curr_value = self.starting_value
for year in range(1, horizon+1):
taxes_div = self.payout_rate * curr_value * self.tax_rate_payout
taxes_cap_gain = (self.turnover_rate * curr_value
* self.tax_rate_cap_gains)
curr_cost_basis += ((self.payout_rate * curr_value) #2
+ (self.turnover_rate * curr_value)
- (taxes_div + taxes_cap_gain))
curr_value = (curr_value * (1+self.avg_ret)
- (taxes_div + taxes_cap_gain))
aftertax_value = (curr_value
- (curr_value - curr_cost_basis)
* self.tax_rate_cap_gains)
return aftertax_value
def Taxable_minus_IRA(self, horizon=30):
difference = (self.Taxable_value(horizon) - self.IRA_value(horizon)
- self.starting_value * self.tax_rate_ord_inc) #3
return difference
def Roth_value(self, horizon=30):
aftertax_value = self.starting_value * (1+self.avg_ret)**horizon
return aftertax_value
Use the Asset class as a compact implementation pattern: store cost_basis beside starting_value and tax assumptions, then compare projected IRA and taxable values. section 8.1
