You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I had a few miscellaneous questions with examples regarding some of the output I am seeing.
Does sending in both a dividend schedule and dividend yield double count the dividend? Should we really only be sending one or the other?
In the below example, it seems that the implied conversion option value calculated by subtracting the value of the straight bond (or bond floor) from the convertible bond price is much less than the directly computed value of the equity call option using the VanillaOption pricer. I was able to tie out the bond floor by pricing just the bond portion using CallableFixedRateBond, so it seems that there is something with how the call option on the equity is being priced that is different. If I either leave the dividend schedule empty or dividend yield at zero then the option price is much closer. Although there is still a gap in the final option values, it seems like discounting using the dividend yield and subtracting out dividend may be double dinging in the equity option valuation, so wanted to make sure I was not missing something else.
Does the binomial convertible engine only use the flat rate that corresponds to the maturity of the bond when discounting? If so, is there another engine that will use the full term structure when discounting?
From what I've seen on the C++ side, it seems that regardless of the zero curve's term structure, the pricing engine will take the rate corresponding to the maturity of the bond from the yield handle and use it to create a flat risk free curve handle for discounting. Continuing with the above example, this can be seen when looking at the key rate durations. Most of the sensitivity when breaking out KRDs is close to maturity (6-7 years out) although the effective duration of the bond and sum of the partials are much lower. It seems that although we shock at each point on the yield curve, it is really being treated as a parallel shift since the only rate used is the one corresponding to maturity and that is why the shock falls into the farther bucket. Please let me know if this is accurate and/or if there are any suggestions to get around this.
####Calculate OAD
shocks = [ql.SimpleQuote(0.0) for t in range(len(maturities))]
shocked_curve = ql.SpreadedLinearZeroInterpolatedTermStructure(yield_ts_handle,
[ql.QuoteHandle(q) for q in shocks],
maturities)
shocked_curve.enableExtrapolation()
shocked_curve_handle = ql.YieldTermStructureHandle(shocked_curve)
yield_shock = 0.01
#prce before yield curve shock
price = convert_price
#apply positive yield shock and reprice cvt
for i in range(len(maturities)):
shocks[i].setValue(yield_shock)
bsm_process = ql.BlackScholesMertonProcess(spot_price_handle,
dividend_ts_handle,
shocked_curve_handle,
volatility_ts_handle)
engine = ql.BinomialConvertibleEngine(bsm_process, "crr", time_steps)
convertible_bond.setPricingEngine(engine)
price_up = convertible_bond.cleanPrice()
#apply negative yield shock and reprice cvt
for i in range(len(maturities)):
shocks[i].setValue(-yield_shock)
bsm_process = ql.BlackScholesMertonProcess(spot_price_handle,
dividend_ts_handle,
shocked_curve_handle,
volatility_ts_handle)
engine = ql.BinomialConvertibleEngine(bsm_process, "crr", time_steps)
convertible_bond.setPricingEngine(engine)
price_down = convertible_bond.cleanPrice()
#clear shocks
for i in range(len(maturities)):
shocks[i].setValue(0.0)
bsm_process = ql.BlackScholesMertonProcess(spot_price_handle,
dividend_ts_handle,
shocked_curve_handle,
volatility_ts_handle)
#reset engine
engine = ql.BinomialConvertibleEngine(bsm_process, "crr", time_steps)
convertible_bond.setPricingEngine(engine)
#calculate duration
oad = (price_down - price_up)/(2 * price * yield_shock)
print("Convertible bond OAD is: %s" % (oad))
#Now look at partials
krd_list = []
price = convert_price
#apply positive yield shock and reprice at each tenor
for i in range(len(maturities)):
shocks[i].setValue(yield_shock)
bsm_process = ql.BlackScholesMertonProcess(spot_price_handle,
dividend_ts_handle,
shocked_curve_handle,
volatility_ts_handle)
engine = ql.BinomialConvertibleEngine(bsm_process, "crr", time_steps)
convertible_bond.setPricingEngine(engine)
price_up = convertible_bond.cleanPrice()
shocks[i].setValue(-yield_shock)
bsm_process = ql.BlackScholesMertonProcess(spot_price_handle,
dividend_ts_handle,
shocked_curve_handle,
volatility_ts_handle)
engine = ql.BinomialConvertibleEngine(bsm_process, "crr", time_steps)
convertible_bond.setPricingEngine(engine)
price_down = convertible_bond.cleanPrice()
shocks[i].setValue(0.0)
bsm_process = ql.BlackScholesMertonProcess(spot_price_handle,
dividend_ts_handle,
shocked_curve_handle,
volatility_ts_handle)
engine = ql.BinomialConvertibleEngine(bsm_process, "crr", time_steps)
convertible_bond.setPricingEngine(engine)
#calculate duration
krd = (price_down - price_up)/(2 * price * yield_shock)
krd_list.append(krd)
print(f"Convertible bond KRD at {maturities[i]} is: {krd}")
I appreciate any suggestions or thoughts with any of the above.
The text was updated successfully, but these errors were encountered:
I am working with the ConvertibleFixedCouponBond object (v1.23) and roughly following the below outlined steps:
http://gouthamanbalaraman.com/blog/value-convertible-bond-quantlib-python.html
I had a few miscellaneous questions with examples regarding some of the output I am seeing.
In the below example, it seems that the implied conversion option value calculated by subtracting the value of the straight bond (or bond floor) from the convertible bond price is much less than the directly computed value of the equity call option using the VanillaOption pricer. I was able to tie out the bond floor by pricing just the bond portion using CallableFixedRateBond, so it seems that there is something with how the call option on the equity is being priced that is different. If I either leave the dividend schedule empty or dividend yield at zero then the option price is much closer. Although there is still a gap in the final option values, it seems like discounting using the dividend yield and subtracting out dividend may be double dinging in the equity option valuation, so wanted to make sure I was not missing something else.
From what I've seen on the C++ side, it seems that regardless of the zero curve's term structure, the pricing engine will take the rate corresponding to the maturity of the bond from the yield handle and use it to create a flat risk free curve handle for discounting. Continuing with the above example, this can be seen when looking at the key rate durations. Most of the sensitivity when breaking out KRDs is close to maturity (6-7 years out) although the effective duration of the bond and sum of the partials are much lower. It seems that although we shock at each point on the yield curve, it is really being treated as a parallel shift since the only rate used is the one corresponding to maturity and that is why the shock falls into the farther bucket. Please let me know if this is accurate and/or if there are any suggestions to get around this.
I appreciate any suggestions or thoughts with any of the above.
The text was updated successfully, but these errors were encountered: