|
From: Ted O. <tm...@ho...> - 2024-04-29 21:42:22
|
Hi, I was playing around with the below code to construct the swaption vol surface. I have 2 questions. Why does it work fine when I try to return the ATM vol using the swaptionVolatilityMatrix handle, but when I add the skew and use the swaptionVolatlityCube I get an error that it's trying to price a maturity for a Saturday: "Fixing date June 29th, 2024 is not valid" when I run on 4/29/24.
Secondly, for the dates that do work the vol using the same strike for both the vol matrix and vol cube are slightly different.
1M 5Y
volmatrix: 32.7
volcube: 33.39
code:
import QuantLib as ql
valDate = ql.Date.todaysDate()
swapTenors = [
'1Y', '2Y', '3Y', '4Y', '5Y',
'6Y', '7Y', '8Y', '9Y', '10Y',
'15Y', '20Y', '25Y', '30Y']
optionTenors = [
'1M', '2M', '3M', '6M', '9M', '1Y',
'18M', '2Y', '3Y', '4Y', '5Y', '7Y',
'10Y', '15Y', '20Y', '25Y', '30Y']
normal_vols = [
[8.6, 12.8, 19.5, 26.9, 32.7, 36.1, 38.7, 40.9, 42.7, 44.3, 48.8, 50.4, 50.8, 50.4],
[9.2, 13.4, 19.7, 26.4, 31.9, 35.2, 38.3, 40.2, 41.9, 43.1, 47.8, 49.9, 50.7, 50.3],
[11.2, 15.3, 21.0, 27.6, 32.7, 35.3, 38.4, 40.8, 42.6, 44.5, 48.6, 50.5, 50.9, 51.0],
[12.9, 17.1, 22.6, 28.8, 33.5, 36.0, 38.8, 41.0, 43.0, 44.6, 48.7, 50.6, 51.1, 51.0],
[14.6, 18.7, 24.6, 30.1, 34.2, 36.9, 39.3, 41.3, 43.2, 44.9, 48.9, 51.0, 51.3, 51.5],
[16.5, 20.9, 26.3, 31.3, 35.0, 37.6, 40.0, 42.0, 43.7, 45.3, 48.8, 50.9, 51.4, 51.7],
[20.9, 25.3, 30.0, 34.0, 37.0, 39.5, 41.9, 43.4, 45.0, 46.4, 49.3, 51.0, 51.3, 51.9],
[25.1, 28.9, 33.2, 36.2, 39.2, 41.2, 43.2, 44.7, 46.0, 47.3, 49.6, 51.0, 51.3, 51.6],
[34.0, 36.6, 39.2, 41.1, 43.2, 44.5, 46.1, 47.2, 48.0, 49.0, 50.3, 51.3, 51.3, 51.2],
[40.3, 41.8, 43.6, 44.9, 46.1, 47.1, 48.2, 49.2, 49.9, 50.5, 51.2, 51.3, 50.9, 50.7],
[44.0, 44.8, 46.0, 47.1, 48.4, 49.1, 49.9, 50.7, 51.4, 51.9, 51.6, 51.4, 50.6, 50.2],
[49.6, 49.7, 50.4, 51.2, 51.8, 52.2, 52.6, 52.9, 53.3, 53.8, 52.6, 51.7, 50.4, 49.6],
[53.9, 53.7, 54.0, 54.2, 54.4, 54.5, 54.5, 54.4, 54.4, 54.9, 53.1, 51.8, 50.1, 49.1],
[54.0, 53.7, 53.8, 53.7, 53.5, 53.6, 53.5, 53.3, 53.5, 53.7, 51.4, 49.8, 47.9, 46.6],
[52.8, 52.4, 52.6, 52.3, 52.2, 52.3, 52.0, 51.9, 51.8, 51.8, 49.5, 47.4, 45.4, 43.8],
[51.4, 51.2, 51.3, 51.0, 50.8, 50.7, 50.3, 49.9, 49.8, 49.7, 47.6, 45.3, 43.1, 41.4],
[49.6, 49.6, 49.7, 49.5, 49.5, 49.2, 48.6, 47.9, 47.4, 47.1, 45.1, 42.9, 40.8, 39.2]
]
swapTenors = [ql.Period(tenor) for tenor in swapTenors]
optionTenors = [ql.Period(tenor) for tenor in optionTenors]
normal_vols = [[vol / 10000 for vol in row] for row in normal_vols]
calendar = ql.TARGET()
bdc = ql.ModifiedFollowing
dayCounter = ql.ActualActual(ql.ActualActual.ISDA)
swaptionVolMatrix = ql.SwaptionVolatilityMatrix(
calendar, bdc,
optionTenors, swapTenors, ql.Matrix(normal_vols),
dayCounter, False, ql.Normal)
exp = ql.Period('1m')
tenor = ql.Period('10y')
optionTenors_skew = ['3m', '2y', '3y']
swapTenors_skew = [ '5Y', '10Y']
strikeSpreads = [ -0.01, 0.0, 0.01]
volSpreads_2 = [
[5.0, 0.0, 5.0],
[5.0, 0.0, 5.0],
[5.0, 0.0, 5.0],
[5.0, 0.0, 5.0],
[5.0, 0.0, 5.0],
[5.0, 0.0, 5.0],
]
optionTenors_skew = [ql.Period(tenor) for tenor in optionTenors_skew]
swapTenors_skew = [ql.Period(tenor) for tenor in swapTenors_skew]
volSpreads = [[ql.QuoteHandle(ql.SimpleQuote(v/10000)) for v in row] for row in volSpreads_2]
paramGuesses = [[ql.QuoteHandle(ql.SimpleQuote(x)) for x in row] for row in[(0.1,0.1,0.1,0.1)] * 6]
flatRate = .04
oisQuote = ql.QuoteHandle(ql.SimpleQuote(flatRate))
ytsOis = ql.FlatForward(valDate, oisQuote, ql.Actual360())
ytsOis.enableExtrapolation()
t0_Ois = ql.YieldTermStructureHandle(ytsOis)
swapIndexBase = ql.EuriborSwapIsdaFixA(ql.Period(1, ql.Years), t0_Ois, t0_Ois)
shortSwapIndexBase = ql.EuriborSwapIsdaFixA(ql.Period(1, ql.Years), t0_Ois, t0_Ois)
vegaWeightedSmileFit = False
volCube = ql.SwaptionVolatilityStructureHandle(ql.InterpolatedSwaptionVolatilityCube(ql.SwaptionVolatilityStructureHandle(swaptionVolMatrix),
optionTenors_skew,
swapTenors_skew,
strikeSpreads,
volSpreads,
swapIndexBase,
shortSwapIndexBase,
vegaWeightedSmileFit)
)
for x in optionTenors:
for y in swapTenors:
print(str(x) + ' ' + str(y))
print(round(swaptionVolMatrix.volatility(valDate + x, y, flatRate)*10000,2))
print(round(volCube.volatility(valDate + x, y, flatRate)*10000,2))
Sent from Outlook<http://aka.ms/weboutlook>
|