1 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3 /*!
4 Copyright (C) 2002, 2003 Sadruddin Rejeb
5 Copyright (C) 2004 Ferdinando Ametrano
6 Copyright (C) 2005, 2006, 2007 StatPro Italia srl
7
8 This file is part of QuantLib, a free-software/open-source library
9 for financial quantitative analysts and developers - http://quantlib.org/
10
11 QuantLib is free software: you can redistribute it and/or modify it
12 under the terms of the QuantLib license. You should have received a
13 copy of the license along with this program; if not, please email
14 <quantlib-dev@lists.sf.net>. The license is also available online at
15 <http://quantlib.org/license.shtml>.
16
17 This program is distributed in the hope that it will be useful, but WITHOUT
18 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19 FOR A PARTICULAR PURPOSE. See the license for more details.
20 */
21
22 #include <ql/qldefines.hpp>
23 #if !defined(BOOST_ALL_NO_LIB) && defined(BOOST_MSVC)
24 # include <ql/auto_link.hpp>
25 #endif
26 #include <ql/instruments/swaption.hpp>
27 #include <ql/pricingengines/swap/discountingswapengine.hpp>
28 #include <ql/pricingengines/swaption/treeswaptionengine.hpp>
29 #include <ql/pricingengines/swaption/jamshidianswaptionengine.hpp>
30 #include <ql/pricingengines/swaption/g2swaptionengine.hpp>
31 #include <ql/pricingengines/swaption/fdhullwhiteswaptionengine.hpp>
32 #include <ql/pricingengines/swaption/fdg2swaptionengine.hpp>
33 #include <ql/models/shortrate/calibrationhelpers/swaptionhelper.hpp>
34 #include <ql/models/shortrate/onefactormodels/blackkarasinski.hpp>
35 #include <ql/math/optimization/levenbergmarquardt.hpp>
36 #include <ql/indexes/ibor/euribor.hpp>
37 #include <ql/cashflows/coupon.hpp>
38 #include <ql/quotes/simplequote.hpp>
39 #include <ql/termstructures/yield/flatforward.hpp>
40 #include <ql/time/calendars/target.hpp>
41 #include <ql/time/daycounters/thirty360.hpp>
42 #include <ql/utilities/dataformatters.hpp>
43
44 #include <iostream>
45 #include <iomanip>
46
47 using namespace QuantLib;
48
49 //Number of swaptions to be calibrated to...
50
51 Size numRows = 5;
52 Size numCols = 5;
53
54 Integer swapLengths[] = {
55 1, 2, 3, 4, 5};
56 Volatility swaptionVols[] = {
57 0.1490, 0.1340, 0.1228, 0.1189, 0.1148,
58 0.1290, 0.1201, 0.1146, 0.1108, 0.1040,
59 0.1149, 0.1112, 0.1070, 0.1010, 0.0957,
60 0.1047, 0.1021, 0.0980, 0.0951, 0.1270,
61 0.1000, 0.0950, 0.0900, 0.1230, 0.1160};
62
63 void calibrateModel(
64 const ext::shared_ptr<ShortRateModel>& model,
65 const std::vector<ext::shared_ptr<BlackCalibrationHelper>>& swaptions) {
66
67 std::vector<ext::shared_ptr<CalibrationHelper>> helpers(swaptions.begin(), swaptions.end());
68 LevenbergMarquardt om;
69 model->calibrate(helpers, om,
70 EndCriteria(400, 100, 1.0e-8, 1.0e-8, 1.0e-8));
71
72 // Output the implied Black volatilities
73 for (Size i=0; i<numRows; i++) {
74 Size j = numCols - i -1; // 1x5, 2x4, 3x3, 4x2, 5x1
75 Size k = i*numCols + j;
76 Real npv = swaptions[i]->modelValue();
77 Volatility implied = swaptions[i]->impliedVolatility(npv, 1e-4,
78 1000, 0.05, 0.50);
79 Volatility diff = implied - swaptionVols[k];
80
81 std::cout << i+1 << "x" << swapLengths[j]
82 << std::setprecision(5) << std::noshowpos
83 << ": model " << std::setw(7) << io::volatility(implied)
84 << ", market " << std::setw(7)
85 << io::volatility(swaptionVols[k])
86 << " (" << std::setw(7) << std::showpos
87 << io::volatility(diff) << std::noshowpos << ")\n";
88 }
89 }
90
91 int main(int, char* []) {
92
93 try {
94
95 std::cout << std::endl;
96
97 Date todaysDate(15, February, 2002);
98 Calendar calendar = TARGET();
99 Date settlementDate(19, February, 2002);
100 Settings::instance().evaluationDate() = todaysDate;
101
102 // flat yield term structure impling 1x5 swap at 5%
103 auto flatRate = ext::make_shared<SimpleQuote>(0.04875825);
104 Handle<YieldTermStructure> rhTermStructure(
105 ext::make_shared<FlatForward>(
106 settlementDate, Handle<Quote>(flatRate),
107 Actual365Fixed()));
108
109 // Define the ATM/OTM/ITM swaps
110 Frequency fixedLegFrequency = Annual;
111 BusinessDayConvention fixedLegConvention = Unadjusted;
112 BusinessDayConvention floatingLegConvention = ModifiedFollowing;
113 DayCounter fixedLegDayCounter = Thirty360(Thirty360::European);
114 Frequency floatingLegFrequency = Semiannual;
115 Swap::Type type = Swap::Payer;
116 Rate dummyFixedRate = 0.03;
117 auto indexSixMonths = ext::make_shared<Euribor6M>(rhTermStructure);
118
119 Date startDate = calendar.advance(settlementDate,1,Years,
120 floatingLegConvention);
121 Date maturity = calendar.advance(startDate,5,Years,
122 floatingLegConvention);
123 Schedule fixedSchedule(startDate,maturity,Period(fixedLegFrequency),
124 calendar,fixedLegConvention,fixedLegConvention,
125 DateGeneration::Forward,false);
126 Schedule floatSchedule(startDate,maturity,Period(floatingLegFrequency),
127 calendar,floatingLegConvention,floatingLegConvention,
128 DateGeneration::Forward,false);
129
130 auto swap = ext::make_shared<VanillaSwap>(
131 type, 1000.0,
132 fixedSchedule, dummyFixedRate, fixedLegDayCounter,
133 floatSchedule, indexSixMonths, 0.0,
134 indexSixMonths->dayCounter());
135 swap->setPricingEngine(ext::make_shared<DiscountingSwapEngine>(rhTermStructure));
136 Rate fixedATMRate = swap->fairRate();
137 Rate fixedOTMRate = fixedATMRate * 1.2;
138 Rate fixedITMRate = fixedATMRate * 0.8;
139
140 auto atmSwap = ext::make_shared<VanillaSwap>(
141 type, 1000.0,
142 fixedSchedule, fixedATMRate, fixedLegDayCounter,
143 floatSchedule, indexSixMonths, 0.0,
144 indexSixMonths->dayCounter());
145 auto otmSwap = ext::make_shared<VanillaSwap>(
146 type, 1000.0,
147 fixedSchedule, fixedOTMRate, fixedLegDayCounter,
148 floatSchedule, indexSixMonths, 0.0,
149 indexSixMonths->dayCounter());
150 auto itmSwap = ext::make_shared<VanillaSwap>(
151 type, 1000.0,
152 fixedSchedule, fixedITMRate, fixedLegDayCounter,
153 floatSchedule, indexSixMonths, 0.0,
154 indexSixMonths->dayCounter());
155
156 // defining the swaptions to be used in model calibration
157 std::vector<Period> swaptionMaturities;
158 swaptionMaturities.emplace_back(1, Years);
159 swaptionMaturities.emplace_back(2, Years);
160 swaptionMaturities.emplace_back(3, Years);
161 swaptionMaturities.emplace_back(4, Years);
162 swaptionMaturities.emplace_back(5, Years);
163
164 std::vector<ext::shared_ptr<BlackCalibrationHelper>> swaptions;
165
166 // List of times that have to be included in the timegrid
167 std::list<Time> times;
168
169 Size i;
170 for (i=0; i<numRows; i++) {
171 Size j = numCols - i -1; // 1x5, 2x4, 3x3, 4x2, 5x1
172 Size k = i*numCols + j;
173 auto vol = ext::make_shared<SimpleQuote>(swaptionVols[k]);
174
175 swaptions.push_back(ext::make_shared<SwaptionHelper>(
176 swaptionMaturities[i],
177 Period(swapLengths[j], Years),
178 Handle<Quote>(vol),
179 indexSixMonths,
180 indexSixMonths->tenor(),
181 indexSixMonths->dayCounter(),
182 indexSixMonths->dayCounter(),
183 rhTermStructure));
184
185 swaptions.back()->addTimesTo(times);
186 }
187
188 // Building time-grid
189 TimeGrid grid(times.begin(), times.end(), 30);
190
191
192 // defining the models
193 auto modelG2 = ext::make_shared<G2>(rhTermStructure);
194 auto modelHW = ext::make_shared<HullWhite>(rhTermStructure);
195 auto modelHW2 = ext::make_shared<HullWhite>(rhTermStructure);
196 auto modelBK = ext::make_shared<BlackKarasinski>(rhTermStructure);
197
198
199 // model calibrations
200
201 std::cout << "G2 (analytic formulae) calibration" << std::endl;
202 for (i=0; i<swaptions.size(); i++)
203 swaptions[i]->setPricingEngine(ext::make_shared<G2SwaptionEngine>(modelG2, 6.0, 16));
204
205 calibrateModel(modelG2, swaptions);
206 std::cout << "calibrated to:\n"
207 << "a = " << modelG2->params()[0] << ", "
208 << "sigma = " << modelG2->params()[1] << "\n"
209 << "b = " << modelG2->params()[2] << ", "
210 << "eta = " << modelG2->params()[3] << "\n"
211 << "rho = " << modelG2->params()[4]
212 << std::endl << std::endl;
213
214
215
216 std::cout << "Hull-White (analytic formulae) calibration" << std::endl;
217 for (i=0; i<swaptions.size(); i++)
218 swaptions[i]->setPricingEngine(ext::make_shared<JamshidianSwaptionEngine>(modelHW));
219
220 calibrateModel(modelHW, swaptions);
221 std::cout << "calibrated to:\n"
222 << "a = " << modelHW->params()[0] << ", "
223 << "sigma = " << modelHW->params()[1]
224 << std::endl << std::endl;
225
226 std::cout << "Hull-White (numerical) calibration" << std::endl;
227 for (i=0; i<swaptions.size(); i++)
228 swaptions[i]->setPricingEngine(ext::make_shared<TreeSwaptionEngine>(modelHW2, grid));
229
230 calibrateModel(modelHW2, swaptions);
231 std::cout << "calibrated to:\n"
232 << "a = " << modelHW2->params()[0] << ", "
233 << "sigma = " << modelHW2->params()[1]
234 << std::endl << std::endl;
235
236 std::cout << "Black-Karasinski (numerical) calibration" << std::endl;
237 for (i=0; i<swaptions.size(); i++)
238 swaptions[i]->setPricingEngine(ext::make_shared<TreeSwaptionEngine>(modelBK, grid));
239
240 calibrateModel(modelBK, swaptions);
241 std::cout << "calibrated to:\n"
242 << "a = " << modelBK->params()[0] << ", "
243 << "sigma = " << modelBK->params()[1]
244 << std::endl << std::endl;
245
246
247 // ATM Bermudan swaption pricing
248
249 std::cout << "Payer bermudan swaption "
250 << "struck at " << io::rate(fixedATMRate)
251 << " (ATM)" << std::endl;
252
253 std::vector<Date> bermudanDates;
254 const std::vector<ext::shared_ptr<CashFlow>>& leg =
255 swap->fixedLeg();
256 for (i=0; i<leg.size(); i++) {
257 auto coupon = ext::dynamic_pointer_cast<Coupon>(leg[i]);
258 bermudanDates.push_back(coupon->accrualStartDate());
259 }
260
261 auto bermudanExercise = ext::make_shared<BermudanExercise>(bermudanDates);
262
263 Swaption bermudanSwaption(atmSwap, bermudanExercise);
264
265 // Do the pricing for each model
266
267 // G2 price the European swaption here, it should switch to bermudan
268 bermudanSwaption.setPricingEngine(ext::make_shared<TreeSwaptionEngine>(modelG2, 50));
269 std::cout << "G2 (tree): " << bermudanSwaption.NPV() << std::endl;
270 bermudanSwaption.setPricingEngine(ext::make_shared<FdG2SwaptionEngine>(modelG2));
271 std::cout << "G2 (fdm) : " << bermudanSwaption.NPV() << std::endl;
272
273 bermudanSwaption.setPricingEngine(ext::make_shared<TreeSwaptionEngine>(modelHW, 50));
274 std::cout << "HW (tree): " << bermudanSwaption.NPV() << std::endl;
275 bermudanSwaption.setPricingEngine(ext::make_shared<FdHullWhiteSwaptionEngine>(modelHW));
276 std::cout << "HW (fdm) : " << bermudanSwaption.NPV() << std::endl;
277
278 bermudanSwaption.setPricingEngine(ext::make_shared<TreeSwaptionEngine>(modelHW2, 50));
279 std::cout << "HW (num, tree): " << bermudanSwaption.NPV() << std::endl;
280 bermudanSwaption.setPricingEngine(ext::make_shared<FdHullWhiteSwaptionEngine>(modelHW2));
281 std::cout << "HW (num, fdm) : " << bermudanSwaption.NPV() << std::endl;
282
283 bermudanSwaption.setPricingEngine(ext::make_shared<TreeSwaptionEngine>(modelBK, 50));
284 std::cout << "BK: " << bermudanSwaption.NPV() << std::endl;
285
286
287 // OTM Bermudan swaption pricing
288
289 std::cout << "Payer bermudan swaption "
290 << "struck at " << io::rate(fixedOTMRate)
291 << " (OTM)" << std::endl;
292
293 Swaption otmBermudanSwaption(otmSwap,bermudanExercise);
294
295 // Do the pricing for each model
296 otmBermudanSwaption.setPricingEngine(ext::make_shared<TreeSwaptionEngine>(modelG2, 300));
297 std::cout << "G2 (tree): " << otmBermudanSwaption.NPV()
298 << std::endl;
299 otmBermudanSwaption.setPricingEngine(ext::make_shared<FdG2SwaptionEngine>(modelG2));
300 std::cout << "G2 (fdm) : " << otmBermudanSwaption.NPV()
301 << std::endl;
302
303 otmBermudanSwaption.setPricingEngine(ext::make_shared<TreeSwaptionEngine>(modelHW, 50));
304 std::cout << "HW (tree): " << otmBermudanSwaption.NPV()
305 << std::endl;
306 otmBermudanSwaption.setPricingEngine(ext::make_shared<FdHullWhiteSwaptionEngine>(modelHW));
307 std::cout << "HW (fdm) : " << otmBermudanSwaption.NPV()
308 << std::endl;
309
310 otmBermudanSwaption.setPricingEngine(ext::make_shared<TreeSwaptionEngine>(modelHW2, 50));
311 std::cout << "HW (num, tree): " << otmBermudanSwaption.NPV()
312 << std::endl;
313 otmBermudanSwaption.setPricingEngine(ext::make_shared<FdHullWhiteSwaptionEngine>(modelHW2));
314 std::cout << "HW (num, fdm): " << otmBermudanSwaption.NPV()
315 << std::endl;
316
317 otmBermudanSwaption.setPricingEngine(ext::make_shared<TreeSwaptionEngine>(modelBK, 50));
318 std::cout << "BK: " << otmBermudanSwaption.NPV()
319 << std::endl;
320
321
322 // ITM Bermudan swaption pricing
323
324 std::cout << "Payer bermudan swaption "
325 << "struck at " << io::rate(fixedITMRate)
326 << " (ITM)" << std::endl;
327
328 Swaption itmBermudanSwaption(itmSwap,bermudanExercise);
329
330 // Do the pricing for each model
331 itmBermudanSwaption.setPricingEngine(ext::make_shared<TreeSwaptionEngine>(modelG2, 50));
332 std::cout << "G2 (tree): " << itmBermudanSwaption.NPV()
333 << std::endl;
334 itmBermudanSwaption.setPricingEngine(ext::make_shared<FdG2SwaptionEngine>(modelG2));
335 std::cout << "G2 (fdm) : " << itmBermudanSwaption.NPV()
336 << std::endl;
337
338 itmBermudanSwaption.setPricingEngine(ext::make_shared<TreeSwaptionEngine>(modelHW, 50));
339 std::cout << "HW (tree): " << itmBermudanSwaption.NPV()
340 << std::endl;
341 itmBermudanSwaption.setPricingEngine(ext::make_shared<FdHullWhiteSwaptionEngine>(modelHW));
342 std::cout << "HW (fdm) : " << itmBermudanSwaption.NPV()
343 << std::endl;
344
345 itmBermudanSwaption.setPricingEngine(ext::make_shared<TreeSwaptionEngine>(modelHW2, 50));
346 std::cout << "HW (num, tree): " << itmBermudanSwaption.NPV()
347 << std::endl;
348 itmBermudanSwaption.setPricingEngine(ext::make_shared<FdHullWhiteSwaptionEngine>(modelHW2));
349 std::cout << "HW (num, fdm) : " << itmBermudanSwaption.NPV()
350 << std::endl;
351
352 itmBermudanSwaption.setPricingEngine(ext::make_shared<TreeSwaptionEngine>(modelBK, 50));
353 std::cout << "BK: " << itmBermudanSwaption.NPV()
354 << std::endl;
355
356 return 0;
357 } catch (std::exception& e) {
358 std::cerr << e.what() << std::endl;
359 return 1;
360 } catch (...) {
361 std::cerr << "unknown error" << std::endl;
362 return 1;
363 }
364 }