A SABR smile
The 1Y into 10Y swaption smile of QuantLib's swaption cube tests' market data: an at-the-money vol and the market's
spreads to it at four strikes about the forward, fitted by SABR with β fixed. The fit's values match QuantLib's on the
same data. The sample, SabrSmile.cs, carries QuantLib's notice.
The smile
A flat 5% curve on 15 October 2026, the ten-year Euribor swap rate a year forward, and its quotes: 14.70% at the money, and the spreads to it at −200, −50, +50 and +200 bp:
// A flat 5% curve, and the ten-year swap the option is on.
YieldTermStructure curve = new FlatForward(today, 0.05, new Actual365Fixed());
var swapIndex = new EuriborSwapIsdaFixA(new Period(10, TimeUnit.Years), curve);
Date optionDate = new TARGET().Advance(today, new Period(1, TimeUnit.Years), BusinessDayConvention.ModifiedFollowing);
double expiry = new Actual365Fixed().YearFraction(today, optionDate);
double forward = swapIndex.Fixing(optionDate, context);
// The market's quotes: 14.70% at the money, and the spreads to it at four strikes about the forward.
double[] strikeSpreads = [-0.020, -0.005, 0.0, 0.005, 0.020];
double[] volSpreads = [0.0729, 0.0086, 0.0, -0.0024, 0.0098];
double[] strikes = [.. strikeSpreads.Select(s => forward + s)];
double[] quotes = [.. volSpreads.Select(s => 0.1470 + s)];
The fit
SABRInterpolation fits α, ν and ρ with β fixed at 0.5, minimizing the vols' errors weighted by the strikes' Black
vegas, from SABR's default guesses:
// β fixed at 0.5; α, ν and ρ fitted from SABR's default guesses, the errors weighted by the strikes' vegas.
var sabr = new SABRInterpolation(strikes, quotes, expiry, forward, alpha: null, beta: 0.5, nu: null, rho: null,
alphaIsFixed: false, betaIsFixed: true, nuIsFixed: false, rhoIsFixed: false);
| SABR | Value |
|---|---|
| Forward | 5.1316% |
| α | 0.032567 |
| β (fixed) | 0.5 |
| ν | 0.522132 |
| ρ | -0.084029 |
| Root-mean-square error | 0.0491% |
| Maximum error | 0.1597% |
The smile section
The fitted parameters as a SabrSmileSection, the smile an engine reads at any strike:
// The fitted parameters as a smile section, the smile an engine or a cube reads at any strike.
var section = new SabrSmileSection(expiry, forward, [sabr.Alpha, sabr.Beta, sabr.Nu, sabr.Rho]);
The smile on a 50 bp grid, beside the quotes:
| Strike against the forward | Strike | Quote | SABR |
|---|---|---|---|
| -200 bp | 3.1316% | 21.99% | 21.8303% |
| -150 bp | 3.6316% | 19.2484% | |
| -100 bp | 4.1316% | 17.1568% | |
| -50 bp | 4.6316% | 15.56% | 15.6055% |
| 0 bp | 5.1316% | 14.70% | 14.6913% |
| +50 bp | 5.6316% | 14.46% | 14.4276% |
| +100 bp | 6.1316% | 14.6552% | |
| +150 bp | 6.6316% | 15.1568% | |
| +200 bp | 7.1316% | 15.68% | 15.7784% |
Five quotes and three free parameters leave a residual: the fit misses the wing quotes by up to 0.16 vol points, and gives the smile between them.