Uncategorized

implied volatility – Python Quantlib for the calibration of interest rate caps


I am trying to calibrate the G2++ model to interest rate caps using the Quantlib library in Python.
I have the problem that my optimization always stops with the starting values. So probably either my setup for the cap helpers or the optimization itself is wrong. Unfortunately, I can’t get any further here and would be delighted to have some help.

I hope that someone has experience with Quantlib and can help. Attached is my code with some sample data.

Thank you very much!

import QuantLib as ql

valuation_date = ql.Date(29, 1, 2024)
ql.Settings.instance().evaluationDate = valuation_date

swap_maturities = [ql.Period(6, ql.Months), ql.Period(1, ql.Years), ql.Period(2, ql.Years),
ql.Period(3, ql.Years), ql.Period(4, ql.Years), ql.Period(5, ql.Years),
ql.Period(6, ql.Years), ql.Period(7, ql.Years), ql.Period(8, ql.Years),
ql.Period(9, ql.Years), ql.Period(10, ql.Years), ql.Period(12, ql.Years),
ql.Period(15, ql.Years), ql.Period(20, ql.Years), ql.Period(25, ql.Years),
ql.Period(30, ql.Years)]
dates = [valuation_date + maturity for maturity in swap_maturities]

yields = [0.03873, 0.03524, 0.02955, 0.02745, 0.02662, 0.02631, 0.02625, 0.02631,
0.02644, 0.02661, 0.02680, 0.02720, 0.02749, 0.02696, 0.02598, 0.02499]

day_count = ql.Actual360()
calendar = ql.Germany()
interpolation = ql.Linear()
compounding = ql.Compounded
compounding_frequency = ql.Semiannual

term_structure = ql.ZeroCurve(dates, yields, day_count, calendar,
interpolation, compounding, compounding_frequency)
ts_handle = ql.YieldTermStructureHandle(term_structure)

market_vols = {
1: 0.9081,
2: 1.0488,
3: 1.0533,
4: 1.0391,
5: 1.0232,
6: 1.008,
7: 0.9926,
8: 0.978,
9: 0.9633,
10: 0.9498,
12: 0.9246,
15: 0.8901,
20: 0.8439,
25: 0.8091,
}

model = ql.G2(ts_handle)

#euribor_index = ql.Euribor6M(ts_handle)
cap_helpers = []
start_date = valuation_date + ql.Period(6,ql.Months)

for maturity, vol in market_vols.items():
period = ql.Period(maturity, ql.Years)
end_date = calendar.advance(valuation_date, period)
schedule = ql.Schedule(start_date, end_date, ql.Period(ql.Annual), calendar,
ql.Unadjusted, ql.Unadjusted, ql.DateGeneration.Forward, False)

fwd_rate = term_structure.forwardRate(start_date, end_date, day_count, compounding, compounding_frequency).rate()
strike_quote = ql.SimpleQuote(fwd_rate)

vol_quote = ql.QuoteHandle(ql.SimpleQuote(vol))

helper = ql.CapHelper(period, vol_quote, strike_quote, ql.Annual, day_count, False, ts_handle)
helper.setPricingEngine(ql.BlackCapFloorEngine(ts_handle, vol_quote))
cap_helpers.append(helper)

optimization_method = ql.LevenbergMarquardt(1e-8, 1e-8, 1e-8)

end_criteria = ql.EndCriteria(1000, 500, 1e-8, 1e-8, 1e-8)

model.calibrate(cap_helpers, optimization_method, end_criteria)

a, sigma, b, eta, rho = model.params()
print(f”G2++ Model parameters: a = {a}, sigma = {sigma}, b = {b}, eta = {eta}, rho = {rho}”)



Source link

Leave a Reply

Your email address will not be published. Required fields are marked *