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