Main Content

Calibrate SABR Model Using Normal (Bachelier) Volatilities with Analytic Pricer

This example shows how to use two different methods to calibrate the SABR stochastic volatility model from market implied Normal (Bachelier) volatilities with negative strikes. Both approaches use the SABR analytic pricer. When the Beta parameter of the SABR model is set to zero, the model is a Normal SABR model, which allows computing the implied Normal volatilities for negative strikes.

Load Market Implied Normal (Bachelier) Volatility Data

Set up hypothetical market implied Normal volatilities for European swaptions over a range of strikes before calibration. The swaptions expire in one year from the Settle date and have two-year swaps as the underlying instrument. The rates are expressed in decimals. The market implied Normal volatilities are converted from basis points to decimals. (Changing the units affects the numerical value and interpretation of the Alpha parameter in the SABR model.)

% Load the market implied Normal volatility data for swaptions expiring in one year.
Settle = datetime(2020, 4, 24);
ExerciseDate = datetime(2021, 4, 24);
Basis = 1;
ZeroDates = Settle + [calmonths([3 6 9]) calyears([1 2 3 4 5 ...
    6 7 10 15 20])]';
ZeroRates = [-.54 -.57 -.60 -.62 -.67 -.67 -.65 -.61 ...
    -.56 -.51 -.36 -.19 -.10]'/100;
Compounding = 1;
ZeroCurve = ratecurve("zero",Settle,ZeroDates,ZeroRates,'Compounding',Compounding);

