1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2014 Peter Caspers
5
6 This file is part of QuantLib, a free-software/open-source library
7 for financial quantitative analysts and developers - http://quantlib.org/
8
9 QuantLib is free software: you can redistribute it and/or modify it
10 under the terms of the QuantLib license. You should have received a
11 copy of the license along with this program; if not, please email
12 <quantlib-dev@lists.sf.net>. The license is also available online at
13 <http://quantlib.org/license.shtml>.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the license for more details.
18*/
19
20#include <ql/qldefines.hpp>
21#if !defined(BOOST_ALL_NO_LIB) && defined(BOOST_MSVC)
22# include <ql/auto_link.hpp>
23#endif
24#include <ql/instruments/floatfloatswap.hpp>
25#include <ql/instruments/floatfloatswaption.hpp>
26#include <ql/instruments/nonstandardswaption.hpp>
27#include <ql/pricingengines/swap/discountingswapengine.hpp>
28#include <ql/pricingengines/swaption/gaussian1dswaptionengine.hpp>
29#include <ql/pricingengines/swaption/gaussian1dnonstandardswaptionengine.hpp>
30#include <ql/pricingengines/swaption/gaussian1dfloatfloatswaptionengine.hpp>
31#include <ql/models/shortrate/onefactormodels/gsr.hpp>
32#include <ql/models/shortrate/onefactormodels/markovfunctional.hpp>
33#include <ql/models/shortrate/calibrationhelpers/swaptionhelper.hpp>
34#include <ql/math/optimization/levenbergmarquardt.hpp>
35#include <ql/cashflows/lineartsrpricer.hpp>
36#include <ql/indexes/ibor/euribor.hpp>
37#include <ql/indexes/swap/euriborswap.hpp>
38#include <ql/termstructures/yield/flatforward.hpp>
39#include <ql/termstructures/volatility/swaption/swaptionconstantvol.hpp>
40#include <ql/rebatedexercise.hpp>
41#include <ql/quotes/simplequote.hpp>
42#include <ql/time/calendars/target.hpp>
43#include <ql/time/daycounters/actual360.hpp>
44#include <ql/time/daycounters/thirty360.hpp>
45
46#include <iostream>
47#include <iomanip>
48
49using namespace QuantLib;
50
51// helper function that prints a basket of calibrating swaptions to std::cout
52
53void printBasket(
54 const std::vector<ext::shared_ptr<BlackCalibrationHelper>> &basket) {
55 std::cout << "\n" << std::left << std::setw(20) << "Expiry" << std::setw(20)
56 << "Maturity" << std::setw(20) << "Nominal" << std::setw(14)
57 << "Rate" << std::setw(12) << "Pay/Rec" << std::setw(14)
58 << "Market ivol" << std::fixed << std::setprecision(6)
59 << std::endl;
60 std::cout << "===================="
61 "===================="
62 "===================="
63 "===================="
64 "==================" << std::endl;
65 for (const auto& j : basket) {
66 auto helper = ext::dynamic_pointer_cast<SwaptionHelper>(r: j);
67 Date endDate = helper->underlyingSwap()->fixedSchedule().dates().back();
68 Real nominal = helper->underlyingSwap()->nominal();
69 Real vol = helper->volatility()->value();
70 Real rate = helper->underlyingSwap()->fixedRate();
71 Date expiry = helper->swaption()->exercise()->date(index: 0);
72 Swap::Type type = helper->swaption()->type();
73 std::ostringstream expiryString, endDateString;
74 expiryString << expiry;
75 endDateString << endDate;
76 std::cout << std::setw(20) << expiryString.str() << std::setw(20)
77 << endDateString.str() << std::setw(20) << nominal
78 << std::setw(14) << rate << std::setw(12)
79 << (type == Swap::Payer ? "Payer" : "Receiver")
80 << std::setw(14) << vol << std::endl;
81 }
82}
83
84// helper function that prints the result of a model calibration to std::cout
85
86void printModelCalibration(
87 const std::vector<ext::shared_ptr<BlackCalibrationHelper>> &basket,
88 const Array &volatility) {
89
90 std::cout << "\n" << std::left << std::setw(20) << "Expiry" << std::setw(14)
91 << "Model sigma" << std::setw(20) << "Model price"
92 << std::setw(20) << "market price" << std::setw(14)
93 << "Model ivol" << std::setw(14) << "Market ivol" << std::fixed
94 << std::setprecision(6) << std::endl;
95 std::cout << "===================="
96 "===================="
97 "===================="
98 "===================="
99 "====================" << std::endl;
100
101 for (Size j = 0; j < basket.size(); ++j) {
102 auto helper = ext::dynamic_pointer_cast<SwaptionHelper>(r: basket[j]);
103 Date expiry = helper->swaption()->exercise()->date(index: 0);
104 std::ostringstream expiryString;
105 expiryString << expiry;
106 std::cout << std::setw(20) << expiryString.str() << std::setw(14)
107 << volatility[j] << std::setw(20) << basket[j]->modelValue()
108 << std::setw(20) << basket[j]->marketValue() << std::setw(14)
109 << basket[j]->impliedVolatility(targetValue: basket[j]->modelValue(), accuracy: 1E-6,
110 maxEvaluations: 1000, minVol: 0.0, maxVol: 2.0)
111 << std::setw(14) << basket[j]->volatility()->value()
112 << std::endl;
113 }
114 if (volatility.size() > basket.size()) // only for markov model
115 std::cout << std::setw(20) << " " << volatility.back() << std::endl;
116}
117
118
119// here the main part of the code starts
120
121int main(int argc, char *argv[]) {
122
123 try {
124
125 std::cout << "\nGaussian1dModel Examples" << std::endl;
126
127 std::cout << "\nThis is some example code showing how to use the GSR "
128 "\n(Gaussian short rate) and Markov Functional model."
129 << std::endl;
130
131 Date refDate(30, April, 2014);
132 Settings::instance().evaluationDate() = refDate;
133
134 std::cout << "\nThe evaluation date for this example is set to "
135 << Settings::instance().evaluationDate() << std::endl;
136
137 Real forward6mLevel = 0.025;
138 Real oisLevel = 0.02;
139
140 Handle<Quote> forward6mQuote(
141 ext::make_shared<SimpleQuote>(args&: forward6mLevel));
142 Handle<Quote> oisQuote(ext::make_shared<SimpleQuote>(args&: oisLevel));
143
144 Handle<YieldTermStructure> yts6m(ext::make_shared<FlatForward>(
145 args: 0, args: TARGET(), args&: forward6mQuote, args: Actual365Fixed()));
146 Handle<YieldTermStructure> ytsOis(ext::make_shared<FlatForward>(
147 args: 0, args: TARGET(), args&: oisQuote, args: Actual365Fixed()));
148
149 auto euribor6m = ext::make_shared<Euribor>(args: 6 * Months, args&: yts6m);
150
151 std::cout
152 << "\nWe assume a multicurve setup, for simplicity with flat yield "
153 "\nterm structures. The discounting curve is an Eonia curve at"
154 "\na level of " << oisLevel
155 << " and the forwarding curve is an Euribior 6m curve"
156 << "\nat a level of " << forward6mLevel << std::endl;
157
158 Real volLevel = 0.20;
159 Handle<Quote> volQuote(ext::make_shared<SimpleQuote>(args&: volLevel));
160 Handle<SwaptionVolatilityStructure> swaptionVol(
161 ext::make_shared<ConstantSwaptionVolatility>(
162 args: 0, args: TARGET(), args: ModifiedFollowing, args&: volQuote, args: Actual365Fixed()));
163
164 std::cout
165 << "\nFor the volatility we assume a flat swaption volatility at "
166 << volLevel << std::endl;
167
168 Real strike = 0.04;
169 std::cout << "\nWe consider a standard 10y bermudan payer swaption "
170 "\nwith yearly exercises at a strike of " << strike
171 << std::endl;
172
173 Date effectiveDate = TARGET().advance(date: refDate, period: 2 * Days);
174 Date maturityDate = TARGET().advance(date: effectiveDate, period: 10 * Years);
175
176 Schedule fixedSchedule(effectiveDate, maturityDate, 1 * Years, TARGET(),
177 ModifiedFollowing, ModifiedFollowing,
178 DateGeneration::Forward, false);
179 Schedule floatingSchedule(effectiveDate, maturityDate, 6 * Months,
180 TARGET(), ModifiedFollowing,
181 ModifiedFollowing, DateGeneration::Forward,
182 false);
183
184 auto underlying = ext::make_shared<NonstandardSwap>(args: VanillaSwap(
185 Swap::Payer, 1.0, fixedSchedule, strike, Thirty360(Thirty360::BondBasis),
186 floatingSchedule, euribor6m, 0.00, Actual360()));
187
188 std::vector<Date> exerciseDates;
189 for (Size i = 1; i < 10; ++i)
190 exerciseDates.push_back(
191 x: TARGET().advance(date: fixedSchedule[i], period: -2 * Days));
192
193 auto exercise = ext::make_shared<BermudanExercise>(args&: exerciseDates, args: false);
194 auto swaption = ext::make_shared<NonstandardSwaption>(args&: underlying, args&: exercise);
195
196 std::cout
197 << "\nThe model is a one factor Hull White model with piecewise "
198 "\nvolatility adapted to our exercise dates." << std::endl;
199
200 std::vector<Date> stepDates(exerciseDates.begin(),
201 exerciseDates.end() - 1);
202 std::vector<Real> sigmas(stepDates.size() + 1, 0.01);
203 Real reversion = 0.01;
204
205 std::cout << "\nThe reversion is just kept constant at a level of "
206 << reversion << std::endl;
207
208 std::cout
209 << "\nThe model's curve is set to the 6m forward curve. Note that "
210 "\nthe model adapts automatically to other curves where "
211 "appropriate "
212 "\n(e.g. if an index requires a different forwarding curve) or "
213 "\nwhere explicitly specified (e.g. in a swaption pricing "
214 "engine)." << std::endl;
215
216 auto gsr = ext::make_shared<Gsr>(args&: yts6m, args&: stepDates, args&: sigmas, args&: reversion);
217
218 auto swaptionEngine =
219 ext::make_shared<Gaussian1dSwaptionEngine>(args&: gsr, args: 64, args: 7.0, args: true,
220 args: false, args&: ytsOis);
221 auto nonstandardSwaptionEngine =
222 ext::make_shared<Gaussian1dNonstandardSwaptionEngine>(
223 args&: gsr, args: 64, args: 7.0, args: true, args: false, args: Handle<Quote>(), args&: ytsOis);
224
225 swaption->setPricingEngine(nonstandardSwaptionEngine);
226
227 std::cout
228 << "\nThe engine can generate a calibration basket in two modes."
229 "\nThe first one is called Naive and generates ATM swaptions "
230 "adapted to"
231 "\nthe exercise dates of the swaption and its maturity date"
232 << std::endl;
233
234 std::cout << "\nThe resulting basket looks as follows:" << std::endl;
235
236 auto swapBase =
237 ext::make_shared<EuriborSwapIsdaFixA>(args: 10 * Years, args&: yts6m, args&: ytsOis);
238
239
240 std::vector<ext::shared_ptr<BlackCalibrationHelper>> basket =
241 swaption->calibrationBasket(standardSwapBase: swapBase, swaptionVolatility: *swaptionVol,
242 basketType: BasketGeneratingEngine::Naive);
243 printBasket(basket);
244
245
246 std::cout
247 << "\nLet's calibrate our model to this basket. We use a "
248 "specialized"
249 "\ncalibration method calibrating the sigma function one by one "
250 "to"
251 "\nthe calibrating vanilla swaptions. The result of this is as "
252 "follows:" << std::endl;
253
254 for (auto& i : basket)
255 i->setPricingEngine(swaptionEngine);
256
257 LevenbergMarquardt method;
258 EndCriteria ec(1000, 10, 1E-8, 1E-8,
259 1E-8); // only max iterations use actually used by LM
260
261
262 gsr->calibrateVolatilitiesIterative(helpers: basket, method, endCriteria: ec);
263
264
265 printModelCalibration(basket, volatility: gsr->volatility());
266
267
268 std::cout << "\nFinally we price our bermudan swaption in the "
269 "calibrated model:" << std::endl;
270
271
272 Real npv = swaption->NPV();
273
274
275 std::cout << "\nBermudan swaption NPV (ATM calibrated GSR) = "
276 << std::fixed << std::setprecision(6) << npv << std::endl;
277
278
279 std::cout << "\nThere is another mode to generate a calibration basket called"
280 "\nMaturityStrikeByDeltaGamma. This means that the maturity,"
281 "\nthe strike and the nominal of the calibrating swaptions are"
282 "\nobtained matching the NPV, first derivative and second derivative"
283 "\nof the swap you will exercise into at at each bermudan call date."
284 "\nThe derivatives are taken with respect to the model's state variable."
285 "\nLet's try this in our case."
286 << std::endl;
287
288
289 basket = swaption->calibrationBasket(
290 standardSwapBase: swapBase, swaptionVolatility: *swaptionVol,
291 basketType: BasketGeneratingEngine::MaturityStrikeByDeltaGamma);
292
293
294 printBasket(basket);
295
296
297 std::cout
298 << "\nThe calibrated nominal is close to the exotics nominal."
299 "\nThe expiries and maturity dates of the vanillas are the same"
300 "\nas in the case above. The difference is the strike which"
301 "\nis now equal to the exotics strike." << std::endl;
302
303 std::cout << "\nLet's see how this affects the exotics npv. The "
304 "\nrecalibrated model is:" << std::endl;
305
306 for (auto& i : basket)
307 i->setPricingEngine(swaptionEngine);
308
309
310 gsr->calibrateVolatilitiesIterative(helpers: basket, method, endCriteria: ec);
311
312
313 printModelCalibration(basket, volatility: gsr->volatility());
314
315
316 std::cout << "\nAnd the bermudan's price becomes:" << std::endl;
317
318
319 npv = swaption->NPV();
320
321
322 std::cout << "\nBermudan swaption NPV (deal strike calibrated GSR) = "
323 << std::setprecision(6) << npv << std::endl;
324
325
326
327 std::cout
328 << "\nWe can do more complicated things, let's e.g. modify the"
329 "\nnominal schedule to be linear amortizing and see what"
330 "\nthe effect on the generated calibration basket is:"
331 << std::endl;
332
333 std::vector<Real> nominalFixed, nominalFloating;
334 for (Size i = 0; i < fixedSchedule.size() - 1; ++i) {
335 Real tmpNom = 1.0 - (Real)i / (fixedSchedule.size() - 1);
336 nominalFixed.push_back(x: tmpNom);
337 nominalFloating.push_back(x: tmpNom);
338 nominalFloating.push_back(
339 x: tmpNom); // we use that the swap is 6m vs. 1y here
340 }
341 std::vector<Real> strikes(nominalFixed.size(), strike);
342
343 auto underlying2 = ext::make_shared<NonstandardSwap>(
344 args: Swap::Payer, args&: nominalFixed, args&: nominalFloating, args&: fixedSchedule,
345 args&: strikes, args: Thirty360(Thirty360::BondBasis), args&: floatingSchedule, args&: euribor6m, args: 1.0, args: 0.0,
346 args: Actual360());
347 auto swaption2 = ext::make_shared<NonstandardSwaption>(args&: underlying2, args&: exercise);
348
349 swaption2->setPricingEngine(nonstandardSwaptionEngine);
350
351
352 basket = swaption2->calibrationBasket(
353 standardSwapBase: swapBase, swaptionVolatility: *swaptionVol,
354 basketType: BasketGeneratingEngine::MaturityStrikeByDeltaGamma);
355
356
357 printBasket(basket);
358
359
360 std::cout << "\nThe notional is weighted over the underlying exercised "
361 "\ninto and the maturity is adjusted downwards. The rate"
362 "\non the other hand is not affected." << std::endl;
363
364 std::cout
365 << "\nYou can also price exotic bond's features. If you have e.g. a"
366 "\nbermudan callable fixed bond you can set up the call right "
367 "\nas a swaption to enter into a one leg swap with notional"
368 "\nreimbursement at maturity."
369 "\nThe exercise should then be written as a rebated exercise"
370 "\npaying the notional in case of exercise." << std::endl;
371
372 std::cout << "\nThe calibration basket looks like this:" << std::endl;
373
374 std::vector<Real> nominalFixed2(nominalFixed.size(), 1.0);
375 std::vector<Real> nominalFloating2(nominalFloating.size(),
376 0.0); // null the second leg
377
378 auto underlying3 = ext::make_shared<NonstandardSwap>(
379 args: Swap::Receiver, args&: nominalFixed2, args&: nominalFloating2,
380 args&: fixedSchedule, args&: strikes, args: Thirty360(Thirty360::BondBasis), args&: floatingSchedule, args&: euribor6m,
381 args: 1.0, args: 0.0, args: Actual360(), args: false,
382 args: true); // final capital exchange
383
384 auto exercise2 = ext::make_shared<RebatedExercise>(args&: *exercise, args: -1.0, args: 2, args: TARGET());
385
386 auto swaption3 = ext::make_shared<NonstandardSwaption>(args&: underlying3, args&: exercise2);
387
388 auto oas0 = ext::make_shared<SimpleQuote>(args: 0.0);
389 auto oas100 = ext::make_shared<SimpleQuote>(args: 0.01);
390 RelinkableHandle<Quote> oas(oas0);
391
392 auto nonstandardSwaptionEngine2 =
393 ext::make_shared<Gaussian1dNonstandardSwaptionEngine>(
394 args&: gsr, args: 64, args: 7.0, args: true, args: false, args&: oas); // change discounting to 6m
395
396 swaption3->setPricingEngine(nonstandardSwaptionEngine2);
397
398
399
400 basket = swaption3->calibrationBasket(
401 standardSwapBase: swapBase, swaptionVolatility: *swaptionVol,
402 basketType: BasketGeneratingEngine::MaturityStrikeByDeltaGamma);
403
404
405 printBasket(basket);
406
407
408 std::cout
409 << "\nNote that nominals are not exactly 1.0 here. This is"
410 << "\nbecause we do our bond discounting on 6m level while"
411 << "\nthe swaptions are still discounted on OIS level."
412 << "\n(You can try this by changing the OIS level to the "
413 << "\n6m level, which will produce nominals near 1.0)."
414 << "\nThe npv of the call right is (after recalibrating the model)"
415 << std::endl;
416
417 for (auto& i : basket)
418 i->setPricingEngine(swaptionEngine);
419
420
421 gsr->calibrateVolatilitiesIterative(helpers: basket, method, endCriteria: ec);
422 Real npv3 = swaption3->NPV();
423
424
425 std::cout << "\nBond's bermudan call right npv = "
426 << std::setprecision(6) << npv3 << std::endl;
427
428
429 std::cout
430 << "\nUp to now, no credit spread is included in the pricing."
431 "\nWe can do so by specifying an oas in the pricing engine."
432 "\nLet's set the spread level to 100bp and regenerate"
433 "\nthe calibration basket." << std::endl;
434
435 oas.linkTo(h: oas100);
436
437
438 basket = swaption3->calibrationBasket(
439 standardSwapBase: swapBase, swaptionVolatility: *swaptionVol,
440 basketType: BasketGeneratingEngine::MaturityStrikeByDeltaGamma);
441
442 printBasket(basket);
443
444
445 std::cout
446 << "\nThe adjusted basket takes the credit spread into account."
447 "\nThis is consistent to a hedge where you would have a"
448 "\nmargin on the float leg around 100bp,too." << std::endl;
449
450 std::cout << "\nThe npv becomes:" << std::endl;
451
452 for (auto& i : basket)
453 i->setPricingEngine(swaptionEngine);
454
455
456 gsr->calibrateVolatilitiesIterative(helpers: basket, method, endCriteria: ec);
457 Real npv4 = swaption3->NPV();
458
459
460 std::cout << "\nBond's bermudan call right npv (oas = 100bp) = "
461 << std::setprecision(6) << npv4 << std::endl;
462
463
464 std::cout
465 << "\nThe next instrument we look at is a CMS 10Y vs Euribor "
466 "\n6M swaption. The maturity is again 10 years and the option"
467 "\nis exercisable on a yearly basis" << std::endl;
468
469 auto underlying4 = ext::make_shared<FloatFloatSwap>(
470 args: Swap::Payer, args: 1.0, args: 1.0, args&: fixedSchedule, args&: swapBase,
471 args: Thirty360(Thirty360::BondBasis), args&: floatingSchedule, args&: euribor6m, args: Actual360(), args: false,
472 args: false, args: 1.0, args: 0.0, args: Null<Real>(), args: Null<Real>(), args: 1.0, args: 0.0010);
473
474 auto swaption4 = ext::make_shared<FloatFloatSwaption>(args&: underlying4, args&: exercise);
475
476 auto floatSwaptionEngine = ext::make_shared<Gaussian1dFloatFloatSwaptionEngine>(
477 args&: gsr, args: 64, args: 7.0, args: true, args: false, args: Handle<Quote>(), args&: ytsOis, args: true);
478
479 swaption4->setPricingEngine(floatSwaptionEngine);
480
481 std::cout
482 << "\nSince the underlying is quite exotic already, we start with"
483 "\npricing this using the LinearTsrPricer for CMS coupon "
484 "estimation" << std::endl;
485
486 Handle<Quote> reversionQuote(
487 ext::make_shared<SimpleQuote>(args&: reversion));
488
489 const Leg &leg0 = underlying4->leg(j: 0);
490 const Leg &leg1 = underlying4->leg(j: 1);
491 auto cmsPricer = ext::make_shared<LinearTsrPricer>(args&: swaptionVol, args&: reversionQuote);
492 auto iborPricer = ext::make_shared<BlackIborCouponPricer>();
493
494 setCouponPricer(leg: leg0, cmsPricer);
495 setCouponPricer(leg: leg1, iborPricer);
496
497 auto swapPricer = ext::make_shared<DiscountingSwapEngine>(args&: ytsOis);
498
499 underlying4->setPricingEngine(swapPricer);
500
501
502 Real npv5 = underlying4->NPV();
503
504
505 std::cout << "Underlying CMS Swap NPV = " << std::setprecision(6)
506 << npv5 << std::endl;
507 std::cout << " CMS Leg NPV = " << underlying4->legNPV(j: 0)
508 << std::endl;
509 std::cout << " Euribor Leg NPV = " << underlying4->legNPV(j: 1)
510 << std::endl;
511
512
513
514 std::cout << "\nWe generate a naive calibration basket and calibrate "
515 "\nthe GSR model to it:" << std::endl;
516
517
518 basket = swaption4->calibrationBasket(standardSwapBase: swapBase, swaptionVolatility: *swaptionVol,
519 basketType: BasketGeneratingEngine::Naive);
520 for (auto& i : basket)
521 i->setPricingEngine(swaptionEngine);
522 gsr->calibrateVolatilitiesIterative(helpers: basket, method, endCriteria: ec);
523
524
525 printBasket(basket);
526 printModelCalibration(basket, volatility: gsr->volatility());
527
528
529 std::cout << "\nThe npv of the bermudan swaption is" << std::endl;
530
531
532 Real npv6 = swaption4->NPV();
533
534
535 std::cout << "\nFloat swaption NPV (GSR) = " << std::setprecision(6)
536 << npv6 << std::endl;
537
538
539 std::cout << "\nIn this case it is also interesting to look at the "
540 "\nunderlying swap npv in the GSR model." << std::endl;
541
542 std::cout << "\nFloat swap NPV (GSR) = " << std::setprecision(6)
543 << swaption4->result<Real>(tag: "underlyingValue") << std::endl;
544
545 std::cout << "\nNot surprisingly, the underlying is priced differently"
546 "\ncompared to the LinearTsrPricer, since a different"
547 "\nsmile is implied by the GSR model." << std::endl;
548
549 std::cout << "\nThis is exactly where the Markov functional model"
550 << "\ncomes into play, because it can calibrate to any"
551 << "\ngiven underlying smile (as long as it is arbitrage"
552 << "\nfree). We try this now. Of course the usual use case"
553 << "\nis not to calibrate to a flat smile as in our simple"
554 << "\nexample, still it should be possible, of course..."
555 << std::endl;
556
557 std::vector<Date> markovStepDates(exerciseDates.begin(),
558 exerciseDates.end());
559 const std::vector<Date>& cmsFixingDates(markovStepDates);
560 std::vector<Real> markovSigmas(markovStepDates.size() + 1, 0.01);
561 std::vector<Period> tenors(cmsFixingDates.size(), 10 * Years);
562 auto markov = ext::make_shared<MarkovFunctional>(
563 args&: yts6m, args&: reversion, args&: markovStepDates, args&: markovSigmas, args&: swaptionVol,
564 args: cmsFixingDates, args&: tenors, args&: swapBase,
565 args&: MarkovFunctional::ModelSettings().withYGridPoints(n: 16));
566
567 auto swaptionEngineMarkov =
568 ext::make_shared<Gaussian1dSwaptionEngine>(args&: markov, args: 8, args: 5.0, args: true,
569 args: false, args&: ytsOis);
570 auto floatEngineMarkov =
571 ext::make_shared<Gaussian1dFloatFloatSwaptionEngine>(
572 args&: markov, args: 16, args: 7.0, args: true, args: false, args: Handle<Quote>(), args&: ytsOis,
573 args: true);
574
575 swaption4->setPricingEngine(floatEngineMarkov);
576
577
578 Real npv7 = swaption4->NPV();
579
580
581 std::cout << "\nThe option npv is the markov model is:" << std::endl;
582
583 std::cout << "\nFloat swaption NPV (Markov) = " << std::setprecision(6)
584 << npv7 << std::endl;
585
586
587 std::cout << "\nThis is not too far from the GSR price." << std::endl;
588
589 std::cout << "\nMore interesting is the question how well the Markov"
590 << "\nmodel did its job to match our input smile. For this"
591 << "\nwe look at the underlying npv under the Markov model"
592 << std::endl;
593
594 std::cout << "\nFloat swap NPV (Markov) = " << std::setprecision(6)
595 << swaption4->result<Real>(tag: "underlyingValue") << std::endl;
596
597 std::cout << "\nThis is closer to our terminal swap rate model price."
598 "\nA perfect match is not expected anyway, because the"
599 "\ndynamics of the underlying rate in the linear"
600 "\nmodel is different from the Markov model, of"
601 "\ncourse." << std::endl;
602
603 std::cout << "\nThe Markov model can not only calibrate to the"
604 "\nunderlying smile, but has at the same time a"
605 "\nsigma function (similar to the GSR model) which"
606 "\ncan be used to calibrate to a second instrument"
607 "\nset. We do this here to calibrate to our coterminal"
608 "\nATM swaptions from above." << std::endl;
609
610 std::cout << "\nThis is a computationally demanding task, so"
611 "\ndepending on your machine, this may take a"
612 "\nwhile now..." << std::endl;
613
614 for (auto& i : basket)
615 i->setPricingEngine(swaptionEngineMarkov);
616
617
618 markov->calibrate(helpers: basket, method, endCriteria: ec);
619
620
621 printModelCalibration(basket, volatility: markov->volatility());
622
623
624 std::cout << "\nNow let's have a look again at the underlying pricing."
625 "\nIt shouldn't have changed much, because the underlying"
626 "\nsmile is still matched." << std::endl;
627
628
629 Real npv8 = swaption4->result<Real>(tag: "underlyingValue");
630
631 std::cout << "\nFloat swap NPV (Markov) = " << std::setprecision(6)
632 << npv8 << std::endl;
633
634
635 std::cout << "\nThis is close to the previous value as expected."
636 << std::endl;
637
638 std::cout << "\nAs a final remark we note that the calibration to"
639 << "\ncoterminal swaptions is not particularly reasonable"
640 << "\nhere, because the european call rights are not"
641 << "\nwell represented by these swaptions."
642 << "\nSecondly, our CMS swaption is sensitive to the"
643 << "\ncorrelation between the 10y swap rate and the"
644 << "\nEuribor 6M rate. Since the Markov model is one factor"
645 << "\nit will most probably underestimate the market value"
646 << "\nby construction." << std::endl;
647
648 std::cout << "\nThat was it. Thank you for running this demo. Bye."
649 << std::endl;
650
651 } catch (const QuantLib::Error& e) {
652 std::cout << "terminated with a ql exception: " << e.what()
653 << std::endl;
654 return 1;
655 } catch (const std::exception& e) {
656 std::cout << "terminated with a general exception: " << e.what()
657 << std::endl;
658 return 1;
659 }
660}
661

source code of quantlib/Examples/Gaussian1dModels/Gaussian1dModels.cpp

Morty Proxy This is a proxified and sanitized view of the page, visit original site.