Calibrate Hull-White tree using caps
[
calibrates the Alpha
,Sigma
,OptimOut
] = hwcalbycap(RateSpec
,MarketStrike
MarketMaturity
,MarketVolatility
)Alpha
(mean reversion) and Sigma
(volatility) using cap market data and the Hull-White model using the entire cap surface.
The Hull-White calibration functions (hwcalbycap
and hwcalbyfloor
) support three models: Black (default), Bachelier or Normal,
and Shifted Black. For more information, see the optional arguments for
Shift
and Model
.
[
estimates the Alpha
,Sigma
,OptimOut
= hwcalbycap(RateSpec
,MarketStrike
MarketMaturity
,MarketVolatility
,Strike
,Settle
,Maturity
)Alpha
(mean reversion) and Sigma
(volatility) using cap market data and the Hull-White model to price a cap at a particular
maturity/volatility using the additional optional input arguments for
Strike
, Settle
, and
Maturity
.
Strike
, Settle
, and
Maturity
arguments are specified to calibrate to a specific point
on the market volatility surface. If omitted, the calibration is performed across all the
market instruments
For an example of calibrating using the Hull-White model with
Strike
, Settle
, and Maturity
input arguments, see Calibrating Hull-White Model Using Market Data.
[
adds optional name-value pair arguments. Alpha
,Sigma
,OptimOut
] = hwcalbycap(___,Name,Value
)
This example shows how to use hwcalbycap
input
arguments for MarketStrike
, MarketMaturity
, and
MarketVolatility
to calibrate the HW model using the entire cap
volatility surface.
Cap market volatility data covering two strikes over 12 maturity dates.
Reset = 4; MarketStrike = [0.0590; 0.0790]; MarketMaturity = {'21-Mar-2008'; '21-Jun-2008'; '21-Sep-2008'; '21-Dec-2008'; '21-Mar-2009'; '21-Jun-2009'; '21-Sep-2009'; '21-Dec-2009'; '21-Mar-2010'; '21-Jun-2010'; '21-Sep-2010'; '21-Dec-2010'}; MarketMaturity = datenum(MarketMaturity); MarketVolaltility = [0.1533 0.1731 0.1727 0.1752 0.1809 0.1800 0.1805 0.1802... 0.1735 0.1757 0.1755 0.1755; 0.1526 0.1730 0.1726 0.1747 0.1808 0.1792 0.1797 0.1794... 0.1733 0.1751 0.1750 0.1745];
Plot market volatility surface.
[AllMaturities,AllStrikes] = meshgrid(MarketMaturity,MarketStrike); figure; surf(AllMaturities,AllStrikes,MarketVolaltility) datetick xlabel('Maturity') ylabel('Strike') zlabel('Volatility') title('Market Volatility Data')
Set interest rate term structure and create a RateSpec
.
Settle = '21-Jan-2008'; Compounding = 4; Basis = 0; Rates= [0.0627; 0.0657; 0.0691; 0.0717; 0.0739; 0.0755; 0.0765; 0.0772; 0.0779; 0.0783; 0.0786; 0.0789]; EndDates = {'21-Mar-2008';'21-Jun-2008';'21-Sep-2008';'21-Dec-2008';... '21-Mar-2009';'21-Jun-2009';'21-Sep-2009';'21-Dec-2009';.... '21-Mar-2010';'21-Jun-2010';'21-Sep-2010';'21-Dec-2010'}; RateSpec = intenvset('ValuationDate', Settle, 'StartDates', Settle,... 'EndDates', EndDates,'Rates', Rates, 'Compounding', Compounding,... 'Basis',Basis)
RateSpec = FinObj: 'RateSpec' Compounding: 4 Disc: [12x1 double] Rates: [12x1 double] EndTimes: [12x1 double] StartTimes: [12x1 double] EndDates: [12x1 double] StartDates: 733428 ValuationDate: 733428 Basis: 0 EndMonthRule: 1
Calibrate Hull-White model from market data.
o = optimoptions('lsqnonlin','TolFun',1e-5,'Display','off'); [Alpha, Sigma] = hwcalbycap(RateSpec, MarketStrike, MarketMaturity,... MarketVolaltility, 'Reset', Reset,'Basis', Basis, 'OptimOptions', o)
Warning: LSQNONLIN did not converge to an optimal solution. It exited with exitflag = 3. > In hwcalbycapfloor>optimizeOverCapSurface at 232 In hwcalbycapfloor at 79 In hwcalbycap at 81 Alpha = 0.0943 Sigma = 0.0146
Compare with Black prices.
BlkPrices = capbyblk(RateSpec,AllStrikes(:), Settle, AllMaturities(:),... MarketVolaltility(:),'Reset',Reset,'Basis',Basis);
BlkPrices = 0.0604 0 0.2729 0.0006 0.6498 0.0412 1.1121 0.1426 1.6426 0.3131 2.1869 0.4998 2.7056 0.6894 3.2124 0.8815 3.7311 1.0686 4.2246 1.2790 4.7027 1.4810 5.1877 1.6919
Setup Hull-White tree using calibrated parameters, alpha, and sigma.
VolDates = EndDates; VolCurve = Sigma*ones(numel(EndDates),1); AlphaDates = EndDates; AlphaCurve = Alpha*ones(numel(EndDates),1); HWVolSpec = hwvolspec(Settle, VolDates, VolCurve, AlphaDates, AlphaCurve); HWTimeSpec = hwtimespec(Settle, EndDates, Compounding); HWTree = hwtree(HWVolSpec, RateSpec, HWTimeSpec, 'Method', 'HW2000')
HWTree = FinObj: 'HWFwdTree' VolSpec: [1x1 struct] TimeSpec: [1x1 struct] RateSpec: [1x1 struct] tObs: [0 0.6593 1.6612 2.6593 3.6612 4.6593 5.6612 6.6593 7.6612 8.6593 9.6612 10.6593] dObs: [733428 733488 733580 733672 733763 733853 733945 734037 734128 734218 734310 734402] CFlowT: {1x12 cell} Probs: {1x11 cell} Connect: {1x11 cell} FwdTree: {1x12 cell}
Compute Hull-White prices based on the calibrated tree.
HWPrices = capbyhw(HWTree, AllStrikes(:), Settle, AllMaturities(:), Reset, Basis)
HWPrices = 0.0601 0 0.2788 0 0.6580 0.0518 1.1254 0.1485 1.6591 0.3123 2.2076 0.5022 2.7319 0.6883 3.2459 0.8774 3.7771 1.0900 4.2769 1.2875 4.7645 1.4845 5.2572 1.6921
Plot Black prices against the calibrated Hull-White tree prices.
figure; plot(AllMaturities(:), BlkPrices, 'or', AllMaturities(:), HWPrices, '*b'); datetick('x', 2) xlabel('Maturity'); ylabel('Price'); title('Black and Calibrated (HW) Prices'); legend('Black Price', 'Calibrated HW Tree Price','Location', 'NorthWest'); grid on
This example shows how to use hwcalbycap
to calibrate market data with the Normal (Bachelier) model to price caplets. Use the Normal (Bachelier) model to perform calibrations when working with negative interest rates, strikes, and normal implied volatilities.
Consider a cap with these parameters:
Settle = 'Dec-30-2016'; Maturity = 'Dec-30-2019'; Strike = -0.001075; Reset = 2; Principal = 100; Basis = 0;
The caplets and market data for this example are defined as:
capletDates = cfdates(Settle, Maturity, Reset, Basis); datestr(capletDates')
ans = 6x11 char array
'30-Jun-2017'
'30-Dec-2017'
'30-Jun-2018'
'30-Dec-2018'
'30-Jun-2019'
'30-Dec-2019'
% Market data information MarketStrike = [-0.0013; 0]; MarketMat = {'30-Jun-2017';'30-Dec-2017';'30-Jun-2018'; '30-Dec-2018';'30-Jun-2019'; '30-Dec-2019'}; MarketVol = [0.184 0.2329 0.2398 0.2467 0.2906 0.3348; % First row in table corresponding to Strike 1 0.217 0.2707 0.2760 0.2814 0.3160 0.3508]; % Second row in table corresponding to Strike 2
Define the RateSpec
.
Rates= [-0.002210;-0.002020;-0.00182;-0.001343;-0.001075]; ValuationDate = 'Dec-30-2016'; EndDates = {'30-Jun-2017';'Dec-30-2017';'30-Jun-2018';'Dec-30-2018';'Dec-30-2019'}; Compounding = 2; Basis = 0; RateSpec = intenvset('ValuationDate', ValuationDate, ... 'StartDates', ValuationDate, 'EndDates', EndDates, ... 'Rates', Rates, 'Compounding', Compounding, 'Basis', Basis);
Use hwcalbycap
to find values for the volatility parameters Alpha
and Sigma
using the Normal (Bachelier) model.
format short o=optimoptions('lsqnonlin','TolFun',100*eps); warning ('off','fininst:hwcalbycapfloor:NoConverge') [Alpha, Sigma, OptimOut] = hwcalbycap(RateSpec, MarketStrike, MarketMat,... MarketVol, Strike, Settle, Maturity, 'Reset', Reset, 'Principal', Principal,... 'Basis', Basis, 'OptimOptions', o, 'model', 'normal')
Local minimum possible. lsqnonlin stopped because the size of the current step is less than the value of the step size tolerance.
Alpha = 1.0000e-06
Sigma = 0.3384
OptimOut = struct with fields:
resnorm: 1.5181e-04
residual: [5x1 double]
exitflag: 2
output: [1x1 struct]
lambda: [1x1 struct]
jacobian: [5x2 double]
The OptimOut.residual
field of the OptimOut
structure is the optimization residual. This value contains the difference between the Normal (Bachelier) caplets and those calculated during the optimization. Use the OptimOut.residual
value to calculate the percentual difference (error) compared to Normal (Bachelier) caplet prices, and then decide whether the residual is acceptable. There is almost always some residual, so decide if it is acceptable to parameterize the market with a single value of Alpha
and Sigma
.
Price the caplets using the market data and Normal (Bachelier) model to obtain the reference caplet values. To determine the effectiveness of the optimization, calculate reference caplet values using the Normal (Bachelier) formula and the market data. Note, you must first interpolate the market data to obtain the caplets for calculation.
MarketMatNum = datenum(MarketMat); [Mats, Strikes] = meshgrid(MarketMatNum, MarketStrike); FlatVol = interp2(Mats, Strikes, MarketVol, datenum(Maturity), Strike, 'spline'); [CapPrice, Caplets] = capbynormal(RateSpec, Strike, Settle, Maturity, FlatVol,... 'Reset', Reset, 'Basis', Basis, 'Principal', Principal); Caplets = Caplets(2:end)'
Caplets = 5×1
4.7392
6.7799
8.2609
9.6136
10.6455
Compare the optimized values and Normal (Bachelier) values, and display the results graphically. After calculating the reference values for the caplets, compare the values analytically and graphically to determine whether the calculated single values of Alpha
and Sigma
provide an adequate approximation.
OptimCaplets = Caplets+OptimOut.residual;
disp(' ');
disp(' Bachelier Calibrated Caplets');
Bachelier Calibrated Caplets
disp([Caplets OptimCaplets])
4.7392 4.7453 6.7799 6.7851 8.2609 8.2657 9.6136 9.6112 10.6455 10.6379
plot(MarketMatNum(2:end), Caplets, 'or', MarketMatNum(2:end), OptimCaplets, '*b'); datetick('x', 2) xlabel('Caplet Maturity'); ylabel('Caplet Price'); ylim ([0 16]); title('Bachelier and Calibrated Caplets'); h = legend('Bachelier Caplets', 'Calibrated Caplets'); set(h, 'color', [0.9 0.9 0.9]); set(h, 'Location', 'SouthEast'); set(gcf, 'NumberTitle', 'off') grid on
MarketStrike
— Market cap strikeMarket cap strike, specified as a NINST
-by-1
vector.
Data Types: double
MarketMaturity
— Market cap maturity dateMarket cap maturity dates, specified as a
NINST
-by-1
vector.
Data Types: double
MarketVolatility
— Market flat volatilitiesMarket flat volatilities, specified as a
NSTRIKES
-by-NMATS
matrix of market flat
volatilities, where NSTRIKES
is the number of caplet strikes from
MarketStrike
and NMATS
is the caplet
maturity dates from MarketMaturity
.
Data Types: double
Strike
— Rate at which cap is exercised(Optional) Rate at which the cap is exercised, specified as a decimal scalar value.
Data Types: single
Settle
— Settlement date of the cap(Optional) Settlement date of the cap, specified as a scalar serial date number or date character.
Data Types: single
| char
Maturity
— Maturity date of the cap(optional) Maturity date of the cap, specified as scalar serial date number or date character vector.
Data Types: single
| char
Specify optional
comma-separated pairs of Name,Value
arguments. Name
is
the argument name and Value
is the corresponding value.
Name
must appear inside quotes. You can specify several name and value
pair arguments in any order as
Name1,Value1,...,NameN,ValueN
.
[Alpha,Sigma,OptimOut] =
hwcalbycap(RateSpec,MarketStrike,MarketMaturity,MarketVolaltility,'Reset',2,'Principal',100000,'Basis',3,'OptimOptions',o)
'Reset'
— Frequency of payments per year1
(default) | numericFrequency of payments per year, specified as the comma-separated pair consisting
of 'Reset'
and a scalar numeric value.
Data Types: double
'Principal'
— Notional principal amount100
(default) | nonnegative integerNotional principal amount, specified as the comma-separated pair consisting of
'Principal'
and a scalar nonnegative integer.
Data Types: single
'Basis'
— Day-count basis used when annualizing the input forward rate0
(actual/actual) (default) | integers of the set [0...13]
Day-count basis used when annualizing the input forward rate, specified as the
comma-separated pair consisting of 'Basis'
and a scalar value.
Values are:
0 = actual/actual
1 = 30/360 (SIA)
2 = actual/360
3 = actual/365
4 = 30/360 (PSA)
5 = 30/360 (ISDA)
6 = 30/360 (European)
7 = actual/365 (Japanese)
8 = actual/actual (ICMA)
9 = actual/360 (ICMA)
10 = actual/365 (ICMA)
11 = 30/360E (ICMA)
12 = actual/365 (ISDA)
13 = BUS/252
For more information, see Basis.
Data Types: single
'LB'
— Lower bounds[0;0]
(default) | numeric vectorLower bounds, specified as the comma-separated pair consisting of
'LB'
and a 2
-by-1
vector of
the lower bounds, defined as [LBSigma; LBAlpha]
, used in the search
algorithm function. For more information, see lsqnonlin
.
Data Types: double
'UB'
— Upper bounds[ ]
(unbound) (default) | numeric vectorUpper bounds, specified as the comma-separated pair consisting of
'UB'
and a 2
-by-1
vector of
the upper bounds, defined as [UBSigma; LBAlpha]
, used in the search
algorithm function. For more information, see lsqnonlin
.
Data Types: double
'XO'
— Initial values[0.5;0.5]
(default) | numeric vectorInitial values, specified as the comma-separated pair consisting of
'XO'
and a 2
-by-1
vector of
the initial values, defined as [Sigma0; Alpha0]
, used in the search
algorithm function. For more information, see lsqnonlin
.
Data Types: double
'OptimOptions'
— Optimization parametersOptimization parameters, specified as the comma-separated pair consisting of
'OptimOptions'
and a structure defined by using optimoptions
.
Data Types: struct
'Shift'
— Shift in decimals for shifted Black model 0
(no shift) (default) | positive decimalShift in decimals for the shifted Black model, specified as the comma-separated
pair consisting of 'Shift'
and a scalar positive decimal value. Set
this parameter to a positive shift in decimals to add a positive shift to forward rate
and Strike
, which effectively sets a negative lower bound for
forward rate and Strike
. For example, a Shift
value of 0.01
is equal to a 1% shift.
Data Types: single
'Model'
— Indicator for model used for calibration routinelognormal
(Black model) (default) | values are normal
and lognormal
Indicator for model used for calibration routine, specified as the
comma-separated pair consisting of 'Model'
and a scalar character
vector with a value of normal
or
lognormal
.
Data Types: char
Alpha
— Mean reversion value obtained from calibrating the cap using market informationMean reversion value obtained from calibrating the cap using market information, returned as a scalar value.
Sigma
— Volatility value obtained from calibrating cap using market informationVolatility value obtained from calibrating the cap using market information, returned as a scalar.
OptimOut
— Optimization resultsOptimization results, returned as a structure.
capbyblk
| HullWhite1F
| hwcalbyfloor
| hwtree
| lsqnonlin
You have a modified version of this example. Do you want to open this example with your edits?