ATMStrike = -0.70/100;
MarketStrikes = ATMStrike + ((-0.5:0.25:1.5)')./100;
MarketVolatilities = [29.89 25.47 23.21 26.17 29.59 33.12 37.81 41.88 46.24]'/10000;

% At the time of Settle, define the underlying forward rate and the at-the-money volatility.
CurrentForwardValue = MarketStrikes(3)
CurrentForwardValue = 
-0.0070
ATMVolatility = MarketVolatilities(3)
ATMVolatility = 
0.0023

Method 1: Calibrate Alpha, Rho, and Nu Directly

You can calibrate the Alpha, Rho, and Nu parameters directly. Set the value of the Beta parameter to zero in order to allow negative rates in the SABR model (Normal SABR). After you fix the value of β (Beta), you fit the parameters α (Alpha), ρ (Rho), and ν (Nu) directly. The Optimization Toolbox™ function lsqnonlin generates the parameter values that minimize the squared error between the market volatilities and the volatilities computed by the SABR analytic pricer.

% Define the predetermined Beta
Beta1 = 0; % Setting Beta to zero allows negative rates for Normal volatilities

% Calibrate Alpha, Rho, and Nu
objFun = @(X) MarketVolatilities - ...
    volatilities(finpricer("Analytic", 'Model', ...
    finmodel("SABR", 'Alpha', X(1), 'Beta', Beta1, 'Rho', X(2), ...
    'Nu', X(3), 'VolatilityType', 'Normal'), 'DiscountCurve', ZeroCurve), ...
    ExerciseDate, CurrentForwardValue, MarketStrikes);

% If necessary, adjust the tolerances and stopping criteria for lsqnonlin 
X = lsqnonlin(objFun, [ATMVolatility 0 0.5], [0 -1 0], [Inf 1 Inf]);
Local minimum found.

Optimization completed because the size of the gradient is less than
the value of the optimality tolerance.
Alpha1 = X(1);
Rho1 = X(2);
Nu1 = X(3);

Method 2: Calibrate Rho and Nu by Implying Alpha from At-The-Money Volatility

Another method is to use an alternative calibration method. As in the first method, you set the value of β (Beta) to zero to allow negative rates. However, after fixing the value of β (Beta), you fit the parameters ρ (Rho) and ν (Nu) directly while α (Alpha) is implied from the market at-the-money volatility. Models calibrated using this method produce at-the-money volatilities that are equal to market quotes. This approach can be useful when at-the-money volatilities are quoted most frequently and are important to match. To imply α (Alpha) from market at-the-money Normal volatility (σNormal,ATM), solve the following cubic polynomial for α (Alpha), and select the smallest positive real root. This is similar to the approach used for implying α (Alpha) from market at-the-money Black volatility [2]. However, note that the following expression that is used for Normal volatilities is different from the expression that is used for Black volatilities.

β(β-2)T24F(2-2β)α3+ρβνT4F(1-β)α2+(1+2-3ρ224ν2T)α-σNormal,ATMF-β=0

% Define the predetermined Beta
Beta2 = 0; % Setting Beta to zero allows negative rates for Normal volatilities

% Year fraction from Settle date to option maturity
T = yearfrac(Settle, ExerciseDate, Basis);

% This function solves the SABR at-the-money volatility equation as a
% polynomial of Alpha
alpharootsNormal = @(Rho,Nu) roots([...
    Beta2.*(Beta2 - 2)*T/24/CurrentForwardValue^(2 - 2*Beta2) ...
    Rho*Beta2*Nu*T/4/CurrentForwardValue^(1 - Beta2) ...
    (1 + (2 - 3*Rho^2)*Nu^2*T/24) ...
    -ATMVolatility*CurrentForwardValue^(-Beta2)]);

% This function converts at-the-money volatility into Alpha by picking the
% smallest positive real root 
atmNormalVol2SabrAlpha = @(Rho,Nu) min(real(arrayfun(@(x) ...
    x*(x>0) + realmax*(x<0 || abs(imag(x))>1e-6), alpharootsNormal(Rho,Nu))));

% Calibrate Rho and Nu (while converting at-the-money volatility into Alpha
% using atmNormalVol2SabrAlpha)
objFun = @(X) MarketVolatilities - ...
    volatilities(finpricer("Analytic", 'Model', ...
    finmodel("SABR", 'Alpha', atmNormalVol2SabrAlpha(X(1), X(2)), ...
    'Beta', Beta2, 'Rho', X(1), 'Nu', X(2), 'VolatilityType', 'Normal'), ...
    'DiscountCurve', ZeroCurve), ...
    ExerciseDate, CurrentForwardValue, MarketStrikes);

% If necessary, adjust the tolerances and stopping criteria for lsqnonlin 
X = lsqnonlin(objFun, [0 0.5], [-1 0], [1 Inf]);
Local minimum found.

Optimization completed because the size of the gradient is less than
the value of the optimality tolerance.
Rho2 = X(1);
Nu2 = X(2);

% Obtain final Alpha from at-the-money volatility using calibrated parameters
Alpha2 = atmNormalVol2SabrAlpha(Rho2, Nu2);

% Display calibrated parameters
C = {Alpha1 Beta1 Rho1 Nu1;Alpha2 Beta2 Rho2 Nu2};
format;
CalibratedPrameters = cell2table(C,...
    'VariableNames',{'Alpha' 'Beta' 'Rho' 'Nu'},...
    'RowNames',{'Method 1';'Method 2'})
CalibratedPrameters=2×4 table
                  Alpha      Beta       Rho         Nu   
                _________    ____    _________    _______

    Method 1    0.0023279     0      -0.010078    0.63538
    Method 2    0.0022389     0      -0.019029    0.66368

Use the Calibrated Models

Use the calibrated models to compute new volatilities at any strike value, including negative strikes.

Compute volatilities for models calibrated using Method 1 and Method 2, then plot the results. The model calibrated using Method 2 reproduces the market at-the-money volatility (marked with a circle) exactly.

PlottingStrikes = (min(MarketStrikes)-0.0025:0.0001:max(MarketStrikes)+0.0025)';

% Compute volatilities for model calibrated by Method 1
SABR_Model_Method_1 = finmodel("SABR", ...
    'Alpha', Alpha1, 'Beta', Beta1, 'Rho', Rho1, 'Nu', Nu1, ...
    'VolatilityType', 'Normal');

ComputedVols1 = volatilities(finpricer("Analytic", ...
    'Model', SABR_Model_Method_1, 'DiscountCurve', ZeroCurve), ...
    ExerciseDate, CurrentForwardValue, PlottingStrikes);

% Compute volatilities for model calibrated by Method 2
SABR_Model_Method_2 = finmodel("SABR", ...
    'Alpha', Alpha2, 'Beta', Beta2, 'Rho', Rho2, 'Nu', Nu2, ...
    'VolatilityType', 'Normal');

ComputedVols2 = volatilities(finpricer("Analytic", ...
    'Model', SABR_Model_Method_2, 'DiscountCurve', ZeroCurve), ...
    ExerciseDate, CurrentForwardValue, PlottingStrikes);


figure;
plot(MarketStrikes,MarketVolatilities*10000,'xk',...
    PlottingStrikes,ComputedVols1*10000,'b', ...  
    PlottingStrikes,ComputedVols2*10000,'r', ...
    CurrentForwardValue,ATMVolatility*10000,'ok',...
    'MarkerSize',10);

h = gca;
line([0,0],[min(h.YLim),max(h.YLim)],'LineStyle','--');

xlabel('Strike', 'FontWeight', 'bold');
ylabel('Implied Normal Volatility (bps)', 'FontWeight', 'bold');
legend('Market Volatilities', 'Normal SABR Model (Method 1)', ...
    'Normal SABR Model (Method 2)', 'At-the-money volatility', ...
    'Location', 'northwest');

Figure contains an axes object. The axes object with xlabel Strike, ylabel Implied Normal Volatility (bps) contains 5 objects of type line. One or more of the lines displays its values using only markers These objects represent Market Volatilities, Normal SABR Model (Method 1), Normal SABR Model (Method 2), At-the-money volatility.

References

[1] Hagan, Patrick S., Deep Kumar, Andrew S. Lesniewski, and Diana E. Woodward. "Managing Smile Risk." Wilmott Magazine, (January 2002):84-108.

[2] West, Graeme. "Calibration of the SABR Model in Illiquid Markets." Applied Mathematical Finance. 12, no. 4 (December 2005): 371–385.