1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2007 Chiara Fornarola
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 "assetswap.hpp"
21#include "utilities.hpp"
22#include <ql/time/schedule.hpp>
23#include <ql/instruments/assetswap.hpp>
24#include <ql/instruments/bond.hpp>
25#include <ql/instruments/bonds/fixedratebond.hpp>
26#include <ql/instruments/bonds/floatingratebond.hpp>
27#include <ql/instruments/bonds/cmsratebond.hpp>
28#include <ql/instruments/bonds/zerocouponbond.hpp>
29#include <ql/index.hpp>
30#include <ql/termstructures/yield/flatforward.hpp>
31#include <ql/time/calendars/nullcalendar.hpp>
32#include <ql/time/calendars/target.hpp>
33#include <ql/time/daycounters/thirty360.hpp>
34#include <ql/time/daycounters/actual365fixed.hpp>
35#include <ql/time/daycounters/actual360.hpp>
36#include <ql/time/daycounters/actualactual.hpp>
37#include <ql/time/daycounters/simpledaycounter.hpp>
38#include <ql/indexes/ibor/euribor.hpp>
39#include <ql/indexes/swapindex.hpp>
40#include <ql/cashflows/fixedratecoupon.hpp>
41#include <ql/cashflows/iborcoupon.hpp>
42#include <ql/cashflows/cmscoupon.hpp>
43#include <ql/cashflows/couponpricer.hpp>
44#include <ql/cashflows/conundrumpricer.hpp>
45#include <ql/termstructures/volatility/optionlet/constantoptionletvol.hpp>
46#include <ql/termstructures/volatility/swaption/swaptionconstantvol.hpp>
47#include <ql/termstructures/volatility/swaption/swaptionvolmatrix.hpp>
48#include <ql/termstructures/volatility/swaption/swaptionvolcube.hpp>
49#include <ql/utilities/dataformatters.hpp>
50#include <ql/cashflows/cashflows.hpp>
51#include <ql/cashflows/simplecashflow.hpp>
52#include <ql/pricingengines/bond/discountingbondengine.hpp>
53#include <ql/pricingengines/bond/bondfunctions.hpp>
54#include <ql/pricingengines/swap/discountingswapengine.hpp>
55#include <ql/quotes/simplequote.hpp>
56
57using namespace QuantLib;
58using namespace boost::unit_test_framework;
59
60namespace asset_swap_test {
61
62 struct CommonVars {
63 // common data
64 ext::shared_ptr<IborIndex> iborIndex;
65 ext::shared_ptr<SwapIndex> swapIndex;
66 ext::shared_ptr<IborCouponPricer> pricer;
67 ext::shared_ptr<CmsCouponPricer> cmspricer;
68 Spread spread;
69 Spread nonnullspread;
70 Real faceAmount;
71 Compounding compounding;
72 RelinkableHandle<YieldTermStructure> termStructure;
73
74 // initial setup
75 CommonVars() {
76 Natural swapSettlementDays = 2;
77 faceAmount = 100.0;
78 BusinessDayConvention fixedConvention = Unadjusted;
79 compounding = Continuous;
80 Frequency fixedFrequency = Annual;
81 Frequency floatingFrequency = Semiannual;
82 iborIndex = ext::shared_ptr<IborIndex>(
83 new Euribor(Period(floatingFrequency), termStructure));
84 Calendar calendar = iborIndex->fixingCalendar();
85 swapIndex= ext::make_shared<SwapIndex>(
86 args: "EuriborSwapIsdaFixA", args: 10*Years, args&: swapSettlementDays,
87 args: iborIndex->currency(), args&: calendar,
88 args: Period(fixedFrequency), args&: fixedConvention,
89 args: iborIndex->dayCounter(), args&: iborIndex);
90 spread = 0.0;
91 nonnullspread = 0.003;
92 Date today(24,April,2007);
93 Settings::instance().evaluationDate() = today;
94
95 //Date today = Settings::instance().evaluationDate();
96
97 termStructure.linkTo(h: flatRate(today, forward: 0.05, dc: Actual365Fixed()));
98 pricer = ext::shared_ptr<IborCouponPricer>(new
99 BlackIborCouponPricer);
100 Handle<SwaptionVolatilityStructure> swaptionVolatilityStructure(
101 ext::shared_ptr<SwaptionVolatilityStructure>(new
102 ConstantSwaptionVolatility(today, NullCalendar(),Following,
103 0.2, Actual365Fixed())));
104 Handle<Quote> meanReversionQuote(ext::shared_ptr<Quote>(new
105 SimpleQuote(0.01)));
106 cmspricer = ext::shared_ptr<CmsCouponPricer>(new
107 AnalyticHaganPricer(swaptionVolatilityStructure,
108 GFunctionFactory::Standard,
109 meanReversionQuote));
110 }
111 };
112
113}
114
115void AssetSwapTest::testConsistency() {
116 BOOST_TEST_MESSAGE(
117 "Testing consistency between fair price and fair spread...");
118
119 using namespace asset_swap_test;
120
121 CommonVars vars;
122
123 Calendar bondCalendar = TARGET();
124 Natural settlementDays = 3;
125
126 // Fixed Underlying bond (Isin: DE0001135275 DBR 4 01/04/37)
127 // maturity doesn't occur on a business day
128
129 Schedule bondSchedule(Date(4,January,2005),
130 Date(4,January,2037),
131 Period(Annual), bondCalendar,
132 Unadjusted, Unadjusted,
133 DateGeneration::Backward, false);
134 ext::shared_ptr<Bond> bond(new
135 FixedRateBond(settlementDays, vars.faceAmount,
136 bondSchedule,
137 std::vector<Rate>(1, 0.04),
138 ActualActual(ActualActual::ISDA),
139 Following,
140 100.0, Date(4,January,2005)));
141
142 bool payFixedRate = true;
143 Real bondPrice = 95.0;
144
145 bool isPar = true;
146 AssetSwap parAssetSwap(payFixedRate,
147 bond, bondPrice,
148 vars.iborIndex, vars.spread,
149 Schedule(),
150 vars.iborIndex->dayCounter(),
151 isPar);
152
153 ext::shared_ptr<PricingEngine> swapEngine(new
154 DiscountingSwapEngine(vars.termStructure,
155 true,
156 bond->settlementDate(),
157 Settings::instance().evaluationDate()));
158
159 parAssetSwap.setPricingEngine(swapEngine);
160 Real fairCleanPrice = parAssetSwap.fairCleanPrice();
161 Spread fairSpread = parAssetSwap.fairSpread();
162
163 Real tolerance = 1.0e-13;
164
165 AssetSwap assetSwap2(payFixedRate,
166 bond, fairCleanPrice,
167 vars.iborIndex, vars.spread,
168 Schedule(),
169 vars.iborIndex->dayCounter(),
170 isPar);
171 assetSwap2.setPricingEngine(swapEngine);
172 if (std::fabs(x: assetSwap2.NPV())>tolerance) {
173 BOOST_FAIL("\npar asset swap fair clean price doesn't zero the NPV: " <<
174 std::fixed << std::setprecision(4) <<
175 "\n clean price: " << bondPrice <<
176 "\n fair clean price: " << fairCleanPrice <<
177 "\n NPV: " << assetSwap2.NPV() <<
178 "\n tolerance: " << tolerance);
179 }
180 if (std::fabs(x: assetSwap2.fairCleanPrice() - fairCleanPrice)>tolerance) {
181 BOOST_FAIL("\npar asset swap fair clean price doesn't equal input "
182 "clean price at zero NPV: " <<
183 std::fixed << std::setprecision(4) <<
184 "\n input clean price: " << fairCleanPrice <<
185 "\n fair clean price: " << assetSwap2.fairCleanPrice() <<
186 "\n NPV: " << assetSwap2.NPV() <<
187 "\n tolerance: " << tolerance);
188 }
189 if (std::fabs(x: assetSwap2.fairSpread() - vars.spread)>tolerance) {
190 BOOST_FAIL("\npar asset swap fair spread doesn't equal input spread "
191 "at zero NPV: " << std::fixed << std::setprecision(4) <<
192 "\n input spread: " << vars.spread <<
193 "\n fair spread: " << assetSwap2.fairSpread() <<
194 "\n NPV: " << assetSwap2.NPV() <<
195 "\n tolerance: " << tolerance);
196 }
197
198 AssetSwap assetSwap3(payFixedRate,
199 bond, bondPrice,
200 vars.iborIndex, fairSpread,
201 Schedule(),
202 vars.iborIndex->dayCounter(),
203 isPar);
204 assetSwap3.setPricingEngine(swapEngine);
205 if (std::fabs(x: assetSwap3.NPV())>tolerance) {
206 BOOST_FAIL("\npar asset swap fair spread doesn't zero the NPV: " <<
207 std::fixed << std::setprecision(4) <<
208 "\n spread: " << vars.spread <<
209 "\n fair spread: " << fairSpread <<
210 "\n NPV: " << assetSwap3.NPV() <<
211 "\n tolerance: " << tolerance);
212 }
213 if (std::fabs(x: assetSwap3.fairCleanPrice() - bondPrice)>tolerance) {
214 BOOST_FAIL("\npar asset swap fair clean price doesn't equal input "
215 "clean price at zero NPV: " <<
216 std::fixed << std::setprecision(4) <<
217 "\n input clean price: " << bondPrice <<
218 "\n fair clean price: " << assetSwap3.fairCleanPrice() <<
219 "\n NPV: " << assetSwap3.NPV() <<
220 "\n tolerance: " << tolerance);
221 }
222 if (std::fabs(x: assetSwap3.fairSpread() - fairSpread)>tolerance) {
223 BOOST_FAIL("\npar asset swap fair spread doesn't equal input spread at"
224 " zero NPV: " << std::fixed << std::setprecision(4) <<
225 "\n input spread: " << fairSpread <<
226 "\n fair spread: " << assetSwap3.fairSpread() <<
227 "\n NPV: " << assetSwap3.NPV() <<
228 "\n tolerance: " << tolerance);
229 }
230
231 // let's change the npv date
232 swapEngine = ext::shared_ptr<PricingEngine>(new
233 DiscountingSwapEngine(vars.termStructure,
234 true,
235 bond->settlementDate(),
236 bond->settlementDate()));
237
238 parAssetSwap.setPricingEngine(swapEngine);
239 // fair clean price and fair spread should not change
240 if (std::fabs(x: parAssetSwap.fairCleanPrice() - fairCleanPrice)>tolerance) {
241 BOOST_FAIL("\npar asset swap fair clean price changed with NpvDate:" <<
242 std::fixed << std::setprecision(4) <<
243 "\n expected clean price: " << fairCleanPrice <<
244 "\n fair clean price: "<<parAssetSwap.fairCleanPrice()<<
245 "\n tolerance: " << tolerance);
246 }
247 if (std::fabs(x: parAssetSwap.fairSpread() - fairSpread)>tolerance) {
248 BOOST_FAIL("\npar asset swap fair spread changed with NpvDate:" <<
249 std::fixed << std::setprecision(4) <<
250 "\n expected spread: " << fairSpread <<
251 "\n fair spread: " << parAssetSwap.fairSpread() <<
252 "\n tolerance: " << tolerance);
253 }
254
255 assetSwap2 = AssetSwap(payFixedRate,
256 bond, fairCleanPrice,
257 vars.iborIndex, vars.spread,
258 Schedule(),
259 vars.iborIndex->dayCounter(),
260 isPar);
261 assetSwap2.setPricingEngine(swapEngine);
262 if (std::fabs(x: assetSwap2.NPV())>tolerance) {
263 BOOST_FAIL("\npar asset swap fair clean price doesn't zero the NPV: " <<
264 std::fixed << std::setprecision(4) <<
265 "\n clean price: " << bondPrice <<
266 "\n fair clean price: " << fairCleanPrice <<
267 "\n NPV: " << assetSwap2.NPV() <<
268 "\n tolerance: " << tolerance);
269 }
270 if (std::fabs(x: assetSwap2.fairCleanPrice() - fairCleanPrice)>tolerance) {
271 BOOST_FAIL("\npar asset swap fair clean price doesn't equal input "
272 "clean price at zero NPV: " <<
273 std::fixed << std::setprecision(4) <<
274 "\n input clean price: " << fairCleanPrice <<
275 "\n fair clean price: " << assetSwap2.fairCleanPrice() <<
276 "\n NPV: " << assetSwap2.NPV() <<
277 "\n tolerance: " << tolerance);
278 }
279 if (std::fabs(x: assetSwap2.fairSpread() - vars.spread)>tolerance) {
280 BOOST_FAIL("\npar asset swap fair spread doesn't equal input spread at zero NPV: " <<
281 std::fixed << std::setprecision(4) <<
282 "\n input spread: " << vars.spread <<
283 "\n fair spread: " << assetSwap2.fairSpread() <<
284 "\n NPV: " << assetSwap2.NPV() <<
285 "\n tolerance: " << tolerance);
286 }
287
288 assetSwap3 = AssetSwap(payFixedRate,
289 bond, bondPrice,
290 vars.iborIndex, fairSpread,
291 Schedule(),
292 vars.iborIndex->dayCounter(),
293 isPar);
294 assetSwap3.setPricingEngine(swapEngine);
295 if (std::fabs(x: assetSwap3.NPV())>tolerance) {
296 BOOST_FAIL("\npar asset swap fair spread doesn't zero the NPV: " <<
297 std::fixed << std::setprecision(4) <<
298 "\n spread: " << vars.spread <<
299 "\n fair spread: " << fairSpread <<
300 "\n NPV: " << assetSwap3.NPV() <<
301 "\n tolerance: " << tolerance);
302 }
303 if (std::fabs(x: assetSwap3.fairCleanPrice() - bondPrice)>tolerance) {
304 BOOST_FAIL("\npar asset swap fair clean price doesn't equal input "
305 "clean price at zero NPV: " <<
306 std::fixed << std::setprecision(4) <<
307 "\n input clean price: " << bondPrice <<
308 "\n fair clean price: " << assetSwap3.fairCleanPrice() <<
309 "\n NPV: " << assetSwap3.NPV() <<
310 "\n tolerance: " << tolerance);
311 }
312 if (std::fabs(x: assetSwap3.fairSpread() - fairSpread)>tolerance) {
313 BOOST_FAIL("\npar asset swap fair spread doesn't equal input spread at zero NPV: " <<
314 std::fixed << std::setprecision(4) <<
315 "\n input spread: " << fairSpread <<
316 "\n fair spread: " << assetSwap3.fairSpread() <<
317 "\n NPV: " << assetSwap3.NPV() <<
318 "\n tolerance: " << tolerance);
319 }
320
321
322
323
324
325 // now market asset swap
326 isPar = false;
327 AssetSwap mktAssetSwap(payFixedRate,
328 bond, bondPrice,
329 vars.iborIndex, vars.spread,
330 Schedule(),
331 vars.iborIndex->dayCounter(),
332 isPar);
333
334 swapEngine = ext::shared_ptr<PricingEngine>(new
335 DiscountingSwapEngine(vars.termStructure,
336 true,
337 bond->settlementDate(),
338 Settings::instance().evaluationDate()));
339
340 mktAssetSwap.setPricingEngine(swapEngine);
341 fairCleanPrice = mktAssetSwap.fairCleanPrice();
342 fairSpread = mktAssetSwap.fairSpread();
343
344 AssetSwap assetSwap4(payFixedRate,
345 bond, fairCleanPrice,
346 vars.iborIndex, vars.spread,
347 Schedule(),
348 vars.iborIndex->dayCounter(),
349 isPar);
350 assetSwap4.setPricingEngine(swapEngine);
351 if (std::fabs(x: assetSwap4.NPV())>tolerance) {
352 BOOST_FAIL("\nmarket asset swap fair clean price doesn't zero the NPV: " <<
353 std::fixed << std::setprecision(4) <<
354 "\n clean price: " << bondPrice <<
355 "\n fair clean price: " << fairCleanPrice <<
356 "\n NPV: " << assetSwap4.NPV() <<
357 "\n tolerance: " << tolerance);
358 }
359 if (std::fabs(x: assetSwap4.fairCleanPrice() - fairCleanPrice)>tolerance) {
360 BOOST_FAIL("\nmarket asset swap fair clean price doesn't equal input "
361 "clean price at zero NPV: " <<
362 std::fixed << std::setprecision(4) <<
363 "\n input clean price: " << fairCleanPrice <<
364 "\n fair clean price: " << assetSwap4.fairCleanPrice() <<
365 "\n NPV: " << assetSwap4.NPV() <<
366 "\n tolerance: " << tolerance);
367 }
368 if (std::fabs(x: assetSwap4.fairSpread() - vars.spread)>tolerance) {
369 BOOST_FAIL("\nmarket asset swap fair spread doesn't equal input spread"
370 " at zero NPV: " << std::fixed << std::setprecision(4) <<
371 "\n input spread: " << vars.spread <<
372 "\n fair spread: " << assetSwap4.fairSpread() <<
373 "\n NPV: " << assetSwap4.NPV() <<
374 "\n tolerance: " << tolerance);
375 }
376
377 AssetSwap assetSwap5(payFixedRate,
378 bond, bondPrice,
379 vars.iborIndex, fairSpread,
380 Schedule(),
381 vars.iborIndex->dayCounter(),
382 isPar);
383 assetSwap5.setPricingEngine(swapEngine);
384 if (std::fabs(x: assetSwap5.NPV())>tolerance) {
385 BOOST_FAIL("\nmarket asset swap fair spread doesn't zero the NPV: " <<
386 std::fixed << std::setprecision(4) <<
387 "\n spread: " << vars.spread <<
388 "\n fair spread: " << fairSpread <<
389 "\n NPV: " << assetSwap5.NPV() <<
390 "\n tolerance: " << tolerance);
391 }
392 if (std::fabs(x: assetSwap5.fairCleanPrice() - bondPrice)>tolerance) {
393 BOOST_FAIL("\nmarket asset swap fair clean price doesn't equal input "
394 "clean price at zero NPV: " <<
395 std::fixed << std::setprecision(4) <<
396 "\n input clean price: " << bondPrice <<
397 "\n fair clean price: " << assetSwap5.fairCleanPrice() <<
398 "\n NPV: " << assetSwap5.NPV() <<
399 "\n tolerance: " << tolerance);
400 }
401 if (std::fabs(x: assetSwap5.fairSpread() - fairSpread)>tolerance) {
402 BOOST_FAIL("\nmarket asset swap fair spread doesn't equal input spread at zero NPV: " <<
403 std::fixed << std::setprecision(4) <<
404 "\n input spread: " << fairSpread <<
405 "\n fair spread: " << assetSwap5.fairSpread() <<
406 "\n NPV: " << assetSwap5.NPV() <<
407 "\n tolerance: " << tolerance);
408 }
409
410 // let's change the npv date
411 swapEngine = ext::shared_ptr<PricingEngine>(new
412 DiscountingSwapEngine(vars.termStructure,
413 true,
414 bond->settlementDate(),
415 bond->settlementDate()));
416
417 mktAssetSwap.setPricingEngine(swapEngine);
418 // fair clean price and fair spread should not change
419 if (std::fabs(x: mktAssetSwap.fairCleanPrice() - fairCleanPrice)>tolerance) {
420 BOOST_FAIL("\nmarket asset swap fair clean price changed with NpvDate:" <<
421 std::fixed << std::setprecision(4) <<
422 "\n expected clean price: " << fairCleanPrice <<
423 "\n fair clean price: " << mktAssetSwap.fairCleanPrice() <<
424 "\n tolerance: " << tolerance);
425 }
426 if (std::fabs(x: mktAssetSwap.fairSpread() - fairSpread)>tolerance) {
427 BOOST_FAIL("\nmarket asset swap fair spread changed with NpvDate:" <<
428 std::fixed << std::setprecision(4) <<
429 "\n expected spread: " << fairSpread <<
430 "\n fair spread: " << mktAssetSwap.fairSpread() <<
431 "\n tolerance: " << tolerance);
432 }
433
434 assetSwap4 = AssetSwap(payFixedRate,
435 bond, fairCleanPrice,
436 vars.iborIndex, vars.spread,
437 Schedule(),
438 vars.iborIndex->dayCounter(),
439 isPar);
440 assetSwap4.setPricingEngine(swapEngine);
441 if (std::fabs(x: assetSwap4.NPV())>tolerance) {
442 BOOST_FAIL("\nmarket asset swap fair clean price doesn't zero the NPV: " <<
443 std::fixed << std::setprecision(4) <<
444 "\n clean price: " << bondPrice <<
445 "\n fair clean price: " << fairCleanPrice <<
446 "\n NPV: " << assetSwap4.NPV() <<
447 "\n tolerance: " << tolerance);
448 }
449 if (std::fabs(x: assetSwap4.fairCleanPrice() - fairCleanPrice)>tolerance) {
450 BOOST_FAIL("\nmarket asset swap fair clean price doesn't equal input "
451 "clean price at zero NPV: " <<
452 std::fixed << std::setprecision(4) <<
453 "\n input clean price: " << fairCleanPrice <<
454 "\n fair clean price: " << assetSwap4.fairCleanPrice() <<
455 "\n NPV: " << assetSwap4.NPV() <<
456 "\n tolerance: " << tolerance);
457 }
458 if (std::fabs(x: assetSwap4.fairSpread() - vars.spread)>tolerance) {
459 BOOST_FAIL("\nmarket asset swap fair spread doesn't equal input spread at zero NPV: " <<
460 std::fixed << std::setprecision(4) <<
461 "\n input spread: " << vars.spread <<
462 "\n fair spread: " << assetSwap4.fairSpread() <<
463 "\n NPV: " << assetSwap4.NPV() <<
464 "\n tolerance: " << tolerance);
465 }
466
467 assetSwap5 = AssetSwap(payFixedRate,
468 bond, bondPrice,
469 vars.iborIndex, fairSpread,
470 Schedule(),
471 vars.iborIndex->dayCounter(),
472 isPar);
473 assetSwap5.setPricingEngine(swapEngine);
474 if (std::fabs(x: assetSwap5.NPV())>tolerance) {
475 BOOST_FAIL("\nmarket asset swap fair spread doesn't zero the NPV: " <<
476 std::fixed << std::setprecision(4) <<
477 "\n spread: " << vars.spread <<
478 "\n fair spread: " << fairSpread <<
479 "\n NPV: " << assetSwap5.NPV() <<
480 "\n tolerance: " << tolerance);
481 }
482 if (std::fabs(x: assetSwap5.fairCleanPrice() - bondPrice)>tolerance) {
483 BOOST_FAIL("\nmarket asset swap fair clean price doesn't equal input "
484 "clean price at zero NPV: " <<
485 std::fixed << std::setprecision(4) <<
486 "\n input clean price: " << bondPrice <<
487 "\n fair clean price: " << assetSwap5.fairCleanPrice() <<
488 "\n NPV: " << assetSwap5.NPV() <<
489 "\n tolerance: " << tolerance);
490 }
491 if (std::fabs(x: assetSwap5.fairSpread() - fairSpread)>tolerance) {
492 BOOST_FAIL("\nmarket asset swap fair spread doesn't equal input spread at zero NPV: " <<
493 std::fixed << std::setprecision(4) <<
494 "\n input spread: " << fairSpread <<
495 "\n fair spread: " << assetSwap5.fairSpread() <<
496 "\n NPV: " << assetSwap5.NPV() <<
497 "\n tolerance: " << tolerance);
498 }
499
500}
501
502void AssetSwapTest::testImpliedValue() {
503
504 BOOST_TEST_MESSAGE("Testing implied bond value against asset-swap fair"
505 " price with null spread...");
506
507 using namespace asset_swap_test;
508
509 bool usingAtParCoupons = IborCoupon::Settings::instance().usingAtParCoupons();
510
511 CommonVars vars;
512
513 Calendar bondCalendar = TARGET();
514 Natural settlementDays = 3;
515 Natural fixingDays = 2;
516 bool payFixedRate = true;
517 bool parAssetSwap = true;
518 bool inArrears = false;
519
520 // Fixed Underlying bond (Isin: DE0001135275 DBR 4 01/04/37)
521 // maturity doesn't occur on a business day
522
523 Schedule fixedBondSchedule1(Date(4,January,2005),
524 Date(4,January,2037),
525 Period(Annual), bondCalendar,
526 Unadjusted, Unadjusted,
527 DateGeneration::Backward, false);
528 ext::shared_ptr<Bond> fixedBond1(
529 new FixedRateBond(settlementDays, vars.faceAmount,
530 fixedBondSchedule1,
531 std::vector<Rate>(1, 0.04),
532 ActualActual(ActualActual::ISDA),
533 Following,
534 100.0, Date(4,January,2005)));
535
536 ext::shared_ptr<PricingEngine> bondEngine(
537 new DiscountingBondEngine(vars.termStructure));
538 ext::shared_ptr<PricingEngine> swapEngine(
539 new DiscountingSwapEngine(vars.termStructure));
540 fixedBond1->setPricingEngine(bondEngine);
541
542 Real fixedBondPrice1 = fixedBond1->cleanPrice();
543 AssetSwap fixedBondAssetSwap1(payFixedRate,
544 fixedBond1, fixedBondPrice1,
545 vars.iborIndex, vars.spread,
546 Schedule(),
547 vars.iborIndex->dayCounter(),
548 parAssetSwap);
549 fixedBondAssetSwap1.setPricingEngine(swapEngine);
550 Real fixedBondAssetSwapPrice1 = fixedBondAssetSwap1.fairCleanPrice();
551 Real tolerance = 1.0e-13;
552
553 // for indexed coupons the float leg will not be par, therefore we
554 // have to relax the tolerance - note that the fair clean price is
555 // correct though, only we can not compare it to the bond price
556 // directly. The same kind of discrepancy will occur for a multi
557 // curve set up, which we do not test here.
558 Real tolerance2 = usingAtParCoupons ? 1.0e-13 : 1.0e-2;
559
560 Real error1 = std::fabs(x: fixedBondAssetSwapPrice1-fixedBondPrice1);
561
562 if (error1>tolerance2) {
563 BOOST_FAIL("wrong zero spread asset swap price for fixed bond:" <<
564 std::fixed << std::setprecision(4) <<
565 "\n bond's clean price: " << fixedBondPrice1 <<
566 "\n asset swap fair price: " << fixedBondAssetSwapPrice1 <<
567 std::scientific << std::setprecision(2) <<
568 "\n error: " << error1 <<
569 "\n tolerance: " << tolerance2);
570 }
571
572 // Fixed Underlying bond (Isin: IT0006527060 IBRD 5 02/05/19)
573 // maturity occurs on a business day
574
575 Schedule fixedBondSchedule2(Date(5,February,2005),
576 Date(5,February,2019),
577 Period(Annual), bondCalendar,
578 Unadjusted, Unadjusted,
579 DateGeneration::Backward, false);
580 ext::shared_ptr<Bond> fixedBond2(
581 new FixedRateBond(settlementDays, vars.faceAmount,
582 fixedBondSchedule2,
583 std::vector<Rate>(1, 0.05),
584 Thirty360(Thirty360::BondBasis),
585 Following,
586 100.0, Date(5,February,2005)));
587
588 fixedBond2->setPricingEngine(bondEngine);
589
590 Real fixedBondPrice2 = fixedBond2->cleanPrice();
591 AssetSwap fixedBondAssetSwap2(payFixedRate,
592 fixedBond2, fixedBondPrice2,
593 vars.iborIndex, vars.spread,
594 Schedule(),
595 vars.iborIndex->dayCounter(),
596 parAssetSwap);
597 fixedBondAssetSwap2.setPricingEngine(swapEngine);
598 Real fixedBondAssetSwapPrice2 = fixedBondAssetSwap2.fairCleanPrice();
599 Real error2 = std::fabs(x: fixedBondAssetSwapPrice2-fixedBondPrice2);
600
601 if (error2>tolerance2) {
602 BOOST_FAIL("wrong zero spread asset swap price for fixed bond:" <<
603 std::fixed << std::setprecision(4) <<
604 "\n bond's clean price: " << fixedBondPrice2 <<
605 "\n asset swap fair price: " << fixedBondAssetSwapPrice2 <<
606 std::scientific << std::setprecision(2) <<
607 "\n error: " << error2 <<
608 "\n tolerance: " << tolerance2);
609 }
610
611 // FRN Underlying bond (Isin: IT0003543847 ISPIM 0 09/29/13)
612 // maturity doesn't occur on a business day
613
614 Schedule floatingBondSchedule1(Date(29,September,2003),
615 Date(29,September,2013),
616 Period(Semiannual), bondCalendar,
617 Unadjusted, Unadjusted,
618 DateGeneration::Backward, false);
619
620 ext::shared_ptr<Bond> floatingBond1(
621 new FloatingRateBond(settlementDays, vars.faceAmount,
622 floatingBondSchedule1,
623 vars.iborIndex, Actual360(),
624 Following, fixingDays,
625 std::vector<Real>(1,1),
626 std::vector<Spread>(1,0.0056),
627 std::vector<Rate>(),
628 std::vector<Rate>(),
629 inArrears,
630 100.0, Date(29,September,2003)));
631
632 floatingBond1->setPricingEngine(bondEngine);
633
634 setCouponPricer(leg: floatingBond1->cashflows(), vars.pricer);
635 vars.iborIndex->addFixing(fixingDate: Date(27,March,2007), fixing: 0.0402);
636 Real floatingBondPrice1 = floatingBond1->cleanPrice();
637 AssetSwap floatingBondAssetSwap1(payFixedRate,
638 floatingBond1, floatingBondPrice1,
639 vars.iborIndex, vars.spread,
640 Schedule(),
641 vars.iborIndex->dayCounter(),
642 parAssetSwap);
643 floatingBondAssetSwap1.setPricingEngine(swapEngine);
644 Real floatingBondAssetSwapPrice1 = floatingBondAssetSwap1.fairCleanPrice();
645 Real error3 = std::fabs(x: floatingBondAssetSwapPrice1-floatingBondPrice1);
646
647 if (error3>tolerance2) {
648 BOOST_FAIL("wrong zero spread asset swap price for floater:" <<
649 std::fixed << std::setprecision(4) <<
650 "\n bond's clean price: " << floatingBondPrice1 <<
651 "\n asset swap fair price: " << floatingBondAssetSwapPrice1 <<
652 std::scientific << std::setprecision(2) <<
653 "\n error: " << error3 <<
654 "\n tolerance: " << tolerance2);
655 }
656
657 // FRN Underlying bond (Isin: XS0090566539 COE 0 09/24/18)
658 // maturity occurs on a business day
659
660 Schedule floatingBondSchedule2(Date(24,September,2004),
661 Date(24,September,2018),
662 Period(Semiannual), bondCalendar,
663 ModifiedFollowing, ModifiedFollowing,
664 DateGeneration::Backward, false);
665 ext::shared_ptr<Bond> floatingBond2(
666 new FloatingRateBond(settlementDays, vars.faceAmount,
667 floatingBondSchedule2,
668 vars.iborIndex, Actual360(),
669 ModifiedFollowing, fixingDays,
670 std::vector<Real>(1,1),
671 std::vector<Spread>(1,0.0025),
672 std::vector<Rate>(),
673 std::vector<Rate>(),
674 inArrears,
675 100.0, Date(24,September,2004)));
676
677 floatingBond2->setPricingEngine(bondEngine);
678
679 setCouponPricer(leg: floatingBond2->cashflows(), vars.pricer);
680 vars.iborIndex->addFixing(fixingDate: Date(22,March,2007), fixing: 0.04013);
681 Real currentCoupon=0.04013+0.0025;
682 Rate floatingCurrentCoupon= floatingBond2->nextCouponRate();
683 Real error4= std::fabs(x: floatingCurrentCoupon-currentCoupon);
684 if (error4>tolerance) {
685 BOOST_FAIL("wrong current coupon is returned for floater bond:" <<
686 std::fixed << std::setprecision(4) <<
687 "\n bond's calculated current coupon: " <<
688 currentCoupon <<
689 "\n current coupon asked to the bond: " <<
690 floatingCurrentCoupon <<
691 std::scientific << std::setprecision(2) <<
692 "\n error: " << error4 <<
693 "\n tolerance: " << tolerance);
694 }
695
696 Real floatingBondPrice2 = floatingBond2->cleanPrice();
697 AssetSwap floatingBondAssetSwap2(payFixedRate,
698 floatingBond2, floatingBondPrice2,
699 vars.iborIndex, vars.spread,
700 Schedule(),
701 vars.iborIndex->dayCounter(),
702 parAssetSwap);
703 floatingBondAssetSwap2.setPricingEngine(swapEngine);
704 Real floatingBondAssetSwapPrice2 = floatingBondAssetSwap2.fairCleanPrice();
705 Real error5 = std::fabs(x: floatingBondAssetSwapPrice2-floatingBondPrice2);
706
707 if (error5>tolerance2) {
708 BOOST_FAIL("wrong zero spread asset swap price for floater:" <<
709 std::fixed << std::setprecision(4) <<
710 "\n bond's clean price: " << floatingBondPrice2 <<
711 "\n asset swap fair price: " << floatingBondAssetSwapPrice2 <<
712 std::scientific << std::setprecision(2) <<
713 "\n error: " << error5 <<
714 "\n tolerance: " << tolerance2);
715 }
716
717 // CMS Underlying bond (Isin: XS0228052402 CRDIT 0 8/22/20)
718 // maturity doesn't occur on a business day
719
720 Schedule cmsBondSchedule1(Date(22,August,2005),
721 Date(22,August,2020),
722 Period(Annual), bondCalendar,
723 Unadjusted, Unadjusted,
724 DateGeneration::Backward, false);
725 ext::shared_ptr<Bond> cmsBond1(
726 new CmsRateBond(settlementDays, vars.faceAmount,
727 cmsBondSchedule1,
728 vars.swapIndex, Thirty360(Thirty360::BondBasis),
729 Following, fixingDays,
730 std::vector<Real>(1,1.0),
731 std::vector<Spread>(1,0.0),
732 std::vector<Rate>(1,0.055),
733 std::vector<Rate>(1,0.025),
734 inArrears,
735 100.0, Date(22,August,2005)));
736
737 cmsBond1->setPricingEngine(bondEngine);
738
739 setCouponPricer(leg: cmsBond1->cashflows(), vars.cmspricer);
740 vars.swapIndex->addFixing(fixingDate: Date(18,August,2006), fixing: 0.04158);
741 Real cmsBondPrice1 = cmsBond1->cleanPrice();
742 AssetSwap cmsBondAssetSwap1(payFixedRate,
743 cmsBond1, cmsBondPrice1,
744 vars.iborIndex, vars.spread,
745 Schedule(),
746 vars.iborIndex->dayCounter(),
747 parAssetSwap);
748 cmsBondAssetSwap1.setPricingEngine(swapEngine);
749 Real cmsBondAssetSwapPrice1 = cmsBondAssetSwap1.fairCleanPrice();
750 Real error6 = std::fabs(x: cmsBondAssetSwapPrice1-cmsBondPrice1);
751
752 if (error6>tolerance2) {
753 BOOST_FAIL("wrong zero spread asset swap price for cms bond:" <<
754 std::fixed << std::setprecision(4) <<
755 "\n bond's clean price: " << cmsBondPrice1 <<
756 "\n asset swap fair price: " << cmsBondAssetSwapPrice1 <<
757 std::scientific << std::setprecision(2) <<
758 "\n error: " << error6 <<
759 "\n tolerance: " << tolerance2);
760 }
761
762 // CMS Underlying bond (Isin: XS0218766664 ISPIM 0 5/6/15)
763 // maturity occurs on a business day
764
765 Schedule cmsBondSchedule2(Date(06,May,2005),
766 Date(06,May,2015),
767 Period(Annual), bondCalendar,
768 Unadjusted, Unadjusted,
769 DateGeneration::Backward, false);
770 ext::shared_ptr<Bond> cmsBond2(new
771 CmsRateBond(settlementDays, vars.faceAmount, cmsBondSchedule2,
772 vars.swapIndex, Thirty360(Thirty360::BondBasis),
773 Following, fixingDays,
774 std::vector<Real>(1,0.84), std::vector<Spread>(1,0.0),
775 std::vector<Rate>(), std::vector<Rate>(),
776 inArrears,
777 100.0, Date(06,May,2005)));
778
779 cmsBond2->setPricingEngine(bondEngine);
780
781 setCouponPricer(leg: cmsBond2->cashflows(), vars.cmspricer);
782 vars.swapIndex->addFixing(fixingDate: Date(04,May,2006), fixing: 0.04217);
783 Real cmsBondPrice2 = cmsBond2->cleanPrice();
784 AssetSwap cmsBondAssetSwap2(payFixedRate,
785 cmsBond2, cmsBondPrice2,
786 vars.iborIndex, vars.spread,
787 Schedule(),
788 vars.iborIndex->dayCounter(),
789 parAssetSwap);
790 cmsBondAssetSwap2.setPricingEngine(swapEngine);
791 Real cmsBondAssetSwapPrice2 = cmsBondAssetSwap2.fairCleanPrice();
792 Real error7 = std::fabs(x: cmsBondAssetSwapPrice2-cmsBondPrice2);
793
794 if (error7>tolerance2) {
795 BOOST_FAIL("wrong zero spread asset swap price for cms bond:" <<
796 std::fixed << std::setprecision(4) <<
797 "\n bond's clean price: " << cmsBondPrice2 <<
798 "\n asset swap fair price: " << cmsBondAssetSwapPrice2 <<
799 std::scientific << std::setprecision(2) <<
800 "\n error: " << error7 <<
801 "\n tolerance: " << tolerance2);
802 }
803
804 // Zero Coupon bond (Isin: DE0004771662 IBRD 0 12/20/15)
805 // maturity doesn't occur on a business day
806
807 ext::shared_ptr<Bond> zeroCpnBond1(new
808 ZeroCouponBond(settlementDays, bondCalendar, vars.faceAmount,
809 Date(20,December,2015),
810 Following,
811 100.0, Date(19,December,1985)));
812
813 zeroCpnBond1->setPricingEngine(bondEngine);
814
815 Real zeroCpnBondPrice1 = zeroCpnBond1->cleanPrice();
816 AssetSwap zeroCpnAssetSwap1(payFixedRate,
817 zeroCpnBond1, zeroCpnBondPrice1,
818 vars.iborIndex, vars.spread,
819 Schedule(),
820 vars.iborIndex->dayCounter(),
821 parAssetSwap);
822 zeroCpnAssetSwap1.setPricingEngine(swapEngine);
823 Real zeroCpnBondAssetSwapPrice1 = zeroCpnAssetSwap1.fairCleanPrice();
824 Real error8 = std::fabs(x: cmsBondAssetSwapPrice1-cmsBondPrice1);
825
826 if (error8>tolerance2) {
827 BOOST_FAIL("wrong zero spread asset swap price for zero cpn bond:" <<
828 std::fixed << std::setprecision(4) <<
829 "\n bond's clean price: " << zeroCpnBondPrice1 <<
830 "\n asset swap fair price: " << zeroCpnBondAssetSwapPrice1 <<
831 std::scientific << std::setprecision(2) <<
832 "\n error: " << error8 <<
833 "\n tolerance: " << tolerance2);
834 }
835
836 // Zero Coupon bond (Isin: IT0001200390 ISPIM 0 02/17/28)
837 // maturity occurs on a business day
838
839 ext::shared_ptr<Bond> zeroCpnBond2(new
840 ZeroCouponBond(settlementDays, bondCalendar, vars.faceAmount,
841 Date(17,February,2028),
842 Following,
843 100.0, Date(17,February,1998)));
844
845 zeroCpnBond2->setPricingEngine(bondEngine);
846
847 Real zeroCpnBondPrice2 = zeroCpnBond2->cleanPrice();
848 AssetSwap zeroCpnAssetSwap2(payFixedRate,
849 zeroCpnBond2, zeroCpnBondPrice2,
850 vars.iborIndex, vars.spread,
851 Schedule(),
852 vars.iborIndex->dayCounter(),
853 parAssetSwap);
854 zeroCpnAssetSwap2.setPricingEngine(swapEngine);
855 Real zeroCpnBondAssetSwapPrice2 = zeroCpnAssetSwap2.fairCleanPrice();
856 Real error9 = std::fabs(x: cmsBondAssetSwapPrice2-cmsBondPrice2);
857
858 if (error9>tolerance2) {
859 BOOST_FAIL("wrong zero spread asset swap price for zero cpn bond:" <<
860 std::fixed << std::setprecision(4) <<
861 "\n bond's clean price: " << zeroCpnBondPrice2 <<
862 "\n asset swap fair price: " << zeroCpnBondAssetSwapPrice2 <<
863 std::scientific << std::setprecision(2) <<
864 "\n error: " << error9 <<
865 "\n tolerance: " << tolerance2);
866 }
867}
868
869
870void AssetSwapTest::testMarketASWSpread() {
871
872 BOOST_TEST_MESSAGE("Testing relationship between market asset swap"
873 " and par asset swap...");
874
875 using namespace asset_swap_test;
876
877 bool usingAtParCoupons = IborCoupon::Settings::instance().usingAtParCoupons();
878
879 CommonVars vars;
880
881 Calendar bondCalendar = TARGET();
882 Natural settlementDays = 3;
883 Natural fixingDays = 2;
884 bool payFixedRate = true;
885 bool parAssetSwap = true;
886 bool mktAssetSwap = false;
887 bool inArrears = false;
888
889 // Fixed Underlying bond (Isin: DE0001135275 DBR 4 01/04/37)
890 // maturity doesn't occur on a business day
891
892 Schedule fixedBondSchedule1(Date(4,January,2005),
893 Date(4,January,2037),
894 Period(Annual), bondCalendar,
895 Unadjusted, Unadjusted,
896 DateGeneration::Backward, false);
897 ext::shared_ptr<Bond> fixedBond1(new
898 FixedRateBond(settlementDays, vars.faceAmount, fixedBondSchedule1,
899 std::vector<Rate>(1, 0.04),
900 ActualActual(ActualActual::ISDA), Following,
901 100.0, Date(4,January,2005)));
902
903 ext::shared_ptr<PricingEngine> bondEngine(
904 new DiscountingBondEngine(vars.termStructure));
905 ext::shared_ptr<PricingEngine> swapEngine(
906 new DiscountingSwapEngine(vars.termStructure));
907 fixedBond1->setPricingEngine(bondEngine);
908
909 Real fixedBondMktPrice1 = 89.22 ; // market price observed on 7th June 2007
910 Real fixedBondMktFullPrice1=fixedBondMktPrice1+fixedBond1->accruedAmount();
911 AssetSwap fixedBondParAssetSwap1(payFixedRate,
912 fixedBond1, fixedBondMktPrice1,
913 vars.iborIndex, vars.spread,
914 Schedule(),
915 vars.iborIndex->dayCounter(),
916 parAssetSwap);
917 fixedBondParAssetSwap1.setPricingEngine(swapEngine);
918 Real fixedBondParAssetSwapSpread1 = fixedBondParAssetSwap1.fairSpread();
919 AssetSwap fixedBondMktAssetSwap1(payFixedRate,
920 fixedBond1, fixedBondMktPrice1,
921 vars.iborIndex, vars.spread,
922 Schedule(),
923 vars.iborIndex->dayCounter(),
924 mktAssetSwap);
925 fixedBondMktAssetSwap1.setPricingEngine(swapEngine);
926 Real fixedBondMktAssetSwapSpread1 = fixedBondMktAssetSwap1.fairSpread();
927
928 // see comment above
929 Real tolerance2 = usingAtParCoupons ? 1.0e-13 : 1.0e-4;
930
931 Real error1 =
932 std::fabs(x: fixedBondMktAssetSwapSpread1-
933 100*fixedBondParAssetSwapSpread1/fixedBondMktFullPrice1);
934
935 if (error1>tolerance2) {
936 BOOST_FAIL("wrong asset swap spreads for fixed bond:" <<
937 std::fixed << std::setprecision(4) <<
938 "\n market ASW spread: " << io::rate(fixedBondMktAssetSwapSpread1) <<
939 "\n par ASW spread: " << io::rate(fixedBondParAssetSwapSpread1) <<
940 std::scientific << std::setprecision(2) <<
941 "\n error: " << error1 <<
942 "\n tolerance: " << tolerance2);
943 }
944
945 // Fixed Underlying bond (Isin: IT0006527060 IBRD 5 02/05/19)
946 // maturity occurs on a business day
947
948 Schedule fixedBondSchedule2(Date(5,February,2005),
949 Date(5,February,2019),
950 Period(Annual), bondCalendar,
951 Unadjusted, Unadjusted,
952 DateGeneration::Backward, false);
953 ext::shared_ptr<Bond> fixedBond2(new
954 FixedRateBond(settlementDays, vars.faceAmount, fixedBondSchedule2,
955 std::vector<Rate>(1, 0.05),
956 Thirty360(Thirty360::BondBasis), Following,
957 100.0, Date(5,February,2005)));
958
959 fixedBond2->setPricingEngine(bondEngine);
960
961 Real fixedBondMktPrice2 = 99.98 ; // market price observed on 7th June 2007
962 Real fixedBondMktFullPrice2=fixedBondMktPrice2+fixedBond2->accruedAmount();
963 AssetSwap fixedBondParAssetSwap2(payFixedRate,
964 fixedBond2, fixedBondMktPrice2,
965 vars.iborIndex, vars.spread,
966 Schedule(),
967 vars.iborIndex->dayCounter(),
968 parAssetSwap);
969 fixedBondParAssetSwap2.setPricingEngine(swapEngine);
970 Real fixedBondParAssetSwapSpread2 = fixedBondParAssetSwap2.fairSpread();
971 AssetSwap fixedBondMktAssetSwap2(payFixedRate,
972 fixedBond2, fixedBondMktPrice2,
973 vars.iborIndex, vars.spread,
974 Schedule(),
975 vars.iborIndex->dayCounter(),
976 mktAssetSwap);
977 fixedBondMktAssetSwap2.setPricingEngine(swapEngine);
978 Real fixedBondMktAssetSwapSpread2 = fixedBondMktAssetSwap2.fairSpread();
979 Real error2 =
980 std::fabs(x: fixedBondMktAssetSwapSpread2-
981 100*fixedBondParAssetSwapSpread2/fixedBondMktFullPrice2);
982
983 if (error2>tolerance2) {
984 BOOST_FAIL("wrong asset swap spreads for fixed bond:" <<
985 std::fixed << std::setprecision(4) <<
986 "\n market ASW spread: " << io::rate(fixedBondMktAssetSwapSpread2) <<
987 "\n par ASW spread: " << io::rate(fixedBondParAssetSwapSpread2) <<
988 std::scientific << std::setprecision(2) <<
989 "\n error: " << error2 <<
990 "\n tolerance: " << tolerance2);
991 }
992
993 // FRN Underlying bond (Isin: IT0003543847 ISPIM 0 09/29/13)
994 // maturity doesn't occur on a business day
995
996 Schedule floatingBondSchedule1(Date(29,September,2003),
997 Date(29,September,2013),
998 Period(Semiannual), bondCalendar,
999 Unadjusted, Unadjusted,
1000 DateGeneration::Backward, false);
1001
1002 ext::shared_ptr<Bond> floatingBond1(new
1003 FloatingRateBond(settlementDays, vars.faceAmount,
1004 floatingBondSchedule1,
1005 vars.iborIndex, Actual360(),
1006 Following, fixingDays,
1007 std::vector<Real>(1,1), std::vector<Spread>(1,0.0056),
1008 std::vector<Rate>(), std::vector<Rate>(),
1009 inArrears,
1010 100.0, Date(29,September,2003)));
1011
1012 floatingBond1->setPricingEngine(bondEngine);
1013
1014 setCouponPricer(leg: floatingBond1->cashflows(), vars.pricer);
1015 vars.iborIndex->addFixing(fixingDate: Date(27,March,2007), fixing: 0.0402);
1016 // market price observed on 7th June 2007
1017 Real floatingBondMktPrice1 = 101.64 ;
1018 Real floatingBondMktFullPrice1 =
1019 floatingBondMktPrice1+floatingBond1->accruedAmount();
1020 AssetSwap floatingBondParAssetSwap1(payFixedRate,
1021 floatingBond1, floatingBondMktPrice1,
1022 vars.iborIndex, vars.spread,
1023 Schedule(),
1024 vars.iborIndex->dayCounter(),
1025 parAssetSwap);
1026 floatingBondParAssetSwap1.setPricingEngine(swapEngine);
1027 Real floatingBondParAssetSwapSpread1 =
1028 floatingBondParAssetSwap1.fairSpread();
1029 AssetSwap floatingBondMktAssetSwap1(payFixedRate,
1030 floatingBond1, floatingBondMktPrice1,
1031 vars.iborIndex, vars.spread,
1032 Schedule(),
1033 vars.iborIndex->dayCounter(),
1034 mktAssetSwap);
1035 floatingBondMktAssetSwap1.setPricingEngine(swapEngine);
1036 Real floatingBondMktAssetSwapSpread1 =
1037 floatingBondMktAssetSwap1.fairSpread();
1038 Real error3 =
1039 std::fabs(x: floatingBondMktAssetSwapSpread1-
1040 100*floatingBondParAssetSwapSpread1/floatingBondMktFullPrice1);
1041
1042 if (error3>tolerance2) {
1043 BOOST_FAIL("wrong asset swap spreads for floating bond:" <<
1044 std::fixed << std::setprecision(4) <<
1045 "\n market ASW spread: " << io::rate(floatingBondMktAssetSwapSpread1) <<
1046 "\n par ASW spread: " << io::rate(floatingBondParAssetSwapSpread1) <<
1047 std::scientific << std::setprecision(2) <<
1048 "\n error: " << error3 <<
1049 "\n tolerance: " << tolerance2);
1050 }
1051
1052 // FRN Underlying bond (Isin: XS0090566539 COE 0 09/24/18)
1053 // maturity occurs on a business day
1054
1055 Schedule floatingBondSchedule2(Date(24,September,2004),
1056 Date(24,September,2018),
1057 Period(Semiannual), bondCalendar,
1058 ModifiedFollowing, ModifiedFollowing,
1059 DateGeneration::Backward, false);
1060 ext::shared_ptr<Bond> floatingBond2(new
1061 FloatingRateBond(settlementDays, vars.faceAmount,
1062 floatingBondSchedule2,
1063 vars.iborIndex, Actual360(),
1064 ModifiedFollowing, fixingDays,
1065 std::vector<Real>(1,1), std::vector<Spread>(1,0.0025),
1066 std::vector<Rate>(), std::vector<Rate>(),
1067 inArrears,
1068 100.0, Date(24,September,2004)));
1069
1070 floatingBond2->setPricingEngine(bondEngine);
1071
1072 setCouponPricer(leg: floatingBond2->cashflows(), vars.pricer);
1073 vars.iborIndex->addFixing(fixingDate: Date(22,March,2007), fixing: 0.04013);
1074 // market price observed on 7th June 2007
1075 Real floatingBondMktPrice2 = 101.248 ;
1076 Real floatingBondMktFullPrice2 =
1077 floatingBondMktPrice2+floatingBond2->accruedAmount();
1078 AssetSwap floatingBondParAssetSwap2(payFixedRate,
1079 floatingBond2, floatingBondMktPrice2,
1080 vars.iborIndex, vars.spread,
1081 Schedule(),
1082 vars.iborIndex->dayCounter(),
1083 parAssetSwap);
1084 floatingBondParAssetSwap2.setPricingEngine(swapEngine);
1085 Spread floatingBondParAssetSwapSpread2 =
1086 floatingBondParAssetSwap2.fairSpread();
1087 AssetSwap floatingBondMktAssetSwap2(payFixedRate,
1088 floatingBond2, floatingBondMktPrice2,
1089 vars.iborIndex, vars.spread,
1090 Schedule(),
1091 vars.iborIndex->dayCounter(),
1092 mktAssetSwap);
1093 floatingBondMktAssetSwap2.setPricingEngine(swapEngine);
1094 Real floatingBondMktAssetSwapSpread2 =
1095 floatingBondMktAssetSwap2.fairSpread();
1096 Real error4 =
1097 std::fabs(x: floatingBondMktAssetSwapSpread2-
1098 100*floatingBondParAssetSwapSpread2/floatingBondMktFullPrice2);
1099
1100 if (error4>tolerance2) {
1101 BOOST_FAIL("wrong asset swap spreads for floating bond:" <<
1102 std::fixed << std::setprecision(4) <<
1103 "\n market ASW spread: " << io::rate(floatingBondMktAssetSwapSpread2) <<
1104 "\n par ASW spread: " << io::rate(floatingBondParAssetSwapSpread2) <<
1105 std::scientific << std::setprecision(2) <<
1106 "\n error: " << error4 <<
1107 "\n tolerance: " << tolerance2);
1108 }
1109
1110 // CMS Underlying bond (Isin: XS0228052402 CRDIT 0 8/22/20)
1111 // maturity doesn't occur on a business day
1112
1113 Schedule cmsBondSchedule1(Date(22,August,2005),
1114 Date(22,August,2020),
1115 Period(Annual), bondCalendar,
1116 Unadjusted, Unadjusted,
1117 DateGeneration::Backward, false);
1118 ext::shared_ptr<Bond> cmsBond1(new
1119 CmsRateBond(settlementDays, vars.faceAmount, cmsBondSchedule1,
1120 vars.swapIndex, Thirty360(Thirty360::BondBasis),
1121 Following, fixingDays,
1122 std::vector<Real>(1,1.0), std::vector<Spread>(1,0.0),
1123 std::vector<Rate>(1,0.055), std::vector<Rate>(1,0.025),
1124 inArrears,
1125 100.0, Date(22,August,2005)));
1126
1127 cmsBond1->setPricingEngine(bondEngine);
1128
1129 setCouponPricer(leg: cmsBond1->cashflows(), vars.cmspricer);
1130 vars.swapIndex->addFixing(fixingDate: Date(18,August,2006), fixing: 0.04158);
1131 Real cmsBondMktPrice1 = 88.45 ; // market price observed on 7th June 2007
1132 Real cmsBondMktFullPrice1 = cmsBondMktPrice1+cmsBond1->accruedAmount();
1133 AssetSwap cmsBondParAssetSwap1(payFixedRate,
1134 cmsBond1, cmsBondMktPrice1,
1135 vars.iborIndex, vars.spread,
1136 Schedule(),
1137 vars.iborIndex->dayCounter(),
1138 parAssetSwap);
1139 cmsBondParAssetSwap1.setPricingEngine(swapEngine);
1140 Real cmsBondParAssetSwapSpread1 = cmsBondParAssetSwap1.fairSpread();
1141 AssetSwap cmsBondMktAssetSwap1(payFixedRate,
1142 cmsBond1, cmsBondMktPrice1,
1143 vars.iborIndex, vars.spread,
1144 Schedule(),
1145 vars.iborIndex->dayCounter(),
1146 mktAssetSwap);
1147 cmsBondMktAssetSwap1.setPricingEngine(swapEngine);
1148 Real cmsBondMktAssetSwapSpread1 = cmsBondMktAssetSwap1.fairSpread();
1149 Real error5 =
1150 std::fabs(x: cmsBondMktAssetSwapSpread1-
1151 100*cmsBondParAssetSwapSpread1/cmsBondMktFullPrice1);
1152
1153 if (error5>tolerance2) {
1154 BOOST_FAIL("wrong asset swap spreads for cms bond:" <<
1155 std::fixed << std::setprecision(4) <<
1156 "\n market ASW spread: " << io::rate(cmsBondMktAssetSwapSpread1) <<
1157 "\n par ASW spread: " << io::rate(cmsBondParAssetSwapSpread1) <<
1158 std::scientific << std::setprecision(2) <<
1159 "\n error: " << error5 <<
1160 "\n tolerance: " << tolerance2);
1161 }
1162
1163 // CMS Underlying bond (Isin: XS0218766664 ISPIM 0 5/6/15)
1164 // maturity occurs on a business day
1165
1166 Schedule cmsBondSchedule2(Date(06,May,2005),
1167 Date(06,May,2015),
1168 Period(Annual), bondCalendar,
1169 Unadjusted, Unadjusted,
1170 DateGeneration::Backward, false);
1171 ext::shared_ptr<Bond> cmsBond2(new
1172 CmsRateBond(settlementDays, vars.faceAmount, cmsBondSchedule2,
1173 vars.swapIndex, Thirty360(Thirty360::BondBasis),
1174 Following, fixingDays,
1175 std::vector<Real>(1,0.84), std::vector<Spread>(1,0.0),
1176 std::vector<Rate>(), std::vector<Rate>(),
1177 inArrears,
1178 100.0, Date(06,May,2005)));
1179
1180 cmsBond2->setPricingEngine(bondEngine);
1181
1182 setCouponPricer(leg: cmsBond2->cashflows(), vars.cmspricer);
1183 vars.swapIndex->addFixing(fixingDate: Date(04,May,2006), fixing: 0.04217);
1184 Real cmsBondMktPrice2 = 94.08 ; // market price observed on 7th June 2007
1185 Real cmsBondMktFullPrice2 = cmsBondMktPrice2+cmsBond2->accruedAmount();
1186 AssetSwap cmsBondParAssetSwap2(payFixedRate,
1187 cmsBond2, cmsBondMktPrice2,
1188 vars.iborIndex, vars.spread,
1189 Schedule(),
1190 vars.iborIndex->dayCounter(),
1191 parAssetSwap);
1192 cmsBondParAssetSwap2.setPricingEngine(swapEngine);
1193 Spread cmsBondParAssetSwapSpread2 = cmsBondParAssetSwap2.fairSpread();
1194 AssetSwap cmsBondMktAssetSwap2(payFixedRate,
1195 cmsBond2, cmsBondMktPrice2,
1196 vars.iborIndex, vars.spread,
1197 Schedule(),
1198 vars.iborIndex->dayCounter(),
1199 mktAssetSwap);
1200 cmsBondMktAssetSwap2.setPricingEngine(swapEngine);
1201 Real cmsBondMktAssetSwapSpread2 = cmsBondMktAssetSwap2.fairSpread();
1202 Real error6 =
1203 std::fabs(x: cmsBondMktAssetSwapSpread2-
1204 100*cmsBondParAssetSwapSpread2/cmsBondMktFullPrice2);
1205
1206 if (error6>tolerance2) {
1207 BOOST_FAIL("wrong asset swap spreads for cms bond:" <<
1208 std::fixed << std::setprecision(4) <<
1209 "\n market ASW spread: " << io::rate(cmsBondMktAssetSwapSpread2) <<
1210 "\n par ASW spread: " << io::rate(cmsBondParAssetSwapSpread2) <<
1211 std::scientific << std::setprecision(2) <<
1212 "\n error: " << error6 <<
1213 "\n tolerance: " << tolerance2);
1214 }
1215
1216 // Zero Coupon bond (Isin: DE0004771662 IBRD 0 12/20/15)
1217 // maturity doesn't occur on a business day
1218
1219 ext::shared_ptr<Bond> zeroCpnBond1(new
1220 ZeroCouponBond(settlementDays, bondCalendar, vars.faceAmount,
1221 Date(20,December,2015),
1222 Following,
1223 100.0, Date(19,December,1985)));
1224
1225 zeroCpnBond1->setPricingEngine(bondEngine);
1226
1227 // market price observed on 12th June 2007
1228 Real zeroCpnBondMktPrice1 = 70.436 ;
1229 Real zeroCpnBondMktFullPrice1 =
1230 zeroCpnBondMktPrice1+zeroCpnBond1->accruedAmount();
1231 AssetSwap zeroCpnBondParAssetSwap1(payFixedRate,zeroCpnBond1,
1232 zeroCpnBondMktPrice1,
1233 vars.iborIndex, vars.spread,
1234 Schedule(),
1235 vars.iborIndex->dayCounter(),
1236 parAssetSwap);
1237 zeroCpnBondParAssetSwap1.setPricingEngine(swapEngine);
1238 Real zeroCpnBondParAssetSwapSpread1 = zeroCpnBondParAssetSwap1.fairSpread();
1239 AssetSwap zeroCpnBondMktAssetSwap1(payFixedRate,zeroCpnBond1,
1240 zeroCpnBondMktPrice1,
1241 vars.iborIndex, vars.spread,
1242 Schedule(),
1243 vars.iborIndex->dayCounter(),
1244 mktAssetSwap);
1245 zeroCpnBondMktAssetSwap1.setPricingEngine(swapEngine);
1246 Real zeroCpnBondMktAssetSwapSpread1 = zeroCpnBondMktAssetSwap1.fairSpread();
1247 Real error7 =
1248 std::fabs(x: zeroCpnBondMktAssetSwapSpread1-
1249 100*zeroCpnBondParAssetSwapSpread1/zeroCpnBondMktFullPrice1);
1250
1251 if (error7>tolerance2) {
1252 BOOST_FAIL("wrong asset swap spreads for zero cpn bond:" <<
1253 std::fixed << std::setprecision(4) <<
1254 "\n market ASW spread: " << io::rate(zeroCpnBondMktAssetSwapSpread1) <<
1255 "\n par ASW spread: " << io::rate(zeroCpnBondParAssetSwapSpread1) <<
1256 std::scientific << std::setprecision(2) <<
1257 "\n error: " << error7 <<
1258 "\n tolerance: " << tolerance2);
1259 }
1260
1261 // Zero Coupon bond (Isin: IT0001200390 ISPIM 0 02/17/28)
1262 // maturity occurs on a business day
1263
1264 ext::shared_ptr<Bond> zeroCpnBond2(new
1265 ZeroCouponBond(settlementDays, bondCalendar, vars.faceAmount,
1266 Date(17,February,2028),
1267 Following,
1268 100.0, Date(17,February,1998)));
1269
1270 zeroCpnBond2->setPricingEngine(bondEngine);
1271
1272 // Real zeroCpnBondPrice2 = zeroCpnBond2->cleanPrice();
1273
1274 // market price observed on 12th June 2007
1275 Real zeroCpnBondMktPrice2 = 35.160 ;
1276 Real zeroCpnBondMktFullPrice2 =
1277 zeroCpnBondMktPrice2+zeroCpnBond2->accruedAmount();
1278 AssetSwap zeroCpnBondParAssetSwap2(payFixedRate,zeroCpnBond2,
1279 zeroCpnBondMktPrice2,
1280 vars.iborIndex, vars.spread,
1281 Schedule(),
1282 vars.iborIndex->dayCounter(),
1283 parAssetSwap);
1284 zeroCpnBondParAssetSwap2.setPricingEngine(swapEngine);
1285 Real zeroCpnBondParAssetSwapSpread2 = zeroCpnBondParAssetSwap2.fairSpread();
1286 AssetSwap zeroCpnBondMktAssetSwap2(payFixedRate,zeroCpnBond2,
1287 zeroCpnBondMktPrice2,
1288 vars.iborIndex, vars.spread,
1289 Schedule(),
1290 vars.iborIndex->dayCounter(),
1291 mktAssetSwap);
1292 zeroCpnBondMktAssetSwap2.setPricingEngine(swapEngine);
1293 Real zeroCpnBondMktAssetSwapSpread2 = zeroCpnBondMktAssetSwap2.fairSpread();
1294 Real error8 =
1295 std::fabs(x: zeroCpnBondMktAssetSwapSpread2-
1296 100*zeroCpnBondParAssetSwapSpread2/zeroCpnBondMktFullPrice2);
1297
1298 if (error8>tolerance2) {
1299 BOOST_FAIL("wrong asset swap spreads for zero cpn bond:" <<
1300 std::fixed << std::setprecision(4) <<
1301 "\n market ASW spread: " << io::rate(zeroCpnBondMktAssetSwapSpread2) <<
1302 "\n par ASW spread: " << io::rate(zeroCpnBondParAssetSwapSpread2) <<
1303 std::scientific << std::setprecision(2) <<
1304 "\n error: " << error8 <<
1305 "\n tolerance: " << tolerance2);
1306 }
1307}
1308
1309
1310void AssetSwapTest::testZSpread() {
1311
1312 BOOST_TEST_MESSAGE("Testing clean and dirty price with null Z-spread "
1313 "against theoretical prices...");
1314
1315 using namespace asset_swap_test;
1316
1317 CommonVars vars;
1318
1319 Calendar bondCalendar = TARGET();
1320 Natural settlementDays = 3;
1321 Natural fixingDays = 2;
1322 bool inArrears = false;
1323
1324 // Fixed bond (Isin: DE0001135275 DBR 4 01/04/37)
1325 // maturity doesn't occur on a business day
1326
1327 Schedule fixedBondSchedule1(Date(4,January,2005),
1328 Date(4,January,2037),
1329 Period(Annual), bondCalendar,
1330 Unadjusted, Unadjusted,
1331 DateGeneration::Backward, false);
1332 ext::shared_ptr<Bond> fixedBond1(new
1333 FixedRateBond(settlementDays, vars.faceAmount, fixedBondSchedule1,
1334 std::vector<Rate>(1, 0.04),
1335 ActualActual(ActualActual::ISDA), Following,
1336 100.0, Date(4,January,2005)));
1337
1338 ext::shared_ptr<PricingEngine> bondEngine(
1339 new DiscountingBondEngine(vars.termStructure));
1340 fixedBond1->setPricingEngine(bondEngine);
1341
1342 Real fixedBondImpliedValue1 = fixedBond1->cleanPrice();
1343 Date fixedBondSettlementDate1= fixedBond1->settlementDate();
1344 // standard market conventions:
1345 // bond's frequency + coumpounding and daycounter of the YC...
1346 Real fixedBondCleanPrice1 = BondFunctions::cleanPrice(
1347 bond: *fixedBond1, discount: *vars.termStructure, zSpread: vars.spread,
1348 dayCounter: Actual365Fixed(), compounding: vars.compounding, frequency: Annual,
1349 settlementDate: fixedBondSettlementDate1);
1350 Real tolerance = 1.0e-13;
1351 Real error1 = std::fabs(x: fixedBondImpliedValue1-fixedBondCleanPrice1);
1352 if (error1>tolerance) {
1353 BOOST_FAIL("wrong clean price for fixed bond:" <<
1354 std::fixed << std::setprecision(4) <<
1355 "\n market asset swap spread: " <<
1356 fixedBondImpliedValue1 <<
1357 "\n par asset swap spread: " << fixedBondCleanPrice1 <<
1358 std::scientific << std::setprecision(2) <<
1359 "\n error: " << error1 <<
1360 "\n tolerance: " << tolerance);
1361 }
1362
1363 // Fixed bond (Isin: IT0006527060 IBRD 5 02/05/19)
1364 // maturity occurs on a business day
1365
1366 Schedule fixedBondSchedule2(Date(5,February,2005),
1367 Date(5,February,2019),
1368 Period(Annual), bondCalendar,
1369 Unadjusted, Unadjusted,
1370 DateGeneration::Backward, false);
1371 ext::shared_ptr<Bond> fixedBond2(new
1372 FixedRateBond(settlementDays, vars.faceAmount, fixedBondSchedule2,
1373 std::vector<Rate>(1, 0.05),
1374 Thirty360(Thirty360::BondBasis), Following,
1375 100.0, Date(5,February,2005)));
1376
1377 fixedBond2->setPricingEngine(bondEngine);
1378
1379 Real fixedBondImpliedValue2 = fixedBond2->cleanPrice();
1380 Date fixedBondSettlementDate2= fixedBond2->settlementDate();
1381 // standard market conventions:
1382 // bond's frequency + coumpounding and daycounter of the YieldCurve
1383 Real fixedBondCleanPrice2 = BondFunctions::cleanPrice(
1384 bond: *fixedBond2, discount: *vars.termStructure, zSpread: vars.spread,
1385 dayCounter: Actual365Fixed(), compounding: vars.compounding, frequency: Annual,
1386 settlementDate: fixedBondSettlementDate2);
1387 Real error3 = std::fabs(x: fixedBondImpliedValue2-fixedBondCleanPrice2);
1388 if (error3>tolerance) {
1389 BOOST_FAIL("wrong clean price for fixed bond:" <<
1390 std::fixed << std::setprecision(4) <<
1391 "\n market asset swap spread: " <<
1392 fixedBondImpliedValue2 <<
1393 "\n par asset swap spread: " << fixedBondCleanPrice2 <<
1394 std::scientific << std::setprecision(2) <<
1395 "\n error: " << error3 <<
1396 "\n tolerance: " << tolerance);
1397 }
1398
1399 // FRN bond (Isin: IT0003543847 ISPIM 0 09/29/13)
1400 // maturity doesn't occur on a business day
1401
1402 Schedule floatingBondSchedule1(Date(29,September,2003),
1403 Date(29,September,2013),
1404 Period(Semiannual), bondCalendar,
1405 Unadjusted, Unadjusted,
1406 DateGeneration::Backward, false);
1407
1408 ext::shared_ptr<Bond> floatingBond1(new
1409 FloatingRateBond(settlementDays, vars.faceAmount,
1410 floatingBondSchedule1,
1411 vars.iborIndex, Actual360(),
1412 Following, fixingDays,
1413 std::vector<Real>(1,1), std::vector<Spread>(1,0.0056),
1414 std::vector<Rate>(), std::vector<Rate>(),
1415 inArrears,
1416 100.0, Date(29,September,2003)));
1417
1418 floatingBond1->setPricingEngine(bondEngine);
1419
1420 setCouponPricer(leg: floatingBond1->cashflows(), vars.pricer);
1421 vars.iborIndex->addFixing(fixingDate: Date(27,March,2007), fixing: 0.0402);
1422 Real floatingBondImpliedValue1 = floatingBond1->cleanPrice();
1423 // standard market conventions:
1424 // bond's frequency + coumpounding and daycounter of the YieldCurve
1425 Real floatingBondCleanPrice1 = BondFunctions::cleanPrice(
1426 bond: *floatingBond1, discount: *vars.termStructure, zSpread: vars.spread,
1427 dayCounter: Actual365Fixed(), compounding: vars.compounding, frequency: Semiannual,
1428 settlementDate: fixedBondSettlementDate1);
1429 Real error5 = std::fabs(x: floatingBondImpliedValue1-floatingBondCleanPrice1);
1430 if (error5>tolerance) {
1431 BOOST_FAIL("wrong clean price for fixed bond:" <<
1432 std::fixed << std::setprecision(4) <<
1433 "\n market asset swap spread: " <<
1434 floatingBondImpliedValue1 <<
1435 "\n par asset swap spread: " << floatingBondCleanPrice1 <<
1436 std::scientific << std::setprecision(2) <<
1437 "\n error: " << error5 <<
1438 "\n tolerance: " << tolerance);
1439 }
1440
1441 // FRN bond (Isin: XS0090566539 COE 0 09/24/18)
1442 // maturity occurs on a business day
1443
1444 Schedule floatingBondSchedule2(Date(24,September,2004),
1445 Date(24,September,2018),
1446 Period(Semiannual), bondCalendar,
1447 ModifiedFollowing, ModifiedFollowing,
1448 DateGeneration::Backward, false);
1449 ext::shared_ptr<Bond> floatingBond2(new
1450 FloatingRateBond(settlementDays, vars.faceAmount,
1451 floatingBondSchedule2,
1452 vars.iborIndex, Actual360(),
1453 ModifiedFollowing, fixingDays,
1454 std::vector<Real>(1,1), std::vector<Spread>(1,0.0025),
1455 std::vector<Rate>(), std::vector<Rate>(),
1456 inArrears,
1457 100.0, Date(24,September,2004)));
1458
1459 floatingBond2->setPricingEngine(bondEngine);
1460
1461 setCouponPricer(leg: floatingBond2->cashflows(), vars.pricer);
1462 vars.iborIndex->addFixing(fixingDate: Date(22,March,2007), fixing: 0.04013);
1463 Real floatingBondImpliedValue2 = floatingBond2->cleanPrice();
1464 // standard market conventions:
1465 // bond's frequency + coumpounding and daycounter of the YieldCurve
1466 Real floatingBondCleanPrice2 = BondFunctions::cleanPrice(
1467 bond: *floatingBond2, discount: *vars.termStructure,
1468 zSpread: vars.spread, dayCounter: Actual365Fixed(), compounding: vars.compounding, frequency: Semiannual,
1469 settlementDate: fixedBondSettlementDate1);
1470 Real error7 = std::fabs(x: floatingBondImpliedValue2-floatingBondCleanPrice2);
1471 if (error7>tolerance) {
1472 BOOST_FAIL("wrong clean price for fixed bond:"
1473 << std::fixed << std::setprecision(4)
1474 << "\n market asset swap spread: " <<
1475 floatingBondImpliedValue2
1476 << "\n par asset swap spread: " << floatingBondCleanPrice2
1477 << std::scientific << std::setprecision(2)
1478 << "\n error: " << error7
1479 << "\n tolerance: " << tolerance);
1480 }
1481
1482 //// CMS bond (Isin: XS0228052402 CRDIT 0 8/22/20)
1483 //// maturity doesn't occur on a business day
1484
1485 Schedule cmsBondSchedule1(Date(22,August,2005),
1486 Date(22,August,2020),
1487 Period(Annual), bondCalendar,
1488 Unadjusted, Unadjusted,
1489 DateGeneration::Backward, false);
1490 ext::shared_ptr<Bond> cmsBond1(new
1491 CmsRateBond(settlementDays, vars.faceAmount, cmsBondSchedule1,
1492 vars.swapIndex, Thirty360(Thirty360::BondBasis),
1493 Following, fixingDays,
1494 std::vector<Real>(1,1.0), std::vector<Spread>(1,0.0),
1495 std::vector<Rate>(1,0.055), std::vector<Rate>(1,0.025),
1496 inArrears,
1497 100.0, Date(22,August,2005)));
1498
1499 cmsBond1->setPricingEngine(bondEngine);
1500
1501 setCouponPricer(leg: cmsBond1->cashflows(), vars.cmspricer);
1502 vars.swapIndex->addFixing(fixingDate: Date(18,August,2006), fixing: 0.04158);
1503 Real cmsBondImpliedValue1 = cmsBond1->cleanPrice();
1504 Date cmsBondSettlementDate1= cmsBond1->settlementDate();
1505 // standard market conventions:
1506 // bond's frequency + coumpounding and daycounter of the YieldCurve
1507 Real cmsBondCleanPrice1 = BondFunctions::cleanPrice(
1508 bond: *cmsBond1, discount: *vars.termStructure, zSpread: vars.spread,
1509 dayCounter: Actual365Fixed(), compounding: vars.compounding, frequency: Annual,
1510 settlementDate: cmsBondSettlementDate1);
1511 Real error9 = std::fabs(x: cmsBondImpliedValue1-cmsBondCleanPrice1);
1512 if (error9>tolerance) {
1513 BOOST_FAIL("wrong clean price for fixed bond:"
1514 << std::fixed << std::setprecision(4)
1515 << "\n market asset swap spread: " << cmsBondImpliedValue1
1516 << "\n par asset swap spread: " << cmsBondCleanPrice1
1517 << std::scientific << std::setprecision(2)
1518 << "\n error: " << error9
1519 << "\n tolerance: " << tolerance);
1520 }
1521
1522 // CMS bond (Isin: XS0218766664 ISPIM 0 5/6/15)
1523 // maturity occurs on a business day
1524
1525 Schedule cmsBondSchedule2(Date(06,May,2005),
1526 Date(06,May,2015),
1527 Period(Annual), bondCalendar,
1528 Unadjusted, Unadjusted,
1529 DateGeneration::Backward, false);
1530 ext::shared_ptr<Bond> cmsBond2(new
1531 CmsRateBond(settlementDays, vars.faceAmount, cmsBondSchedule2,
1532 vars.swapIndex, Thirty360(Thirty360::BondBasis),
1533 Following, fixingDays,
1534 std::vector<Real>(1,0.84), std::vector<Spread>(1,0.0),
1535 std::vector<Rate>(), std::vector<Rate>(),
1536 inArrears,
1537 100.0, Date(06,May,2005)));
1538
1539 cmsBond2->setPricingEngine(bondEngine);
1540
1541 setCouponPricer(leg: cmsBond2->cashflows(), vars.cmspricer);
1542 vars.swapIndex->addFixing(fixingDate: Date(04,May,2006), fixing: 0.04217);
1543 Real cmsBondImpliedValue2 = cmsBond2->cleanPrice();
1544 Date cmsBondSettlementDate2= cmsBond2->settlementDate();
1545 // standard market conventions:
1546 // bond's frequency + coumpounding and daycounter of the YieldCurve
1547 Real cmsBondCleanPrice2 = BondFunctions::cleanPrice(
1548 bond: *cmsBond2, discount: *vars.termStructure, zSpread: vars.spread,
1549 dayCounter: Actual365Fixed(), compounding: vars.compounding, frequency: Annual,
1550 settlementDate: cmsBondSettlementDate2);
1551 Real error11 = std::fabs(x: cmsBondImpliedValue2-cmsBondCleanPrice2);
1552 if (error11>tolerance) {
1553 BOOST_FAIL("wrong clean price for fixed bond:"
1554 << std::fixed << std::setprecision(4)
1555 << "\n market asset swap spread: " << cmsBondImpliedValue2
1556 << "\n par asset swap spread: " << cmsBondCleanPrice2
1557 << std::scientific << std::setprecision(2)
1558 << "\n error: " << error11
1559 << "\n tolerance: " << tolerance);
1560 }
1561
1562 // Zero-Coupon bond (Isin: DE0004771662 IBRD 0 12/20/15)
1563 // maturity doesn't occur on a business day
1564
1565 ext::shared_ptr<Bond> zeroCpnBond1(new
1566 ZeroCouponBond(settlementDays, bondCalendar, vars.faceAmount,
1567 Date(20,December,2015),
1568 Following,
1569 100.0, Date(19,December,1985)));
1570
1571 zeroCpnBond1->setPricingEngine(bondEngine);
1572
1573 Real zeroCpnBondImpliedValue1 = zeroCpnBond1->cleanPrice();
1574 Date zeroCpnBondSettlementDate1= zeroCpnBond1->settlementDate();
1575 // standard market conventions:
1576 // bond's frequency + coumpounding and daycounter of the YieldCurve
1577 Real zeroCpnBondCleanPrice1 =
1578 BondFunctions::cleanPrice(bond: *zeroCpnBond1,
1579 discount: *vars.termStructure,
1580 zSpread: vars.spread,
1581 dayCounter: Actual365Fixed(),
1582 compounding: vars.compounding, frequency: Annual,
1583 settlementDate: zeroCpnBondSettlementDate1);
1584 Real error13 = std::fabs(x: zeroCpnBondImpliedValue1-zeroCpnBondCleanPrice1);
1585 if (error13>tolerance) {
1586 BOOST_FAIL("wrong clean price for zero coupon bond:"
1587 << std::fixed << std::setprecision(4)
1588 << "\n zero cpn implied value: " <<
1589 zeroCpnBondImpliedValue1
1590 << "\n zero cpn price: " << zeroCpnBondCleanPrice1
1591 << std::scientific << std::setprecision(2)
1592 << "\n error: " << error13
1593 << "\n tolerance: " << tolerance);
1594 }
1595
1596 // Zero Coupon bond (Isin: IT0001200390 ISPIM 0 02/17/28)
1597 // maturity doesn't occur on a business day
1598
1599 ext::shared_ptr<Bond> zeroCpnBond2(new
1600 ZeroCouponBond(settlementDays, bondCalendar, vars.faceAmount,
1601 Date(17,February,2028),
1602 Following,
1603 100.0, Date(17,February,1998)));
1604
1605 zeroCpnBond2->setPricingEngine(bondEngine);
1606
1607 Real zeroCpnBondImpliedValue2 = zeroCpnBond2->cleanPrice();
1608 Date zeroCpnBondSettlementDate2= zeroCpnBond2->settlementDate();
1609 // standard market conventions:
1610 // bond's frequency + coumpounding and daycounter of the YieldCurve
1611 Real zeroCpnBondCleanPrice2 =
1612 BondFunctions::cleanPrice(bond: *zeroCpnBond2,
1613 discount: *vars.termStructure,
1614 zSpread: vars.spread,
1615 dayCounter: Actual365Fixed(),
1616 compounding: vars.compounding, frequency: Annual,
1617 settlementDate: zeroCpnBondSettlementDate2);
1618 Real error15 = std::fabs(x: zeroCpnBondImpliedValue2-zeroCpnBondCleanPrice2);
1619 if (error15>tolerance) {
1620 BOOST_FAIL("wrong clean price for zero coupon bond:"
1621 << std::fixed << std::setprecision(4)
1622 << "\n zero cpn implied value: " <<
1623 zeroCpnBondImpliedValue2
1624 << "\n zero cpn price: " << zeroCpnBondCleanPrice2
1625 << std::scientific << std::setprecision(2)
1626 << "\n error: " << error15
1627 << "\n tolerance: " << tolerance);
1628 }
1629}
1630
1631
1632void AssetSwapTest::testGenericBondImplied() {
1633
1634 BOOST_TEST_MESSAGE("Testing implied generic-bond value against"
1635 " asset-swap fair price with null spread...");
1636
1637 using namespace asset_swap_test;
1638
1639 bool usingAtParCoupons = IborCoupon::Settings::instance().usingAtParCoupons();
1640
1641 CommonVars vars;
1642
1643 Calendar bondCalendar = TARGET();
1644 Natural settlementDays = 3;
1645 Natural fixingDays = 2;
1646 bool payFixedRate = true;
1647 bool parAssetSwap = true;
1648 bool inArrears = false;
1649
1650 // Fixed Underlying bond (Isin: DE0001135275 DBR 4 01/04/37)
1651 // maturity doesn't occur on a business day
1652 Date fixedBondStartDate1 = Date(4,January,2005);
1653 Date fixedBondMaturityDate1 = Date(4,January,2037);
1654 Schedule fixedBondSchedule1(fixedBondStartDate1,
1655 fixedBondMaturityDate1,
1656 Period(Annual), bondCalendar,
1657 Unadjusted, Unadjusted,
1658 DateGeneration::Backward, false);
1659 Leg fixedBondLeg1 = FixedRateLeg(fixedBondSchedule1)
1660 .withNotionals(vars.faceAmount)
1661 .withCouponRates(0.04, paymentDayCounter: ActualActual(ActualActual::ISDA));
1662 Date fixedbondRedemption1 = bondCalendar.adjust(fixedBondMaturityDate1,
1663 convention: Following);
1664 fixedBondLeg1.push_back(x: ext::shared_ptr<CashFlow>(new
1665 SimpleCashFlow(100.0, fixedbondRedemption1)));
1666 ext::shared_ptr<Bond> fixedBond1(new
1667 Bond(settlementDays, bondCalendar, vars.faceAmount,
1668 fixedBondMaturityDate1, fixedBondStartDate1,
1669 fixedBondLeg1));
1670 ext::shared_ptr<PricingEngine> bondEngine(
1671 new DiscountingBondEngine(vars.termStructure));
1672 ext::shared_ptr<PricingEngine> swapEngine(
1673 new DiscountingSwapEngine(vars.termStructure));
1674 fixedBond1->setPricingEngine(bondEngine);
1675
1676 Real fixedBondPrice1 = fixedBond1->cleanPrice();
1677 AssetSwap fixedBondAssetSwap1(payFixedRate,
1678 fixedBond1, fixedBondPrice1,
1679 vars.iborIndex, vars.spread,
1680 Schedule(),
1681 vars.iborIndex->dayCounter(),
1682 parAssetSwap);
1683 fixedBondAssetSwap1.setPricingEngine(swapEngine);
1684 Real fixedBondAssetSwapPrice1 = fixedBondAssetSwap1.fairCleanPrice();
1685 Real tolerance = 1.0e-13;
1686
1687 // see comment above
1688 Real tolerance2 = usingAtParCoupons? 1.0e-13 : 1.0e-2;
1689
1690 Real error1 = std::fabs(x: fixedBondAssetSwapPrice1-fixedBondPrice1);
1691
1692 if (error1>tolerance2) {
1693 BOOST_FAIL("wrong zero spread asset swap price for fixed bond:"
1694 << std::fixed << std::setprecision(4)
1695 << "\n bond's clean price: " << fixedBondPrice1
1696 << "\n asset swap fair price: " << fixedBondAssetSwapPrice1
1697 << std::scientific << std::setprecision(2)
1698 << "\n error: " << error1
1699 << "\n tolerance: " << tolerance2);
1700 }
1701
1702 // Fixed Underlying bond (Isin: IT0006527060 IBRD 5 02/05/19)
1703 // maturity occurs on a business day
1704 Date fixedBondStartDate2 = Date(5,February,2005);
1705 Date fixedBondMaturityDate2 = Date(5,February,2019);
1706 Schedule fixedBondSchedule2(fixedBondStartDate2,
1707 fixedBondMaturityDate2,
1708 Period(Annual), bondCalendar,
1709 Unadjusted, Unadjusted,
1710 DateGeneration::Backward, false);
1711 Leg fixedBondLeg2 = FixedRateLeg(fixedBondSchedule2)
1712 .withNotionals(vars.faceAmount)
1713 .withCouponRates(0.05, paymentDayCounter: Thirty360(Thirty360::BondBasis));
1714 Date fixedbondRedemption2 = bondCalendar.adjust(fixedBondMaturityDate2,
1715 convention: Following);
1716 fixedBondLeg2.push_back(x: ext::shared_ptr<CashFlow>(new
1717 SimpleCashFlow(100.0, fixedbondRedemption2)));
1718 ext::shared_ptr<Bond> fixedBond2(new
1719 Bond(settlementDays, bondCalendar, vars.faceAmount,
1720 fixedBondMaturityDate2, fixedBondStartDate2, fixedBondLeg2));
1721 fixedBond2->setPricingEngine(bondEngine);
1722
1723 Real fixedBondPrice2 = fixedBond2->cleanPrice();
1724 AssetSwap fixedBondAssetSwap2(payFixedRate,
1725 fixedBond2, fixedBondPrice2,
1726 vars.iborIndex, vars.spread,
1727 Schedule(),
1728 vars.iborIndex->dayCounter(),
1729 parAssetSwap);
1730 fixedBondAssetSwap2.setPricingEngine(swapEngine);
1731 Real fixedBondAssetSwapPrice2 = fixedBondAssetSwap2.fairCleanPrice();
1732 Real error2 = std::fabs(x: fixedBondAssetSwapPrice2-fixedBondPrice2);
1733
1734 if (error2>tolerance2) {
1735 BOOST_FAIL("wrong zero spread asset swap price for fixed bond:"
1736 << std::fixed << std::setprecision(4)
1737 << "\n bond's clean price: " << fixedBondPrice2
1738 << "\n asset swap fair price: " << fixedBondAssetSwapPrice2
1739 << std::scientific << std::setprecision(2)
1740 << "\n error: " << error2
1741 << "\n tolerance: " << tolerance2);
1742 }
1743
1744 // FRN Underlying bond (Isin: IT0003543847 ISPIM 0 09/29/13)
1745 // maturity doesn't occur on a business day
1746 Date floatingBondStartDate1 = Date(29,September,2003);
1747 Date floatingBondMaturityDate1 = Date(29,September,2013);
1748 Schedule floatingBondSchedule1(floatingBondStartDate1,
1749 floatingBondMaturityDate1,
1750 Period(Semiannual), bondCalendar,
1751 Unadjusted, Unadjusted,
1752 DateGeneration::Backward, false);
1753 Leg floatingBondLeg1 = IborLeg(floatingBondSchedule1, vars.iborIndex)
1754 .withNotionals(notional: vars.faceAmount)
1755 .withPaymentDayCounter(Actual360())
1756 .withFixingDays(fixingDays)
1757 .withSpreads(spread: 0.0056)
1758 .inArrears(flag: inArrears);
1759 Date floatingbondRedemption1 =
1760 bondCalendar.adjust(floatingBondMaturityDate1, convention: Following);
1761 floatingBondLeg1.push_back(x: ext::shared_ptr<CashFlow>(new
1762 SimpleCashFlow(100.0, floatingbondRedemption1)));
1763 ext::shared_ptr<Bond> floatingBond1(new
1764 Bond(settlementDays, bondCalendar, vars.faceAmount,
1765 floatingBondMaturityDate1, floatingBondStartDate1,
1766 floatingBondLeg1));
1767 floatingBond1->setPricingEngine(bondEngine);
1768
1769 setCouponPricer(leg: floatingBond1->cashflows(), vars.pricer);
1770 vars.iborIndex->addFixing(fixingDate: Date(27,March,2007), fixing: 0.0402);
1771 Real floatingBondPrice1 = floatingBond1->cleanPrice();
1772 AssetSwap floatingBondAssetSwap1(payFixedRate,
1773 floatingBond1, floatingBondPrice1,
1774 vars.iborIndex, vars.spread,
1775 Schedule(),
1776 vars.iborIndex->dayCounter(),
1777 parAssetSwap);
1778 floatingBondAssetSwap1.setPricingEngine(swapEngine);
1779 Real floatingBondAssetSwapPrice1 = floatingBondAssetSwap1.fairCleanPrice();
1780 Real error3 = std::fabs(x: floatingBondAssetSwapPrice1-floatingBondPrice1);
1781
1782 if (error3>tolerance2) {
1783 BOOST_FAIL("wrong zero spread asset swap price for floater:"
1784 << std::fixed << std::setprecision(4)
1785 << "\n bond's clean price: " << floatingBondPrice1
1786 << "\n asset swap fair price: " <<
1787 floatingBondAssetSwapPrice1
1788 << std::scientific << std::setprecision(2)
1789 << "\n error: " << error3
1790 << "\n tolerance: " << tolerance2);
1791 }
1792
1793 // FRN Underlying bond (Isin: XS0090566539 COE 0 09/24/18)
1794 // maturity occurs on a business day
1795 Date floatingBondStartDate2 = Date(24,September,2004);
1796 Date floatingBondMaturityDate2 = Date(24,September,2018);
1797 Schedule floatingBondSchedule2(floatingBondStartDate2,
1798 floatingBondMaturityDate2,
1799 Period(Semiannual), bondCalendar,
1800 ModifiedFollowing, ModifiedFollowing,
1801 DateGeneration::Backward, false);
1802 Leg floatingBondLeg2 = IborLeg(floatingBondSchedule2, vars.iborIndex)
1803 .withNotionals(notional: vars.faceAmount)
1804 .withPaymentDayCounter(Actual360())
1805 .withPaymentAdjustment(ModifiedFollowing)
1806 .withFixingDays(fixingDays)
1807 .withSpreads(spread: 0.0025)
1808 .inArrears(flag: inArrears);
1809 Date floatingbondRedemption2 =
1810 bondCalendar.adjust(floatingBondMaturityDate2, convention: ModifiedFollowing);
1811 floatingBondLeg2.push_back(x: ext::shared_ptr<CashFlow>(new
1812 SimpleCashFlow(100.0, floatingbondRedemption2)));
1813 ext::shared_ptr<Bond> floatingBond2(new
1814 Bond(settlementDays, bondCalendar, vars.faceAmount,
1815 floatingBondMaturityDate2, floatingBondStartDate2,
1816 floatingBondLeg2));
1817 floatingBond2->setPricingEngine(bondEngine);
1818
1819 setCouponPricer(leg: floatingBond2->cashflows(), vars.pricer);
1820 vars.iborIndex->addFixing(fixingDate: Date(22,March,2007), fixing: 0.04013);
1821 Real currentCoupon=0.04013+0.0025;
1822 Rate floatingCurrentCoupon= floatingBond2->nextCouponRate();
1823 Real error4= std::fabs(x: floatingCurrentCoupon-currentCoupon);
1824 if (error4>tolerance) {
1825 BOOST_FAIL("wrong current coupon is returned for floater bond:"
1826 << std::fixed << std::setprecision(4)
1827 << "\n bond's calculated current coupon: " <<
1828 currentCoupon
1829 << "\n current coupon asked to the bond: " <<
1830 floatingCurrentCoupon
1831 << std::scientific << std::setprecision(2)
1832 << "\n error: " << error4
1833 << "\n tolerance: " << tolerance);
1834 }
1835
1836 Real floatingBondPrice2 = floatingBond2->cleanPrice();
1837 AssetSwap floatingBondAssetSwap2(payFixedRate,
1838 floatingBond2, floatingBondPrice2,
1839 vars.iborIndex, vars.spread,
1840 Schedule(),
1841 vars.iborIndex->dayCounter(),
1842 parAssetSwap);
1843 floatingBondAssetSwap2.setPricingEngine(swapEngine);
1844 Real floatingBondAssetSwapPrice2 = floatingBondAssetSwap2.fairCleanPrice();
1845 Real error5 = std::fabs(x: floatingBondAssetSwapPrice2-floatingBondPrice2);
1846
1847 if (error5>tolerance2) {
1848 BOOST_FAIL("wrong zero spread asset swap price for floater:"
1849 << std::fixed << std::setprecision(4)
1850 << "\n bond's clean price: " << floatingBondPrice2
1851 << "\n asset swap fair price: " <<
1852 floatingBondAssetSwapPrice2
1853 << std::scientific << std::setprecision(2)
1854 << "\n error: " << error5
1855 << "\n tolerance: " << tolerance2);
1856 }
1857
1858 // CMS Underlying bond (Isin: XS0228052402 CRDIT 0 8/22/20)
1859 // maturity doesn't occur on a business day
1860 Date cmsBondStartDate1 = Date(22,August,2005);
1861 Date cmsBondMaturityDate1 = Date(22,August,2020);
1862 Schedule cmsBondSchedule1(cmsBondStartDate1,
1863 cmsBondMaturityDate1,
1864 Period(Annual), bondCalendar,
1865 Unadjusted, Unadjusted,
1866 DateGeneration::Backward, false);
1867 Leg cmsBondLeg1 = CmsLeg(cmsBondSchedule1, vars.swapIndex)
1868 .withNotionals(notional: vars.faceAmount)
1869 .withPaymentDayCounter(Thirty360(Thirty360::BondBasis))
1870 .withFixingDays(fixingDays)
1871 .withCaps(cap: 0.055)
1872 .withFloors(floor: 0.025)
1873 .inArrears(flag: inArrears);
1874 Date cmsbondRedemption1 = bondCalendar.adjust(cmsBondMaturityDate1,
1875 convention: Following);
1876 cmsBondLeg1.push_back(x: ext::shared_ptr<CashFlow>(new
1877 SimpleCashFlow(100.0, cmsbondRedemption1)));
1878 ext::shared_ptr<Bond> cmsBond1(new
1879 Bond(settlementDays, bondCalendar, vars.faceAmount,
1880 cmsBondMaturityDate1, cmsBondStartDate1, cmsBondLeg1));
1881 cmsBond1->setPricingEngine(bondEngine);
1882
1883 setCouponPricer(leg: cmsBond1->cashflows(), vars.cmspricer);
1884 vars.swapIndex->addFixing(fixingDate: Date(18,August,2006), fixing: 0.04158);
1885 Real cmsBondPrice1 = cmsBond1->cleanPrice();
1886 AssetSwap cmsBondAssetSwap1(payFixedRate,
1887 cmsBond1, cmsBondPrice1,
1888 vars.iborIndex, vars.spread,
1889 Schedule(),
1890 vars.iborIndex->dayCounter(),
1891 parAssetSwap);
1892 cmsBondAssetSwap1.setPricingEngine(swapEngine);
1893 Real cmsBondAssetSwapPrice1 = cmsBondAssetSwap1.fairCleanPrice();
1894 Real error6 = std::fabs(x: cmsBondAssetSwapPrice1-cmsBondPrice1);
1895
1896 if (error6>tolerance2) {
1897 BOOST_FAIL("wrong zero spread asset swap price for cms bond:"
1898 << std::fixed << std::setprecision(4)
1899 << "\n bond's clean price: " << cmsBondPrice1
1900 << "\n asset swap fair price: " << cmsBondAssetSwapPrice1
1901 << std::scientific << std::setprecision(2)
1902 << "\n error: " << error6
1903 << "\n tolerance: " << tolerance2);
1904 }
1905
1906 // CMS Underlying bond (Isin: XS0218766664 ISPIM 0 5/6/15)
1907 // maturity occurs on a business day
1908 Date cmsBondStartDate2 = Date(06,May,2005);
1909 Date cmsBondMaturityDate2 = Date(06,May,2015);
1910 Schedule cmsBondSchedule2(cmsBondStartDate2,
1911 cmsBondMaturityDate2,
1912 Period(Annual), bondCalendar,
1913 Unadjusted, Unadjusted,
1914 DateGeneration::Backward, false);
1915 Leg cmsBondLeg2 = CmsLeg(cmsBondSchedule2, vars.swapIndex)
1916 .withNotionals(notional: vars.faceAmount)
1917 .withPaymentDayCounter(Thirty360(Thirty360::BondBasis))
1918 .withFixingDays(fixingDays)
1919 .withGearings(gearing: 0.84)
1920 .inArrears(flag: inArrears);
1921 Date cmsbondRedemption2 = bondCalendar.adjust(cmsBondMaturityDate2,
1922 convention: Following);
1923 cmsBondLeg2.push_back(x: ext::shared_ptr<CashFlow>(new
1924 SimpleCashFlow(100.0, cmsbondRedemption2)));
1925 ext::shared_ptr<Bond> cmsBond2(new
1926 Bond(settlementDays, bondCalendar, vars.faceAmount,
1927 cmsBondMaturityDate2, cmsBondStartDate2, cmsBondLeg2));
1928 cmsBond2->setPricingEngine(bondEngine);
1929
1930 setCouponPricer(leg: cmsBond2->cashflows(), vars.cmspricer);
1931 vars.swapIndex->addFixing(fixingDate: Date(04,May,2006), fixing: 0.04217);
1932 Real cmsBondPrice2 = cmsBond2->cleanPrice();
1933 AssetSwap cmsBondAssetSwap2(payFixedRate,
1934 cmsBond2, cmsBondPrice2,
1935 vars.iborIndex, vars.spread,
1936 Schedule(),
1937 vars.iborIndex->dayCounter(),
1938 parAssetSwap);
1939 cmsBondAssetSwap2.setPricingEngine(swapEngine);
1940 Real cmsBondAssetSwapPrice2 = cmsBondAssetSwap2.fairCleanPrice();
1941 Real error7 = std::fabs(x: cmsBondAssetSwapPrice2-cmsBondPrice2);
1942
1943 if (error7>tolerance2) {
1944 BOOST_FAIL("wrong zero spread asset swap price for cms bond:"
1945 << std::fixed << std::setprecision(4)
1946 << "\n bond's clean price: " << cmsBondPrice2
1947 << "\n asset swap fair price: " << cmsBondAssetSwapPrice2
1948 << std::scientific << std::setprecision(2)
1949 << "\n error: " << error7
1950 << "\n tolerance: " << tolerance2);
1951 }
1952
1953 // Zero Coupon bond (Isin: DE0004771662 IBRD 0 12/20/15)
1954 // maturity doesn't occur on a business day
1955 Date zeroCpnBondStartDate1 = Date(19,December,1985);
1956 Date zeroCpnBondMaturityDate1 = Date(20,December,2015);
1957 Date zeroCpnBondRedemption1 = bondCalendar.adjust(zeroCpnBondMaturityDate1,
1958 convention: Following);
1959 Leg zeroCpnBondLeg1 = Leg(1, ext::shared_ptr<CashFlow>(new
1960 SimpleCashFlow(100.0, zeroCpnBondRedemption1)));
1961 ext::shared_ptr<Bond> zeroCpnBond1(new
1962 Bond(settlementDays, bondCalendar, vars.faceAmount,
1963 zeroCpnBondMaturityDate1, zeroCpnBondStartDate1, zeroCpnBondLeg1));
1964 zeroCpnBond1->setPricingEngine(bondEngine);
1965
1966 Real zeroCpnBondPrice1 = zeroCpnBond1->cleanPrice();
1967 AssetSwap zeroCpnAssetSwap1(payFixedRate,
1968 zeroCpnBond1, zeroCpnBondPrice1,
1969 vars.iborIndex, vars.spread,
1970 Schedule(),
1971 vars.iborIndex->dayCounter(),
1972 parAssetSwap);
1973 zeroCpnAssetSwap1.setPricingEngine(swapEngine);
1974 Real zeroCpnBondAssetSwapPrice1 = zeroCpnAssetSwap1.fairCleanPrice();
1975 Real error8 = std::fabs(x: zeroCpnBondAssetSwapPrice1-zeroCpnBondPrice1);
1976
1977 if (error8>tolerance2) {
1978 BOOST_FAIL("wrong zero spread asset swap price for zero cpn bond:"
1979 << std::fixed << std::setprecision(4)
1980 << "\n bond's clean price: " << zeroCpnBondPrice1
1981 << "\n asset swap fair price: " << zeroCpnBondAssetSwapPrice1
1982 << std::scientific << std::setprecision(2)
1983 << "\n error: " << error8
1984 << "\n tolerance: " << tolerance2);
1985 }
1986
1987 // Zero Coupon bond (Isin: IT0001200390 ISPIM 0 02/17/28)
1988 // maturity occurs on a business day
1989 Date zeroCpnBondStartDate2 = Date(17,February,1998);
1990 Date zeroCpnBondMaturityDate2 = Date(17,February,2028);
1991 Date zerocpbondRedemption2 = bondCalendar.adjust(zeroCpnBondMaturityDate2,
1992 convention: Following);
1993 Leg zeroCpnBondLeg2 = Leg(1, ext::shared_ptr<CashFlow>(new
1994 SimpleCashFlow(100.0, zerocpbondRedemption2)));
1995 ext::shared_ptr<Bond> zeroCpnBond2(new
1996 Bond(settlementDays, bondCalendar, vars.faceAmount,
1997 zeroCpnBondMaturityDate2, zeroCpnBondStartDate2, zeroCpnBondLeg2));
1998 zeroCpnBond2->setPricingEngine(bondEngine);
1999
2000 Real zeroCpnBondPrice2 = zeroCpnBond2->cleanPrice();
2001 AssetSwap zeroCpnAssetSwap2(payFixedRate,
2002 zeroCpnBond2, zeroCpnBondPrice2,
2003 vars.iborIndex, vars.spread,
2004 Schedule(),
2005 vars.iborIndex->dayCounter(),
2006 parAssetSwap);
2007 zeroCpnAssetSwap2.setPricingEngine(swapEngine);
2008 Real zeroCpnBondAssetSwapPrice2 = zeroCpnAssetSwap2.fairCleanPrice();
2009 Real error9 = std::fabs(x: zeroCpnBondAssetSwapPrice2-zeroCpnBondPrice2);
2010
2011 if (error9>tolerance2) {
2012 BOOST_FAIL("wrong zero spread asset swap price for zero cpn bond:"
2013 << std::fixed << std::setprecision(4)
2014 << "\n bond's clean price: " << zeroCpnBondPrice2
2015 << "\n asset swap fair price: " << zeroCpnBondAssetSwapPrice2
2016 << std::scientific << std::setprecision(2)
2017 << "\n error: " << error9
2018 << "\n tolerance: " << tolerance2);
2019 }
2020}
2021
2022
2023void AssetSwapTest::testMASWWithGenericBond() {
2024
2025 BOOST_TEST_MESSAGE("Testing market asset swap against par asset swap "
2026 "with generic bond...");
2027
2028 using namespace asset_swap_test;
2029
2030 bool usingAtParCoupons = IborCoupon::Settings::instance().usingAtParCoupons();
2031
2032 CommonVars vars;
2033
2034 Calendar bondCalendar = TARGET();
2035 Natural settlementDays = 3;
2036 Natural fixingDays = 2;
2037 bool payFixedRate = true;
2038 bool parAssetSwap = true;
2039 bool mktAssetSwap = false;
2040 bool inArrears = false;
2041
2042 // Fixed Underlying bond (Isin: DE0001135275 DBR 4 01/04/37)
2043 // maturity doesn't occur on a business day
2044
2045 Date fixedBondStartDate1 = Date(4,January,2005);
2046 Date fixedBondMaturityDate1 = Date(4,January,2037);
2047 Schedule fixedBondSchedule1(fixedBondStartDate1,
2048 fixedBondMaturityDate1,
2049 Period(Annual), bondCalendar,
2050 Unadjusted, Unadjusted,
2051 DateGeneration::Backward, false);
2052 Leg fixedBondLeg1 = FixedRateLeg(fixedBondSchedule1)
2053 .withNotionals(vars.faceAmount)
2054 .withCouponRates(0.04, paymentDayCounter: ActualActual(ActualActual::ISDA));
2055 Date fixedbondRedemption1 = bondCalendar.adjust(fixedBondMaturityDate1,
2056 convention: Following);
2057 fixedBondLeg1.push_back(x: ext::shared_ptr<CashFlow>(new
2058 SimpleCashFlow(100.0, fixedbondRedemption1)));
2059 ext::shared_ptr<Bond> fixedBond1(new
2060 Bond(settlementDays, bondCalendar, vars.faceAmount,
2061 fixedBondMaturityDate1, fixedBondStartDate1,
2062 fixedBondLeg1));
2063 ext::shared_ptr<PricingEngine> bondEngine(
2064 new DiscountingBondEngine(vars.termStructure));
2065 ext::shared_ptr<PricingEngine> swapEngine(
2066 new DiscountingSwapEngine(vars.termStructure));
2067 fixedBond1->setPricingEngine(bondEngine);
2068
2069 Real fixedBondMktPrice1 = 89.22 ; // market price observed on 7th June 2007
2070 Real fixedBondMktFullPrice1=fixedBondMktPrice1+fixedBond1->accruedAmount();
2071 AssetSwap fixedBondParAssetSwap1(payFixedRate,
2072 fixedBond1, fixedBondMktPrice1,
2073 vars.iborIndex, vars.spread,
2074 Schedule(),
2075 vars.iborIndex->dayCounter(),
2076 parAssetSwap);
2077 fixedBondParAssetSwap1.setPricingEngine(swapEngine);
2078 Real fixedBondParAssetSwapSpread1 = fixedBondParAssetSwap1.fairSpread();
2079 AssetSwap fixedBondMktAssetSwap1(payFixedRate,
2080 fixedBond1, fixedBondMktPrice1,
2081 vars.iborIndex, vars.spread,
2082 Schedule(),
2083 vars.iborIndex->dayCounter(),
2084 mktAssetSwap);
2085 fixedBondMktAssetSwap1.setPricingEngine(swapEngine);
2086 Real fixedBondMktAssetSwapSpread1 = fixedBondMktAssetSwap1.fairSpread();
2087
2088 // see comment above
2089 Real tolerance2 = usingAtParCoupons ? 1.0e-13 : 1.0e-4;
2090
2091 Real error1 =
2092 std::fabs(x: fixedBondMktAssetSwapSpread1-
2093 100*fixedBondParAssetSwapSpread1/fixedBondMktFullPrice1);
2094
2095 if (error1>tolerance2)
2096 BOOST_FAIL("wrong asset swap spreads for fixed bond:" <<
2097 std::fixed << std::setprecision(4) <<
2098 "\n market asset swap spread: " << io::rate(fixedBondMktAssetSwapSpread1) <<
2099 "\n par asset swap spread: " << io::rate(fixedBondParAssetSwapSpread1) <<
2100 std::scientific << std::setprecision(2) <<
2101 "\n error: " << error1 <<
2102 "\n tolerance: " << tolerance2);
2103
2104 // Fixed Underlying bond (Isin: IT0006527060 IBRD 5 02/05/19)
2105 // maturity occurs on a business day
2106
2107 Date fixedBondStartDate2 = Date(5,February,2005);
2108 Date fixedBondMaturityDate2 = Date(5,February,2019);
2109 Schedule fixedBondSchedule2(fixedBondStartDate2,
2110 fixedBondMaturityDate2,
2111 Period(Annual), bondCalendar,
2112 Unadjusted, Unadjusted,
2113 DateGeneration::Backward, false);
2114 Leg fixedBondLeg2 = FixedRateLeg(fixedBondSchedule2)
2115 .withNotionals(vars.faceAmount)
2116 .withCouponRates(0.05, paymentDayCounter: Thirty360(Thirty360::BondBasis));
2117 Date fixedbondRedemption2 = bondCalendar.adjust(fixedBondMaturityDate2,
2118 convention: Following);
2119 fixedBondLeg2.push_back(x: ext::shared_ptr<CashFlow>(new
2120 SimpleCashFlow(100.0, fixedbondRedemption2)));
2121 ext::shared_ptr<Bond> fixedBond2(new
2122 Bond(settlementDays, bondCalendar, vars.faceAmount,
2123 fixedBondMaturityDate2, fixedBondStartDate2, fixedBondLeg2));
2124 fixedBond2->setPricingEngine(bondEngine);
2125
2126 Real fixedBondMktPrice2 = 99.98 ; // market price observed on 7th June 2007
2127 Real fixedBondMktFullPrice2=fixedBondMktPrice2+fixedBond2->accruedAmount();
2128 AssetSwap fixedBondParAssetSwap2(payFixedRate,
2129 fixedBond2, fixedBondMktPrice2,
2130 vars.iborIndex, vars.spread,
2131 Schedule(),
2132 vars.iborIndex->dayCounter(),
2133 parAssetSwap);
2134 fixedBondParAssetSwap2.setPricingEngine(swapEngine);
2135 Real fixedBondParAssetSwapSpread2 = fixedBondParAssetSwap2.fairSpread();
2136 AssetSwap fixedBondMktAssetSwap2(payFixedRate,
2137 fixedBond2, fixedBondMktPrice2,
2138 vars.iborIndex, vars.spread,
2139 Schedule(),
2140 vars.iborIndex->dayCounter(),
2141 mktAssetSwap);
2142 fixedBondMktAssetSwap2.setPricingEngine(swapEngine);
2143 Real fixedBondMktAssetSwapSpread2 = fixedBondMktAssetSwap2.fairSpread();
2144 Real error2 =
2145 std::fabs(x: fixedBondMktAssetSwapSpread2-
2146 100*fixedBondParAssetSwapSpread2/fixedBondMktFullPrice2);
2147
2148 if (error2>tolerance2)
2149 BOOST_FAIL("wrong asset swap spreads for fixed bond:" <<
2150 std::fixed << std::setprecision(4) <<
2151 "\n market asset swap spread: " << io::rate(fixedBondMktAssetSwapSpread2) <<
2152 "\n par asset swap spread: " << io::rate(fixedBondParAssetSwapSpread2) <<
2153 std::scientific << std::setprecision(2) <<
2154 "\n error: " << error2 <<
2155 "\n tolerance: " << tolerance2);
2156
2157 // FRN Underlying bond (Isin: IT0003543847 ISPIM 0 09/29/13)
2158 // maturity doesn't occur on a business day
2159
2160 Date floatingBondStartDate1 = Date(29,September,2003);
2161 Date floatingBondMaturityDate1 = Date(29,September,2013);
2162 Schedule floatingBondSchedule1(floatingBondStartDate1,
2163 floatingBondMaturityDate1,
2164 Period(Semiannual), bondCalendar,
2165 Unadjusted, Unadjusted,
2166 DateGeneration::Backward, false);
2167 Leg floatingBondLeg1 = IborLeg(floatingBondSchedule1, vars.iborIndex)
2168 .withNotionals(notional: vars.faceAmount)
2169 .withPaymentDayCounter(Actual360())
2170 .withFixingDays(fixingDays)
2171 .withSpreads(spread: 0.0056)
2172 .inArrears(flag: inArrears);
2173 Date floatingbondRedemption1 =
2174 bondCalendar.adjust(floatingBondMaturityDate1, convention: Following);
2175 floatingBondLeg1.push_back(x: ext::shared_ptr<CashFlow>(new
2176 SimpleCashFlow(100.0, floatingbondRedemption1)));
2177 ext::shared_ptr<Bond> floatingBond1(new
2178 Bond(settlementDays, bondCalendar, vars.faceAmount,
2179 floatingBondMaturityDate1, floatingBondStartDate1,
2180 floatingBondLeg1));
2181 floatingBond1->setPricingEngine(bondEngine);
2182
2183 setCouponPricer(leg: floatingBond1->cashflows(), vars.pricer);
2184 vars.iborIndex->addFixing(fixingDate: Date(27,March,2007), fixing: 0.0402);
2185 // market price observed on 7th June 2007
2186 Real floatingBondMktPrice1 = 101.64 ;
2187 Real floatingBondMktFullPrice1 =
2188 floatingBondMktPrice1+floatingBond1->accruedAmount();
2189 AssetSwap floatingBondParAssetSwap1(payFixedRate,
2190 floatingBond1, floatingBondMktPrice1,
2191 vars.iborIndex, vars.spread,
2192 Schedule(),
2193 vars.iborIndex->dayCounter(),
2194 parAssetSwap);
2195 floatingBondParAssetSwap1.setPricingEngine(swapEngine);
2196 Real floatingBondParAssetSwapSpread1 =
2197 floatingBondParAssetSwap1.fairSpread();
2198 AssetSwap floatingBondMktAssetSwap1(payFixedRate,
2199 floatingBond1, floatingBondMktPrice1,
2200 vars.iborIndex, vars.spread,
2201 Schedule(),
2202 vars.iborIndex->dayCounter(),
2203 mktAssetSwap);
2204 floatingBondMktAssetSwap1.setPricingEngine(swapEngine);
2205 Real floatingBondMktAssetSwapSpread1 =
2206 floatingBondMktAssetSwap1.fairSpread();
2207 Real error3 =
2208 std::fabs(x: floatingBondMktAssetSwapSpread1-
2209 100*floatingBondParAssetSwapSpread1/floatingBondMktFullPrice1);
2210
2211 if (error3>tolerance2)
2212 BOOST_FAIL("wrong asset swap spreads for floating bond:" <<
2213 std::fixed << std::setprecision(4) <<
2214 "\n market asset swap spread: " << io::rate(floatingBondMktAssetSwapSpread1) <<
2215 "\n par asset swap spread: " << io::rate(floatingBondParAssetSwapSpread1) <<
2216 std::scientific << std::setprecision(2) <<
2217 "\n error: " << error3 <<
2218 "\n tolerance: " << tolerance2);
2219
2220 // FRN Underlying bond (Isin: XS0090566539 COE 0 09/24/18)
2221 // maturity occurs on a business day
2222
2223 Date floatingBondStartDate2 = Date(24,September,2004);
2224 Date floatingBondMaturityDate2 = Date(24,September,2018);
2225 Schedule floatingBondSchedule2(floatingBondStartDate2,
2226 floatingBondMaturityDate2,
2227 Period(Semiannual), bondCalendar,
2228 ModifiedFollowing, ModifiedFollowing,
2229 DateGeneration::Backward, false);
2230 Leg floatingBondLeg2 = IborLeg(floatingBondSchedule2, vars.iborIndex)
2231 .withNotionals(notional: vars.faceAmount)
2232 .withPaymentDayCounter(Actual360())
2233 .withPaymentAdjustment(ModifiedFollowing)
2234 .withFixingDays(fixingDays)
2235 .withSpreads(spread: 0.0025)
2236 .inArrears(flag: inArrears);
2237 Date floatingbondRedemption2 =
2238 bondCalendar.adjust(floatingBondMaturityDate2, convention: ModifiedFollowing);
2239 floatingBondLeg2.push_back(x: ext::shared_ptr<CashFlow>(new
2240 SimpleCashFlow(100.0, floatingbondRedemption2)));
2241 ext::shared_ptr<Bond> floatingBond2(new
2242 Bond(settlementDays, bondCalendar, vars.faceAmount,
2243 floatingBondMaturityDate2, floatingBondStartDate2,
2244 floatingBondLeg2));
2245 floatingBond2->setPricingEngine(bondEngine);
2246
2247 setCouponPricer(leg: floatingBond2->cashflows(), vars.pricer);
2248 vars.iborIndex->addFixing(fixingDate: Date(22,March,2007), fixing: 0.04013);
2249 // market price observed on 7th June 2007
2250 Real floatingBondMktPrice2 = 101.248 ;
2251 Real floatingBondMktFullPrice2 =
2252 floatingBondMktPrice2+floatingBond2->accruedAmount();
2253 AssetSwap floatingBondParAssetSwap2(payFixedRate,
2254 floatingBond2, floatingBondMktPrice2,
2255 vars.iborIndex, vars.spread,
2256 Schedule(),
2257 vars.iborIndex->dayCounter(),
2258 parAssetSwap);
2259 floatingBondParAssetSwap2.setPricingEngine(swapEngine);
2260 Spread floatingBondParAssetSwapSpread2 =
2261 floatingBondParAssetSwap2.fairSpread();
2262 AssetSwap floatingBondMktAssetSwap2(payFixedRate,
2263 floatingBond2, floatingBondMktPrice2,
2264 vars.iborIndex, vars.spread,
2265 Schedule(),
2266 vars.iborIndex->dayCounter(),
2267 mktAssetSwap);
2268 floatingBondMktAssetSwap2.setPricingEngine(swapEngine);
2269 Real floatingBondMktAssetSwapSpread2 =
2270 floatingBondMktAssetSwap2.fairSpread();
2271 Real error4 =
2272 std::fabs(x: floatingBondMktAssetSwapSpread2-
2273 100*floatingBondParAssetSwapSpread2/floatingBondMktFullPrice2);
2274
2275 if (error4>tolerance2)
2276 BOOST_FAIL("wrong asset swap spreads for floating bond:" <<
2277 std::fixed << std::setprecision(4) <<
2278 "\n market asset swap spread: " << io::rate(floatingBondMktAssetSwapSpread2) <<
2279 "\n par asset swap spread: " << io::rate(floatingBondParAssetSwapSpread2) <<
2280 std::scientific << std::setprecision(2) <<
2281 "\n error: " << error4 <<
2282 "\n tolerance: " << tolerance2);
2283
2284 // CMS Underlying bond (Isin: XS0228052402 CRDIT 0 8/22/20)
2285 // maturity doesn't occur on a business day
2286
2287 Date cmsBondStartDate1 = Date(22,August,2005);
2288 Date cmsBondMaturityDate1 = Date(22,August,2020);
2289 Schedule cmsBondSchedule1(cmsBondStartDate1,
2290 cmsBondMaturityDate1,
2291 Period(Annual), bondCalendar,
2292 Unadjusted, Unadjusted,
2293 DateGeneration::Backward, false);
2294 Leg cmsBondLeg1 = CmsLeg(cmsBondSchedule1, vars.swapIndex)
2295 .withNotionals(notional: vars.faceAmount)
2296 .withPaymentDayCounter(Thirty360(Thirty360::BondBasis))
2297 .withFixingDays(fixingDays)
2298 .withCaps(cap: 0.055)
2299 .withFloors(floor: 0.025)
2300 .inArrears(flag: inArrears);
2301 Date cmsbondRedemption1 = bondCalendar.adjust(cmsBondMaturityDate1,
2302 convention: Following);
2303 cmsBondLeg1.push_back(x: ext::shared_ptr<CashFlow>(new
2304 SimpleCashFlow(100.0, cmsbondRedemption1)));
2305 ext::shared_ptr<Bond> cmsBond1(new
2306 Bond(settlementDays, bondCalendar, vars.faceAmount,
2307 cmsBondMaturityDate1, cmsBondStartDate1, cmsBondLeg1));
2308 cmsBond1->setPricingEngine(bondEngine);
2309
2310 setCouponPricer(leg: cmsBond1->cashflows(), vars.cmspricer);
2311 vars.swapIndex->addFixing(fixingDate: Date(18,August,2006), fixing: 0.04158);
2312 Real cmsBondMktPrice1 = 88.45 ; // market price observed on 7th June 2007
2313 Real cmsBondMktFullPrice1 = cmsBondMktPrice1+cmsBond1->accruedAmount();
2314 AssetSwap cmsBondParAssetSwap1(payFixedRate,
2315 cmsBond1, cmsBondMktPrice1,
2316 vars.iborIndex, vars.spread,
2317 Schedule(),
2318 vars.iborIndex->dayCounter(),
2319 parAssetSwap);
2320 cmsBondParAssetSwap1.setPricingEngine(swapEngine);
2321 Real cmsBondParAssetSwapSpread1 = cmsBondParAssetSwap1.fairSpread();
2322 AssetSwap cmsBondMktAssetSwap1(payFixedRate,
2323 cmsBond1, cmsBondMktPrice1,
2324 vars.iborIndex, vars.spread,
2325 Schedule(),
2326 vars.iborIndex->dayCounter(),
2327 mktAssetSwap);
2328 cmsBondMktAssetSwap1.setPricingEngine(swapEngine);
2329 Real cmsBondMktAssetSwapSpread1 = cmsBondMktAssetSwap1.fairSpread();
2330 Real error5 =
2331 std::fabs(x: cmsBondMktAssetSwapSpread1-
2332 100*cmsBondParAssetSwapSpread1/cmsBondMktFullPrice1);
2333
2334 if (error5>tolerance2)
2335 BOOST_FAIL("wrong asset swap spreads for cms bond:" <<
2336 std::fixed << std::setprecision(4) <<
2337 "\n market asset swap spread: " << io::rate(cmsBondMktAssetSwapSpread1) <<
2338 "\n par asset swap spread: " << io::rate(cmsBondParAssetSwapSpread1) <<
2339 std::scientific << std::setprecision(2) <<
2340 "\n error: " << error5 <<
2341 "\n tolerance: " << tolerance2);
2342
2343 // CMS Underlying bond (Isin: XS0218766664 ISPIM 0 5/6/15)
2344 // maturity occurs on a business day
2345
2346 Date cmsBondStartDate2 = Date(06,May,2005);
2347 Date cmsBondMaturityDate2 = Date(06,May,2015);
2348 Schedule cmsBondSchedule2(cmsBondStartDate2,
2349 cmsBondMaturityDate2,
2350 Period(Annual), bondCalendar,
2351 Unadjusted, Unadjusted,
2352 DateGeneration::Backward, false);
2353 Leg cmsBondLeg2 = CmsLeg(cmsBondSchedule2, vars.swapIndex)
2354 .withNotionals(notional: vars.faceAmount)
2355 .withPaymentDayCounter(Thirty360(Thirty360::BondBasis))
2356 .withFixingDays(fixingDays)
2357 .withGearings(gearing: 0.84)
2358 .inArrears(flag: inArrears);
2359 Date cmsbondRedemption2 = bondCalendar.adjust(cmsBondMaturityDate2,
2360 convention: Following);
2361 cmsBondLeg2.push_back(x: ext::shared_ptr<CashFlow>(new
2362 SimpleCashFlow(100.0, cmsbondRedemption2)));
2363 ext::shared_ptr<Bond> cmsBond2(new
2364 Bond(settlementDays, bondCalendar, vars.faceAmount,
2365 cmsBondMaturityDate2, cmsBondStartDate2, cmsBondLeg2));
2366 cmsBond2->setPricingEngine(bondEngine);
2367
2368 setCouponPricer(leg: cmsBond2->cashflows(), vars.cmspricer);
2369 vars.swapIndex->addFixing(fixingDate: Date(04,May,2006), fixing: 0.04217);
2370 Real cmsBondMktPrice2 = 94.08 ; // market price observed on 7th June 2007
2371 Real cmsBondMktFullPrice2 = cmsBondMktPrice2+cmsBond2->accruedAmount();
2372 AssetSwap cmsBondParAssetSwap2(payFixedRate,
2373 cmsBond2, cmsBondMktPrice2,
2374 vars.iborIndex, vars.spread,
2375 Schedule(),
2376 vars.iborIndex->dayCounter(),
2377 parAssetSwap);
2378 cmsBondParAssetSwap2.setPricingEngine(swapEngine);
2379 Spread cmsBondParAssetSwapSpread2 = cmsBondParAssetSwap2.fairSpread();
2380 AssetSwap cmsBondMktAssetSwap2(payFixedRate,
2381 cmsBond2, cmsBondMktPrice2,
2382 vars.iborIndex, vars.spread,
2383 Schedule(),
2384 vars.iborIndex->dayCounter(),
2385 mktAssetSwap);
2386 cmsBondMktAssetSwap2.setPricingEngine(swapEngine);
2387 Real cmsBondMktAssetSwapSpread2 = cmsBondMktAssetSwap2.fairSpread();
2388 Real error6 =
2389 std::fabs(x: cmsBondMktAssetSwapSpread2-
2390 100*cmsBondParAssetSwapSpread2/cmsBondMktFullPrice2);
2391
2392 if (error6>tolerance2)
2393 BOOST_FAIL("wrong asset swap spreads for cms bond:" <<
2394 std::fixed << std::setprecision(4) <<
2395 "\n market asset swap spread: " << io::rate(cmsBondMktAssetSwapSpread2) <<
2396 "\n par asset swap spread: " << io::rate(cmsBondParAssetSwapSpread2) <<
2397 std::scientific << std::setprecision(2) <<
2398 "\n error: " << error6 <<
2399 "\n tolerance: " << tolerance2);
2400
2401 // Zero Coupon bond (Isin: DE0004771662 IBRD 0 12/20/15)
2402 // maturity doesn't occur on a business day
2403
2404 Date zeroCpnBondStartDate1 = Date(19,December,1985);
2405 Date zeroCpnBondMaturityDate1 = Date(20,December,2015);
2406 Date zeroCpnBondRedemption1 = bondCalendar.adjust(zeroCpnBondMaturityDate1,
2407 convention: Following);
2408 Leg zeroCpnBondLeg1 = Leg(1, ext::shared_ptr<CashFlow>(new
2409 SimpleCashFlow(100.0, zeroCpnBondRedemption1)));
2410 ext::shared_ptr<Bond> zeroCpnBond1(new
2411 Bond(settlementDays, bondCalendar, vars.faceAmount,
2412 zeroCpnBondMaturityDate1, zeroCpnBondStartDate1, zeroCpnBondLeg1));
2413 zeroCpnBond1->setPricingEngine(bondEngine);
2414
2415 // market price observed on 12th June 2007
2416 Real zeroCpnBondMktPrice1 = 70.436 ;
2417 Real zeroCpnBondMktFullPrice1 =
2418 zeroCpnBondMktPrice1+zeroCpnBond1->accruedAmount();
2419 AssetSwap zeroCpnBondParAssetSwap1(payFixedRate,zeroCpnBond1,
2420 zeroCpnBondMktPrice1,
2421 vars.iborIndex, vars.spread,
2422 Schedule(),
2423 vars.iborIndex->dayCounter(),
2424 parAssetSwap);
2425 zeroCpnBondParAssetSwap1.setPricingEngine(swapEngine);
2426 Real zeroCpnBondParAssetSwapSpread1 = zeroCpnBondParAssetSwap1.fairSpread();
2427 AssetSwap zeroCpnBondMktAssetSwap1(payFixedRate,zeroCpnBond1,
2428 zeroCpnBondMktPrice1,
2429 vars.iborIndex, vars.spread,
2430 Schedule(),
2431 vars.iborIndex->dayCounter(),
2432 mktAssetSwap);
2433 zeroCpnBondMktAssetSwap1.setPricingEngine(swapEngine);
2434 Real zeroCpnBondMktAssetSwapSpread1 = zeroCpnBondMktAssetSwap1.fairSpread();
2435 Real error7 =
2436 std::fabs(x: zeroCpnBondMktAssetSwapSpread1-
2437 100*zeroCpnBondParAssetSwapSpread1/zeroCpnBondMktFullPrice1);
2438
2439 if (error7>tolerance2)
2440 BOOST_FAIL("wrong asset swap spreads for zero cpn bond:" <<
2441 std::fixed << std::setprecision(4) <<
2442 "\n market asset swap spread: " << io::rate(zeroCpnBondMktAssetSwapSpread1) <<
2443 "\n par asset swap spread: " << io::rate(zeroCpnBondParAssetSwapSpread1) <<
2444 std::scientific << std::setprecision(2) <<
2445 "\n error: " << error7 <<
2446 "\n tolerance: " << tolerance2);
2447
2448 // Zero Coupon bond (Isin: IT0001200390 ISPIM 0 02/17/28)
2449 // maturity occurs on a business day
2450
2451 Date zeroCpnBondStartDate2 = Date(17,February,1998);
2452 Date zeroCpnBondMaturityDate2 = Date(17,February,2028);
2453 Date zerocpbondRedemption2 = bondCalendar.adjust(zeroCpnBondMaturityDate2,
2454 convention: Following);
2455 Leg zeroCpnBondLeg2 = Leg(1, ext::shared_ptr<CashFlow>(new
2456 SimpleCashFlow(100.0, zerocpbondRedemption2)));
2457 ext::shared_ptr<Bond> zeroCpnBond2(new
2458 Bond(settlementDays, bondCalendar, vars.faceAmount,
2459 zeroCpnBondMaturityDate2, zeroCpnBondStartDate2, zeroCpnBondLeg2));
2460 zeroCpnBond2->setPricingEngine(bondEngine);
2461
2462 // Real zeroCpnBondPrice2 = zeroCpnBond2->cleanPrice();
2463 // market price observed on 12th June 2007
2464 Real zeroCpnBondMktPrice2 = 35.160 ;
2465 Real zeroCpnBondMktFullPrice2 =
2466 zeroCpnBondMktPrice2+zeroCpnBond2->accruedAmount();
2467 AssetSwap zeroCpnBondParAssetSwap2(payFixedRate,zeroCpnBond2,
2468 zeroCpnBondMktPrice2,
2469 vars.iborIndex, vars.spread,
2470 Schedule(),
2471 vars.iborIndex->dayCounter(),
2472 parAssetSwap);
2473 zeroCpnBondParAssetSwap2.setPricingEngine(swapEngine);
2474 Real zeroCpnBondParAssetSwapSpread2 = zeroCpnBondParAssetSwap2.fairSpread();
2475 AssetSwap zeroCpnBondMktAssetSwap2(payFixedRate,zeroCpnBond2,
2476 zeroCpnBondMktPrice2,
2477 vars.iborIndex, vars.spread,
2478 Schedule(),
2479 vars.iborIndex->dayCounter(),
2480 mktAssetSwap);
2481 zeroCpnBondMktAssetSwap2.setPricingEngine(swapEngine);
2482 Real zeroCpnBondMktAssetSwapSpread2 = zeroCpnBondMktAssetSwap2.fairSpread();
2483 Real error8 =
2484 std::fabs(x: zeroCpnBondMktAssetSwapSpread2-
2485 100*zeroCpnBondParAssetSwapSpread2/zeroCpnBondMktFullPrice2);
2486
2487 if (error8>tolerance2)
2488 BOOST_FAIL("wrong asset swap spreads for zero cpn bond:" <<
2489 std::fixed << std::setprecision(4) <<
2490 "\n market asset swap spread: " << io::rate(zeroCpnBondMktAssetSwapSpread2) <<
2491 "\n par asset swap spread: " << io::rate(zeroCpnBondParAssetSwapSpread2) <<
2492 std::scientific << std::setprecision(2) <<
2493 "\n error: " << error8 <<
2494 "\n tolerance: " << tolerance2);
2495}
2496
2497
2498void AssetSwapTest::testZSpreadWithGenericBond() {
2499
2500 BOOST_TEST_MESSAGE("Testing clean and dirty price with null Z-spread "
2501 "against theoretical prices...");
2502
2503 using namespace asset_swap_test;
2504
2505 CommonVars vars;
2506
2507 Calendar bondCalendar = TARGET();
2508 Natural settlementDays = 3;
2509 Natural fixingDays = 2;
2510 bool inArrears = false;
2511
2512 // Fixed Underlying bond (Isin: DE0001135275 DBR 4 01/04/37)
2513 // maturity doesn't occur on a business day
2514
2515 Date fixedBondStartDate1 = Date(4,January,2005);
2516 Date fixedBondMaturityDate1 = Date(4,January,2037);
2517 Schedule fixedBondSchedule1(fixedBondStartDate1,
2518 fixedBondMaturityDate1,
2519 Period(Annual), bondCalendar,
2520 Unadjusted, Unadjusted,
2521 DateGeneration::Backward, false);
2522 Leg fixedBondLeg1 = FixedRateLeg(fixedBondSchedule1)
2523 .withNotionals(vars.faceAmount)
2524 .withCouponRates(0.04, paymentDayCounter: ActualActual(ActualActual::ISDA));
2525 Date fixedbondRedemption1 = bondCalendar.adjust(fixedBondMaturityDate1,
2526 convention: Following);
2527 fixedBondLeg1.push_back(x: ext::shared_ptr<CashFlow>(new
2528 SimpleCashFlow(100.0, fixedbondRedemption1)));
2529 ext::shared_ptr<Bond> fixedBond1(new
2530 Bond(settlementDays, bondCalendar, vars.faceAmount,
2531 fixedBondMaturityDate1, fixedBondStartDate1,
2532 fixedBondLeg1));
2533 ext::shared_ptr<PricingEngine> bondEngine(new
2534 DiscountingBondEngine(vars.termStructure));
2535 fixedBond1->setPricingEngine(bondEngine);
2536
2537 Real fixedBondImpliedValue1 = fixedBond1->cleanPrice();
2538 Date fixedBondSettlementDate1= fixedBond1->settlementDate();
2539 // standard market conventions:
2540 // bond's frequency + coumpounding and daycounter of the YieldCurve
2541 Real fixedBondCleanPrice1 = BondFunctions::cleanPrice(
2542 bond: *fixedBond1, discount: *vars.termStructure, zSpread: vars.spread,
2543 dayCounter: Actual365Fixed(), compounding: vars.compounding, frequency: Annual,
2544 settlementDate: fixedBondSettlementDate1);
2545 Real tolerance = 1.0e-13;
2546 Real error1 = std::fabs(x: fixedBondImpliedValue1-fixedBondCleanPrice1);
2547 if (error1>tolerance) {
2548 BOOST_FAIL("wrong clean price for fixed bond:"
2549 << std::fixed << std::setprecision(4)
2550 << "\n market asset swap spread: "
2551 << fixedBondImpliedValue1
2552 << "\n par asset swap spread: " << fixedBondCleanPrice1
2553 << std::scientific << std::setprecision(2)
2554 << "\n error: " << error1
2555 << "\n tolerance: " << tolerance);
2556 }
2557
2558 // Fixed Underlying bond (Isin: IT0006527060 IBRD 5 02/05/19)
2559 // maturity occurs on a business day
2560
2561 Date fixedBondStartDate2 = Date(5,February,2005);
2562 Date fixedBondMaturityDate2 = Date(5,February,2019);
2563 Schedule fixedBondSchedule2(fixedBondStartDate2,
2564 fixedBondMaturityDate2,
2565 Period(Annual), bondCalendar,
2566 Unadjusted, Unadjusted,
2567 DateGeneration::Backward, false);
2568 Leg fixedBondLeg2 = FixedRateLeg(fixedBondSchedule2)
2569 .withNotionals(vars.faceAmount)
2570 .withCouponRates(0.05, paymentDayCounter: Thirty360(Thirty360::BondBasis));
2571 Date fixedbondRedemption2 = bondCalendar.adjust(fixedBondMaturityDate2,
2572 convention: Following);
2573 fixedBondLeg2.push_back(x: ext::shared_ptr<CashFlow>(new
2574 SimpleCashFlow(100.0, fixedbondRedemption2)));
2575 ext::shared_ptr<Bond> fixedBond2(new
2576 Bond(settlementDays, bondCalendar, vars.faceAmount,
2577 fixedBondMaturityDate2, fixedBondStartDate2, fixedBondLeg2));
2578 fixedBond2->setPricingEngine(bondEngine);
2579
2580 Real fixedBondImpliedValue2 = fixedBond2->cleanPrice();
2581 Date fixedBondSettlementDate2= fixedBond2->settlementDate();
2582 // standard market conventions:
2583 // bond's frequency + coumpounding and daycounter of the YieldCurve
2584
2585 Real fixedBondCleanPrice2 = BondFunctions::cleanPrice(
2586 bond: *fixedBond2, discount: *vars.termStructure, zSpread: vars.spread,
2587 dayCounter: Actual365Fixed(), compounding: vars.compounding, frequency: Annual,
2588 settlementDate: fixedBondSettlementDate2);
2589 Real error3 = std::fabs(x: fixedBondImpliedValue2-fixedBondCleanPrice2);
2590 if (error3>tolerance) {
2591 BOOST_FAIL("wrong clean price for fixed bond:"
2592 << std::fixed << std::setprecision(4)
2593 << "\n market asset swap spread: "
2594 << fixedBondImpliedValue2
2595 << "\n par asset swap spread: " << fixedBondCleanPrice2
2596 << std::scientific << std::setprecision(2)
2597 << "\n error: " << error3
2598 << "\n tolerance: " << tolerance);
2599 }
2600
2601 // FRN Underlying bond (Isin: IT0003543847 ISPIM 0 09/29/13)
2602 // maturity doesn't occur on a business day
2603
2604 Date floatingBondStartDate1 = Date(29,September,2003);
2605 Date floatingBondMaturityDate1 = Date(29,September,2013);
2606 Schedule floatingBondSchedule1(floatingBondStartDate1,
2607 floatingBondMaturityDate1,
2608 Period(Semiannual), bondCalendar,
2609 Unadjusted, Unadjusted,
2610 DateGeneration::Backward, false);
2611 Leg floatingBondLeg1 = IborLeg(floatingBondSchedule1, vars.iborIndex)
2612 .withNotionals(notional: vars.faceAmount)
2613 .withPaymentDayCounter(Actual360())
2614 .withFixingDays(fixingDays)
2615 .withSpreads(spread: 0.0056)
2616 .inArrears(flag: inArrears);
2617 Date floatingbondRedemption1 =
2618 bondCalendar.adjust(floatingBondMaturityDate1, convention: Following);
2619 floatingBondLeg1.push_back(x: ext::shared_ptr<CashFlow>(new
2620 SimpleCashFlow(100.0, floatingbondRedemption1)));
2621 ext::shared_ptr<Bond> floatingBond1(new
2622 Bond(settlementDays, bondCalendar, vars.faceAmount,
2623 floatingBondMaturityDate1, floatingBondStartDate1,
2624 floatingBondLeg1));
2625 floatingBond1->setPricingEngine(bondEngine);
2626
2627 setCouponPricer(leg: floatingBond1->cashflows(), vars.pricer);
2628 vars.iborIndex->addFixing(fixingDate: Date(27,March,2007), fixing: 0.0402);
2629 Real floatingBondImpliedValue1 = floatingBond1->cleanPrice();
2630 // standard market conventions:
2631 // bond's frequency + coumpounding and daycounter of the YieldCurve
2632 Real floatingBondCleanPrice1 = BondFunctions::cleanPrice(
2633 bond: *floatingBond1, discount: *vars.termStructure,
2634 zSpread: vars.spread, dayCounter: Actual365Fixed(), compounding: vars.compounding, frequency: Semiannual,
2635 settlementDate: fixedBondSettlementDate1);
2636 Real error5 = std::fabs(x: floatingBondImpliedValue1-floatingBondCleanPrice1);
2637 if (error5>tolerance) {
2638 BOOST_FAIL("wrong clean price for fixed bond:"
2639 << std::fixed << std::setprecision(4)
2640 << "\n market asset swap spread: " <<
2641 floatingBondImpliedValue1
2642 << "\n par asset swap spread: " << floatingBondCleanPrice1
2643 << std::scientific << std::setprecision(2)
2644 << "\n error: " << error5
2645 << "\n tolerance: " << tolerance);
2646 }
2647
2648 // FRN Underlying bond (Isin: XS0090566539 COE 0 09/24/18)
2649 // maturity occurs on a business day
2650
2651 Date floatingBondStartDate2 = Date(24,September,2004);
2652 Date floatingBondMaturityDate2 = Date(24,September,2018);
2653 Schedule floatingBondSchedule2(floatingBondStartDate2,
2654 floatingBondMaturityDate2,
2655 Period(Semiannual), bondCalendar,
2656 ModifiedFollowing, ModifiedFollowing,
2657 DateGeneration::Backward, false);
2658 Leg floatingBondLeg2 = IborLeg(floatingBondSchedule2, vars.iborIndex)
2659 .withNotionals(notional: vars.faceAmount)
2660 .withPaymentDayCounter(Actual360())
2661 .withPaymentAdjustment(ModifiedFollowing)
2662 .withFixingDays(fixingDays)
2663 .withSpreads(spread: 0.0025)
2664 .inArrears(flag: inArrears);
2665 Date floatingbondRedemption2 =
2666 bondCalendar.adjust(floatingBondMaturityDate2, convention: ModifiedFollowing);
2667 floatingBondLeg2.push_back(x: ext::shared_ptr<CashFlow>(new
2668 SimpleCashFlow(100.0, floatingbondRedemption2)));
2669 ext::shared_ptr<Bond> floatingBond2(new
2670 Bond(settlementDays, bondCalendar, vars.faceAmount,
2671 floatingBondMaturityDate2, floatingBondStartDate2,
2672 floatingBondLeg2));
2673 floatingBond2->setPricingEngine(bondEngine);
2674
2675 setCouponPricer(leg: floatingBond2->cashflows(), vars.pricer);
2676 vars.iborIndex->addFixing(fixingDate: Date(22,March,2007), fixing: 0.04013);
2677 Real floatingBondImpliedValue2 = floatingBond2->cleanPrice();
2678 // standard market conventions:
2679 // bond's frequency + coumpounding and daycounter of the YieldCurve
2680 Real floatingBondCleanPrice2 = BondFunctions::cleanPrice(
2681 bond: *floatingBond2, discount: *vars.termStructure,
2682 zSpread: vars.spread, dayCounter: Actual365Fixed(), compounding: vars.compounding, frequency: Semiannual,
2683 settlementDate: fixedBondSettlementDate1);
2684 Real error7 = std::fabs(x: floatingBondImpliedValue2-floatingBondCleanPrice2);
2685 if (error7>tolerance) {
2686 BOOST_FAIL("wrong clean price for fixed bond:"
2687 << std::fixed << std::setprecision(4)
2688 << "\n market asset swap spread: " <<
2689 floatingBondImpliedValue2
2690 << "\n par asset swap spread: " << floatingBondCleanPrice2
2691 << std::scientific << std::setprecision(2)
2692 << "\n error: " << error7
2693 << "\n tolerance: " << tolerance);
2694 }
2695
2696 // CMS Underlying bond (Isin: XS0228052402 CRDIT 0 8/22/20)
2697 // maturity doesn't occur on a business day
2698
2699 Date cmsBondStartDate1 = Date(22,August,2005);
2700 Date cmsBondMaturityDate1 = Date(22,August,2020);
2701 Schedule cmsBondSchedule1(cmsBondStartDate1,
2702 cmsBondMaturityDate1,
2703 Period(Annual), bondCalendar,
2704 Unadjusted, Unadjusted,
2705 DateGeneration::Backward, false);
2706 Leg cmsBondLeg1 = CmsLeg(cmsBondSchedule1, vars.swapIndex)
2707 .withNotionals(notional: vars.faceAmount)
2708 .withPaymentDayCounter(Thirty360(Thirty360::BondBasis))
2709 .withFixingDays(fixingDays)
2710 .withCaps(cap: 0.055)
2711 .withFloors(floor: 0.025)
2712 .inArrears(flag: inArrears);
2713 Date cmsbondRedemption1 = bondCalendar.adjust(cmsBondMaturityDate1,
2714 convention: Following);
2715 cmsBondLeg1.push_back(x: ext::shared_ptr<CashFlow>(new
2716 SimpleCashFlow(100.0, cmsbondRedemption1)));
2717 ext::shared_ptr<Bond> cmsBond1(new
2718 Bond(settlementDays, bondCalendar, vars.faceAmount,
2719 cmsBondMaturityDate1, cmsBondStartDate1, cmsBondLeg1));
2720 cmsBond1->setPricingEngine(bondEngine);
2721
2722 setCouponPricer(leg: cmsBond1->cashflows(), vars.cmspricer);
2723 vars.swapIndex->addFixing(fixingDate: Date(18,August,2006), fixing: 0.04158);
2724 Real cmsBondImpliedValue1 = cmsBond1->cleanPrice();
2725 Date cmsBondSettlementDate1= cmsBond1->settlementDate();
2726 // standard market conventions:
2727 // bond's frequency + coumpounding and daycounter of the YieldCurve
2728 Real cmsBondCleanPrice1 = BondFunctions::cleanPrice(
2729 bond: *cmsBond1, discount: *vars.termStructure, zSpread: vars.spread,
2730 dayCounter: Actual365Fixed(), compounding: vars.compounding, frequency: Annual,
2731 settlementDate: cmsBondSettlementDate1);
2732 Real error9 = std::fabs(x: cmsBondImpliedValue1-cmsBondCleanPrice1);
2733 if (error9>tolerance) {
2734 BOOST_FAIL("wrong clean price for fixed bond:"
2735 << std::fixed << std::setprecision(4)
2736 << "\n market asset swap spread: " << cmsBondImpliedValue1
2737 << "\n par asset swap spread: " << cmsBondCleanPrice1
2738 << std::scientific << std::setprecision(2)
2739 << "\n error: " << error9
2740 << "\n tolerance: " << tolerance);
2741 }
2742
2743 // CMS Underlying bond (Isin: XS0218766664 ISPIM 0 5/6/15)
2744 // maturity occurs on a business day
2745
2746 Date cmsBondStartDate2 = Date(06,May,2005);
2747 Date cmsBondMaturityDate2 = Date(06,May,2015);
2748 Schedule cmsBondSchedule2(cmsBondStartDate2,
2749 cmsBondMaturityDate2,
2750 Period(Annual), bondCalendar,
2751 Unadjusted, Unadjusted,
2752 DateGeneration::Backward, false);
2753 Leg cmsBondLeg2 = CmsLeg(cmsBondSchedule2, vars.swapIndex)
2754 .withNotionals(notional: vars.faceAmount)
2755 .withPaymentDayCounter(Thirty360(Thirty360::BondBasis))
2756 .withFixingDays(fixingDays)
2757 .withGearings(gearing: 0.84)
2758 .inArrears(flag: inArrears);
2759 Date cmsbondRedemption2 = bondCalendar.adjust(cmsBondMaturityDate2,
2760 convention: Following);
2761 cmsBondLeg2.push_back(x: ext::shared_ptr<CashFlow>(new
2762 SimpleCashFlow(100.0, cmsbondRedemption2)));
2763 ext::shared_ptr<Bond> cmsBond2(new
2764 Bond(settlementDays, bondCalendar, vars.faceAmount,
2765 cmsBondMaturityDate2, cmsBondStartDate2, cmsBondLeg2));
2766 cmsBond2->setPricingEngine(bondEngine);
2767
2768 setCouponPricer(leg: cmsBond2->cashflows(), vars.cmspricer);
2769 vars.swapIndex->addFixing(fixingDate: Date(04,May,2006), fixing: 0.04217);
2770 Real cmsBondImpliedValue2 = cmsBond2->cleanPrice();
2771 Date cmsBondSettlementDate2= cmsBond2->settlementDate();
2772 // standard market conventions:
2773 // bond's frequency + coumpounding and daycounter of the YieldCurve
2774 Real cmsBondCleanPrice2 = BondFunctions::cleanPrice(
2775 bond: *cmsBond2, discount: *vars.termStructure, zSpread: vars.spread,
2776 dayCounter: Actual365Fixed(), compounding: vars.compounding, frequency: Annual,
2777 settlementDate: cmsBondSettlementDate2);
2778 Real error11 = std::fabs(x: cmsBondImpliedValue2-cmsBondCleanPrice2);
2779 if (error11>tolerance) {
2780 BOOST_FAIL("wrong clean price for fixed bond:"
2781 << std::fixed << std::setprecision(4)
2782 << "\n market asset swap spread: " << cmsBondImpliedValue2
2783 << "\n par asset swap spread: " << cmsBondCleanPrice2
2784 << std::scientific << std::setprecision(2)
2785 << "\n error: " << error11
2786 << "\n tolerance: " << tolerance);
2787 }
2788
2789 // Zero Coupon bond (Isin: DE0004771662 IBRD 0 12/20/15)
2790 // maturity doesn't occur on a business day
2791
2792 Date zeroCpnBondStartDate1 = Date(19,December,1985);
2793 Date zeroCpnBondMaturityDate1 = Date(20,December,2015);
2794 Date zeroCpnBondRedemption1 = bondCalendar.adjust(zeroCpnBondMaturityDate1,
2795 convention: Following);
2796 Leg zeroCpnBondLeg1 = Leg(1, ext::shared_ptr<CashFlow>(new
2797 SimpleCashFlow(100.0, zeroCpnBondRedemption1)));
2798 ext::shared_ptr<Bond> zeroCpnBond1(new
2799 Bond(settlementDays, bondCalendar, vars.faceAmount,
2800 zeroCpnBondMaturityDate1, zeroCpnBondStartDate1, zeroCpnBondLeg1));
2801 zeroCpnBond1->setPricingEngine(bondEngine);
2802
2803 Real zeroCpnBondImpliedValue1 = zeroCpnBond1->cleanPrice();
2804 Date zeroCpnBondSettlementDate1= zeroCpnBond1->settlementDate();
2805 // standard market conventions:
2806 // bond's frequency + coumpounding and daycounter of the YieldCurve
2807 Real zeroCpnBondCleanPrice1 =
2808 BondFunctions::cleanPrice(bond: *zeroCpnBond1,
2809 discount: *vars.termStructure,
2810 zSpread: vars.spread,
2811 dayCounter: Actual365Fixed(),
2812 compounding: vars.compounding, frequency: Annual,
2813 settlementDate: zeroCpnBondSettlementDate1);
2814 Real error13 = std::fabs(x: zeroCpnBondImpliedValue1-zeroCpnBondCleanPrice1);
2815 if (error13>tolerance) {
2816 BOOST_FAIL("wrong clean price for zero coupon bond:"
2817 << std::fixed << std::setprecision(4)
2818 << "\n zero cpn implied value: " <<
2819 zeroCpnBondImpliedValue1
2820 << "\n zero cpn price: " << zeroCpnBondCleanPrice1
2821 << std::scientific << std::setprecision(2)
2822 << "\n error: " << error13
2823 << "\n tolerance: " << tolerance);
2824 }
2825
2826 // Zero Coupon bond (Isin: IT0001200390 ISPIM 0 02/17/28)
2827 // maturity occurs on a business day
2828
2829 Date zeroCpnBondStartDate2 = Date(17,February,1998);
2830 Date zeroCpnBondMaturityDate2 = Date(17,February,2028);
2831 Date zerocpbondRedemption2 = bondCalendar.adjust(zeroCpnBondMaturityDate2,
2832 convention: Following);
2833 Leg zeroCpnBondLeg2 = Leg(1, ext::shared_ptr<CashFlow>(new
2834 SimpleCashFlow(100.0, zerocpbondRedemption2)));
2835 ext::shared_ptr<Bond> zeroCpnBond2(new
2836 Bond(settlementDays, bondCalendar, vars.faceAmount,
2837 zeroCpnBondMaturityDate2, zeroCpnBondStartDate2, zeroCpnBondLeg2));
2838 zeroCpnBond2->setPricingEngine(bondEngine);
2839
2840 Real zeroCpnBondImpliedValue2 = zeroCpnBond2->cleanPrice();
2841 Date zeroCpnBondSettlementDate2= zeroCpnBond2->settlementDate();
2842 // standard market conventions:
2843 // bond's frequency + coumpounding and daycounter of the YieldCurve
2844 Real zeroCpnBondCleanPrice2 =
2845 BondFunctions::cleanPrice(bond: *zeroCpnBond2,
2846 discount: *vars.termStructure,
2847 zSpread: vars.spread,
2848 dayCounter: Actual365Fixed(),
2849 compounding: vars.compounding, frequency: Annual,
2850 settlementDate: zeroCpnBondSettlementDate2);
2851 Real error15 = std::fabs(x: zeroCpnBondImpliedValue2-zeroCpnBondCleanPrice2);
2852 if (error15>tolerance) {
2853 BOOST_FAIL("wrong clean price for zero coupon bond:"
2854 << std::fixed << std::setprecision(4)
2855 << "\n zero cpn implied value: " <<
2856 zeroCpnBondImpliedValue2
2857 << "\n zero cpn price: " << zeroCpnBondCleanPrice2
2858 << std::scientific << std::setprecision(2)
2859 << "\n error: " << error15
2860 << "\n tolerance: " << tolerance);
2861 }
2862}
2863
2864
2865void AssetSwapTest::testSpecializedBondVsGenericBond() {
2866
2867 BOOST_TEST_MESSAGE("Testing clean and dirty prices for specialized bond"
2868 " against equivalent generic bond...");
2869
2870 using namespace asset_swap_test;
2871
2872 CommonVars vars;
2873
2874 Calendar bondCalendar = TARGET();
2875 Natural settlementDays = 3;
2876 Natural fixingDays = 2;
2877 bool inArrears = false;
2878
2879 // Fixed Underlying bond (Isin: DE0001135275 DBR 4 01/04/37)
2880 // maturity doesn't occur on a business day
2881 Date fixedBondStartDate1 = Date(4,January,2005);
2882 Date fixedBondMaturityDate1 = Date(4,January,2037);
2883 Schedule fixedBondSchedule1(fixedBondStartDate1,
2884 fixedBondMaturityDate1,
2885 Period(Annual), bondCalendar,
2886 Unadjusted, Unadjusted,
2887 DateGeneration::Backward, false);
2888 Leg fixedBondLeg1 = FixedRateLeg(fixedBondSchedule1)
2889 .withNotionals(vars.faceAmount)
2890 .withCouponRates(0.04, paymentDayCounter: ActualActual(ActualActual::ISDA));
2891 Date fixedbondRedemption1 = bondCalendar.adjust(fixedBondMaturityDate1,
2892 convention: Following);
2893 fixedBondLeg1.push_back(x: ext::shared_ptr<CashFlow>(new
2894 SimpleCashFlow(100.0, fixedbondRedemption1)));
2895 // generic bond
2896 ext::shared_ptr<Bond> fixedBond1(new
2897 Bond(settlementDays, bondCalendar, vars.faceAmount,
2898 fixedBondMaturityDate1, fixedBondStartDate1,
2899 fixedBondLeg1));
2900 ext::shared_ptr<PricingEngine> bondEngine(new
2901 DiscountingBondEngine(vars.termStructure));
2902 fixedBond1->setPricingEngine(bondEngine);
2903
2904 // equivalent specialized fixed rate bond
2905 ext::shared_ptr<Bond> fixedSpecializedBond1(new
2906 FixedRateBond(settlementDays, vars.faceAmount, fixedBondSchedule1,
2907 std::vector<Rate>(1, 0.04),
2908 ActualActual(ActualActual::ISDA), Following,
2909 100.0, Date(4,January,2005) ));
2910 fixedSpecializedBond1->setPricingEngine(bondEngine);
2911
2912 Real fixedBondTheoValue1 = fixedBond1->cleanPrice();
2913 Real fixedSpecializedBondTheoValue1 = fixedSpecializedBond1->cleanPrice();
2914 Real tolerance = 1.0e-13;
2915 Real error1 = std::fabs(x: fixedBondTheoValue1-fixedSpecializedBondTheoValue1);
2916 if (error1>tolerance) {
2917 BOOST_FAIL("wrong clean price for fixed bond:"
2918 << std::fixed << std::setprecision(4)
2919 << "\n specialized fixed rate bond's theo clean price: "
2920 << fixedBondTheoValue1
2921 << "\n generic equivalent bond's theo clean price: "
2922 << fixedSpecializedBondTheoValue1
2923 << std::scientific << std::setprecision(2)
2924 << "\n error: " << error1
2925 << "\n tolerance: " << tolerance);
2926 }
2927 Real fixedBondTheoDirty1 = fixedBondTheoValue1+fixedBond1->accruedAmount();
2928 Real fixedSpecializedTheoDirty1 = fixedSpecializedBondTheoValue1+
2929 fixedSpecializedBond1->accruedAmount();
2930 Real error2 = std::fabs(x: fixedBondTheoDirty1-fixedSpecializedTheoDirty1);
2931 if (error2>tolerance) {
2932 BOOST_FAIL("wrong dirty price for fixed bond:"
2933 << std::fixed << std::setprecision(4)
2934 << "\n specialized fixed rate bond's theo dirty price: "
2935 << fixedBondTheoDirty1
2936 << "\n generic equivalent bond's theo dirty price: "
2937 << fixedSpecializedTheoDirty1
2938 << std::scientific << std::setprecision(2)
2939 << "\n error: " << error2
2940 << "\n tolerance: " << tolerance);
2941 }
2942
2943 // Fixed Underlying bond (Isin: IT0006527060 IBRD 5 02/05/19)
2944 // maturity occurs on a business day
2945 Date fixedBondStartDate2 = Date(5,February,2005);
2946 Date fixedBondMaturityDate2 = Date(5,February,2019);
2947 Schedule fixedBondSchedule2(fixedBondStartDate2,
2948 fixedBondMaturityDate2,
2949 Period(Annual), bondCalendar,
2950 Unadjusted, Unadjusted,
2951 DateGeneration::Backward, false);
2952 Leg fixedBondLeg2 = FixedRateLeg(fixedBondSchedule2)
2953 .withNotionals(vars.faceAmount)
2954 .withCouponRates(0.05, paymentDayCounter: Thirty360(Thirty360::BondBasis));
2955 Date fixedbondRedemption2 = bondCalendar.adjust(fixedBondMaturityDate2,
2956 convention: Following);
2957 fixedBondLeg2.push_back(x: ext::shared_ptr<CashFlow>(new
2958 SimpleCashFlow(100.0, fixedbondRedemption2)));
2959
2960 // generic bond
2961 ext::shared_ptr<Bond> fixedBond2(new
2962 Bond(settlementDays, bondCalendar, vars.faceAmount,
2963 fixedBondMaturityDate2, fixedBondStartDate2, fixedBondLeg2));
2964 fixedBond2->setPricingEngine(bondEngine);
2965
2966 // equivalent specialized fixed rate bond
2967 ext::shared_ptr<Bond> fixedSpecializedBond2(new
2968 FixedRateBond(settlementDays, vars.faceAmount, fixedBondSchedule2,
2969 std::vector<Rate>(1, 0.05),
2970 Thirty360(Thirty360::BondBasis), Following,
2971 100.0, Date(5,February,2005)));
2972 fixedSpecializedBond2->setPricingEngine(bondEngine);
2973
2974 Real fixedBondTheoValue2 = fixedBond2->cleanPrice();
2975 Real fixedSpecializedBondTheoValue2 = fixedSpecializedBond2->cleanPrice();
2976
2977 Real error3 = std::fabs(x: fixedBondTheoValue2-fixedSpecializedBondTheoValue2);
2978 if (error3>tolerance) {
2979 BOOST_FAIL("wrong clean price for fixed bond:"
2980 << std::fixed << std::setprecision(4)
2981 << "\n specialized fixed rate bond's theo clean price: "
2982 << fixedBondTheoValue2
2983 << "\n generic equivalent bond's theo clean price: "
2984 << fixedSpecializedBondTheoValue2
2985 << "\n error: " << error3
2986 << "\n tolerance: " << tolerance);
2987 }
2988 Real fixedBondTheoDirty2 = fixedBondTheoValue2+
2989 fixedBond2->accruedAmount();
2990 Real fixedSpecializedBondTheoDirty2 = fixedSpecializedBondTheoValue2+
2991 fixedSpecializedBond2->accruedAmount();
2992
2993 Real error4 = std::fabs(x: fixedBondTheoDirty2-fixedSpecializedBondTheoDirty2);
2994 if (error4>tolerance) {
2995 BOOST_FAIL("wrong dirty price for fixed bond:"
2996 << std::fixed << std::setprecision(4)
2997 << "\n specialized fixed rate bond's dirty clean price: "
2998 << fixedBondTheoDirty2
2999 << "\n generic equivalent bond's theo dirty price: "
3000 << fixedSpecializedBondTheoDirty2
3001 << std::scientific << std::setprecision(2)
3002 << "\n error: " << error4
3003 << "\n tolerance: " << tolerance);
3004 }
3005
3006 // FRN Underlying bond (Isin: IT0003543847 ISPIM 0 09/29/13)
3007 // maturity doesn't occur on a business day
3008 Date floatingBondStartDate1 = Date(29,September,2003);
3009 Date floatingBondMaturityDate1 = Date(29,September,2013);
3010 Schedule floatingBondSchedule1(floatingBondStartDate1,
3011 floatingBondMaturityDate1,
3012 Period(Semiannual), bondCalendar,
3013 Unadjusted, Unadjusted,
3014 DateGeneration::Backward, false);
3015 Leg floatingBondLeg1 = IborLeg(floatingBondSchedule1, vars.iborIndex)
3016 .withNotionals(notional: vars.faceAmount)
3017 .withPaymentDayCounter(Actual360())
3018 .withFixingDays(fixingDays)
3019 .withSpreads(spread: 0.0056)
3020 .inArrears(flag: inArrears);
3021 Date floatingbondRedemption1 =
3022 bondCalendar.adjust(floatingBondMaturityDate1, convention: Following);
3023 floatingBondLeg1.push_back(x: ext::shared_ptr<CashFlow>(new
3024 SimpleCashFlow(100.0, floatingbondRedemption1)));
3025 // generic bond
3026 ext::shared_ptr<Bond> floatingBond1(new
3027 Bond(settlementDays, bondCalendar, vars.faceAmount,
3028 floatingBondMaturityDate1, floatingBondStartDate1,
3029 floatingBondLeg1));
3030 floatingBond1->setPricingEngine(bondEngine);
3031
3032 // equivalent specialized floater
3033 ext::shared_ptr<Bond> floatingSpecializedBond1(new
3034 FloatingRateBond(settlementDays, vars.faceAmount,
3035 floatingBondSchedule1,
3036 vars.iborIndex, Actual360(),
3037 Following, fixingDays,
3038 std::vector<Real>(1,1),
3039 std::vector<Spread>(1,0.0056),
3040 std::vector<Rate>(), std::vector<Rate>(),
3041 inArrears,
3042 100.0, Date(29,September,2003)));
3043 floatingSpecializedBond1->setPricingEngine(bondEngine);
3044
3045 setCouponPricer(leg: floatingBond1->cashflows(), vars.pricer);
3046 setCouponPricer(leg: floatingSpecializedBond1->cashflows(), vars.pricer);
3047 vars.iborIndex->addFixing(fixingDate: Date(27,March,2007), fixing: 0.0402);
3048 Real floatingBondTheoValue1 = floatingBond1->cleanPrice();
3049 Real floatingSpecializedBondTheoValue1 =
3050 floatingSpecializedBond1->cleanPrice();
3051
3052 Real error5 = std::fabs(x: floatingBondTheoValue1-
3053 floatingSpecializedBondTheoValue1);
3054 if (error5>tolerance) {
3055 BOOST_FAIL("wrong clean price for fixed bond:"
3056 << std::fixed << std::setprecision(4)
3057 << "\n generic fixed rate bond's theo clean price: "
3058 << floatingBondTheoValue1
3059 << "\n equivalent specialized bond's theo clean price: "
3060 << floatingSpecializedBondTheoValue1
3061 << std::scientific << std::setprecision(2)
3062 << "\n error: " << error5
3063 << "\n tolerance: " << tolerance);
3064 }
3065 Real floatingBondTheoDirty1 = floatingBondTheoValue1+
3066 floatingBond1->accruedAmount();
3067 Real floatingSpecializedBondTheoDirty1 =
3068 floatingSpecializedBondTheoValue1+
3069 floatingSpecializedBond1->accruedAmount();
3070 Real error6 = std::fabs(x: floatingBondTheoDirty1-
3071 floatingSpecializedBondTheoDirty1);
3072 if (error6>tolerance) {
3073 BOOST_FAIL("wrong dirty price for frn bond:"
3074 << std::fixed << std::setprecision(4)
3075 << "\n generic frn bond's dirty clean price: "
3076 << floatingBondTheoDirty1
3077 << "\n equivalent specialized bond's theo dirty price: "
3078 << floatingSpecializedBondTheoDirty1
3079 << std::scientific << std::setprecision(2)
3080 << "\n error: " << error6
3081 << "\n tolerance: " << tolerance);
3082 }
3083
3084 // FRN Underlying bond (Isin: XS0090566539 COE 0 09/24/18)
3085 // maturity occurs on a business day
3086 Date floatingBondStartDate2 = Date(24,September,2004);
3087 Date floatingBondMaturityDate2 = Date(24,September,2018);
3088 Schedule floatingBondSchedule2(floatingBondStartDate2,
3089 floatingBondMaturityDate2,
3090 Period(Semiannual), bondCalendar,
3091 ModifiedFollowing, ModifiedFollowing,
3092 DateGeneration::Backward, false);
3093 Leg floatingBondLeg2 = IborLeg(floatingBondSchedule2, vars.iborIndex)
3094 .withNotionals(notional: vars.faceAmount)
3095 .withPaymentDayCounter(Actual360())
3096 .withPaymentAdjustment(ModifiedFollowing)
3097 .withFixingDays(fixingDays)
3098 .withSpreads(spread: 0.0025)
3099 .inArrears(flag: inArrears);
3100 Date floatingbondRedemption2 =
3101 bondCalendar.adjust(floatingBondMaturityDate2, convention: ModifiedFollowing);
3102 floatingBondLeg2.push_back(x: ext::shared_ptr<CashFlow>(new
3103 SimpleCashFlow(100.0, floatingbondRedemption2)));
3104 // generic bond
3105 ext::shared_ptr<Bond> floatingBond2(new
3106 Bond(settlementDays, bondCalendar, vars.faceAmount,
3107 floatingBondMaturityDate2, floatingBondStartDate2,
3108 floatingBondLeg2));
3109 floatingBond2->setPricingEngine(bondEngine);
3110
3111 // equivalent specialized floater
3112 ext::shared_ptr<Bond> floatingSpecializedBond2(new
3113 FloatingRateBond(settlementDays, vars.faceAmount,
3114 floatingBondSchedule2,
3115 vars.iborIndex, Actual360(),
3116 ModifiedFollowing, fixingDays,
3117 std::vector<Real>(1,1),
3118 std::vector<Spread>(1,0.0025),
3119 std::vector<Rate>(), std::vector<Rate>(),
3120 inArrears,
3121 100.0, Date(24,September,2004)));
3122 floatingSpecializedBond2->setPricingEngine(bondEngine);
3123
3124 setCouponPricer(leg: floatingBond2->cashflows(), vars.pricer);
3125 setCouponPricer(leg: floatingSpecializedBond2->cashflows(), vars.pricer);
3126
3127 vars.iborIndex->addFixing(fixingDate: Date(22,March,2007), fixing: 0.04013);
3128
3129 Real floatingBondTheoValue2 = floatingBond2->cleanPrice();
3130 Real floatingSpecializedBondTheoValue2 =
3131 floatingSpecializedBond2->cleanPrice();
3132
3133 Real error7 =
3134 std::fabs(x: floatingBondTheoValue2-floatingSpecializedBondTheoValue2);
3135 if (error7>tolerance) {
3136 BOOST_FAIL("wrong clean price for floater bond:"
3137 << std::fixed << std::setprecision(4)
3138 << "\n generic floater bond's theo clean price: "
3139 << floatingBondTheoValue2
3140 << "\n equivalent specialized bond's theo clean price: "
3141 << floatingSpecializedBondTheoValue2
3142 << std::scientific << std::setprecision(2)
3143 << "\n error: " << error7
3144 << "\n tolerance: " << tolerance);
3145 }
3146 Real floatingBondTheoDirty2 = floatingBondTheoValue2+
3147 floatingBond2->accruedAmount();
3148 Real floatingSpecializedTheoDirty2 = floatingSpecializedBondTheoValue2+
3149 floatingSpecializedBond2->accruedAmount();
3150
3151 Real error8 =
3152 std::fabs(x: floatingBondTheoDirty2-floatingSpecializedTheoDirty2);
3153 if (error8>tolerance) {
3154 BOOST_FAIL("wrong dirty price for floater bond:"
3155 << std::fixed << std::setprecision(4)
3156 << "\n generic floater bond's theo dirty price: "
3157 << floatingBondTheoDirty2
3158 << "\n equivalent specialized bond's theo dirty price: "
3159 << floatingSpecializedTheoDirty2
3160 << std::scientific << std::setprecision(2)
3161 << "\n error: " << error8
3162 << "\n tolerance: " << tolerance);
3163 }
3164
3165
3166 // CMS Underlying bond (Isin: XS0228052402 CRDIT 0 8/22/20)
3167 // maturity doesn't occur on a business day
3168 Date cmsBondStartDate1 = Date(22,August,2005);
3169 Date cmsBondMaturityDate1 = Date(22,August,2020);
3170 Schedule cmsBondSchedule1(cmsBondStartDate1,
3171 cmsBondMaturityDate1,
3172 Period(Annual), bondCalendar,
3173 Unadjusted, Unadjusted,
3174 DateGeneration::Backward, false);
3175 Leg cmsBondLeg1 = CmsLeg(cmsBondSchedule1, vars.swapIndex)
3176 .withNotionals(notional: vars.faceAmount)
3177 .withPaymentDayCounter(Thirty360(Thirty360::BondBasis))
3178 .withFixingDays(fixingDays)
3179 .withCaps(cap: 0.055)
3180 .withFloors(floor: 0.025)
3181 .inArrears(flag: inArrears);
3182 Date cmsbondRedemption1 = bondCalendar.adjust(cmsBondMaturityDate1,
3183 convention: Following);
3184 cmsBondLeg1.push_back(x: ext::shared_ptr<CashFlow>(new
3185 SimpleCashFlow(100.0, cmsbondRedemption1)));
3186 // generic cms bond
3187 ext::shared_ptr<Bond> cmsBond1(new
3188 Bond(settlementDays, bondCalendar, vars.faceAmount,
3189 cmsBondMaturityDate1, cmsBondStartDate1, cmsBondLeg1));
3190 cmsBond1->setPricingEngine(bondEngine);
3191
3192 // equivalent specialized cms bond
3193 ext::shared_ptr<Bond> cmsSpecializedBond1(new
3194 CmsRateBond(settlementDays, vars.faceAmount, cmsBondSchedule1,
3195 vars.swapIndex, Thirty360(Thirty360::BondBasis),
3196 Following, fixingDays,
3197 std::vector<Real>(1,1.0), std::vector<Spread>(1,0.0),
3198 std::vector<Rate>(1,0.055), std::vector<Rate>(1,0.025),
3199 inArrears,
3200 100.0, Date(22,August,2005)));
3201 cmsSpecializedBond1->setPricingEngine(bondEngine);
3202
3203 setCouponPricer(leg: cmsBond1->cashflows(), vars.cmspricer);
3204 setCouponPricer(leg: cmsSpecializedBond1->cashflows(), vars.cmspricer);
3205 vars.swapIndex->addFixing(fixingDate: Date(18,August,2006), fixing: 0.04158);
3206 Real cmsBondTheoValue1 = cmsBond1->cleanPrice();
3207 Real cmsSpecializedBondTheoValue1 = cmsSpecializedBond1->cleanPrice();
3208 Real error9 = std::fabs(x: cmsBondTheoValue1-cmsSpecializedBondTheoValue1);
3209 if (error9>tolerance) {
3210 BOOST_FAIL("wrong clean price for cms bond:"
3211 << std::fixed << std::setprecision(4)
3212 << "\n generic cms bond's theo clean price: "
3213 << cmsBondTheoValue1
3214 << "\n equivalent specialized bond's theo clean price: "
3215 << cmsSpecializedBondTheoValue1
3216 << std::scientific << std::setprecision(2)
3217 << "\n error: " << error9
3218 << "\n tolerance: " << tolerance);
3219 }
3220 Real cmsBondTheoDirty1 = cmsBondTheoValue1+cmsBond1->accruedAmount();
3221 Real cmsSpecializedBondTheoDirty1 = cmsSpecializedBondTheoValue1+
3222 cmsSpecializedBond1->accruedAmount();
3223 Real error10 = std::fabs(x: cmsBondTheoDirty1-cmsSpecializedBondTheoDirty1);
3224 if (error10>tolerance) {
3225 BOOST_FAIL("wrong dirty price for cms bond:"
3226 << std::fixed << std::setprecision(4)
3227 << "\n generic cms bond's theo dirty price: "
3228 << cmsBondTheoDirty1
3229 << "\n specialized cms bond's theo dirty price: "
3230 << cmsSpecializedBondTheoDirty1
3231 << std::scientific << std::setprecision(2)
3232 << "\n error: " << error10
3233 << "\n tolerance: " << tolerance);
3234 }
3235
3236 // CMS Underlying bond (Isin: XS0218766664 ISPIM 0 5/6/15)
3237 // maturity occurs on a business day
3238 Date cmsBondStartDate2 = Date(06,May,2005);
3239 Date cmsBondMaturityDate2 = Date(06,May,2015);
3240 Schedule cmsBondSchedule2(cmsBondStartDate2,
3241 cmsBondMaturityDate2,
3242 Period(Annual), bondCalendar,
3243 Unadjusted, Unadjusted,
3244 DateGeneration::Backward, false);
3245 Leg cmsBondLeg2 = CmsLeg(cmsBondSchedule2, vars.swapIndex)
3246 .withNotionals(notional: vars.faceAmount)
3247 .withPaymentDayCounter(Thirty360(Thirty360::BondBasis))
3248 .withFixingDays(fixingDays)
3249 .withGearings(gearing: 0.84)
3250 .inArrears(flag: inArrears);
3251 Date cmsbondRedemption2 = bondCalendar.adjust(cmsBondMaturityDate2,
3252 convention: Following);
3253 cmsBondLeg2.push_back(x: ext::shared_ptr<CashFlow>(new
3254 SimpleCashFlow(100.0, cmsbondRedemption2)));
3255 // generic bond
3256 ext::shared_ptr<Bond> cmsBond2(new
3257 Bond(settlementDays, bondCalendar, vars.faceAmount,
3258 cmsBondMaturityDate2, cmsBondStartDate2, cmsBondLeg2));
3259 cmsBond2->setPricingEngine(bondEngine);
3260
3261 // equivalent specialized cms bond
3262 ext::shared_ptr<Bond> cmsSpecializedBond2(new
3263 CmsRateBond(settlementDays, vars.faceAmount, cmsBondSchedule2,
3264 vars.swapIndex, Thirty360(Thirty360::BondBasis),
3265 Following, fixingDays,
3266 std::vector<Real>(1,0.84), std::vector<Spread>(1,0.0),
3267 std::vector<Rate>(), std::vector<Rate>(),
3268 inArrears,
3269 100.0, Date(06,May,2005)));
3270 cmsSpecializedBond2->setPricingEngine(bondEngine);
3271
3272 setCouponPricer(leg: cmsBond2->cashflows(), vars.cmspricer);
3273 setCouponPricer(leg: cmsSpecializedBond2->cashflows(), vars.cmspricer);
3274 vars.swapIndex->addFixing(fixingDate: Date(04,May,2006), fixing: 0.04217);
3275 Real cmsBondTheoValue2 = cmsBond2->cleanPrice();
3276 Real cmsSpecializedBondTheoValue2 = cmsSpecializedBond2->cleanPrice();
3277
3278 Real error11 = std::fabs(x: cmsBondTheoValue2-cmsSpecializedBondTheoValue2);
3279 if (error11>tolerance) {
3280 BOOST_FAIL("wrong clean price for cms bond:"
3281 << std::fixed << std::setprecision(4)
3282 << "\n generic cms bond's theo clean price: "
3283 << cmsBondTheoValue2
3284 << "\n cms bond's theo clean price: "
3285 << cmsSpecializedBondTheoValue2
3286 << std::scientific << std::setprecision(2)
3287 << "\n error: " << error11
3288 << "\n tolerance: " << tolerance);
3289 }
3290 Real cmsBondTheoDirty2 = cmsBondTheoValue2+cmsBond2->accruedAmount();
3291 Real cmsSpecializedBondTheoDirty2 =
3292 cmsSpecializedBondTheoValue2+cmsSpecializedBond2->accruedAmount();
3293 Real error12 = std::fabs(x: cmsBondTheoDirty2-cmsSpecializedBondTheoDirty2);
3294 if (error12>tolerance) {
3295 BOOST_FAIL("wrong dirty price for cms bond:"
3296 << std::fixed << std::setprecision(4)
3297 << "\n generic cms bond's dirty price: "
3298 << cmsBondTheoDirty2
3299 << "\n specialized cms bond's theo dirty price: "
3300 << cmsSpecializedBondTheoDirty2
3301 << std::scientific << std::setprecision(2)
3302 << "\n error: " << error12
3303 << "\n tolerance: " << tolerance);
3304 }
3305
3306 // Zero Coupon bond (Isin: DE0004771662 IBRD 0 12/20/15)
3307 // maturity doesn't occur on a business day
3308 Date zeroCpnBondStartDate1 = Date(19,December,1985);
3309 Date zeroCpnBondMaturityDate1 = Date(20,December,2015);
3310 Date zeroCpnBondRedemption1 = bondCalendar.adjust(zeroCpnBondMaturityDate1,
3311 convention: Following);
3312 Leg zeroCpnBondLeg1 = Leg(1, ext::shared_ptr<CashFlow>(new
3313 SimpleCashFlow(100.0, zeroCpnBondRedemption1)));
3314 // generic bond
3315 ext::shared_ptr<Bond> zeroCpnBond1(new
3316 Bond(settlementDays, bondCalendar, vars.faceAmount,
3317 zeroCpnBondMaturityDate1, zeroCpnBondStartDate1, zeroCpnBondLeg1));
3318 zeroCpnBond1->setPricingEngine(bondEngine);
3319
3320 // specialized zerocpn bond
3321 ext::shared_ptr<Bond> zeroCpnSpecializedBond1(new
3322 ZeroCouponBond(settlementDays, bondCalendar, vars.faceAmount,
3323 Date(20,December,2015),
3324 Following,
3325 100.0, Date(19,December,1985)));
3326 zeroCpnSpecializedBond1->setPricingEngine(bondEngine);
3327
3328 Real zeroCpnBondTheoValue1 = zeroCpnBond1->cleanPrice();
3329 Real zeroCpnSpecializedBondTheoValue1 =
3330 zeroCpnSpecializedBond1->cleanPrice();
3331
3332 Real error13 =
3333 std::fabs(x: zeroCpnBondTheoValue1-zeroCpnSpecializedBondTheoValue1);
3334 if (error13>tolerance) {
3335 BOOST_FAIL("wrong clean price for zero coupon bond:"
3336 << std::fixed << std::setprecision(4)
3337 << "\n generic zero bond's clean price: "
3338 << zeroCpnBondTheoValue1
3339 << "\n specialized zero bond's clean price: "
3340 << zeroCpnSpecializedBondTheoValue1
3341 << std::scientific << std::setprecision(2)
3342 << "\n error: " << error13
3343 << "\n tolerance: " << tolerance);
3344 }
3345 Real zeroCpnBondTheoDirty1 = zeroCpnBondTheoValue1+
3346 zeroCpnBond1->accruedAmount();
3347 Real zeroCpnSpecializedBondTheoDirty1 =
3348 zeroCpnSpecializedBondTheoValue1+
3349 zeroCpnSpecializedBond1->accruedAmount();
3350 Real error14 =
3351 std::fabs(x: zeroCpnBondTheoDirty1-zeroCpnSpecializedBondTheoDirty1);
3352 if (error14>tolerance) {
3353 BOOST_FAIL("wrong dirty price for zero bond:"
3354 << std::fixed << std::setprecision(4)
3355 << "\n generic zerocpn bond's dirty price: "
3356 << zeroCpnBondTheoDirty1
3357 << "\n specialized zerocpn bond's clean price: "
3358 << zeroCpnSpecializedBondTheoDirty1
3359 << std::scientific << std::setprecision(2)
3360 << "\n error: " << error14
3361 << "\n tolerance: " << tolerance);
3362 }
3363
3364 // Zero Coupon bond (Isin: IT0001200390 ISPIM 0 02/17/28)
3365 // maturity occurs on a business day
3366 Date zeroCpnBondStartDate2 = Date(17,February,1998);
3367 Date zeroCpnBondMaturityDate2 = Date(17,February,2028);
3368 Date zerocpbondRedemption2 = bondCalendar.adjust(zeroCpnBondMaturityDate2,
3369 convention: Following);
3370 Leg zeroCpnBondLeg2 = Leg(1, ext::shared_ptr<CashFlow>(new
3371 SimpleCashFlow(100.0, zerocpbondRedemption2)));
3372 // generic bond
3373 ext::shared_ptr<Bond> zeroCpnBond2(new
3374 Bond(settlementDays, bondCalendar, vars.faceAmount,
3375 zeroCpnBondMaturityDate2, zeroCpnBondStartDate2, zeroCpnBondLeg2));
3376 zeroCpnBond2->setPricingEngine(bondEngine);
3377
3378 // specialized zerocpn bond
3379 ext::shared_ptr<Bond> zeroCpnSpecializedBond2(new
3380 ZeroCouponBond(settlementDays, bondCalendar, vars.faceAmount,
3381 Date(17,February,2028),
3382 Following,
3383 100.0, Date(17,February,1998)));
3384 zeroCpnSpecializedBond2->setPricingEngine(bondEngine);
3385
3386 Real zeroCpnBondTheoValue2 = zeroCpnBond2->cleanPrice();
3387 Real zeroCpnSpecializedBondTheoValue2 =
3388 zeroCpnSpecializedBond2->cleanPrice();
3389
3390 Real error15 =
3391 std::fabs(x: zeroCpnBondTheoValue2 -zeroCpnSpecializedBondTheoValue2);
3392 if (error15>tolerance) {
3393 BOOST_FAIL("wrong clean price for zero coupon bond:"
3394 << std::fixed << std::setprecision(4)
3395 << "\n generic zerocpn bond's clean price: "
3396 << zeroCpnBondTheoValue2
3397 << "\n specialized zerocpn bond's clean price: "
3398 << zeroCpnSpecializedBondTheoValue2
3399 << std::scientific << std::setprecision(2)
3400 << "\n error: " << error15
3401 << "\n tolerance: " << tolerance);
3402 }
3403 Real zeroCpnBondTheoDirty2 = zeroCpnBondTheoValue2+
3404 zeroCpnBond2->accruedAmount();
3405
3406 Real zeroCpnSpecializedBondTheoDirty2 =
3407 zeroCpnSpecializedBondTheoValue2+
3408 zeroCpnSpecializedBond2->accruedAmount();
3409
3410 Real error16 =
3411 std::fabs(x: zeroCpnBondTheoDirty2-zeroCpnSpecializedBondTheoDirty2);
3412 if (error16>tolerance) {
3413 BOOST_FAIL("wrong dirty price for zero coupon bond:"
3414 << std::fixed << std::setprecision(4)
3415 << "\n generic zerocpn bond's dirty price: "
3416 << zeroCpnBondTheoDirty2
3417 << "\n specialized zerocpn bond's dirty price: "
3418 << zeroCpnSpecializedBondTheoDirty2
3419 << std::scientific << std::setprecision(2)
3420 << "\n error: " << error16
3421 << "\n tolerance: " << tolerance);
3422 }
3423}
3424
3425
3426void AssetSwapTest::testSpecializedBondVsGenericBondUsingAsw() {
3427
3428 BOOST_TEST_MESSAGE("Testing asset-swap prices and spreads for specialized"
3429 " bond against equivalent generic bond...");
3430
3431 using namespace asset_swap_test;
3432
3433 CommonVars vars;
3434
3435 Calendar bondCalendar = TARGET();
3436 Natural settlementDays = 3;
3437 Natural fixingDays = 2;
3438 bool payFixedRate = true;
3439 bool parAssetSwap = true;
3440 bool inArrears = false;
3441
3442 // Fixed bond (Isin: DE0001135275 DBR 4 01/04/37)
3443 // maturity doesn't occur on a business day
3444 Date fixedBondStartDate1 = Date(4,January,2005);
3445 Date fixedBondMaturityDate1 = Date(4,January,2037);
3446 Schedule fixedBondSchedule1(fixedBondStartDate1,
3447 fixedBondMaturityDate1,
3448 Period(Annual), bondCalendar,
3449 Unadjusted, Unadjusted,
3450 DateGeneration::Backward, false);
3451 Leg fixedBondLeg1 = FixedRateLeg(fixedBondSchedule1)
3452 .withNotionals(vars.faceAmount)
3453 .withCouponRates(0.04, paymentDayCounter: ActualActual(ActualActual::ISDA));
3454 Date fixedbondRedemption1 = bondCalendar.adjust(fixedBondMaturityDate1,
3455 convention: Following);
3456 fixedBondLeg1.push_back(x: ext::shared_ptr<CashFlow>(new
3457 SimpleCashFlow(100.0, fixedbondRedemption1)));
3458 // generic bond
3459 ext::shared_ptr<Bond> fixedBond1(new
3460 Bond(settlementDays, bondCalendar, vars.faceAmount,
3461 fixedBondMaturityDate1, fixedBondStartDate1,
3462 fixedBondLeg1));
3463 ext::shared_ptr<PricingEngine> bondEngine(
3464 new DiscountingBondEngine(vars.termStructure));
3465 ext::shared_ptr<PricingEngine> swapEngine(
3466 new DiscountingSwapEngine(vars.termStructure));
3467 fixedBond1->setPricingEngine(bondEngine);
3468
3469 // equivalent specialized fixed rate bond
3470 ext::shared_ptr<Bond> fixedSpecializedBond1(new
3471 FixedRateBond(settlementDays, vars.faceAmount, fixedBondSchedule1,
3472 std::vector<Rate>(1, 0.04),
3473 ActualActual(ActualActual::ISDA), Following,
3474 100.0, Date(4,January,2005) ));
3475 fixedSpecializedBond1->setPricingEngine(bondEngine);
3476
3477 Real fixedBondPrice1 = fixedBond1->cleanPrice();
3478 Real fixedSpecializedBondPrice1 = fixedSpecializedBond1->cleanPrice();
3479 AssetSwap fixedBondAssetSwap1(payFixedRate,
3480 fixedBond1, fixedBondPrice1,
3481 vars.iborIndex, vars.nonnullspread,
3482 Schedule(),
3483 vars.iborIndex->dayCounter(),
3484 parAssetSwap);
3485 fixedBondAssetSwap1.setPricingEngine(swapEngine);
3486 AssetSwap fixedSpecializedBondAssetSwap1(payFixedRate,
3487 fixedSpecializedBond1,
3488 fixedSpecializedBondPrice1,
3489 vars.iborIndex,
3490 vars.nonnullspread,
3491 Schedule(),
3492 vars.iborIndex->dayCounter(),
3493 parAssetSwap);
3494 fixedSpecializedBondAssetSwap1.setPricingEngine(swapEngine);
3495 Real fixedBondAssetSwapPrice1 = fixedBondAssetSwap1.fairCleanPrice();
3496 Real fixedSpecializedBondAssetSwapPrice1 =
3497 fixedSpecializedBondAssetSwap1.fairCleanPrice();
3498 Real tolerance = 1.0e-13;
3499 Real error1 =
3500 std::fabs(x: fixedBondAssetSwapPrice1-fixedSpecializedBondAssetSwapPrice1);
3501 if (error1>tolerance) {
3502 BOOST_FAIL("wrong clean price for fixed bond:"
3503 << std::fixed << std::setprecision(4)
3504 << "\n generic fixed rate bond's clean price: "
3505 << fixedBondAssetSwapPrice1
3506 << "\n equivalent specialized bond's clean price: "
3507 << fixedSpecializedBondAssetSwapPrice1
3508 << std::scientific << std::setprecision(2)
3509 << "\n error: " << error1
3510 << "\n tolerance: " << tolerance);
3511 }
3512 // market executable price as of 4th sept 2007
3513 Real fixedBondMktPrice1= 91.832;
3514 AssetSwap fixedBondASW1(payFixedRate,
3515 fixedBond1, fixedBondMktPrice1,
3516 vars.iborIndex, vars.spread,
3517 Schedule(),
3518 vars.iborIndex->dayCounter(),
3519 parAssetSwap);
3520 fixedBondASW1.setPricingEngine(swapEngine);
3521 AssetSwap fixedSpecializedBondASW1(payFixedRate,
3522 fixedSpecializedBond1,
3523 fixedBondMktPrice1,
3524 vars.iborIndex, vars.spread,
3525 Schedule(),
3526 vars.iborIndex->dayCounter(),
3527 parAssetSwap);
3528 fixedSpecializedBondASW1.setPricingEngine(swapEngine);
3529 Real fixedBondASWSpread1 = fixedBondASW1.fairSpread();
3530 Real fixedSpecializedBondASWSpread1 = fixedSpecializedBondASW1.fairSpread();
3531 Real error2 = std::fabs(x: fixedBondASWSpread1-fixedSpecializedBondASWSpread1);
3532 if (error2>tolerance) {
3533 BOOST_FAIL("wrong asw spread for fixed bond:"
3534 << std::fixed << std::setprecision(4)
3535 << "\n generic fixed rate bond's asw spread: "
3536 << fixedBondASWSpread1
3537 << "\n equivalent specialized bond's asw spread: "
3538 << fixedSpecializedBondASWSpread1
3539 << std::scientific << std::setprecision(2)
3540 << "\n error: " << error2
3541 << "\n tolerance: " << tolerance);
3542 }
3543
3544 //Fixed bond (Isin: IT0006527060 IBRD 5 02/05/19)
3545 //maturity occurs on a business day
3546
3547 Date fixedBondStartDate2 = Date(5,February,2005);
3548 Date fixedBondMaturityDate2 = Date(5,February,2019);
3549 Schedule fixedBondSchedule2(fixedBondStartDate2,
3550 fixedBondMaturityDate2,
3551 Period(Annual), bondCalendar,
3552 Unadjusted, Unadjusted,
3553 DateGeneration::Backward, false);
3554 Leg fixedBondLeg2 = FixedRateLeg(fixedBondSchedule2)
3555 .withNotionals(vars.faceAmount)
3556 .withCouponRates(0.05, paymentDayCounter: Thirty360(Thirty360::BondBasis));
3557 Date fixedbondRedemption2 = bondCalendar.adjust(fixedBondMaturityDate2,
3558 convention: Following);
3559 fixedBondLeg2.push_back(x: ext::shared_ptr<CashFlow>(new
3560 SimpleCashFlow(100.0, fixedbondRedemption2)));
3561
3562 // generic bond
3563 ext::shared_ptr<Bond> fixedBond2(new
3564 Bond(settlementDays, bondCalendar, vars.faceAmount,
3565 fixedBondMaturityDate2, fixedBondStartDate2, fixedBondLeg2));
3566 fixedBond2->setPricingEngine(bondEngine);
3567
3568 // equivalent specialized fixed rate bond
3569 ext::shared_ptr<Bond> fixedSpecializedBond2(new
3570 FixedRateBond(settlementDays, vars.faceAmount, fixedBondSchedule2,
3571 std::vector<Rate>(1, 0.05),
3572 Thirty360(Thirty360::BondBasis), Following,
3573 100.0, Date(5,February,2005)));
3574 fixedSpecializedBond2->setPricingEngine(bondEngine);
3575
3576 Real fixedBondPrice2 = fixedBond2->cleanPrice();
3577 Real fixedSpecializedBondPrice2 = fixedSpecializedBond2->cleanPrice();
3578 AssetSwap fixedBondAssetSwap2(payFixedRate,
3579 fixedBond2, fixedBondPrice2,
3580 vars.iborIndex, vars.nonnullspread,
3581 Schedule(),
3582 vars.iborIndex->dayCounter(),
3583 parAssetSwap);
3584 fixedBondAssetSwap2.setPricingEngine(swapEngine);
3585 AssetSwap fixedSpecializedBondAssetSwap2(payFixedRate,
3586 fixedSpecializedBond2,
3587 fixedSpecializedBondPrice2,
3588 vars.iborIndex,
3589 vars.nonnullspread,
3590 Schedule(),
3591 vars.iborIndex->dayCounter(),
3592 parAssetSwap);
3593 fixedSpecializedBondAssetSwap2.setPricingEngine(swapEngine);
3594 Real fixedBondAssetSwapPrice2 = fixedBondAssetSwap2.fairCleanPrice();
3595 Real fixedSpecializedBondAssetSwapPrice2 =
3596 fixedSpecializedBondAssetSwap2.fairCleanPrice();
3597
3598 Real error3 =
3599 std::fabs(x: fixedBondAssetSwapPrice2-fixedSpecializedBondAssetSwapPrice2);
3600 if (error3>tolerance) {
3601 BOOST_FAIL("wrong clean price for fixed bond:"
3602 << std::fixed << std::setprecision(4)
3603 << "\n generic fixed rate bond's clean price: "
3604 << fixedBondAssetSwapPrice2
3605 << "\n equivalent specialized bond's clean price: "
3606 << fixedSpecializedBondAssetSwapPrice2
3607 << std::scientific << std::setprecision(2)
3608 << "\n error: " << error3
3609 << "\n tolerance: " << tolerance);
3610 }
3611 // market executable price as of 4th sept 2007
3612 Real fixedBondMktPrice2= 102.178;
3613 AssetSwap fixedBondASW2(payFixedRate,
3614 fixedBond2, fixedBondMktPrice2,
3615 vars.iborIndex, vars.spread,
3616 Schedule(),
3617 vars.iborIndex->dayCounter(),
3618 parAssetSwap);
3619 fixedBondASW2.setPricingEngine(swapEngine);
3620 AssetSwap fixedSpecializedBondASW2(payFixedRate,
3621 fixedSpecializedBond2,
3622 fixedBondMktPrice2,
3623 vars.iborIndex, vars.spread,
3624 Schedule(),
3625 vars.iborIndex->dayCounter(),
3626 parAssetSwap);
3627 fixedSpecializedBondASW2.setPricingEngine(swapEngine);
3628 Real fixedBondASWSpread2 = fixedBondASW2.fairSpread();
3629 Real fixedSpecializedBondASWSpread2 = fixedSpecializedBondASW2.fairSpread();
3630 Real error4 = std::fabs(x: fixedBondASWSpread2-fixedSpecializedBondASWSpread2);
3631 if (error4>tolerance) {
3632 BOOST_FAIL("wrong asw spread for fixed bond:"
3633 << std::fixed << std::setprecision(4)
3634 << "\n generic fixed rate bond's asw spread: "
3635 << fixedBondASWSpread2
3636 << "\n equivalent specialized bond's asw spread: "
3637 << fixedSpecializedBondASWSpread2
3638 << std::scientific << std::setprecision(2)
3639 << "\n error: " << error4
3640 << "\n tolerance: " << tolerance);
3641 }
3642
3643
3644 //FRN bond (Isin: IT0003543847 ISPIM 0 09/29/13)
3645 //maturity doesn't occur on a business day
3646 Date floatingBondStartDate1 = Date(29,September,2003);
3647 Date floatingBondMaturityDate1 = Date(29,September,2013);
3648 Schedule floatingBondSchedule1(floatingBondStartDate1,
3649 floatingBondMaturityDate1,
3650 Period(Semiannual), bondCalendar,
3651 Unadjusted, Unadjusted,
3652 DateGeneration::Backward, false);
3653 Leg floatingBondLeg1 = IborLeg(floatingBondSchedule1, vars.iborIndex)
3654 .withNotionals(notional: vars.faceAmount)
3655 .withPaymentDayCounter(Actual360())
3656 .withFixingDays(fixingDays)
3657 .withSpreads(spread: 0.0056)
3658 .inArrears(flag: inArrears);
3659 Date floatingbondRedemption1 =
3660 bondCalendar.adjust(floatingBondMaturityDate1, convention: Following);
3661 floatingBondLeg1.push_back(x: ext::shared_ptr<CashFlow>(new
3662 SimpleCashFlow(100.0, floatingbondRedemption1)));
3663 // generic bond
3664 ext::shared_ptr<Bond> floatingBond1(new
3665 Bond(settlementDays, bondCalendar, vars.faceAmount,
3666 floatingBondMaturityDate1, floatingBondStartDate1,
3667 floatingBondLeg1));
3668 floatingBond1->setPricingEngine(bondEngine);
3669
3670 // equivalent specialized floater
3671 ext::shared_ptr<Bond> floatingSpecializedBond1(new
3672 FloatingRateBond(settlementDays, vars.faceAmount,
3673 floatingBondSchedule1,
3674 vars.iborIndex, Actual360(),
3675 Following, fixingDays,
3676 std::vector<Real>(1,1),
3677 std::vector<Spread>(1,0.0056),
3678 std::vector<Rate>(), std::vector<Rate>(),
3679 inArrears,
3680 100.0, Date(29,September,2003)));
3681 floatingSpecializedBond1->setPricingEngine(bondEngine);
3682
3683 setCouponPricer(leg: floatingBond1->cashflows(), vars.pricer);
3684 setCouponPricer(leg: floatingSpecializedBond1->cashflows(), vars.pricer);
3685 vars.iborIndex->addFixing(fixingDate: Date(27,March,2007), fixing: 0.0402);
3686 Real floatingBondPrice1 = floatingBond1->cleanPrice();
3687 Real floatingSpecializedBondPrice1= floatingSpecializedBond1->cleanPrice();
3688 AssetSwap floatingBondAssetSwap1(payFixedRate,
3689 floatingBond1, floatingBondPrice1,
3690 vars.iborIndex, vars.nonnullspread,
3691 Schedule(),
3692 vars.iborIndex->dayCounter(),
3693 parAssetSwap);
3694 floatingBondAssetSwap1.setPricingEngine(swapEngine);
3695 AssetSwap floatingSpecializedBondAssetSwap1(payFixedRate,
3696 floatingSpecializedBond1,
3697 floatingSpecializedBondPrice1,
3698 vars.iborIndex,
3699 vars.nonnullspread,
3700 Schedule(),
3701 vars.iborIndex->dayCounter(),
3702 parAssetSwap);
3703 floatingSpecializedBondAssetSwap1.setPricingEngine(swapEngine);
3704 Real floatingBondAssetSwapPrice1 = floatingBondAssetSwap1.fairCleanPrice();
3705 Real floatingSpecializedBondAssetSwapPrice1 =
3706 floatingSpecializedBondAssetSwap1.fairCleanPrice();
3707
3708 Real error5 =
3709 std::fabs(x: floatingBondAssetSwapPrice1-floatingSpecializedBondAssetSwapPrice1);
3710 if (error5>tolerance) {
3711 BOOST_FAIL("wrong clean price for frnbond:"
3712 << std::fixed << std::setprecision(4)
3713 << "\n generic frn rate bond's clean price: "
3714 << floatingBondAssetSwapPrice1
3715 << "\n equivalent specialized bond's price: "
3716 << floatingSpecializedBondAssetSwapPrice1
3717 << std::scientific << std::setprecision(2)
3718 << "\n error: " << error5
3719 << "\n tolerance: " << tolerance);
3720 }
3721 // market executable price as of 4th sept 2007
3722 Real floatingBondMktPrice1= 101.33;
3723 AssetSwap floatingBondASW1(payFixedRate,
3724 floatingBond1, floatingBondMktPrice1,
3725 vars.iborIndex, vars.spread,
3726 Schedule(),
3727 vars.iborIndex->dayCounter(),
3728 parAssetSwap);
3729 floatingBondASW1.setPricingEngine(swapEngine);
3730 AssetSwap floatingSpecializedBondASW1(payFixedRate,
3731 floatingSpecializedBond1,
3732 floatingBondMktPrice1,
3733 vars.iborIndex, vars.spread,
3734 Schedule(),
3735 vars.iborIndex->dayCounter(),
3736 parAssetSwap);
3737 floatingSpecializedBondASW1.setPricingEngine(swapEngine);
3738 Real floatingBondASWSpread1 = floatingBondASW1.fairSpread();
3739 Real floatingSpecializedBondASWSpread1 =
3740 floatingSpecializedBondASW1.fairSpread();
3741 Real error6 =
3742 std::fabs(x: floatingBondASWSpread1-floatingSpecializedBondASWSpread1);
3743 if (error6>tolerance) {
3744 BOOST_FAIL("wrong asw spread for fixed bond:"
3745 << std::fixed << std::setprecision(4)
3746 << "\n generic frn rate bond's asw spread: "
3747 << floatingBondASWSpread1
3748 << "\n equivalent specialized bond's asw spread: "
3749 << floatingSpecializedBondASWSpread1
3750 << std::scientific << std::setprecision(2)
3751 << "\n error: " << error6
3752 << "\n tolerance: " << tolerance);
3753 }
3754 //FRN bond (Isin: XS0090566539 COE 0 09/24/18)
3755 //maturity occurs on a business day
3756 Date floatingBondStartDate2 = Date(24,September,2004);
3757 Date floatingBondMaturityDate2 = Date(24,September,2018);
3758 Schedule floatingBondSchedule2(floatingBondStartDate2,
3759 floatingBondMaturityDate2,
3760 Period(Semiannual), bondCalendar,
3761 ModifiedFollowing, ModifiedFollowing,
3762 DateGeneration::Backward, false);
3763 Leg floatingBondLeg2 = IborLeg(floatingBondSchedule2, vars.iborIndex)
3764 .withNotionals(notional: vars.faceAmount)
3765 .withPaymentDayCounter(Actual360())
3766 .withPaymentAdjustment(ModifiedFollowing)
3767 .withFixingDays(fixingDays)
3768 .withSpreads(spread: 0.0025)
3769 .inArrears(flag: inArrears);
3770 Date floatingbondRedemption2 =
3771 bondCalendar.adjust(floatingBondMaturityDate2,
3772 convention: ModifiedFollowing);
3773 floatingBondLeg2.push_back(x: ext::shared_ptr<CashFlow>(new
3774 SimpleCashFlow(100.0, floatingbondRedemption2)));
3775 // generic bond
3776 ext::shared_ptr<Bond> floatingBond2(new
3777 Bond(settlementDays, bondCalendar, vars.faceAmount,
3778 floatingBondMaturityDate2, floatingBondStartDate2,
3779 floatingBondLeg2));
3780 floatingBond2->setPricingEngine(bondEngine);
3781
3782 // equivalent specialized floater
3783 ext::shared_ptr<Bond> floatingSpecializedBond2(new
3784 FloatingRateBond(settlementDays, vars.faceAmount,
3785 floatingBondSchedule2,
3786 vars.iborIndex, Actual360(),
3787 ModifiedFollowing, fixingDays,
3788 std::vector<Real>(1,1),
3789 std::vector<Spread>(1,0.0025),
3790 std::vector<Rate>(), std::vector<Rate>(),
3791 inArrears,
3792 100.0, Date(24,September,2004)));
3793 floatingSpecializedBond2->setPricingEngine(bondEngine);
3794
3795 setCouponPricer(leg: floatingBond2->cashflows(), vars.pricer);
3796 setCouponPricer(leg: floatingSpecializedBond2->cashflows(), vars.pricer);
3797
3798 vars.iborIndex->addFixing(fixingDate: Date(22,March,2007), fixing: 0.04013);
3799
3800 Real floatingBondPrice2 = floatingBond2->cleanPrice();
3801 Real floatingSpecializedBondPrice2= floatingSpecializedBond2->cleanPrice();
3802 AssetSwap floatingBondAssetSwap2(payFixedRate,
3803 floatingBond2, floatingBondPrice2,
3804 vars.iborIndex, vars.nonnullspread,
3805 Schedule(),
3806 vars.iborIndex->dayCounter(),
3807 parAssetSwap);
3808 floatingBondAssetSwap2.setPricingEngine(swapEngine);
3809 AssetSwap floatingSpecializedBondAssetSwap2(payFixedRate,
3810 floatingSpecializedBond2,
3811 floatingSpecializedBondPrice2,
3812 vars.iborIndex,
3813 vars.nonnullspread,
3814 Schedule(),
3815 vars.iborIndex->dayCounter(),
3816 parAssetSwap);
3817 floatingSpecializedBondAssetSwap2.setPricingEngine(swapEngine);
3818 Real floatingBondAssetSwapPrice2 = floatingBondAssetSwap2.fairCleanPrice();
3819 Real floatingSpecializedBondAssetSwapPrice2 =
3820 floatingSpecializedBondAssetSwap2.fairCleanPrice();
3821 Real error7 =
3822 std::fabs(x: floatingBondAssetSwapPrice2-floatingSpecializedBondAssetSwapPrice2);
3823 if (error7>tolerance) {
3824 BOOST_FAIL("wrong clean price for frnbond:"
3825 << std::fixed << std::setprecision(4)
3826 << "\n generic frn rate bond's clean price: "
3827 << floatingBondAssetSwapPrice2
3828 << "\n equivalent specialized frn bond's price: "
3829 << floatingSpecializedBondAssetSwapPrice2
3830 << std::scientific << std::setprecision(2)
3831 << "\n error: " << error7
3832 << "\n tolerance: " << tolerance);
3833 }
3834 // market executable price as of 4th sept 2007
3835 Real floatingBondMktPrice2 = 101.26;
3836 AssetSwap floatingBondASW2(payFixedRate,
3837 floatingBond2, floatingBondMktPrice2,
3838 vars.iborIndex, vars.spread,
3839 Schedule(),
3840 vars.iborIndex->dayCounter(),
3841 parAssetSwap);
3842 floatingBondASW2.setPricingEngine(swapEngine);
3843 AssetSwap floatingSpecializedBondASW2(payFixedRate,
3844 floatingSpecializedBond2,
3845 floatingBondMktPrice2,
3846 vars.iborIndex, vars.spread,
3847 Schedule(),
3848 vars.iborIndex->dayCounter(),
3849 parAssetSwap);
3850 floatingSpecializedBondASW2.setPricingEngine(swapEngine);
3851 Real floatingBondASWSpread2 = floatingBondASW2.fairSpread();
3852 Real floatingSpecializedBondASWSpread2 =
3853 floatingSpecializedBondASW2.fairSpread();
3854 Real error8 =
3855 std::fabs(x: floatingBondASWSpread2-floatingSpecializedBondASWSpread2);
3856 if (error8>tolerance) {
3857 BOOST_FAIL("wrong asw spread for frn bond:"
3858 << std::fixed << std::setprecision(4)
3859 << "\n generic frn rate bond's asw spread: "
3860 << floatingBondASWSpread2
3861 << "\n equivalent specialized bond's asw spread: "
3862 << floatingSpecializedBondASWSpread2
3863 << std::scientific << std::setprecision(2)
3864 << "\n error: " << error8
3865 << "\n tolerance: " << tolerance);
3866 }
3867
3868 // CMS bond (Isin: XS0228052402 CRDIT 0 8/22/20)
3869 // maturity doesn't occur on a business day
3870 Date cmsBondStartDate1 = Date(22,August,2005);
3871 Date cmsBondMaturityDate1 = Date(22,August,2020);
3872 Schedule cmsBondSchedule1(cmsBondStartDate1,
3873 cmsBondMaturityDate1,
3874 Period(Annual), bondCalendar,
3875 Unadjusted, Unadjusted,
3876 DateGeneration::Backward, false);
3877 Leg cmsBondLeg1 = CmsLeg(cmsBondSchedule1, vars.swapIndex)
3878 .withNotionals(notional: vars.faceAmount)
3879 .withPaymentDayCounter(Thirty360(Thirty360::BondBasis))
3880 .withFixingDays(fixingDays)
3881 .withCaps(cap: 0.055)
3882 .withFloors(floor: 0.025)
3883 .inArrears(flag: inArrears);
3884 Date cmsbondRedemption1 = bondCalendar.adjust(cmsBondMaturityDate1,
3885 convention: Following);
3886 cmsBondLeg1.push_back(x: ext::shared_ptr<CashFlow>(new
3887 SimpleCashFlow(100.0, cmsbondRedemption1)));
3888 // generic cms bond
3889 ext::shared_ptr<Bond> cmsBond1(new
3890 Bond(settlementDays, bondCalendar, vars.faceAmount,
3891 cmsBondMaturityDate1, cmsBondStartDate1, cmsBondLeg1));
3892 cmsBond1->setPricingEngine(bondEngine);
3893
3894 // equivalent specialized cms bond
3895 ext::shared_ptr<Bond> cmsSpecializedBond1(new
3896 CmsRateBond(settlementDays, vars.faceAmount, cmsBondSchedule1,
3897 vars.swapIndex, Thirty360(Thirty360::BondBasis),
3898 Following, fixingDays,
3899 std::vector<Real>(1,1.0), std::vector<Spread>(1,0.0),
3900 std::vector<Rate>(1,0.055), std::vector<Rate>(1,0.025),
3901 inArrears,
3902 100.0, Date(22,August,2005)));
3903 cmsSpecializedBond1->setPricingEngine(bondEngine);
3904
3905
3906 setCouponPricer(leg: cmsBond1->cashflows(), vars.cmspricer);
3907 setCouponPricer(leg: cmsSpecializedBond1->cashflows(), vars.cmspricer);
3908 vars.swapIndex->addFixing(fixingDate: Date(18,August,2006), fixing: 0.04158);
3909 Real cmsBondPrice1 = cmsBond1->cleanPrice();
3910 Real cmsSpecializedBondPrice1 = cmsSpecializedBond1->cleanPrice();
3911 AssetSwap cmsBondAssetSwap1(payFixedRate,cmsBond1, cmsBondPrice1,
3912 vars.iborIndex, vars.nonnullspread,
3913 Schedule(),vars.iborIndex->dayCounter(),
3914 parAssetSwap);
3915 cmsBondAssetSwap1.setPricingEngine(swapEngine);
3916 AssetSwap cmsSpecializedBondAssetSwap1(payFixedRate,cmsSpecializedBond1,
3917 cmsSpecializedBondPrice1,
3918 vars.iborIndex,
3919 vars.nonnullspread,
3920 Schedule(),
3921 vars.iborIndex->dayCounter(),
3922 parAssetSwap);
3923 cmsSpecializedBondAssetSwap1.setPricingEngine(swapEngine);
3924 Real cmsBondAssetSwapPrice1 = cmsBondAssetSwap1.fairCleanPrice();
3925 Real cmsSpecializedBondAssetSwapPrice1 =
3926 cmsSpecializedBondAssetSwap1.fairCleanPrice();
3927 Real error9 =
3928 std::fabs(x: cmsBondAssetSwapPrice1-cmsSpecializedBondAssetSwapPrice1);
3929 if (error9>tolerance) {
3930 BOOST_FAIL("wrong clean price for cmsbond:"
3931 << std::fixed << std::setprecision(4)
3932 << "\n generic bond's clean price: "
3933 << cmsBondAssetSwapPrice1
3934 << "\n equivalent specialized cms rate bond's price: "
3935 << cmsSpecializedBondAssetSwapPrice1
3936 << std::scientific << std::setprecision(2)
3937 << "\n error: " << error9
3938 << "\n tolerance: " << tolerance);
3939 }
3940 Real cmsBondMktPrice1 = 87.02;// market executable price as of 4th sept 2007
3941 AssetSwap cmsBondASW1(payFixedRate,
3942 cmsBond1, cmsBondMktPrice1,
3943 vars.iborIndex, vars.spread,
3944 Schedule(),
3945 vars.iborIndex->dayCounter(),
3946 parAssetSwap);
3947 cmsBondASW1.setPricingEngine(swapEngine);
3948 AssetSwap cmsSpecializedBondASW1(payFixedRate,
3949 cmsSpecializedBond1,
3950 cmsBondMktPrice1,
3951 vars.iborIndex, vars.spread,
3952 Schedule(),
3953 vars.iborIndex->dayCounter(),
3954 parAssetSwap);
3955 cmsSpecializedBondASW1.setPricingEngine(swapEngine);
3956 Real cmsBondASWSpread1 = cmsBondASW1.fairSpread();
3957 Real cmsSpecializedBondASWSpread1 = cmsSpecializedBondASW1.fairSpread();
3958 Real error10 = std::fabs(x: cmsBondASWSpread1-cmsSpecializedBondASWSpread1);
3959 if (error10>tolerance) {
3960 BOOST_FAIL("wrong asw spread for cm bond:"
3961 << std::fixed << std::setprecision(4)
3962 << "\n generic cms rate bond's asw spread: "
3963 << cmsBondASWSpread1
3964 << "\n equivalent specialized bond's asw spread: "
3965 << cmsSpecializedBondASWSpread1
3966 << std::scientific << std::setprecision(2)
3967 << "\n error: " << error10
3968 << "\n tolerance: " << tolerance);
3969 }
3970
3971 //CMS bond (Isin: XS0218766664 ISPIM 0 5/6/15)
3972 //maturity occurs on a business day
3973 Date cmsBondStartDate2 = Date(06,May,2005);
3974 Date cmsBondMaturityDate2 = Date(06,May,2015);
3975 Schedule cmsBondSchedule2(cmsBondStartDate2,
3976 cmsBondMaturityDate2,
3977 Period(Annual), bondCalendar,
3978 Unadjusted, Unadjusted,
3979 DateGeneration::Backward, false);
3980 Leg cmsBondLeg2 = CmsLeg(cmsBondSchedule2, vars.swapIndex)
3981 .withNotionals(notional: vars.faceAmount)
3982 .withPaymentDayCounter(Thirty360(Thirty360::BondBasis))
3983 .withFixingDays(fixingDays)
3984 .withGearings(gearing: 0.84)
3985 .inArrears(flag: inArrears);
3986 Date cmsbondRedemption2 = bondCalendar.adjust(cmsBondMaturityDate2,
3987 convention: Following);
3988 cmsBondLeg2.push_back(x: ext::shared_ptr<CashFlow>(new
3989 SimpleCashFlow(100.0, cmsbondRedemption2)));
3990 // generic bond
3991 ext::shared_ptr<Bond> cmsBond2(new
3992 Bond(settlementDays, bondCalendar, vars.faceAmount,
3993 cmsBondMaturityDate2, cmsBondStartDate2, cmsBondLeg2));
3994 cmsBond2->setPricingEngine(bondEngine);
3995
3996 // equivalent specialized cms bond
3997 ext::shared_ptr<Bond> cmsSpecializedBond2(new
3998 CmsRateBond(settlementDays, vars.faceAmount, cmsBondSchedule2,
3999 vars.swapIndex, Thirty360(Thirty360::BondBasis),
4000 Following, fixingDays,
4001 std::vector<Real>(1,0.84), std::vector<Spread>(1,0.0),
4002 std::vector<Rate>(), std::vector<Rate>(),
4003 inArrears,
4004 100.0, Date(06,May,2005)));
4005 cmsSpecializedBond2->setPricingEngine(bondEngine);
4006
4007 setCouponPricer(leg: cmsBond2->cashflows(), vars.cmspricer);
4008 setCouponPricer(leg: cmsSpecializedBond2->cashflows(), vars.cmspricer);
4009 vars.swapIndex->addFixing(fixingDate: Date(04,May,2006), fixing: 0.04217);
4010 Real cmsBondPrice2 = cmsBond2->cleanPrice();
4011 Real cmsSpecializedBondPrice2 = cmsSpecializedBond2->cleanPrice();
4012 AssetSwap cmsBondAssetSwap2(payFixedRate,cmsBond2, cmsBondPrice2,
4013 vars.iborIndex, vars.nonnullspread,
4014 Schedule(),
4015 vars.iborIndex->dayCounter(),
4016 parAssetSwap);
4017 cmsBondAssetSwap2.setPricingEngine(swapEngine);
4018 AssetSwap cmsSpecializedBondAssetSwap2(payFixedRate,cmsSpecializedBond2,
4019 cmsSpecializedBondPrice2,
4020 vars.iborIndex,
4021 vars.nonnullspread,
4022 Schedule(),
4023 vars.iborIndex->dayCounter(),
4024 parAssetSwap);
4025 cmsSpecializedBondAssetSwap2.setPricingEngine(swapEngine);
4026 Real cmsBondAssetSwapPrice2 = cmsBondAssetSwap2.fairCleanPrice();
4027 Real cmsSpecializedBondAssetSwapPrice2 =
4028 cmsSpecializedBondAssetSwap2.fairCleanPrice();
4029 Real error11 =
4030 std::fabs(x: cmsBondAssetSwapPrice2-cmsSpecializedBondAssetSwapPrice2);
4031 if (error11>tolerance) {
4032 BOOST_FAIL("wrong clean price for cmsbond:"
4033 << std::fixed << std::setprecision(4)
4034 << "\n generic bond's clean price: "
4035 << cmsBondAssetSwapPrice2
4036 << "\n equivalent specialized cms rate bond's price: "
4037 << cmsSpecializedBondAssetSwapPrice2
4038 << std::scientific << std::setprecision(2)
4039 << "\n error: " << error11
4040 << "\n tolerance: " << tolerance);
4041 }
4042 Real cmsBondMktPrice2 = 94.35;// market executable price as of 4th sept 2007
4043 AssetSwap cmsBondASW2(payFixedRate,
4044 cmsBond2, cmsBondMktPrice2,
4045 vars.iborIndex, vars.spread,
4046 Schedule(),
4047 vars.iborIndex->dayCounter(),
4048 parAssetSwap);
4049 cmsBondASW2.setPricingEngine(swapEngine);
4050 AssetSwap cmsSpecializedBondASW2(payFixedRate,
4051 cmsSpecializedBond2,
4052 cmsBondMktPrice2,
4053 vars.iborIndex, vars.spread,
4054 Schedule(),
4055 vars.iborIndex->dayCounter(),
4056 parAssetSwap);
4057 cmsSpecializedBondASW2.setPricingEngine(swapEngine);
4058 Real cmsBondASWSpread2 = cmsBondASW2.fairSpread();
4059 Real cmsSpecializedBondASWSpread2 = cmsSpecializedBondASW2.fairSpread();
4060 Real error12 = std::fabs(x: cmsBondASWSpread2-cmsSpecializedBondASWSpread2);
4061 if (error12>tolerance) {
4062 BOOST_FAIL("wrong asw spread for cm bond:"
4063 << std::fixed << std::setprecision(4)
4064 << "\n generic cms rate bond's asw spread: "
4065 << cmsBondASWSpread2
4066 << "\n equivalent specialized bond's asw spread: "
4067 << cmsSpecializedBondASWSpread2
4068 << std::scientific << std::setprecision(2)
4069 << "\n error: " << error12
4070 << "\n tolerance: " << tolerance);
4071 }
4072
4073
4074 // Zero-Coupon bond (Isin: DE0004771662 IBRD 0 12/20/15)
4075 // maturity doesn't occur on a business day
4076 Date zeroCpnBondStartDate1 = Date(19,December,1985);
4077 Date zeroCpnBondMaturityDate1 = Date(20,December,2015);
4078 Date zeroCpnBondRedemption1 = bondCalendar.adjust(zeroCpnBondMaturityDate1,
4079 convention: Following);
4080 Leg zeroCpnBondLeg1 = Leg(1, ext::shared_ptr<CashFlow>(new
4081 SimpleCashFlow(100.0, zeroCpnBondRedemption1)));
4082 // generic bond
4083 ext::shared_ptr<Bond> zeroCpnBond1(new
4084 Bond(settlementDays, bondCalendar, vars.faceAmount,
4085 zeroCpnBondMaturityDate1, zeroCpnBondStartDate1, zeroCpnBondLeg1));
4086 zeroCpnBond1->setPricingEngine(bondEngine);
4087
4088 // specialized zerocpn bond
4089 ext::shared_ptr<Bond> zeroCpnSpecializedBond1(new
4090 ZeroCouponBond(settlementDays, bondCalendar, vars.faceAmount,
4091 Date(20,December,2015),
4092 Following,
4093 100.0, Date(19,December,1985)));
4094 zeroCpnSpecializedBond1->setPricingEngine(bondEngine);
4095
4096 Real zeroCpnBondPrice1 = zeroCpnBond1->cleanPrice();
4097 Real zeroCpnSpecializedBondPrice1 = zeroCpnSpecializedBond1->cleanPrice();
4098 AssetSwap zeroCpnBondAssetSwap1(payFixedRate,zeroCpnBond1,
4099 zeroCpnBondPrice1,
4100 vars.iborIndex, vars.nonnullspread,
4101 Schedule(),
4102 vars.iborIndex->dayCounter(),
4103 parAssetSwap);
4104 zeroCpnBondAssetSwap1.setPricingEngine(swapEngine);
4105 AssetSwap zeroCpnSpecializedBondAssetSwap1(payFixedRate,
4106 zeroCpnSpecializedBond1,
4107 zeroCpnSpecializedBondPrice1,
4108 vars.iborIndex,
4109 vars.nonnullspread,
4110 Schedule(),
4111 vars.iborIndex->dayCounter(),
4112 parAssetSwap);
4113 zeroCpnSpecializedBondAssetSwap1.setPricingEngine(swapEngine);
4114 Real zeroCpnBondAssetSwapPrice1 = zeroCpnBondAssetSwap1.fairCleanPrice();
4115 Real zeroCpnSpecializedBondAssetSwapPrice1 =
4116 zeroCpnSpecializedBondAssetSwap1.fairCleanPrice();
4117 Real error13 =
4118 std::fabs(x: zeroCpnBondAssetSwapPrice1-zeroCpnSpecializedBondAssetSwapPrice1);
4119 if (error13>tolerance) {
4120 BOOST_FAIL("wrong clean price for zerocpn bond:"
4121 << std::fixed << std::setprecision(4)
4122 << "\n generic zero cpn bond's clean price: "
4123 << zeroCpnBondAssetSwapPrice1
4124 << "\n specialized equivalent bond's price: "
4125 << zeroCpnSpecializedBondAssetSwapPrice1
4126 << "\n error: " << error13
4127 << "\n tolerance: " << tolerance);
4128 }
4129 // market executable price as of 4th sept 2007
4130 Real zeroCpnBondMktPrice1 = 72.277;
4131 AssetSwap zeroCpnBondASW1(payFixedRate,
4132 zeroCpnBond1,zeroCpnBondMktPrice1,
4133 vars.iborIndex, vars.spread,
4134 Schedule(),
4135 vars.iborIndex->dayCounter(),
4136 parAssetSwap);
4137 zeroCpnBondASW1.setPricingEngine(swapEngine);
4138 AssetSwap zeroCpnSpecializedBondASW1(payFixedRate,
4139 zeroCpnSpecializedBond1,
4140 zeroCpnBondMktPrice1,
4141 vars.iborIndex, vars.spread,
4142 Schedule(),
4143 vars.iborIndex->dayCounter(),
4144 parAssetSwap);
4145 zeroCpnSpecializedBondASW1.setPricingEngine(swapEngine);
4146 Real zeroCpnBondASWSpread1 = zeroCpnBondASW1.fairSpread();
4147 Real zeroCpnSpecializedBondASWSpread1 =
4148 zeroCpnSpecializedBondASW1.fairSpread();
4149 Real error14 =
4150 std::fabs(x: zeroCpnBondASWSpread1-zeroCpnSpecializedBondASWSpread1);
4151 if (error14>tolerance) {
4152 BOOST_FAIL("wrong asw spread for zeroCpn bond:"
4153 << std::fixed << std::setprecision(4)
4154 << "\n generic zeroCpn bond's asw spread: "
4155 << zeroCpnBondASWSpread1
4156 << "\n equivalent specialized bond's asw spread: "
4157 << zeroCpnSpecializedBondASWSpread1
4158 << std::scientific << std::setprecision(2)
4159 << "\n error: " << error14
4160 << "\n tolerance: " << tolerance);
4161 }
4162
4163
4164 // Zero Coupon bond (Isin: IT0001200390 ISPIM 0 02/17/28)
4165 // maturity doesn't occur on a business day
4166 Date zeroCpnBondStartDate2 = Date(17,February,1998);
4167 Date zeroCpnBondMaturityDate2 = Date(17,February,2028);
4168 Date zerocpbondRedemption2 = bondCalendar.adjust(zeroCpnBondMaturityDate2,
4169 convention: Following);
4170 Leg zeroCpnBondLeg2 = Leg(1, ext::shared_ptr<CashFlow>(new
4171 SimpleCashFlow(100.0, zerocpbondRedemption2)));
4172 // generic bond
4173 ext::shared_ptr<Bond> zeroCpnBond2(new
4174 Bond(settlementDays, bondCalendar, vars.faceAmount,
4175 zeroCpnBondMaturityDate2, zeroCpnBondStartDate2, zeroCpnBondLeg2));
4176 zeroCpnBond2->setPricingEngine(bondEngine);
4177
4178 // specialized zerocpn bond
4179 ext::shared_ptr<Bond> zeroCpnSpecializedBond2(new
4180 ZeroCouponBond(settlementDays, bondCalendar, vars.faceAmount,
4181 Date(17,February,2028),
4182 Following,
4183 100.0, Date(17,February,1998)));
4184 zeroCpnSpecializedBond2->setPricingEngine(bondEngine);
4185
4186 Real zeroCpnBondPrice2 = zeroCpnBond2->cleanPrice();
4187 Real zeroCpnSpecializedBondPrice2 = zeroCpnSpecializedBond2->cleanPrice();
4188
4189 AssetSwap zeroCpnBondAssetSwap2(payFixedRate,zeroCpnBond2,
4190 zeroCpnBondPrice2,
4191 vars.iborIndex, vars.nonnullspread,
4192 Schedule(),
4193 vars.iborIndex->dayCounter(),
4194 parAssetSwap);
4195 zeroCpnBondAssetSwap2.setPricingEngine(swapEngine);
4196 AssetSwap zeroCpnSpecializedBondAssetSwap2(payFixedRate,
4197 zeroCpnSpecializedBond2,
4198 zeroCpnSpecializedBondPrice2,
4199 vars.iborIndex,
4200 vars.nonnullspread,
4201 Schedule(),
4202 vars.iborIndex->dayCounter(),
4203 parAssetSwap);
4204 zeroCpnSpecializedBondAssetSwap2.setPricingEngine(swapEngine);
4205 Real zeroCpnBondAssetSwapPrice2 = zeroCpnBondAssetSwap2.fairCleanPrice();
4206 Real zeroCpnSpecializedBondAssetSwapPrice2 =
4207 zeroCpnSpecializedBondAssetSwap2.fairCleanPrice();
4208 Real error15 = std::fabs(x: zeroCpnBondAssetSwapPrice2
4209 -zeroCpnSpecializedBondAssetSwapPrice2);
4210 if (error15>tolerance) {
4211 BOOST_FAIL("wrong clean price for zerocpn bond:"
4212 << std::fixed << std::setprecision(4)
4213 << "\n generic zero cpn bond's clean price: "
4214 << zeroCpnBondAssetSwapPrice2
4215 << "\n equivalent specialized bond's price: "
4216 << zeroCpnSpecializedBondAssetSwapPrice2
4217 << "\n error: " << error15
4218 << "\n tolerance: " << tolerance);
4219 }
4220 // market executable price as of 4th sept 2007
4221 Real zeroCpnBondMktPrice2 = 72.277;
4222 AssetSwap zeroCpnBondASW2(payFixedRate,
4223 zeroCpnBond2,zeroCpnBondMktPrice2,
4224 vars.iborIndex, vars.spread,
4225 Schedule(),
4226 vars.iborIndex->dayCounter(),
4227 parAssetSwap);
4228 zeroCpnBondASW2.setPricingEngine(swapEngine);
4229 AssetSwap zeroCpnSpecializedBondASW2(payFixedRate,
4230 zeroCpnSpecializedBond2,
4231 zeroCpnBondMktPrice2,
4232 vars.iborIndex, vars.spread,
4233 Schedule(),
4234 vars.iborIndex->dayCounter(),
4235 parAssetSwap);
4236 zeroCpnSpecializedBondASW2.setPricingEngine(swapEngine);
4237 Real zeroCpnBondASWSpread2 = zeroCpnBondASW2.fairSpread();
4238 Real zeroCpnSpecializedBondASWSpread2 =
4239 zeroCpnSpecializedBondASW2.fairSpread();
4240 Real error16 =
4241 std::fabs(x: zeroCpnBondASWSpread2-zeroCpnSpecializedBondASWSpread2);
4242 if (error16>tolerance) {
4243 BOOST_FAIL("wrong asw spread for zeroCpn bond:"
4244 << std::fixed << std::setprecision(4)
4245 << "\n generic zeroCpn bond's asw spread: "
4246 << zeroCpnBondASWSpread2
4247 << "\n equivalent specialized bond's asw spread: "
4248 << zeroCpnSpecializedBondASWSpread2
4249 << std::scientific << std::setprecision(2)
4250 << "\n error: " << error16
4251 << "\n tolerance: " << tolerance);
4252 }
4253}
4254
4255
4256test_suite* AssetSwapTest::suite() {
4257 auto* suite = BOOST_TEST_SUITE("AssetSwap tests");
4258 suite->add(QUANTLIB_TEST_CASE(&AssetSwapTest::testConsistency));
4259 suite->add(QUANTLIB_TEST_CASE(&AssetSwapTest::testImpliedValue));
4260 suite->add(QUANTLIB_TEST_CASE(&AssetSwapTest::testMarketASWSpread));
4261 suite->add(QUANTLIB_TEST_CASE(&AssetSwapTest::testZSpread));
4262 suite->add(QUANTLIB_TEST_CASE(&AssetSwapTest::testGenericBondImplied));
4263 suite->add(QUANTLIB_TEST_CASE(&AssetSwapTest::testMASWWithGenericBond));
4264 suite->add(QUANTLIB_TEST_CASE(&AssetSwapTest::testZSpreadWithGenericBond));
4265 suite->add(QUANTLIB_TEST_CASE(
4266 &AssetSwapTest::testSpecializedBondVsGenericBond));
4267 suite->add(QUANTLIB_TEST_CASE(
4268 &AssetSwapTest::testSpecializedBondVsGenericBondUsingAsw));
4269
4270 return suite;
4271}
4272

source code of quantlib/test-suite/assetswap.cpp