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) &amp;&amp; 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	
40	using namespace std;
41	using namespace QuantLib;
42	
43	ext::shared_ptr<YieldTermStructure>
44	    flatRate(const Date&amp; today,
45	             const ext::shared_ptr<Quote>&amp; forward,
46	             const DayCounter&amp; dc,
47	             const Compounding&amp; compounding,
48	             const Frequency&amp; frequency) {
49	    return ext::make_shared<FlatForward>(today,
50	                                         Handle<Quote>(forward),
51	                                         dc,
52	                                         compounding,
53	                                         frequency);
54	}
55	
56	
57	ext::shared_ptr<YieldTermStructure>
58	    flatRate(const Date&amp; today,
59	             Rate forward,
60	             const DayCounter&amp; dc,
61	             const Compounding &amp;compounding,
62	             const Frequency &amp;frequency) {
63	    return flatRate(today,
64	            ext::make_shared<SimpleQuote>(forward),
65	            dc,
66	            compounding,
67	            frequency);
68	}
69	
70	
71	int 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	                                                          bbIR.rate(),
104	                                                          bbIR.dayCounter(),
105	                                                          bbIR.compounding(),
106	                                                          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	                ext::make_shared<Callability>(
121	                                    myPrice,
122	                                    Callability::Call,
123	                                    callDate ));
124	            callDate = nullCalendar.advance(callDate, 3, 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>(termStructure,reversionParameter,sigma);
165	
166	        auto engine0 = ext::make_shared<TreeCallableFixedRateBondEngine>(hw0,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(bondDayCounter,
184	                                          Compounded,
185	                                          frequency,
186	                                          accuracy,
187	                                          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>(termStructure,reversionParameter,sigma);
200	
201	        auto engine1 = ext::make_shared<TreeCallableFixedRateBondEngine>(hw1,gridIntervals);
202	
203	        callableBond.setPricingEngine(engine1);
204	
205	        cout << "QuantLib price/yld (%)  ";
206	        cout << callableBond.cleanPrice() << " / "
207	             << 100.* callableBond.yield(bondDayCounter,
208	                                         Compounded,
209	                                         frequency,
210	                                         accuracy,
211	                                         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>(termStructure, reversionParameter, sigma);
224	
225	        auto engine2 = ext::make_shared<TreeCallableFixedRateBondEngine>(hw2,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(bondDayCounter,
236	                                          Compounded,
237	                                          frequency,
238	                                          accuracy,
239	                                          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>(termStructure, reversionParameter, sigma);
252	
253	        auto engine3 = ext::make_shared<TreeCallableFixedRateBondEngine>(hw3,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(bondDayCounter,
264	                                          Compounded,
265	                                          frequency,
266	                                          accuracy,
267	                                          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>(termStructure, reversionParameter, sigma);
280	
281	        auto engine4 = ext::make_shared<TreeCallableFixedRateBondEngine>(hw4,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(bondDayCounter,
292	                                         Compounded,
293	                                         frequency,
294	                                         accuracy,
295	                                         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&amp; 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	}