223 {
224
225 BOOST_TEST_MESSAGE("Testing LGM Flexi-Swap engine in multiple swaption case...");
226
227
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
266
267
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
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
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
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
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
344
345 Real tol = 3E-5 * 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}