Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
lgmflexiswapengine.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2018 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
19#include "toplevelfixture.hpp"
20
22#include <qle/models/lgm.hpp>
25
26#include <ql/cashflows/floatingratecoupon.hpp>
27#include <ql/currencies/europe.hpp>
28#include <ql/indexes/ibor/euribor.hpp>
29#include <ql/models/shortrate/onefactormodels/gsr.hpp>
30#include <ql/pricingengines/swap/discountingswapengine.hpp>
31#include <ql/pricingengines/swaption/gaussian1dswaptionengine.hpp>
32#include <ql/termstructures/yield/flatforward.hpp>
33#include <ql/time/all.hpp>
34
35#include <boost/assign/std/vector.hpp>
36#include <boost/timer/timer.hpp>
37#include <boost/test/unit_test.hpp>
38
39#include <algorithm>
40
41using namespace boost::assign;
42using namespace QuantLib;
43using namespace QuantExt;
44using namespace boost::unit_test_framework;
45using namespace std;
46
47namespace {
48
49struct TestData : qle::test::TopLevelFixture {
50 TestData() : qle::test::TopLevelFixture() {
51 cal = TARGET();
52 evalDate = Date(5, February, 2016);
53 Settings::instance().evaluationDate() = evalDate;
54 effectiveDate = Date(cal.advance(evalDate, 2 * Days));
55 maturityDate = Date(cal.advance(effectiveDate, 10 * Years));
56 fixedSchedule = Schedule(effectiveDate, maturityDate, 1 * Years, cal, ModifiedFollowing, ModifiedFollowing,
57 DateGeneration::Forward, false);
58 floatingSchedule = Schedule(effectiveDate, maturityDate, 6 * Months, cal, ModifiedFollowing, ModifiedFollowing,
59 DateGeneration::Forward, false);
60 rateLevel = 0.02;
61 strike = 0.025;
62 nominal = 1000.0;
63 yts = Handle<YieldTermStructure>(QuantLib::ext::make_shared<FlatForward>(evalDate, rateLevel, Actual365Fixed()));
64 euribor6m = QuantLib::ext::make_shared<Euribor>(6 * Months, yts);
65 vanillaSwap = QuantLib::ext::make_shared<VanillaSwap>(VanillaSwap::Receiver, nominal, fixedSchedule, strike,
66 Thirty360(Thirty360::BondBasis), floatingSchedule, euribor6m, 0.0, Actual360());
67 for (Size i = 0; i < vanillaSwap->floatingLeg().size(); ++i) {
68 auto cpn = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(vanillaSwap->floatingLeg()[i]);
69 BOOST_REQUIRE(cpn != nullptr);
70 if (cpn->fixingDate() > evalDate && i % 2 == 0)
71 exerciseDates.push_back(cpn->fixingDate());
72 }
73 stepDates = std::vector<Date>(exerciseDates.begin(), exerciseDates.end() - 1);
74 stepTimes = Array(stepDates.size());
75 for (Size i = 0; i < stepDates.size(); ++i) {
76 stepTimes[i] = yts->timeFromReference(stepDates[i]);
77 }
78 sigmas = Array(stepDates.size() + 1);
79 for (Size i = 0; i < sigmas.size(); ++i) {
80 sigmas[i] = 0.0050 + (0.0080 - 0.0050) * std::exp(-0.2 * static_cast<double>(i));
81 }
82 reversion = 0.03;
83 lgmParam = QuantLib::ext::make_shared<IrLgm1fPiecewiseConstantHullWhiteAdaptor>(
84 EURCurrency(), yts, stepTimes, Array(sigmas.begin(), sigmas.end()), stepTimes,
85 Array(sigmas.size(), reversion));
86 lgm = QuantLib::ext::make_shared<LinearGaussMarkovModel>(lgmParam);
87 dscSwapEngine = QuantLib::ext::make_shared<DiscountingSwapEngine>(yts);
88 vanillaSwap->setPricingEngine(dscSwapEngine);
89 }
90
91 Calendar cal;
92 Date evalDate, effectiveDate, maturityDate;
93 Schedule fixedSchedule, floatingSchedule;
94 Real rateLevel, strike, nominal;
95 Handle<YieldTermStructure> yts;
96 QuantLib::ext::shared_ptr<IborIndex> euribor6m;
97 QuantLib::ext::shared_ptr<VanillaSwap> vanillaSwap;
98 std::vector<Date> exerciseDates, stepDates;
99 Array stepTimes, sigmas;
100 Real reversion;
101 QuantLib::ext::shared_ptr<IrLgm1fParametrization> lgmParam;
102 QuantLib::ext::shared_ptr<LinearGaussMarkovModel> lgm;
103 QuantLib::ext::shared_ptr<DiscountingSwapEngine> dscSwapEngine;
104};
105
106} // namespace
107
108BOOST_FIXTURE_TEST_SUITE(QuantExtTestSuite, qle::test::TopLevelFixture)
109
110BOOST_FIXTURE_TEST_SUITE(LgmFlexiSwapEngineTest, TestData)
111
112BOOST_AUTO_TEST_CASE(testSingleSwaption) {
113
114 BOOST_TEST_MESSAGE("Testing LGM Flexi-Swap engine in single swaption case...");
115
116 // vanilla bermudan swaption
117
118 QuantLib::ext::shared_ptr<Exercise> exercise = QuantLib::ext::make_shared<BermudanExercise>(exerciseDates, false);
119 QuantLib::ext::shared_ptr<Swaption> swaption = QuantLib::ext::make_shared<Swaption>(vanillaSwap, exercise);
120
121 QuantLib::ext::shared_ptr<PricingEngine> swaptionEngine =
122 QuantLib::ext::make_shared<NumericLgmSwaptionEngine>(lgm, 7.0, 16, 7.0, 32);
123
124 swaption->setPricingEngine(swaptionEngine);
125 boost::timer::cpu_timer timer;
126 Real swaptionNpv = swaption->NPV();
127 timer.stop();
128
129 Real swapNpv = vanillaSwap->NPV();
130
131 BOOST_TEST_MESSAGE("swaption npv = " << swaptionNpv << " swap npv = " << swapNpv
132 << " fix = " << vanillaSwap->legNPV(0) << " float =" << vanillaSwap->legNPV(1)
133 << " timing = " << timer.elapsed().wall * 1e-6 << " ms");
134
135 // flexi swap
136
137 Size nFixed = fixedSchedule.size() - 1, nFloat = floatingSchedule.size() - 1;
138 QuantLib::ext::shared_ptr<FlexiSwap> flexiSwap = QuantLib::ext::make_shared<FlexiSwap>(
139 VanillaSwap::Payer, std::vector<Real>(nFixed, nominal), std::vector<Real>(nFloat, nominal), fixedSchedule,
140 std::vector<Real>(nFixed, strike), Thirty360(Thirty360::BondBasis), floatingSchedule, euribor6m, std::vector<Real>(nFloat, 1.0),
141 std::vector<Real>(nFloat, 0.0), std::vector<Real>(nFloat, Null<Real>()),
142 std::vector<Real>(nFloat, Null<Real>()), Actual360(), std::vector<Real>(nFixed, 0.0), Position::Long);
143 QuantLib::ext::shared_ptr<FlexiSwap> flexiSwap2 = QuantLib::ext::make_shared<FlexiSwap>(
144 VanillaSwap::Receiver, std::vector<Real>(nFixed, nominal), std::vector<Real>(nFloat, nominal), fixedSchedule,
145 std::vector<Real>(nFixed, strike), Thirty360(Thirty360::BondBasis), floatingSchedule, euribor6m, std::vector<Real>(nFloat, 1.0),
146 std::vector<Real>(nFloat, 0.0), std::vector<Real>(nFloat, Null<Real>()),
147 std::vector<Real>(nFloat, Null<Real>()), Actual360(), std::vector<Real>(nFixed, 0.0), Position::Short);
148
149 auto flexiEngine = QuantLib::ext::make_shared<NumericLgmFlexiSwapEngine>(
151 auto flexiEngine2 = QuantLib::ext::make_shared<NumericLgmFlexiSwapEngine>(
153
154 flexiSwap->setPricingEngine(dscSwapEngine);
155 flexiSwap2->setPricingEngine(dscSwapEngine);
156 Real flexiUnderlyingNpvAnalytical = flexiSwap->NPV();
157 Real flexiUnderlyingNpvAnalytical2 = flexiSwap2->NPV();
158
159 flexiSwap->setPricingEngine(flexiEngine);
160 flexiSwap2->setPricingEngine(flexiEngine);
161 timer.start();
162 Real flexiNpv = flexiSwap->NPV();
163 timer.stop();
164 Real timing2 = timer.elapsed().wall * 1e-6;
165 Real flexiUnderlyingNpv = flexiSwap->underlyingValue();
166 Real flexiOptionNpv = flexiNpv - flexiUnderlyingNpv;
167 Real flexiNpv2 = flexiSwap2->NPV();
168 Real flexiUnderlyingNpv2 = flexiSwap2->underlyingValue();
169 Real flexiOptionNpv2 = flexiNpv2 - flexiUnderlyingNpv2;
170
171 flexiSwap->setPricingEngine(flexiEngine2);
172 flexiSwap2->setPricingEngine(flexiEngine2);
173 timer.start();
174 Real flexiNpvb = flexiSwap->NPV();
175 timer.stop();
176 Real timing3 = timer.elapsed().wall * 1e-6;
177 Real flexiUnderlyingNpvb = flexiSwap->underlyingValue();
178 Real flexiOptionNpvb = flexiNpv - flexiUnderlyingNpv;
179 Real flexiNpvb2 = flexiSwap2->NPV();
180 Real flexiUnderlyingNpvb2 = flexiSwap2->underlyingValue();
181 Real flexiOptionNpvb2 = flexiNpv2 - flexiUnderlyingNpv2;
182
183 BOOST_TEST_MESSAGE("A1 flexi npv = " << flexiNpv << " flexi underlying npv = " << flexiUnderlyingNpv
184 << " flexi option npv = " << flexiOptionNpv
185 << " flexi analytical underlying npv = " << flexiUnderlyingNpvAnalytical
186 << " timing = " << timing2 << " ms (method=SwaptionArray)");
187 BOOST_TEST_MESSAGE("A2 flexi npv = " << flexiNpv2 << " flexi underlying npv = " << flexiUnderlyingNpv2
188 << " flexi option npv = " << flexiOptionNpv2
189 << " flexi analytical underlying npv = " << flexiUnderlyingNpvAnalytical2);
190
191 BOOST_TEST_MESSAGE("B1 flexi npv = " << flexiNpvb << " flexi underlying npv = " << flexiUnderlyingNpvb
192 << " flexi option npv = " << flexiOptionNpvb
193 << " flexi analytical underlying npv = " << flexiUnderlyingNpvAnalytical
194 << " timing = " << timing3 << " ms (method=SingleSwaptions)");
195 BOOST_TEST_MESSAGE("B2 flexi npv = " << flexiNpvb2 << " flexi underlying npv = " << flexiUnderlyingNpvb2
196 << " flexi option npv = " << flexiOptionNpvb2
197 << " flexi analytical underlying npv = " << flexiUnderlyingNpvAnalytical2);
198
199 // checks
200
201 Real tol = 3E-5 * nominal; // 0.3 bp on nominal
202
203 BOOST_CHECK_SMALL(std::abs(flexiUnderlyingNpv + swapNpv), tol);
204 BOOST_CHECK_SMALL(std::abs(flexiOptionNpv - swaptionNpv), tol);
205
206 BOOST_CHECK_SMALL(std::abs(flexiUnderlyingNpv2 - swapNpv), tol);
207 BOOST_CHECK_SMALL(std::abs(flexiOptionNpv2 + swaptionNpv), tol);
208
209 BOOST_CHECK_SMALL(std::abs(flexiUnderlyingNpvAnalytical + swapNpv), tol);
210 BOOST_CHECK_SMALL(std::abs(flexiUnderlyingNpvAnalytical2 - swapNpv), tol);
211
212 BOOST_CHECK_SMALL(std::abs(flexiUnderlyingNpvb + swapNpv), tol);
213 BOOST_CHECK_SMALL(std::abs(flexiOptionNpvb - swaptionNpv), tol);
214
215 BOOST_CHECK_SMALL(std::abs(flexiUnderlyingNpvb2 - swapNpv), tol);
216 BOOST_CHECK_SMALL(std::abs(flexiOptionNpvb2 + swaptionNpv), tol);
217
218 BOOST_CHECK_SMALL(std::abs(flexiUnderlyingNpvAnalytical + swapNpv), tol);
219 BOOST_CHECK_SMALL(std::abs(flexiUnderlyingNpvAnalytical2 - swapNpv), tol);
220
221} // testSingleSwaption
222
223BOOST_AUTO_TEST_CASE(testMultipleSwaptions) {
224
225 BOOST_TEST_MESSAGE("Testing LGM Flexi-Swap engine in multiple swaption case...");
226
227 // flexi swap
228
229 Size nFixed = fixedSchedule.size() - 1, nFloat = floatingSchedule.size() - 1;
230 std::vector<Real> fixedNotionals{900.0, 1000.0, 1000.0, 800.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0};
231 std::vector<Real> floatNotionals{900.0, 900.0, 1000.0, 1000.0, 1000.0, 1000.0, 800.0, 800.0, 500.0, 500.0,
232 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0};
233 std::vector<Real> lowerNotionals{900.0, 1000.0, 750.0, 600.0, 250.0, 0.0, 0.0, 0.0, 0.0, 0.0};
234
235 QuantLib::ext::shared_ptr<FlexiSwap> flexiSwap = QuantLib::ext::make_shared<FlexiSwap>(
236 VanillaSwap::Payer, fixedNotionals, floatNotionals, fixedSchedule, std::vector<Real>(nFixed, strike),
237 Thirty360(Thirty360::BondBasis), floatingSchedule, euribor6m, std::vector<Real>(nFloat, 1.0), std::vector<Real>(nFloat, 0.0),
238 std::vector<Real>(nFloat, Null<Real>()), std::vector<Real>(nFloat, Null<Real>()), Actual360(), lowerNotionals,
239 Position::Long);
240
241 auto flexiEngine = QuantLib::ext::make_shared<NumericLgmFlexiSwapEngine>(
243 auto flexiEngine2 = QuantLib::ext::make_shared<NumericLgmFlexiSwapEngine>(
245
246 flexiSwap->setPricingEngine(flexiEngine);
247 boost::timer::cpu_timer timer;
248 Real flexiNpv = flexiSwap->NPV();
249 timer.stop();
250 Real timing1 = timer.elapsed().wall * 1e-6;
251 Real flexiUnderlyingNpv = flexiSwap->underlyingValue();
252 Real flexiOptionNpv = flexiNpv - flexiUnderlyingNpv;
253
254 flexiSwap->setPricingEngine(flexiEngine2);
255 timer.start();
256 Real flexiNpv2 = flexiSwap->NPV();
257 timer.stop();
258 Real timing3 = timer.elapsed().wall * 1e-6;
259 Real flexiUnderlyingNpv2 = flexiSwap->underlyingValue();
260 Real flexiOptionNpv2 = flexiNpv2 - flexiUnderlyingNpv2;
261
262 flexiSwap->setPricingEngine(dscSwapEngine);
263 Real flexiUnderlyingNpvAnalytical = flexiSwap->NPV();
264
265 // replicating swaptions
266
267 // 1) vol = 200, start 2, end 3
268 Schedule fixedSchedule1(fixedSchedule[2], fixedSchedule[3], 1 * Years, cal, ModifiedFollowing, ModifiedFollowing,
269 DateGeneration::Forward, false);
270 Schedule floatingSchedule1(floatingSchedule[4], floatingSchedule[6], 6 * Months, cal, ModifiedFollowing,
271 ModifiedFollowing, DateGeneration::Forward, false);
272 auto swap1 = QuantLib::ext::make_shared<VanillaSwap>(VanillaSwap::Receiver, 200.0, fixedSchedule1, strike, Thirty360(Thirty360::BondBasis),
273 floatingSchedule1, euribor6m, 0.0, Actual360());
274 std::vector<Date> exerciseDates1(exerciseDates.begin() + 1, exerciseDates.begin() + 2);
275 auto exercise1 = QuantLib::ext::make_shared<BermudanExercise>(exerciseDates1, false);
276 auto swaption1 = QuantLib::ext::make_shared<Swaption>(swap1, exercise1);
277
278 // 1) vol = 50, start 2, end 4
279 Schedule fixedSchedule2(fixedSchedule[2], fixedSchedule[4], 1 * Years, cal, ModifiedFollowing, ModifiedFollowing,
280 DateGeneration::Forward, false);
281 Schedule floatingSchedule2(floatingSchedule[4], floatingSchedule[8], 6 * Months, cal, ModifiedFollowing,
282 ModifiedFollowing, DateGeneration::Forward, false);
283 auto swap2 = QuantLib::ext::make_shared<VanillaSwap>(VanillaSwap::Receiver, 50.0, fixedSchedule2, strike, Thirty360(Thirty360::BondBasis),
284 floatingSchedule2, euribor6m, 0.0, Actual360());
285 std::vector<Date> exerciseDates2(exerciseDates.begin() + 1, exerciseDates.begin() + 3);
286 auto exercise2 = QuantLib::ext::make_shared<BermudanExercise>(exerciseDates2, false);
287 auto swaption2 = QuantLib::ext::make_shared<Swaption>(swap2, exercise2);
288
289 // 3) vol = 150, start 3, end 4
290 Schedule fixedSchedule3(fixedSchedule[3], fixedSchedule[4], 1 * Years, cal, ModifiedFollowing, ModifiedFollowing,
291 DateGeneration::Forward, false);
292 Schedule floatingSchedule3(floatingSchedule[6], floatingSchedule[8], 6 * Months, cal, ModifiedFollowing,
293 ModifiedFollowing, DateGeneration::Forward, false);
294 auto swap3 = QuantLib::ext::make_shared<VanillaSwap>(VanillaSwap::Receiver, 150.0, fixedSchedule3, strike, Thirty360(Thirty360::BondBasis),
295 floatingSchedule3, euribor6m, 0.0, Actual360());
296 std::vector<Date> exerciseDates3(exerciseDates.begin() + 2, exerciseDates.begin() + 3);
297 auto exercise3 = QuantLib::ext::make_shared<BermudanExercise>(exerciseDates3, false);
298 auto swaption3 = QuantLib::ext::make_shared<Swaption>(swap3, exercise3);
299
300 // 4) vol = 250, start 4, end 10
301 Schedule fixedSchedule4(fixedSchedule[4], fixedSchedule[10], 1 * Years, cal, ModifiedFollowing, ModifiedFollowing,
302 DateGeneration::Forward, false);
303 Schedule floatingSchedule4(floatingSchedule[8], floatingSchedule[20], 6 * Months, cal, ModifiedFollowing,
304 ModifiedFollowing, DateGeneration::Forward, false);
305 auto swap4 = QuantLib::ext::make_shared<VanillaSwap>(VanillaSwap::Receiver, 250.0, fixedSchedule4, strike, Thirty360(Thirty360::BondBasis),
306 floatingSchedule4, euribor6m, 0.0, Actual360());
307 std::vector<Date> exerciseDates4(exerciseDates.begin() + 3, exerciseDates.begin() + 9);
308 auto exercise4 = QuantLib::ext::make_shared<BermudanExercise>(exerciseDates4, false);
309 auto swaption4 = QuantLib::ext::make_shared<Swaption>(swap4, exercise4);
310
311 // 5) vol = 250, start 5, end 10
312 Schedule fixedSchedule5(fixedSchedule[5], fixedSchedule[10], 1 * Years, cal, ModifiedFollowing, ModifiedFollowing,
313 DateGeneration::Forward, false);
314 Schedule floatingSchedule5(floatingSchedule[10], floatingSchedule[20], 6 * Months, cal, ModifiedFollowing,
315 ModifiedFollowing, DateGeneration::Forward, false);
316 auto swap5 = QuantLib::ext::make_shared<VanillaSwap>(VanillaSwap::Receiver, 250.0, fixedSchedule5, strike, Thirty360(Thirty360::BondBasis),
317 floatingSchedule5, euribor6m, 0.0, Actual360());
318 std::vector<Date> exerciseDates5(exerciseDates.begin() + 4, exerciseDates.begin() + 9);
319 auto exercise5 = QuantLib::ext::make_shared<BermudanExercise>(exerciseDates5, false);
320 auto swaption5 = QuantLib::ext::make_shared<Swaption>(swap5, exercise5);
321
322 QuantLib::ext::shared_ptr<PricingEngine> swaptionEngine =
323 QuantLib::ext::make_shared<NumericLgmSwaptionEngine>(lgm, 7.0, 16, 7.0, 32);
324 swaption1->setPricingEngine(swaptionEngine);
325 swaption2->setPricingEngine(swaptionEngine);
326 swaption3->setPricingEngine(swaptionEngine);
327 swaption4->setPricingEngine(swaptionEngine);
328 swaption5->setPricingEngine(swaptionEngine);
329 timer.start();
330 Real swaptionNpv = swaption1->NPV() + swaption2->NPV() + swaption3->NPV() + swaption4->NPV() + swaption5->NPV();
331 timer.stop();
332 Real timing2 = timer.elapsed().wall * 1e-6;
333
334 BOOST_TEST_MESSAGE("swaption basket npv =" << swaptionNpv << " timing = " << timing2 << " ms");
335 BOOST_TEST_MESSAGE("A flexi npv = " << flexiNpv << " flexi underlying npv = " << flexiUnderlyingNpv
336 << " flexi option npv = " << flexiOptionNpv
337 << " flexi analytical underlying npv = " << flexiUnderlyingNpvAnalytical
338 << " timing = " << timing1 << " ms (method=SwaptionArray)");
339 BOOST_TEST_MESSAGE("B flexi npv = " << flexiNpv2 << " flexi underlying npv = " << flexiUnderlyingNpv2
340 << " flexi option npv = " << flexiOptionNpv2
341 << " flexi analytical underlying npv = " << flexiUnderlyingNpvAnalytical
342 << " timing = " << timing3 << " ms (method=SingleSwaptions)");
343 // checks
344
345 Real tol = 3E-5 * nominal; // 0.3 bp on nominal
346
347 BOOST_CHECK_SMALL(std::abs(flexiOptionNpv - swaptionNpv), tol);
348 BOOST_CHECK_SMALL(std::abs(flexiUnderlyingNpv - flexiUnderlyingNpvAnalytical), tol);
349 BOOST_CHECK_SMALL(std::abs(flexiNpv - flexiUnderlyingNpv - flexiOptionNpv), 1E-10);
350
351 BOOST_CHECK_SMALL(std::abs(flexiOptionNpv2 - swaptionNpv), tol);
352 BOOST_CHECK_SMALL(std::abs(flexiUnderlyingNpv2 - flexiUnderlyingNpvAnalytical), tol);
353 BOOST_CHECK_SMALL(std::abs(flexiNpv2 - flexiUnderlyingNpv2 - flexiOptionNpv2), 1E-10);
354}
355
356BOOST_AUTO_TEST_CASE(testDeterministicCase) {
357
358 BOOST_TEST_MESSAGE("Testing LGM Flexi-Swap engine in deterministic case (zero swaptions)...");
359
360 // vanilla swap
361
362 Real swapNpv = vanillaSwap->NPV();
363 BOOST_TEST_MESSAGE("swap npv = " << swapNpv << " fix = " << vanillaSwap->legNPV(0)
364 << " float =" << vanillaSwap->legNPV(1));
365
366 // flexi swap
367
368 Size nFixed = fixedSchedule.size() - 1, nFloat = floatingSchedule.size() - 1;
369 QuantLib::ext::shared_ptr<FlexiSwap> flexiSwap = QuantLib::ext::make_shared<FlexiSwap>(
370 VanillaSwap::Payer, std::vector<Real>(nFixed, nominal), std::vector<Real>(nFloat, nominal), fixedSchedule,
371 std::vector<Real>(nFixed, strike), Thirty360(Thirty360::BondBasis), floatingSchedule, euribor6m, std::vector<Real>(nFloat, 1.0),
372 std::vector<Real>(nFloat, 0.0), std::vector<Real>(nFloat, Null<Real>()),
373 std::vector<Real>(nFloat, Null<Real>()), Actual360(), std::vector<Real>(nFixed, nominal), Position::Long);
374
375 auto flexiEngine = QuantLib::ext::make_shared<NumericLgmFlexiSwapEngine>(
377 auto flexiEngine2 = QuantLib::ext::make_shared<NumericLgmFlexiSwapEngine>(
379 auto flexiEngine3 = QuantLib::ext::make_shared<NumericLgmFlexiSwapEngine>(
381
382 flexiSwap->setPricingEngine(flexiEngine);
383 Real flexiNpv = flexiSwap->NPV();
384 Real flexiUnderlyingNpv = flexiSwap->underlyingValue();
385 Real flexiOptionNpv = flexiNpv - flexiUnderlyingNpv;
386 flexiSwap->setPricingEngine(flexiEngine2);
387 Real flexiNpv2 = flexiSwap->NPV();
388 Real flexiUnderlyingNpv2 = flexiSwap->underlyingValue();
389 Real flexiOptionNpv2 = flexiNpv2 - flexiUnderlyingNpv2;
390 flexiSwap->setPricingEngine(flexiEngine3);
391 Real flexiNpv3 = flexiSwap->NPV();
392 Real flexiUnderlyingNpv3 = flexiSwap->underlyingValue();
393 Real flexiOptionNpv3 = flexiNpv3 - flexiUnderlyingNpv3;
394
395 BOOST_TEST_MESSAGE("1 flexi npv = " << flexiNpv << " flexi underlying npv = " << flexiUnderlyingNpv
396 << " flexi option npv = " << flexiOptionNpv << " (method=SwaptionArray)");
397 BOOST_TEST_MESSAGE("2 flexi npv = " << flexiNpv2 << " flexi underlying npv = " << flexiUnderlyingNpv2
398 << " flexi option npv = " << flexiOptionNpv2 << " (method=SwaptionArray)");
399 BOOST_TEST_MESSAGE("3 flexi npv = " << flexiNpv3 << " flexi underlying npv = " << flexiUnderlyingNpv3
400 << " flexi option npv = " << flexiOptionNpv3 << " (method=SwaptionArray)");
401
402 // checks
403
404 Real tol = 3E-5 * nominal; // 0.3 bp on nominal
405
406 BOOST_CHECK_SMALL(std::abs(flexiUnderlyingNpv + swapNpv), tol);
407 BOOST_CHECK_SMALL(std::abs(flexiOptionNpv), tol);
408 BOOST_CHECK_SMALL(std::abs(flexiUnderlyingNpv2 + swapNpv), tol);
409 BOOST_CHECK_SMALL(std::abs(flexiOptionNpv2), tol);
410 BOOST_CHECK_SMALL(std::abs(flexiUnderlyingNpv3 + swapNpv), tol);
411 BOOST_CHECK_SMALL(std::abs(flexiOptionNpv3), tol);
412
413} // testDeterministicCase
414
415BOOST_AUTO_TEST_SUITE_END()
416
417BOOST_AUTO_TEST_SUITE_END()
adaptor to emulate piecewise constant Hull White parameters
lgm model class
BOOST_AUTO_TEST_CASE(testSingleSwaption)
numeric engine for flexi swaps in the LGM model
Fixture that can be used at top level.