2

I want to retrieve a Black Vol from a swaption price calculated by the Quantlib BachelierSwaptionEngine. It looks like this can be done in Quantlib via an optimizer (such as the newton method) or direct via the impliedVolatility method. I'm unable to use the Quantlib optimizer or the impliedVolatility method within Quantlib Python.

The code below shows how I calculate the swaption price in Quantlib. From there I need to retrieve a Black vol based on the swaption price calculated in the code

import Quantlib as ql
from scipy import optimize

calc_date = ql.Date(29,3,2019)

rate = ql.SimpleQuote(0.01)
rate_handle = ql.QuoteHandle(rate)
dc = ql.Actual365Fixed()
spot_curve = ql.FlatForward(calc_date, rate_handle, dc)

start = 10
length = 10
start_date =  ql.TARGET().advance(calc_date, start, ql.Years)
maturity_date = start_date + ql.Period(length, ql.Years)
fixed_schedule = ql.Schedule(start_date, maturity_date,
                      ql.Period(1, ql.Years), ql.TARGET(), ql.Unadjusted, 
                      ql.Unadjusted,ql.DateGeneration.Forward, False)
floating_schedule = ql.Schedule(start_date, maturity_date,
                        ql.Period(6, ql.Months), ql.TARGET(), 
                        ql.ModifiedFollowing, ql.ModifiedFollowing,
                        ql.DateGeneration.Forward, True)

index6m = ql.Euribor6M(ql.YieldTermStructureHandle(spot_curve))

rate = 1.45 / 100
swap = ql.VanillaSwap(ql.VanillaSwap.Receiver, 10000000,
               fixed_schedule, rate, ql.Thirty360(ql.Thirty360.BondBasis),
               floating_schedule, index6m, 0.0, index6m.dayCounter())

swap.setPricingEngine(ql.DiscountingSwapEngine( 
ql.YieldTermStructureHandle(spot_curve)))


swaption_normal_model = ql.Swaption(swap, 
  ql.EuropeanExercise(swap.startDate()))


normal_vol = ql.SimpleQuote(0.005266)
swaption_normal_model.setPricingEngine
(ql.BachelierSwaptionEngine(ql.YieldTermStructureHandle(spot_curve), 
ql.QuoteHandle(normal_vol)))
swaption_normal_model_value = swaption_normal_model.NPV()
Oamriotn
  • 257
  • 1
  • 3
  • 8

2 Answers2

2

I used the newton minimize function from scipy the retrieve the implied black vol, see below:

swaption_black_model = ql.Swaption(swap, ql.EuropeanExercise(swap.startDate()))
initial_vol_guess = 0.60


def find_implied_black(vol):
    black_vol = ql.SimpleQuote(vol)
    swaption_black_model.setPricingEngine(
    ql.BlackSwaptionEngine(ql.YieldTermStructureHandle(spot_curve), 
    ql.QuoteHandle(black_vol)))
    swaption_black_model_value = swaption_black_model.NPV()
    diff = swaption_normal_model_value - swaption_black_model_value

    return diff


implied_black_vol = optimize.newton(find_implied_black, initial_vol_guess)
implied_black_vol = ql.SimpleQuote(implied_black_vol)
swaption_black_model.setPricingEngine(
ql.BlackSwaptionEngine(ql.YieldTermStructureHandle(spot_curve), 
ql.QuoteHandle(implied_black_vol)))
swaption_black_model_value = swaption_black_model.NPV()

print('Normal swaption price is {}'.format(swaption_normal_model_value))
print('Black swaption price is {}'.format(swaption_black_model_value))
Oamriotn
  • 257
  • 1
  • 3
  • 8
0

QuantLib has an internal function to determine impliedVolatility and you can solve for either ShiftedLognormal vol or Normal vol.

Here is an example:

yts = ql.YieldTermStructureHandle(spot_curve)
blackVol = swaption_normal_model.impliedVolatility(swaption_normal_model_value, yts, 0.5)

blackEngine = ql.BlackSwaptionEngine(yts, ql.QuoteHandle(ql.SimpleQuote(blackVol)))
swaption_normal_model.setPricingEngine(blackEngine)

print(swaption_normal_model.NPV(), swaption_normal_model_value)

Also, naming your swaption object as swaption_normal_model is not really a good ideia since you can set different pricing engines

David Duarte
  • 644
  • 4
  • 11