Calibrating SABR Volatility Surfaces for SOFR Futures Options
Summary
This discussion describes fitting a SABR volatility surface to options on SOFR futures. The workflow solves for implied Black or Bachelier volatilities at selected out-of-the-money strikes, calibrates SABR with QuantLib, adjusts parameters by hand, then interpolates across expiries with a variance surface. The author notes that a Black-volatility setup is ultimately transformed to normal volatility because that is how the market quotes these options.
The reported fit is acceptable at high strikes and closer to, but still imperfect at, the money. At low strikes it produces volatilities that are too high relative to exchange settlements, leading to a mismatch between cap prices and equivalent call strips. Changing between normal SABR with beta zero and lognormal SABR with beta one does not resolve the behavior. The post is a calibration question rather than a worked solution: it provides no plots in the text, market data, parameter values, or diagnosis, so it does not establish whether the issue comes from model assumptions, calibration choices, or implementation details.
Key ideas
- The workflow fits implied volatilities by expiry before interpolating the resulting surface across tenor.
- The market’s normal volatility quotes affect how Black-based SABR results are interpreted.
- The author reports excessive fitted volatility at low strikes compared with exchange settlements.
- Switching between normal and lognormal SABR parameterizations did not fix the low-strike fit in this case.
Tags
Full text
# Fitting volatility using SABR # Fitting volatility using SABR I have been working on generating a volatility surface for options on SOFR futures with the help of the SABR model. I am running into some trouble for low strikes in particular, in that I cannot seem to find an adequate fit (will explain more what I mean by adequate later). My process is essentially the below: - Solve for implied black (I also solve for bachelier) vols for out of the money options across the selection of strikes I am interested in (only taking into account the first unique price listed) - Calibrate SABR using the provided implementation in QuantLib (this gives a good fit for my purposes but not great) - Modify parameters to attempt to fit the smile in the places I care most about - Once I have a fit for each expiry I feed the vols into QuantLib's BlackVarianceSurface implementation to interpolate over tenor - Note if I use the black variation I end up in normal anyway via Hagan's transform since the market is quoted in normal vols The surface does very well for high strikes and somewhat well for ATM, however for low strikes (\$97-\$100+, 3%-0%) I am too high. When I say too high, I am specifically attempting to fit my surface to exchange settles so that when pricing caps/floors I get a good match for a cap price vs. a call strip of same tenor on the exchange. That is the idea at least. The pictures below should explain more: Initial calibration for single expiry (normal) As you can see it misses the ATM (the yellow dot), now I can fix this, however I am way too high on the low strikes, as seen below: Note that this essentially uses the normal variation of SABR (beta = 0), however the behavior doesn't seem to change when employing the lognormal variation as seen below: Initial calibration (Black, lognormal variation, Beta = 1): Adjusted: I am expecting the behavior to be more similar to the below images when using the lognormal variation, i.e. producing lower vols on the ends. I am at a loss for why this is not occurring. I don't believe it has to do with my code, and think it is likely to do with me having misunderstood some aspect of the SABR model. Any help/pointers would be greatly appreciated.
Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.