|
From: <Gre...@ca...> - 2023-09-27 14:09:28
|
Hi Aleksis,
Thank you for confirming how the strike is determined for the vol cube, I was not positive if it should be relative to ATM or absolute. However, neither seem to produce the correct vol.
[cid:image001.png@01D9F110.9DCD79C0]
When I plug my forward rate into the vol cube to represent ATM, I still get a different number. I wasn’t positive if it should be in percent or decimal, so I am showing both here. Interestingly, the vol cube is roughly double what I am expecting. Are you able to advise if I am doing something else wrong with building my cube?
Thanks again,
Greg
From: Aleksis Ali Raza <ale...@go...>
Sent: Wednesday, September 27, 2023 1:12 AM
To: Gregory Zuroff (GQQZ) <Gre...@ca...>
Cc: qua...@li...
Subject: Re: [Quantlib-users] Quantlib-Python Swaption Volatility Cube
hi, you seem to be enquiring for a 0 strike 3m10y swaption volatility. the third (rate) parameter in the volatility attribute is absolute strike level, not spread to atm.
because the swaption vol matrix doesn’t include skew data while the volcube does, these would agree on ATM vols, but the cube would return a skew adjusted vol for an off-strike enquiry (as in your case) while the swaption matrix would just give the ATM vol in both cases.
On Sep 27, 2023, at 1:49 AM, Gre...@ca...<mailto:Gre...@ca...> wrote:
Hello,
I am hoping you can help me better understand how to create a swaption vol cube using normal vols.
I successfully create the ATM vol surface
swaption_vol_matrix = ql.SwaptionVolatilityMatrix(
calendar,
bdc,
option_tenors,
swap_tenors,
ql.Matrix(normal_atm_vols),
day_counter,
False,
ql.Normal
)
I am able to confirm that the vols are as expected
swaption_vol_matrix.volatility(today + ql.Period('3m'), ql.Period('10y'), 0)
This volatility function returns the same vol for 3m10y that I supplied.
I then format all of my swaption vols into a cube such that I have one row for each expiry X swap tenor combination and one column for each strike spread [-2.25, 2.25]
swaptions.query('cusip.str.startswith("SR")').pivot(index=['expiry', 'tenor'], columns='strike', values='vol')
I convert this dataframe to numpy such that I have a 2d numpy array of size (120, 19) which is (num expiries * num tenors, num strike spreads).
These are SOFR swaptions, so I create an OvernightIndexedSwapIndex.
base_index = ql.OvernightIndexedSwapIndex('SOFR', ql.Period('1d'), 2, ql.USDCurrency(), sofr_handle)
Finally, I try to actually create the vol cube
vol_cube = ql.SwaptionVolatilityStructureHandle(
ql.InterpolatedSwaptionVolatilityCube(
ql.SwaptionVolatilityStructureHandle(swaption_vol_matrix),
option_tenors,
swap_tenors,
strikes,
otm_vol_spreads,
base_index,
base_index,
False
)
)
However, when I check the same point on the cube that I confirmed on the ATM surface, the vol is wrong.
vol_cube.volatility(today + ql.Period('3m'), ql.Period('10y'), 0)
Could you please help me understand what I am doing wrong in creating my vol cube?
Thanks,
Greg
Gregory Zuroff, CFA
Fundamental Research Group
Direct: (310) 996-9413
Email: Gre...@ca...<mailto:Gre...@ca...>
11100 Santa Monica Blvd. Los Angeles, CA 90025
<image002.png>
Your privacy and security are important to us. See our privacy policy (Canada<https://www.capitalgroup.com/individual/ca/en/about/legal.html>, Europe & Asia<https://www.capitalgroup.com/content/sites/the-capital-group/entry-page/shared/privacy.html>, United States<https://www.capitalgroup.com/individual/privacy.html>).
_______________________________________________
QuantLib-users mailing list
Qua...@li...<mailto:Qua...@li...>
https://lists.sourceforge.net/lists/listinfo/quantlib-users
Your privacy and security are important to us. See our privacy policy (Canada https://www.capitalgroup.com/individual/ca/en/about/legal.html, Europe & Asia https://www.capitalgroup.com/content/sites/the-capital-group/entry-page/shared/privacy.html, United States https://www.capitalgroup.com/individual/privacy.html).
|