1 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3 /*!
4 Copyright (C) 2007 Allen Kuo
5 Copyright (C) 2015 Andres Hernandez
6
7 This file is part of QuantLib, a free-software/open-source library
8 for financial quantitative analysts and developers - http://quantlib.org/
9
10 QuantLib is free software: you can redistribute it and/or modify it
11 under the terms of the QuantLib license. You should have received a
12 copy of the license along with this program; if not, please email
13 <quantlib-dev@lists.sf.net>. The license is also available online at
14 <http://quantlib.org/license.shtml>.
15
16 This program is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 FOR A PARTICULAR PURPOSE. See the license for more details.
19 */
20
21 /* This example shows how to fit a term structure to a set of bonds
22 using four different fitting methodologies. Though fitting is most
23 useful for large numbers of bonds with non-smooth yield tenor
24 structures, for comparison purposes, relatively smooth bond yields
25 are fit here and compared to known solutions (par coupons), or
26 results generated from the bootstrap fitting method.
27 */
28
29 #include <ql/qldefines.hpp>
30 #if !defined(BOOST_ALL_NO_LIB) && defined(BOOST_MSVC)
31 # include <ql/auto_link.hpp>
32 #endif
33 #include <ql/termstructures/yield/fittedbonddiscountcurve.hpp>
34 #include <ql/termstructures/yield/piecewiseyieldcurve.hpp>
35 #include <ql/termstructures/yield/flatforward.hpp>
36 #include <ql/termstructures/yield/bondhelpers.hpp>
37 #include <ql/termstructures/yield/nonlinearfittingmethods.hpp>
38 #include <ql/pricingengines/bond/bondfunctions.hpp>
39 #include <ql/time/calendars/target.hpp>
40 #include <ql/time/daycounters/simpledaycounter.hpp>
41
42 #include <iostream>
43 #include <iomanip>
44
45 #define LENGTH(a) (sizeof(a)/sizeof(a[0]))
46
47 using namespace std;
48 using namespace QuantLib;
49
50 // par-rate approximation
51 Rate parRate(const YieldTermStructure& yts,
52 const std::vector<Date>& dates,
53 const DayCounter& resultDayCounter) {
54 QL_REQUIRE(dates.size() >= 2, "at least two dates are required");
55 Real sum = 0.0;
56 Time dt;
57 for (Size i=1; i<dates.size(); ++i) {
58 dt = resultDayCounter.yearFraction(dates[i-1], dates[i]);
59 QL_REQUIRE(dt>=0.0, "unsorted dates");
60 sum += yts.discount(dates[i]) * dt;
61 }
62 Real result = yts.discount(dates.front()) - yts.discount(dates.back());
63 return result/sum;
64 }
65
66 void printOutput(const std::string& tag,
67 const ext::shared_ptr<FittedBondDiscountCurve>& curve) {
68 cout << tag << endl;
69 cout << "reference date : "
70 << curve->referenceDate()
71 << endl;
72 cout << "number of iterations : "
73 << curve->fitResults().numberOfIterations()
74 << endl
75 << endl;
76 }
77
78
79 int main(int, char* []) {
80
81 try {
82
83 const Size numberOfBonds = 15;
84 Real cleanPrice[numberOfBonds];
85
86 for (Real& i : cleanPrice) {
87 i = 100.0;
88 }
89
90 std::vector< ext::shared_ptr<SimpleQuote>> quote;
91 for (Real i : cleanPrice) {
92 quote.push_back(ext::make_shared<SimpleQuote>(i));
93 }
94
95 RelinkableHandle<Quote> quoteHandle[numberOfBonds];
96 for (Size i=0; i<numberOfBonds; i++) {
97 quoteHandle[i].linkTo(quote[i]);
98 }
99
100 Integer lengths[] = { 2, 4, 6, 8, 10, 12, 14, 16,
101 18, 20, 22, 24, 26, 28, 30 };
102 Real coupons[] = { 0.0200, 0.0225, 0.0250, 0.0275, 0.0300,
103 0.0325, 0.0350, 0.0375, 0.0400, 0.0425,
104 0.0450, 0.0475, 0.0500, 0.0525, 0.0550 };
105
106 Frequency frequency = Annual;
107 DayCounter dc = SimpleDayCounter();
108 BusinessDayConvention accrualConvention = ModifiedFollowing;
109 BusinessDayConvention convention = ModifiedFollowing;
110 Real redemption = 100.0;
111
112 Calendar calendar = TARGET();
113 Date today = calendar.adjust(Date::todaysDate());
114 Date origToday = today;
115 Settings::instance().evaluationDate() = today;
116
117 // changing bondSettlementDays=3 increases calculation
118 // time of exponentialsplines fitting method
119 Natural bondSettlementDays = 0;
120 Natural curveSettlementDays = 0;
121
122 Date bondSettlementDate = calendar.advance(today, bondSettlementDays*Days);
123
124 cout << endl;
125 cout << "Today's date: " << today << endl;
126 cout << "Bonds' settlement date: " << bondSettlementDate << endl;
127 cout << "Calculating fit for 15 bonds....." << endl << endl;
128
129 std::vector<ext::shared_ptr<BondHelper>> instrumentsA;
130 std::vector<ext::shared_ptr<RateHelper>> instrumentsB;
131
132 for (Size j=0; j<LENGTH(lengths); j++) {
133
134 Date maturity = calendar.advance(bondSettlementDate, lengths[j]*Years);
135
136 Schedule schedule(bondSettlementDate, maturity, Period(frequency),
137 calendar, accrualConvention, accrualConvention,
138 DateGeneration::Backward, false);
139
140 auto helperA = ext::make_shared<FixedRateBondHelper>(quoteHandle[j],
141 bondSettlementDays,
142 100.0,
143 schedule,
144 std::vector<Rate>(1,coupons[j]),
145 dc,
146 convention,
147 redemption);
148
149 auto helperB = ext::make_shared<FixedRateBondHelper>(quoteHandle[j],
150 bondSettlementDays,
151 100.0,
152 schedule,
153 std::vector<Rate>(1, coupons[j]),
154 dc,
155 convention,
156 redemption);
157 instrumentsA.push_back(helperA);
158 instrumentsB.push_back(helperB);
159 }
160
161
162 bool constrainAtZero = true;
163 Real tolerance = 1.0e-10;
164 Size max = 5000;
165
166 auto ts0 = ext::make_shared<PiecewiseYieldCurve<Discount, LogLinear>>(curveSettlementDays,
167 calendar,
168 instrumentsB,
169 dc);
170
171 ExponentialSplinesFitting exponentialSplines(constrainAtZero);
172
173 auto ts1 = ext::make_shared<FittedBondDiscountCurve>(curveSettlementDays,
174 calendar,
175 instrumentsA,
176 dc,
177 exponentialSplines,
178 tolerance,
179 max);
180
181 printOutput("(a) exponential splines", ts1);
182
183
184 SimplePolynomialFitting simplePolynomial(3, constrainAtZero);
185
186 auto ts2 = ext::make_shared<FittedBondDiscountCurve>(curveSettlementDays,
187 calendar,
188 instrumentsA,
189 dc,
190 simplePolynomial,
191 tolerance,
192 max);
193
194 printOutput("(b) simple polynomial", ts2);
195
196
197 NelsonSiegelFitting nelsonSiegel;
198
199 auto ts3 = ext::make_shared<FittedBondDiscountCurve>(curveSettlementDays,
200 calendar,
201 instrumentsA,
202 dc,
203 nelsonSiegel,
204 tolerance,
205 max);
206
207 printOutput("(c) Nelson-Siegel", ts3);
208
209
210 // a cubic bspline curve with 11 knot points, implies
211 // n=6 (constrained problem) basis functions
212
213 Time knots[] = { -30.0, -20.0, 0.0, 5.0, 10.0, 15.0,
214 20.0, 25.0, 30.0, 40.0, 50.0 };
215
216 std::vector<Time> knotVector;
217 for (Real& knot : knots) {
218 knotVector.push_back(knot);
219 }
220
221 CubicBSplinesFitting cubicBSplines(knotVector, constrainAtZero);
222
223 auto ts4 = ext::make_shared<FittedBondDiscountCurve>(curveSettlementDays,
224 calendar,
225 instrumentsA,
226 dc,
227 cubicBSplines,
228 tolerance,
229 max);
230
231 printOutput("(d) cubic B-splines", ts4);
232
233 SvenssonFitting svensson;
234
235 auto ts5 = ext::make_shared<FittedBondDiscountCurve>(curveSettlementDays,
236 calendar,
237 instrumentsA,
238 dc,
239 svensson,
240 tolerance,
241 max);
242
243 printOutput("(e) Svensson", ts5);
244
245 Handle<YieldTermStructure> discountCurve(
246 ext::make_shared<FlatForward>(
247 curveSettlementDays, calendar, 0.01, dc));
248 SpreadFittingMethod nelsonSiegelSpread(
249 ext::make_shared<NelsonSiegelFitting>(),
250 discountCurve);
251
252 auto ts6 = ext::make_shared<FittedBondDiscountCurve>(curveSettlementDays,
253 calendar,
254 instrumentsA,
255 dc,
256 nelsonSiegelSpread,
257 tolerance,
258 max);
259
260 printOutput("(f) Nelson-Siegel spread", ts6);
261
262 //Fixed kappa, and 7 coefficients
263 ExponentialSplinesFitting exponentialSplinesFixed(constrainAtZero,7,0.02);
264
265 auto ts7 = ext::make_shared<FittedBondDiscountCurve>(curveSettlementDays,
266 calendar,
267 instrumentsA,
268 dc,
269 exponentialSplinesFixed,
270 tolerance,
271 max);
272
273 printOutput("(g) exponential splines, fixed kappa", ts7);
274
275 cout << "Output par rates for each curve. In this case, "
276 << endl
277 << "par rates should equal coupons for these par bonds."
278 << endl
279 << endl;
280
281 cout << setw(6) << "tenor" << " | "
282 << setw(6) << "coupon" << " | "
283 << setw(6) << "bstrap" << " | "
284 << setw(6) << "(a)" << " | "
285 << setw(6) << "(b)" << " | "
286 << setw(6) << "(c)" << " | "
287 << setw(6) << "(d)" << " | "
288 << setw(6) << "(e)" << " | "
289 << setw(6) << "(f)" << " | "
290 << setw(6) << "(g)" << endl;
291
292 for (Size i=0; i<instrumentsA.size(); i++) {
293
294 std::vector<ext::shared_ptr<CashFlow>> cfs =
295 instrumentsA[i]->bond()->cashflows();
296
297 Size cfSize = instrumentsA[i]->bond()->cashflows().size();
298 std::vector<Date> keyDates;
299 keyDates.push_back(bondSettlementDate);
300
301 for (Size j=0; j<cfSize-1; j++) {
302 if (!cfs[j]->hasOccurred(bondSettlementDate, false)) {
303 Date myDate = cfs[j]->date();
304 keyDates.push_back(myDate);
305 }
306 }
307
308 Real tenor = dc.yearFraction(today, cfs[cfSize-1]->date());
309
310 cout << setw(6) << fixed << setprecision(3) << tenor << " | "
311 << setw(6) << fixed << setprecision(3)
312 << 100.*coupons[i] << " | "
313 // piecewise bootstrap
314 << setw(6) << fixed << setprecision(3)
315 << 100.*parRate(*ts0,keyDates,dc) << " | "
316 // exponential splines
317 << setw(6) << fixed << setprecision(3)
318 << 100.*parRate(*ts1,keyDates,dc) << " | "
319 // simple polynomial
320 << setw(6) << fixed << setprecision(3)
321 << 100.*parRate(*ts2,keyDates,dc) << " | "
322 // Nelson-Siegel
323 << setw(6) << fixed << setprecision(3)
324 << 100.*parRate(*ts3,keyDates,dc) << " | "
325 // cubic bsplines
326 << setw(6) << fixed << setprecision(3)
327 << 100.*parRate(*ts4,keyDates,dc) << " | "
328 // Svensson
329 << setw(6) << fixed << setprecision(3)
330 << 100.*parRate(*ts5,keyDates,dc) << " | "
331 // Nelson-Siegel Spread
332 << setw(6) << fixed << setprecision(3)
333 << 100.*parRate(*ts6,keyDates,dc) << " | "
334 // Exponential, fixed kappa
335 << setw(6) << fixed << setprecision(3)
336 << 100. *parRate(*ts7, keyDates, dc) << endl;
337 }
338
339 cout << endl << endl << endl;
340 cout << "Now add 23 months to today. Par rates should be " << endl
341 << "automatically recalculated because today's date " << endl
342 << "changes. Par rates will NOT equal coupons (YTM " << endl
343 << "will, with the correct compounding), but the " << endl
344 << "piecewise yield curve par rates can be used as " << endl
345 << "a benchmark for correct par rates."
346 << endl
347 << endl;
348
349 today = calendar.advance(origToday,23,Months,convention);
350 Settings::instance().evaluationDate() = today;
351 bondSettlementDate = calendar.advance(today, bondSettlementDays*Days);
352
353 printOutput("(a) exponential splines", ts1);
354
355 printOutput("(b) simple polynomial", ts2);
356
357 printOutput("(c) Nelson-Siegel", ts3);
358
359 printOutput("(d) cubic B-splines", ts4);
360
361 printOutput("(e) Svensson", ts5);
362
363 printOutput("(f) Nelson-Siegel spread", ts6);
364
365 printOutput("(g) exponential spline, fixed kappa", ts7);
366
367 cout << endl
368 << endl;
369
370
371 cout << setw(6) << "tenor" << " | "
372 << setw(6) << "coupon" << " | "
373 << setw(6) << "bstrap" << " | "
374 << setw(6) << "(a)" << " | "
375 << setw(6) << "(b)" << " | "
376 << setw(6) << "(c)" << " | "
377 << setw(6) << "(d)" << " | "
378 << setw(6) << "(e)" << " | "
379 << setw(6) << "(f)" << " | "
380 << setw(6) << "(g)" << endl;
381
382 for (Size i=0; i<instrumentsA.size(); i++) {
383
384 std::vector<ext::shared_ptr<CashFlow>> cfs =
385 instrumentsA[i]->bond()->cashflows();
386
387 Size cfSize = instrumentsA[i]->bond()->cashflows().size();
388 std::vector<Date> keyDates;
389 keyDates.push_back(bondSettlementDate);
390
391 for (Size j=0; j<cfSize-1; j++) {
392 if (!cfs[j]->hasOccurred(bondSettlementDate, false)) {
393 Date myDate = cfs[j]->date();
394 keyDates.push_back(myDate);
395 }
396 }
397
398 Real tenor = dc.yearFraction(today, cfs[cfSize-1]->date());
399
400 cout << setw(6) << fixed << setprecision(3) << tenor << " | "
401 << setw(6) << fixed << setprecision(3)
402 << 100.*coupons[i] << " | "
403 // piecewise bootstrap
404 << setw(6) << fixed << setprecision(3)
405 << 100.*parRate(*ts0,keyDates,dc) << " | "
406 // exponential splines
407 << setw(6) << fixed << setprecision(3)
408 << 100.*parRate(*ts1,keyDates,dc) << " | "
409 // simple polynomial
410 << setw(6) << fixed << setprecision(3)
411 << 100.*parRate(*ts2,keyDates,dc) << " | "
412 // Nelson-Siegel
413 << setw(6) << fixed << setprecision(3)
414 << 100.*parRate(*ts3,keyDates,dc) << " | "
415 // cubic bsplines
416 << setw(6) << fixed << setprecision(3)
417 << 100.*parRate(*ts4,keyDates,dc) << " | "
418 // Svensson
419 << setw(6) << fixed << setprecision(3)
420 << 100.*parRate(*ts5,keyDates,dc) << " | "
421 // Nelson-Siegel Spread
422 << setw(6) << fixed << setprecision(3)
423 << 100.*parRate(*ts6,keyDates,dc) << " | "
424 // exponential, fixed kappa
425 << setw(6) << fixed << setprecision(3)
426 << 100. * parRate(*ts7, keyDates, dc) << endl;
427 }
428
429 cout << endl << endl << endl;
430 cout << "Now add one more month, for a total of two years " << endl
431 << "from the original date. The first instrument is " << endl
432 << "now expired and par rates should again equal " << endl
433 << "coupon values, since clean prices did not change."
434 << endl
435 << endl;
436
437 instrumentsA.erase(instrumentsA.begin(),
438 instrumentsA.begin()+1);
439 instrumentsB.erase(instrumentsB.begin(),
440 instrumentsB.begin()+1);
441
442 today = calendar.advance(origToday,24,Months,convention);
443 Settings::instance().evaluationDate() = today;
444 bondSettlementDate = calendar.advance(today, bondSettlementDays*Days);
445
446 auto ts00 = ext::make_shared<PiecewiseYieldCurve<Discount, LogLinear>>(curveSettlementDays,
447 calendar,
448 instrumentsB,
449 dc);
450
451 auto ts11 = ext::make_shared<FittedBondDiscountCurve>(curveSettlementDays,
452 calendar,
453 instrumentsA,
454 dc,
455 exponentialSplines,
456 tolerance,
457 max);
458
459 printOutput("(a) exponential splines", ts11);
460
461
462 auto ts22 = ext::make_shared<FittedBondDiscountCurve>(curveSettlementDays,
463 calendar,
464 instrumentsA,
465 dc,
466 simplePolynomial,
467 tolerance,
468 max);
469
470 printOutput("(b) simple polynomial", ts22);
471
472
473 auto ts33 = ext::make_shared<FittedBondDiscountCurve>(curveSettlementDays,
474 calendar,
475 instrumentsA,
476 dc,
477 nelsonSiegel,
478 tolerance,
479 max);
480
481 printOutput("(c) Nelson-Siegel", ts33);
482
483
484 auto ts44 = ext::make_shared<FittedBondDiscountCurve>(curveSettlementDays,
485 calendar,
486 instrumentsA,
487 dc,
488 cubicBSplines,
489 tolerance,
490 max);
491
492 printOutput("(d) cubic B-splines", ts44);
493
494 auto ts55 = ext::make_shared<FittedBondDiscountCurve>(curveSettlementDays,
495 calendar,
496 instrumentsA,
497 dc,
498 svensson,
499 tolerance,
500 max);
501
502 printOutput("(e) Svensson", ts55);
503
504 auto ts66 = ext::make_shared<FittedBondDiscountCurve>(curveSettlementDays,
505 calendar,
506 instrumentsA,
507 dc,
508 nelsonSiegelSpread,
509 tolerance,
510 max);
511
512 printOutput("(f) Nelson-Siegel spread", ts66);
513
514 auto ts77 = ext::make_shared<FittedBondDiscountCurve>(curveSettlementDays,
515 calendar,
516 instrumentsA,
517 dc,
518 exponentialSplinesFixed,
519 tolerance,
520 max);
521
522 printOutput("(g) exponential, fixed kappa", ts77);
523
524 cout << setw(6) << "tenor" << " | "
525 << setw(6) << "coupon" << " | "
526 << setw(6) << "bstrap" << " | "
527 << setw(6) << "(a)" << " | "
528 << setw(6) << "(b)" << " | "
529 << setw(6) << "(c)" << " | "
530 << setw(6) << "(d)" << " | "
531 << setw(6) << "(e)" << " | "
532 << setw(6) << "(f)" << " | "
533 << setw(6) << "(g)" << endl;
534
535 for (Size i=0; i<instrumentsA.size(); i++) {
536
537 std::vector<ext::shared_ptr<CashFlow>> cfs =
538 instrumentsA[i]->bond()->cashflows();
539
540 Size cfSize = instrumentsA[i]->bond()->cashflows().size();
541 std::vector<Date> keyDates;
542 keyDates.push_back(bondSettlementDate);
543
544 for (Size j=0; j<cfSize-1; j++) {
545 if (!cfs[j]->hasOccurred(bondSettlementDate, false)) {
546 Date myDate = cfs[j]->date();
547 keyDates.push_back(myDate);
548 }
549 }
550
551 Real tenor = dc.yearFraction(today, cfs[cfSize-1]->date());
552
553 cout << setw(6) << fixed << setprecision(3) << tenor << " | "
554 << setw(6) << fixed << setprecision(3)
555 << 100.*coupons[i+1] << " | "
556 // piecewise bootstrap
557 << setw(6) << fixed << setprecision(3)
558 << 100.*parRate(*ts00,keyDates,dc) << " | "
559 // exponential splines
560 << setw(6) << fixed << setprecision(3)
561 << 100.*parRate(*ts11,keyDates,dc) << " | "
562 // simple polynomial
563 << setw(6) << fixed << setprecision(3)
564 << 100.*parRate(*ts22,keyDates,dc) << " | "
565 // Nelson-Siegel
566 << setw(6) << fixed << setprecision(3)
567 << 100.*parRate(*ts33,keyDates,dc) << " | "
568 // cubic bsplines
569 << setw(6) << fixed << setprecision(3)
570 << 100.*parRate(*ts44,keyDates,dc) << " | "
571 // Svensson
572 << setw(6) << fixed << setprecision(3)
573 << 100.*parRate(*ts55,keyDates,dc) << " | "
574 // Nelson-Siegel Spread
575 << setw(6) << fixed << setprecision(3)
576 << 100.*parRate(*ts66,keyDates,dc) << " | "
577 // exponential, fixed kappa
578 << setw(6) << fixed << setprecision(3)
579 << 100. *parRate(*ts77, keyDates, dc) << endl;
580 }
581
582
583 cout << endl << endl << endl;
584 cout << "Now decrease prices by a small amount, corresponding" << endl
585 << "to a theoretical five basis point parallel + shift of" << endl
586 << "the yield curve. Because bond quotes change, the new " << endl
587 << "par rates should be recalculated automatically."
588 << endl
589 << endl;
590
591 for (Size k=0; k<LENGTH(lengths)-1; k++) {
592
593 Real P = instrumentsA[k]->quote()->value();
594 const Bond& b = *instrumentsA[k]->bond();
595 Rate ytm = BondFunctions::yield(b, P,
596 dc, Compounded, frequency,
597 today);
598 Time dur = BondFunctions::duration(b, ytm,
599 dc, Compounded, frequency,
600 Duration::Modified,
601 today);
602
603 const Real bpsChange = 5.;
604 // dP = -dur * P * dY
605 Real deltaP = -dur * P * (bpsChange/10000.);
606 quote[k+1]->setValue(P + deltaP);
607 }
608
609
610 cout << setw(6) << "tenor" << " | "
611 << setw(6) << "coupon" << " | "
612 << setw(6) << "bstrap" << " | "
613 << setw(6) << "(a)" << " | "
614 << setw(6) << "(b)" << " | "
615 << setw(6) << "(c)" << " | "
616 << setw(6) << "(d)" << " | "
617 << setw(6) << "(e)" << " | "
618 << setw(6) << "(f)" << " | "
619 << setw(6) << "(g)" << endl;
620
621 for (Size i=0; i<instrumentsA.size(); i++) {
622
623 std::vector<ext::shared_ptr<CashFlow>> cfs =
624 instrumentsA[i]->bond()->cashflows();
625
626 Size cfSize = instrumentsA[i]->bond()->cashflows().size();
627 std::vector<Date> keyDates;
628 keyDates.push_back(bondSettlementDate);
629
630 for (Size j=0; j<cfSize-1; j++) {
631 if (!cfs[j]->hasOccurred(bondSettlementDate, false)) {
632 Date myDate = cfs[j]->date();
633 keyDates.push_back(myDate);
634 }
635 }
636
637 Real tenor = dc.yearFraction(today, cfs[cfSize-1]->date());
638
639 cout << setw(6) << fixed << setprecision(3) << tenor << " | "
640 << setw(6) << fixed << setprecision(3)
641 << 100.*coupons[i+1] << " | "
642 // piecewise bootstrap
643 << setw(6) << fixed << setprecision(3)
644 << 100.*parRate(*ts00,keyDates,dc) << " | "
645 // exponential splines
646 << setw(6) << fixed << setprecision(3)
647 << 100.*parRate(*ts11,keyDates,dc) << " | "
648 // simple polynomial
649 << setw(6) << fixed << setprecision(3)
650 << 100.*parRate(*ts22,keyDates,dc) << " | "
651 // Nelson-Siegel
652 << setw(6) << fixed << setprecision(3)
653 << 100.*parRate(*ts33,keyDates,dc) << " | "
654 // cubic bsplines
655 << setw(6) << fixed << setprecision(3)
656 << 100.*parRate(*ts44,keyDates,dc) << " | "
657 // Svensson
658 << setw(6) << fixed << setprecision(3)
659 << 100.*parRate(*ts55,keyDates,dc) << " | "
660 // Nelson-Siegel Spread
661 << setw(6) << fixed << setprecision(3)
662 << 100.*parRate(*ts66,keyDates,dc) << " | "
663 // exponential spline, fixed kappa
664 << setw(6) << fixed << setprecision(3)
665 << 100. *parRate(*ts77, keyDates, dc) << endl;
666 }
667
668 return 0;
669
670 } catch (std::exception& e) {
671 cerr << e.what() << endl;
672 return 1;
673 } catch (...) {
674 cerr << "unknown error" << endl;
675 return 1;
676 }
677
678 }