[go: up one dir, main page]

1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*!
4 Copyright (C) 2008 Allen Kuo
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 sets up a callable fixed rate bond with a Hull White pricing
21 engine and compares to Bloomberg's Hull White price/yield calculations.
22*/
23
24#include <ql/qldefines.hpp>
25#if !defined(BOOST_ALL_NO_LIB) && defined(BOOST_MSVC)
26# include <ql/auto_link.hpp>
27#endif
28#include <ql/experimental/callablebonds/callablebond.hpp>
29#include <ql/experimental/callablebonds/treecallablebondengine.hpp>
30#include <ql/models/shortrate/onefactormodels/hullwhite.hpp>
31#include <ql/termstructures/yield/flatforward.hpp>
32#include <ql/time/calendars/unitedstates.hpp>
33#include <ql/time/daycounters/actualactual.hpp>
34
35#include <vector>
36#include <cmath>
37#include <iomanip>
38#include <iostream>
39
40using namespace std;
41using namespace QuantLib;
42
43ext::shared_ptr<YieldTermStructure>
44 flatRate(const Date& today,
45 const ext::shared_ptr<Quote>& forward,
46 const DayCounter& dc,
47 const Compounding& compounding,
48 const Frequency& frequency) {
49 return ext::make_shared<FlatForward>(args: today,
50 args: Handle<Quote>(forward),
51 args: dc,
52 args: compounding,
53 args: frequency);
54}
55
56
57ext::shared_ptr<YieldTermStructure>
58 flatRate(const Date& today,
59 Rate forward,
60 const DayCounter& dc,
61 const Compounding &compounding,
62 const Frequency &frequency) {
63 return flatRate(today,
64 forward: ext::make_shared<SimpleQuote>(args&: forward),
65 dc,
66 compounding,
67 frequency);
68}
69
70
71int main(int, char* [])
72{
73 try {
74
75
76 Date today = Date(16,October,2007);
77 Settings::instance().evaluationDate() = today;
78
79 cout << endl;
80 cout << "Pricing a callable fixed rate bond using" << endl;
81 cout << "Hull White model w/ reversion parameter = 0.03" << endl;
82 cout << "BAC4.65 09/15/12 ISIN: US06060WBJ36" << endl;
83 cout << "roughly five year tenor, ";
84 cout << "quarterly coupon and call dates" << endl;
85 cout << "reference date is : " << today << endl << endl;
86
87 /* Bloomberg OAS1: "N" model (Hull White)
88 varying volatility parameter
89
90 The curve entered into Bloomberg OAS1 is a flat curve,
91 at constant yield = 5.5%, semiannual compounding.
92 Assume here OAS1 curve uses an ACT/ACT day counter,
93 as documented in PFC1 as a "default" in the latter case.
94 */
95
96 // set up a flat curve corresponding to Bloomberg flat curve
97
98 Rate bbCurveRate = 0.055;
99 DayCounter bbDayCounter = ActualActual(ActualActual::Bond);
100 InterestRate bbIR(bbCurveRate,bbDayCounter,Compounded,Semiannual);
101
102 Handle<YieldTermStructure> termStructure(flatRate(today,
103 forward: bbIR.rate(),
104 dc: bbIR.dayCounter(),
105 compounding: bbIR.compounding(),
106 frequency: bbIR.frequency()));
107
108 // set up the call schedule
109
110 CallabilitySchedule callSchedule;
111 Real callPrice = 100.;
112 Size numberOfCallDates = 24;
113 Date callDate = Date(15,September,2006);
114
115 for (Size i=0; i< numberOfCallDates; i++) {
116 Calendar nullCalendar = NullCalendar();
117
118 Bond::Price myPrice(callPrice, Bond::Price::Clean);
119 callSchedule.push_back(
120 x: ext::make_shared<Callability>(
121 args&: myPrice,
122 args: Callability::Call,
123 args&: callDate ));
124 callDate = nullCalendar.advance(callDate, n: 3, unit: Months);
125 }
126
127
128 // set up the callable bond
129
130 Date dated = Date(16,September,2004);
131 Date issue = dated;
132 Date maturity = Date(15,September,2012);
133 Natural settlementDays = 3; // Bloomberg OAS1 settle is Oct 19, 2007
134 Calendar bondCalendar = UnitedStates(UnitedStates::GovernmentBond);
135 Real coupon = .0465;
136 Frequency frequency = Quarterly;
137 Real redemption = 100.0;
138 Real faceAmount = 100.0;
139
140 /* The 30/360 day counter Bloomberg uses for this bond cannot
141 reproduce the US Bond/ISMA (constant) cashflows used in PFC1.
142 Therefore use ActAct(Bond)
143 */
144 DayCounter bondDayCounter = ActualActual(ActualActual::Bond);
145
146 // PFC1 shows no indication dates are being adjusted
147 // for weekends/holidays for vanilla bonds
148 BusinessDayConvention accrualConvention = Unadjusted;
149 BusinessDayConvention paymentConvention = Unadjusted;
150
151 Schedule sch(dated, maturity, Period(frequency), bondCalendar,
152 accrualConvention, accrualConvention,
153 DateGeneration::Backward, false);
154
155 Size maxIterations = 1000;
156 Real accuracy = 1e-8;
157 Integer gridIntervals = 40;
158 Real reversionParameter = .03;
159
160 // output price/yield results for varying volatility parameter
161
162 Real sigma = QL_EPSILON; // core dumps if zero on Cygwin
163
164 auto hw0 = ext::make_shared<HullWhite>(args&: termStructure,args&: reversionParameter,args&: sigma);
165
166 auto engine0 = ext::make_shared<TreeCallableFixedRateBondEngine>(args&: hw0,args&: gridIntervals);
167
168 CallableFixedRateBond callableBond(settlementDays, faceAmount, sch,
169 vector<Rate>(1, coupon),
170 bondDayCounter, paymentConvention,
171 redemption, issue, callSchedule);
172 callableBond.setPricingEngine(engine0);
173
174 cout << setprecision(2)
175 << showpoint
176 << fixed
177 << "sigma/vol (%) = "
178 << 100.*sigma
179 << endl;
180
181 cout << "QuantLib price/yld (%) ";
182 cout << callableBond.cleanPrice() << " / "
183 << 100. * callableBond.yield(dc: bondDayCounter,
184 comp: Compounded,
185 freq: frequency,
186 accuracy,
187 maxEvaluations: maxIterations)
188 << endl;
189
190 cout << "Bloomberg price/yld (%) ";
191 cout << "96.50 / 5.47"
192 << endl
193 << endl;
194
195 sigma = .01;
196
197 cout << "sigma/vol (%) = " << 100.*sigma << endl;
198
199 auto hw1 = ext::make_shared<HullWhite>(args&: termStructure,args&: reversionParameter,args&: sigma);
200
201 auto engine1 = ext::make_shared<TreeCallableFixedRateBondEngine>(args&: hw1,args&: gridIntervals);
202
203 callableBond.setPricingEngine(engine1);
204
205 cout << "QuantLib price/yld (%) ";
206 cout << callableBond.cleanPrice() << " / "
207 << 100.* callableBond.yield(dc: bondDayCounter,
208 comp: Compounded,
209 freq: frequency,
210 accuracy,
211 maxEvaluations: maxIterations)
212 << endl;
213
214 cout << "Bloomberg price/yld (%) ";
215 cout << "95.68 / 5.66"
216 << endl
217 << endl;
218
219 ////////////////////
220
221 sigma = .03;
222
223 auto hw2 = ext::make_shared<HullWhite>(args&: termStructure, args&: reversionParameter, args&: sigma);
224
225 auto engine2 = ext::make_shared<TreeCallableFixedRateBondEngine>(args&: hw2,args&: gridIntervals);
226
227 callableBond.setPricingEngine(engine2);
228
229 cout << "sigma/vol (%) = "
230 << 100.*sigma
231 << endl;
232
233 cout << "QuantLib price/yld (%) ";
234 cout << callableBond.cleanPrice() << " / "
235 << 100. * callableBond.yield(dc: bondDayCounter,
236 comp: Compounded,
237 freq: frequency,
238 accuracy,
239 maxEvaluations: maxIterations)
240 << endl;
241
242 cout << "Bloomberg price/yld (%) ";
243 cout << "92.34 / 6.49"
244 << endl
245 << endl;
246
247 ////////////////////////////
248
249 sigma = .06;
250
251 auto hw3 = ext::make_shared<HullWhite>(args&: termStructure, args&: reversionParameter, args&: sigma);
252
253 auto engine3 = ext::make_shared<TreeCallableFixedRateBondEngine>(args&: hw3,args&: gridIntervals);
254
255 callableBond.setPricingEngine(engine3);
256
257 cout << "sigma/vol (%) = "
258 << 100.*sigma
259 << endl;
260
261 cout << "QuantLib price/yld (%) ";
262 cout << callableBond.cleanPrice() << " / "
263 << 100. * callableBond.yield(dc: bondDayCounter,
264 comp: Compounded,
265 freq: frequency,
266 accuracy,
267 maxEvaluations: maxIterations)
268 << endl;
269
270 cout << "Bloomberg price/yld (%) ";
271 cout << "87.16 / 7.83"
272 << endl
273 << endl;
274
275 /////////////////////////
276
277 sigma = .12;
278
279 auto hw4 = ext::make_shared<HullWhite>(args&: termStructure, args&: reversionParameter, args&: sigma);
280
281 auto engine4 = ext::make_shared<TreeCallableFixedRateBondEngine>(args&: hw4,args&: gridIntervals);
282
283 callableBond.setPricingEngine(engine4);
284
285 cout << "sigma/vol (%) = "
286 << 100.*sigma
287 << endl;
288
289 cout << "QuantLib price/yld (%) ";
290 cout << callableBond.cleanPrice() << " / "
291 << 100.* callableBond.yield(dc: bondDayCounter,
292 comp: Compounded,
293 freq: frequency,
294 accuracy,
295 maxEvaluations: maxIterations)
296 << endl;
297
298 cout << "Bloomberg price/yld (%) ";
299 cout << "77.31 / 10.65"
300 << endl
301 << endl;
302
303 return 0;
304
305 } catch (std::exception& e) {
306 std::cerr << e.what() << std::endl;
307 return 1;
308 } catch (...) {
309 std::cerr << "unknown error" << std::endl;
310 return 1;
311 }
312}
313
314

source code of quantlib/Examples/CallableBonds/CallableBonds.cpp