I am using Quantlib to obtain the option value embedded in a convertible bond. I create an american option as follows:
strike_price = redemption / conversion_ratio
option_type = ql.Option.Call
payoff = ql.PlainVanillaPayoff(option_type, strike_price)
settlement = calculation_date
am_exercise = ql.AmericanExercise(settlement, maturity_date)
american_option = ql.VanillaOption(payoff, am_exercise)
flat_vol_ts = ql.BlackVolTermStructureHandle(ql.BlackConstantVol(calculation_date, calendar, volatility, day_count))
bsm_process = ql.BlackScholesMertonProcess(spot_price_handle,
dividend_ts_handle,
yield_ts_handle,
volatility_ts_handle)
binomial_engine = ql.BinomialVanillaEngine(bsm_process, "crr", time_steps)
american_option.setPricingEngine(binomial_engine)
option_position1 = round(american_option.NPV(),4)
delta_position1 = round(american_option.delta(),4)
gamma_position1 = round(american_option.gamma(),4)
I want to obtain the exercise probability as this is a measure of how equity or debt like a convertible bond is. (e.g. >60% exercise probability is labelled as equity-like). Is there function within quantlib that will provide me the exercise probability (exercise probability is not the same as the delta)?
Edit 1: Approach of obtaining the equity or debtness of the convertible bond:
Edit 2: I have tried to incorporate a dual delta in code. I calculate the dual delta by retrieving two seperate option values with a slightly different strike price. However, first results show a huge difference between the delta and the dual delta, delta being 2-3x as high, so I must be doing something wrong. Does my code as it currently is makes sense to manually calculate the dual delta?
strike_price_up = strike_price + 0.0001
strike_price_down = strike_price - 0.0001
payoff_up = ql.PlainVanillaPayoff(option_type, strike_price_up)
payoff_down = ql.PlainVanillaPayoff(option_type, strike_price_down)
american_option_up = ql.VanillaOption(payoff_up, am_exercise)
flat_vol_ts = ql.BlackVolTermStructureHandle(ql.BlackConstantVol(calculation_date, calendar, volatility, day_count))
bsm_process = ql.BlackScholesMertonProcess(spot_price_handle,
dividend_ts_handle,
yield_ts_handle,
flat_vol_ts)
binomial_engine = ql.BinomialVanillaEngine(bsm_process, "crr", time_steps)
american_option_up.setPricingEngine(binomial_engine)
dd_u = american_option_up.NPV()
american_option_down = ql.VanillaOption(payoff_down, am_exercise)
flat_vol_ts = ql.BlackVolTermStructureHandle(ql.BlackConstantVol(calculation_date, calendar, volatility, day_count))
bsm_process = ql.BlackScholesMertonProcess(spot_price_handle,
dividend_ts_handle,
yield_ts_handle,
flat_vol_ts)
binomial_engine = ql.BinomialVanillaEngine(bsm_process, "crr", time_steps)
american_option_down.setPricingEngine(binomial_engine)
dd_d = american_option_down.NPV()
dualdelta = (dd_d - dd_u)/(2*0.0001)
dualdelta_position1 = round(dualdelta,4)
Edit 3: I believe the correct formula should be: dualdelta = (dd_u - dd_d)/(2*0.0001)
. This returns a negative dual delta..?