I am trying to solve the following problem, but it is proving tougher than I originally thought and there are surprisingly few resources available online. I have essentially given up looking for an exact solution and will settle for a rough approximation.
Assume that an investor buys a bond that settles on April 19 2023 and matures on March 1st 2026. It pays a $0.25\%$ coupon semiannually and was purchased for $\$90.99$ per $\$100$ face value. Further, assume that interest income is taxed at $50\%$ and capital gains at $25\%$. I am looking to find the net after-tax yield to maturity of this bond.
My thinking is as follows:
- Find the after-tax coupon: $(1-0.5)0.25=0.125$
- Find the after-tax capital gain: $(1-0.25)(100-90.99)=6.7575$
- Now we use the bisection algorithm (python code below) to find a yield to maturity for a bond with $0.125\$$ coupons and a market price equal to $100-6.7575$. The idea is to proxy the after-tax cash flows of the target bond with a whole new bond with the above adjusted parameters.
Do any of you have experience with this problem? Can you offer me any feedback? Tell me why my idea is a worse approximation than I think it is? Or better yet, point me in the direction of a known method? Thank you very much.
def bisect(low_brac, high_brac, func, tolerance=0.0001):
if func(high_brac) * func(low_brac) > 0:
raise ValueError("initial bracket does not contain root")
while abs(high_brac - low_brac) > tolerance:
x_mid = (low_brac + high_brac) / 2
if func(x_mid) * func(low_brac) > 0:
low_brac = x_mid
else:
high_brac = x_mid
return (high_brac + low_brac) / 2
from price_formulas import price
mktprice = 0.9324
coupon = 0.0025*(1-0.50)
freq = 2
settle_date = 20230419
mat_date = 20260301
def obj_func(x):
return price(settle_date, mat_date, coupon, x, freq) - mktprice
print(bisect(0.001, 0.10, obj_func))
Code outputs YTM of $0.0259$ or $2.59\%$