1 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3 /*!
4 Copyright (C) 2008 Florent Grenier
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 /* This example shows how to set up a term structure and then price
21 some simple bonds. The last part is dedicated to peripherical
22 computations such as "Yield to Price" or "Price to Yield"
23 */
24
25 #include <ql/qldefines.hpp>
26 #if !defined(BOOST_ALL_NO_LIB) && defined(BOOST_MSVC)
27 # include <ql/auto_link.hpp>
28 #endif
29 #include <ql/instruments/bonds/zerocouponbond.hpp>
30 #include <ql/instruments/bonds/floatingratebond.hpp>
31 #include <ql/pricingengines/bond/discountingbondengine.hpp>
32 #include <ql/cashflows/couponpricer.hpp>
33 #include <ql/termstructures/yield/piecewiseyieldcurve.hpp>
34 #include <ql/termstructures/yield/bondhelpers.hpp>
35 #include <ql/termstructures/volatility/optionlet/constantoptionletvol.hpp>
36 #include <ql/indexes/ibor/euribor.hpp>
37 #include <ql/indexes/ibor/usdlibor.hpp>
38 #include <ql/time/calendars/target.hpp>
39 #include <ql/time/calendars/unitedstates.hpp>
40 #include <ql/time/daycounters/actualactual.hpp>
41 #include <ql/time/daycounters/actual360.hpp>
42 #include <ql/time/daycounters/thirty360.hpp>
43
44 #include <iostream>
45 #include <iomanip>
46
47 using namespace QuantLib;
48
49 int main(int, char* []) {
50
51 try {
52
53 std::cout << std::endl;
54
55 /*********************
56 *** MARKET DATA ***
57 *********************/
58
59 Calendar calendar = TARGET();
60
61 Date settlementDate(18, September, 2008);
62 // must be a business day
63 settlementDate = calendar.adjust(settlementDate);
64
65 Integer fixingDays = 3;
66 Natural settlementDays = 3;
67
68 Date todaysDate = calendar.advance(settlementDate, -fixingDays, Days);
69 // nothing to do with Date::todaysDate
70 Settings::instance().evaluationDate() = todaysDate;
71
72 std::cout << "Today: " << todaysDate.weekday()
73 << ", " << todaysDate << std::endl;
74
75 std::cout << "Settlement date: " << settlementDate.weekday()
76 << ", " << settlementDate << std::endl;
77
78
79 // Building of the bonds discounting yield curve
80
81 /*********************
82 *** RATE HELPERS ***
83 *********************/
84
85 // RateHelpers are built from the above quotes together with
86 // other instrument dependant infos. Quotes are passed in
87 // relinkable handles which could be relinked to some other
88 // data source later.
89
90 // Common data
91
92 // ZC rates for the short end
93 Rate zc3mQuote=0.0096;
94 Rate zc6mQuote=0.0145;
95 Rate zc1yQuote=0.0194;
96
97 auto zc3mRate = ext::make_shared<SimpleQuote>(zc3mQuote);
98 auto zc6mRate = ext::make_shared<SimpleQuote>(zc6mQuote);
99 auto zc1yRate = ext::make_shared<SimpleQuote>(zc1yQuote);
100
101 DayCounter zcBondsDayCounter = Actual365Fixed();
102
103 auto zc3m = ext::make_shared<DepositRateHelper>(
104 Handle<Quote>(zc3mRate),
105 3*Months, fixingDays,
106 calendar, ModifiedFollowing,
107 true, zcBondsDayCounter);
108 auto zc6m = ext::make_shared<DepositRateHelper>(
109 Handle<Quote>(zc6mRate),
110 6*Months, fixingDays,
111 calendar, ModifiedFollowing,
112 true, zcBondsDayCounter);
113 auto zc1y = ext::make_shared<DepositRateHelper>(
114 Handle<Quote>(zc1yRate),
115 1*Years, fixingDays,
116 calendar, ModifiedFollowing,
117 true, zcBondsDayCounter);
118
119 // setup bonds
120 Real redemption = 100.0;
121
122 const Size numberOfBonds = 5;
123
124 Date issueDates[] = {
125 Date (15, March, 2005),
126 Date (15, June, 2005),
127 Date (30, June, 2006),
128 Date (15, November, 2002),
129 Date (15, May, 1987)
130 };
131
132 Date maturities[] = {
133 Date (31, August, 2010),
134 Date (31, August, 2011),
135 Date (31, August, 2013),
136 Date (15, August, 2018),
137 Date (15, May, 2038)
138 };
139
140 Real couponRates[] = {
141 0.02375,
142 0.04625,
143 0.03125,
144 0.04000,
145 0.045
146 };
147
148 Real marketQuotes[] = {
149 100.390625,
150 106.21875,
151 100.59375,
152 101.6875,
153 102.140625
154 };
155
156 std::vector<ext::shared_ptr<SimpleQuote>> quote;
157 for (Real marketQuote : marketQuotes) {
158 quote.push_back(ext::make_shared<SimpleQuote>(marketQuote));
159 }
160
161 RelinkableHandle<Quote> quoteHandle[numberOfBonds];
162 for (Size i=0; i<numberOfBonds; i++) {
163 quoteHandle[i].linkTo(quote[i]);
164 }
165
166 // Definition of the rate helpers
167 std::vector<ext::shared_ptr<BondHelper>> bondsHelpers;
168
169 for (Size i=0; i<numberOfBonds; i++) {
170
171 Schedule schedule(issueDates[i], maturities[i], Period(Semiannual), UnitedStates(UnitedStates::GovernmentBond),
172 Unadjusted, Unadjusted, DateGeneration::Backward, false);
173
174 auto bondHelper = ext::make_shared<FixedRateBondHelper>(
175 quoteHandle[i],
176 settlementDays,
177 100.0,
178 schedule,
179 std::vector<Rate>(1,couponRates[i]),
180 ActualActual(ActualActual::Bond),
181 Unadjusted,
182 redemption,
183 issueDates[i]);
184
185 // the above could also be done by creating a
186 // FixedRateBond instance and writing:
187 //
188 // auto bondHelper = ext::make_shared<BondHelper>(quoteHandle[i], bond);
189 //
190 // This would also work for bonds that still don't have a
191 // specialized helper, such as floating-rate bonds.
192
193
194 bondsHelpers.push_back(bondHelper);
195 }
196
197 /*********************
198 ** CURVE BUILDING **
199 *********************/
200
201 // Any DayCounter would be fine.
202 // ActualActual::ISDA ensures that 30 years is 30.0
203 DayCounter termStructureDayCounter =
204 ActualActual(ActualActual::ISDA);
205
206 // A depo-bond curve
207 std::vector<ext::shared_ptr<RateHelper>> bondInstruments;
208
209 // Adding the ZC bonds to the curve for the short end
210 bondInstruments.push_back(zc3m);
211 bondInstruments.push_back(zc6m);
212 bondInstruments.push_back(zc1y);
213
214 // Adding the Fixed rate bonds to the curve for the long end
215 for (Size i=0; i<numberOfBonds; i++) {
216 bondInstruments.push_back(bondsHelpers[i]);
217 }
218
219 auto bondDiscountingTermStructure = ext::make_shared<PiecewiseYieldCurve<Discount,LogLinear>>(
220 settlementDate, bondInstruments, termStructureDayCounter);
221
222 // Building of the Libor forecasting curve
223 // deposits
224 Rate d1wQuote=0.043375;
225 Rate d1mQuote=0.031875;
226 Rate d3mQuote=0.0320375;
227 Rate d6mQuote=0.03385;
228 Rate d9mQuote=0.0338125;
229 Rate d1yQuote=0.0335125;
230 // swaps
231 Rate s2yQuote=0.0295;
232 Rate s3yQuote=0.0323;
233 Rate s5yQuote=0.0359;
234 Rate s10yQuote=0.0412;
235 Rate s15yQuote=0.0433;
236
237
238 /********************
239 *** QUOTES ***
240 ********************/
241
242 // SimpleQuote stores a value which can be manually changed;
243 // other Quote subclasses could read the value from a database
244 // or some kind of data feed.
245
246 // deposits
247 auto d1wRate = ext::make_shared<SimpleQuote>(d1wQuote);
248 auto d1mRate = ext::make_shared<SimpleQuote>(d1mQuote);
249 auto d3mRate = ext::make_shared<SimpleQuote>(d3mQuote);
250 auto d6mRate = ext::make_shared<SimpleQuote>(d6mQuote);
251 auto d9mRate = ext::make_shared<SimpleQuote>(d9mQuote);
252 auto d1yRate = ext::make_shared<SimpleQuote>(d1yQuote);
253 // swaps
254 auto s2yRate = ext::make_shared<SimpleQuote>(s2yQuote);
255 auto s3yRate = ext::make_shared<SimpleQuote>(s3yQuote);
256 auto s5yRate = ext::make_shared<SimpleQuote>(s5yQuote);
257 auto s10yRate = ext::make_shared<SimpleQuote>(s10yQuote);
258 auto s15yRate = ext::make_shared<SimpleQuote>(s15yQuote);
259
260 /*********************
261 *** RATE HELPERS ***
262 *********************/
263
264 // RateHelpers are built from the above quotes together with
265 // other instrument dependant infos. Quotes are passed in
266 // relinkable handles which could be relinked to some other
267 // data source later.
268
269 // deposits
270 DayCounter depositDayCounter = Actual360();
271
272 auto d1w = ext::make_shared<DepositRateHelper>(
273 Handle<Quote>(d1wRate),
274 1*Weeks, fixingDays,
275 calendar, ModifiedFollowing,
276 true, depositDayCounter);
277 auto d1m = ext::make_shared<DepositRateHelper>(
278 Handle<Quote>(d1mRate),
279 1*Months, fixingDays,
280 calendar, ModifiedFollowing,
281 true, depositDayCounter);
282 auto d3m = ext::make_shared<DepositRateHelper>(
283 Handle<Quote>(d3mRate),
284 3*Months, fixingDays,
285 calendar, ModifiedFollowing,
286 true, depositDayCounter);
287 auto d6m = ext::make_shared<DepositRateHelper>(
288 Handle<Quote>(d6mRate),
289 6*Months, fixingDays,
290 calendar, ModifiedFollowing,
291 true, depositDayCounter);
292 auto d9m = ext::make_shared<DepositRateHelper>(
293 Handle<Quote>(d9mRate),
294 9*Months, fixingDays,
295 calendar, ModifiedFollowing,
296 true, depositDayCounter);
297 auto d1y = ext::make_shared<DepositRateHelper>(
298 Handle<Quote>(d1yRate),
299 1*Years, fixingDays,
300 calendar, ModifiedFollowing,
301 true, depositDayCounter);
302
303 // setup swaps
304 auto swFixedLegFrequency = Annual;
305 auto swFixedLegConvention = Unadjusted;
306 auto swFixedLegDayCounter = Thirty360(Thirty360::European);
307 auto swFloatingLegIndex = ext::make_shared<Euribor6M>();
308
309 const Period forwardStart(1*Days);
310
311 auto s2y = ext::make_shared<SwapRateHelper>(
312 Handle<Quote>(s2yRate), 2*Years,
313 calendar, swFixedLegFrequency,
314 swFixedLegConvention, swFixedLegDayCounter,
315 swFloatingLegIndex, Handle<Quote>(), forwardStart);
316 auto s3y = ext::make_shared<SwapRateHelper>(
317 Handle<Quote>(s3yRate), 3*Years,
318 calendar, swFixedLegFrequency,
319 swFixedLegConvention, swFixedLegDayCounter,
320 swFloatingLegIndex, Handle<Quote>(), forwardStart);
321 auto s5y = ext::make_shared<SwapRateHelper>(
322 Handle<Quote>(s5yRate), 5*Years,
323 calendar, swFixedLegFrequency,
324 swFixedLegConvention, swFixedLegDayCounter,
325 swFloatingLegIndex, Handle<Quote>(), forwardStart);
326 auto s10y = ext::make_shared<SwapRateHelper>(
327 Handle<Quote>(s10yRate), 10*Years,
328 calendar, swFixedLegFrequency,
329 swFixedLegConvention, swFixedLegDayCounter,
330 swFloatingLegIndex, Handle<Quote>(), forwardStart);
331 auto s15y = ext::make_shared<SwapRateHelper>(
332 Handle<Quote>(s15yRate), 15*Years,
333 calendar, swFixedLegFrequency,
334 swFixedLegConvention, swFixedLegDayCounter,
335 swFloatingLegIndex, Handle<Quote>(), forwardStart);
336
337
338 /*********************
339 ** CURVE BUILDING **
340 *********************/
341
342 // Any DayCounter would be fine.
343 // ActualActual::ISDA ensures that 30 years is 30.0
344
345 // A depo-swap curve
346 std::vector<ext::shared_ptr<RateHelper>> depoSwapInstruments;
347 depoSwapInstruments.push_back(d1w);
348 depoSwapInstruments.push_back(d1m);
349 depoSwapInstruments.push_back(d3m);
350 depoSwapInstruments.push_back(d6m);
351 depoSwapInstruments.push_back(d9m);
352 depoSwapInstruments.push_back(d1y);
353 depoSwapInstruments.push_back(s2y);
354 depoSwapInstruments.push_back(s3y);
355 depoSwapInstruments.push_back(s5y);
356 depoSwapInstruments.push_back(s10y);
357 depoSwapInstruments.push_back(s15y);
358 auto depoSwapTermStructure = ext::make_shared<PiecewiseYieldCurve<Discount, LogLinear>>(
359 settlementDate, depoSwapInstruments,
360 termStructureDayCounter);
361
362 // Term structures that will be used for pricing:
363 // the one used for discounting cash flows
364 RelinkableHandle<YieldTermStructure> discountingTermStructure;
365 // the one used for forward rate forecasting
366 RelinkableHandle<YieldTermStructure> forecastingTermStructure;
367
368 /*********************
369 * BONDS TO BE PRICED *
370 **********************/
371
372 // Common data
373 Real faceAmount = 100;
374
375 // Pricing engine
376 auto bondEngine = ext::make_shared<DiscountingBondEngine>(discountingTermStructure);
377
378 // Zero coupon bond
379 ZeroCouponBond zeroCouponBond(
380 settlementDays,
381 UnitedStates(UnitedStates::GovernmentBond),
382 faceAmount,
383 Date(15,August,2013),
384 Following,
385 Real(116.92),
386 Date(15,August,2003));
387
388 zeroCouponBond.setPricingEngine(bondEngine);
389
390 // Fixed 4.5% US Treasury Note
391 Schedule fixedBondSchedule(Date(15, May, 2007),
392 Date(15,May,2017), Period(Semiannual),
393 UnitedStates(UnitedStates::GovernmentBond),
394 Unadjusted, Unadjusted, DateGeneration::Backward, false);
395
396 FixedRateBond fixedRateBond(
397 settlementDays,
398 faceAmount,
399 fixedBondSchedule,
400 std::vector<Rate>(1, 0.045),
401 ActualActual(ActualActual::Bond),
402 ModifiedFollowing,
403 100.0, Date(15, May, 2007));
404
405 fixedRateBond.setPricingEngine(bondEngine);
406
407 // Floating rate bond (3M USD Libor + 0.1%)
408 // Should and will be priced on another curve later...
409
410 RelinkableHandle<YieldTermStructure> liborTermStructure;
411 const auto libor3m = ext::make_shared<USDLibor>(Period(3, Months), liborTermStructure);
412 libor3m->addFixing(Date(17, July, 2008),0.0278625);
413
414 Schedule floatingBondSchedule(Date(21, October, 2005),
415 Date(21, October, 2010), Period(Quarterly),
416 UnitedStates(UnitedStates::NYSE),
417 Unadjusted, Unadjusted, DateGeneration::Backward, true);
418
419 FloatingRateBond floatingRateBond(
420 settlementDays,
421 faceAmount,
422 floatingBondSchedule,
423 libor3m,
424 Actual360(),
425 ModifiedFollowing,
426 Natural(2),
427 // Gearings
428 std::vector<Real>(1, 1.0),
429 // Spreads
430 std::vector<Rate>(1, 0.001),
431 // Caps
432 std::vector<Rate>(),
433 // Floors
434 std::vector<Rate>(),
435 // Fixing in arrears
436 true,
437 Real(100.0),
438 Date(21, October, 2005));
439
440 floatingRateBond.setPricingEngine(bondEngine);
441
442 // Coupon pricers
443 auto pricer = ext::make_shared<BlackIborCouponPricer>();
444
445 // optionLet volatilities
446 Volatility volatility = 0.0;
447 Handle<OptionletVolatilityStructure> vol;
448 vol = Handle<OptionletVolatilityStructure>(
449 ext::make_shared<ConstantOptionletVolatility>(
450 settlementDays,
451 calendar,
452 ModifiedFollowing,
453 volatility,
454 Actual365Fixed()));
455
456 pricer->setCapletVolatility(vol);
457 setCouponPricer(floatingRateBond.cashflows(),pricer);
458
459 // Yield curve bootstrapping
460 forecastingTermStructure.linkTo(depoSwapTermStructure);
461 discountingTermStructure.linkTo(bondDiscountingTermStructure);
462
463 // We are using the depo & swap curve to estimate the future Libor rates
464 liborTermStructure.linkTo(depoSwapTermStructure);
465
466 /***************
467 * BOND PRICING *
468 ****************/
469
470 std::cout << std::endl;
471
472 // write column headings
473 Size widths[] = { 18, 10, 10, 10 };
474
475 std::cout << std::setw(widths[0]) << " "
476 << std::setw(widths[1]) << "ZC"
477 << std::setw(widths[2]) << "Fixed"
478 << std::setw(widths[3]) << "Floating"
479 << std::endl;
480
481 Size width = widths[0] + widths[1] + widths[2] + widths[3];
482 std::string rule(width, '-');
483
484 std::cout << rule << std::endl;
485
486 std::cout << std::fixed;
487 std::cout << std::setprecision(2);
488
489 std::cout << std::setw(widths[0]) << "Net present value"
490 << std::setw(widths[1]) << zeroCouponBond.NPV()
491 << std::setw(widths[2]) << fixedRateBond.NPV()
492 << std::setw(widths[3]) << floatingRateBond.NPV()
493 << std::endl;
494
495 std::cout << std::setw(widths[0]) << "Clean price"
496 << std::setw(widths[1]) << zeroCouponBond.cleanPrice()
497 << std::setw(widths[2]) << fixedRateBond.cleanPrice()
498 << std::setw(widths[3]) << floatingRateBond.cleanPrice()
499 << std::endl;
500
501 std::cout << std::setw(widths[0]) << "Dirty price"
502 << std::setw(widths[1]) << zeroCouponBond.dirtyPrice()
503 << std::setw(widths[2]) << fixedRateBond.dirtyPrice()
504 << std::setw(widths[3]) << floatingRateBond.dirtyPrice()
505 << std::endl;
506
507 std::cout << std::setw(widths[0]) << "Accrued coupon"
508 << std::setw(widths[1]) << zeroCouponBond.accruedAmount()
509 << std::setw(widths[2]) << fixedRateBond.accruedAmount()
510 << std::setw(widths[3]) << floatingRateBond.accruedAmount()
511 << std::endl;
512
513 std::cout << std::setw(widths[0]) << "Previous coupon"
514 << std::setw(widths[1]) << "N/A" // zeroCouponBond
515 << std::setw(widths[2]) << io::rate(fixedRateBond.previousCouponRate())
516 << std::setw(widths[3]) << io::rate(floatingRateBond.previousCouponRate())
517 << std::endl;
518
519 std::cout << std::setw(widths[0]) << "Next coupon"
520 << std::setw(widths[1]) << "N/A" // zeroCouponBond
521 << std::setw(widths[2]) << io::rate(fixedRateBond.nextCouponRate())
522 << std::setw(widths[3]) << io::rate(floatingRateBond.nextCouponRate())
523 << std::endl;
524
525 std::cout << std::setw(widths[0]) << "Yield"
526 << std::setw(widths[1])
527 << io::rate(zeroCouponBond.yield(Actual360(),Compounded,Annual))
528 << std::setw(widths[2])
529 << io::rate(fixedRateBond.yield(Actual360(),Compounded,Annual))
530 << std::setw(widths[3])
531 << io::rate(floatingRateBond.yield(Actual360(),Compounded,Annual))
532 << std::endl;
533
534 std::cout << std::endl;
535
536 // Other computations
537 std::cout << "Sample indirect computations (for the floating rate bond): " << std::endl;
538 std::cout << rule << std::endl;
539
540 std::cout << "Yield to Clean Price: "
541 << floatingRateBond.cleanPrice(floatingRateBond.yield(Actual360(),Compounded,Annual),Actual360(),Compounded,Annual,settlementDate) << std::endl;
542
543 std::cout << "Clean Price to Yield: "
544 << io::rate(floatingRateBond.yield(floatingRateBond.cleanPrice(),Actual360(),Compounded,Annual,settlementDate)) << std::endl;
545
546 /* "Yield to Price"
547 "Price to Yield" */
548
549 return 0;
550
551 } catch (std::exception& e) {
552 std::cerr << e.what() << std::endl;
553 return 1;
554 } catch (...) {
555 std::cerr << "unknown error" << std::endl;
556 return 1;
557 }
558 }