1	/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2	
3	/*!
4	 Copyright (C) 2002, 2003 Sadruddin Rejeb
5	 Copyright (C) 2004 Ferdinando Ametrano
6	 Copyright (C) 2005, 2006, 2007 StatPro Italia srl
7	
8	 This file is part of QuantLib, a free-software/open-source library
9	 for financial quantitative analysts and developers - http://quantlib.org/
10	
11	 QuantLib is free software: you can redistribute it and/or modify it
12	 under the terms of the QuantLib license.  You should have received a
13	 copy of the license along with this program; if not, please email
14	 <quantlib-dev@lists.sf.net>. The license is also available online at
15	 <http://quantlib.org/license.shtml>.
16	
17	 This program is distributed in the hope that it will be useful, but WITHOUT
18	 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19	 FOR A PARTICULAR PURPOSE.  See the license for more details.
20	*/
21	
22	#include <ql/qldefines.hpp>
23	#if !defined(BOOST_ALL_NO_LIB) && defined(BOOST_MSVC)
24	#  include <ql/auto_link.hpp>
25	#endif
26	#include <ql/instruments/swaption.hpp>
27	#include <ql/pricingengines/swap/discountingswapengine.hpp>
28	#include <ql/pricingengines/swaption/treeswaptionengine.hpp>
29	#include <ql/pricingengines/swaption/jamshidianswaptionengine.hpp>
30	#include <ql/pricingengines/swaption/g2swaptionengine.hpp>
31	#include <ql/pricingengines/swaption/fdhullwhiteswaptionengine.hpp>
32	#include <ql/pricingengines/swaption/fdg2swaptionengine.hpp>
33	#include <ql/models/shortrate/calibrationhelpers/swaptionhelper.hpp>
34	#include <ql/models/shortrate/onefactormodels/blackkarasinski.hpp>
35	#include <ql/math/optimization/levenbergmarquardt.hpp>
36	#include <ql/indexes/ibor/euribor.hpp>
37	#include <ql/cashflows/coupon.hpp>
38	#include <ql/quotes/simplequote.hpp>
39	#include <ql/termstructures/yield/flatforward.hpp>
40	#include <ql/time/calendars/target.hpp>
41	#include <ql/time/daycounters/thirty360.hpp>
42	#include <ql/utilities/dataformatters.hpp>
43	
44	#include <iostream>
45	#include <iomanip>
46	
47	using namespace QuantLib;
48	
49	//Number of swaptions to be calibrated to...
50	
51	Size numRows = 5;
52	Size numCols = 5;
53	
54	Integer swapLengths[] = {
55	      1,     2,     3,     4,     5};
56	Volatility swaptionVols[] = {
57	  0.1490, 0.1340, 0.1228, 0.1189, 0.1148,
58	  0.1290, 0.1201, 0.1146, 0.1108, 0.1040,
59	  0.1149, 0.1112, 0.1070, 0.1010, 0.0957,
60	  0.1047, 0.1021, 0.0980, 0.0951, 0.1270,
61	  0.1000, 0.0950, 0.0900, 0.1230, 0.1160};
62	
63	void calibrateModel(
64	          const ext::shared_ptr<ShortRateModel>& model,
65	          const std::vector<ext::shared_ptr<BlackCalibrationHelper>>& swaptions) {
66	
67	    std::vector<ext::shared_ptr<CalibrationHelper>> helpers(swaptions.begin(), swaptions.end());
68	    LevenbergMarquardt om;
69	    model->calibrate(helpers, om,
70	                     EndCriteria(400, 100, 1.0e-8, 1.0e-8, 1.0e-8));
71	
72	    // Output the implied Black volatilities
73	    for (Size i=0; i<numRows; i++) {
74	        Size j = numCols - i -1; // 1x5, 2x4, 3x3, 4x2, 5x1
75	        Size k = i*numCols + j;
76	        Real npv = swaptions[i]->modelValue();
77	        Volatility implied = swaptions[i]->impliedVolatility(npv, 1e-4,
78	                                                             1000, 0.05, 0.50);
79	        Volatility diff = implied - swaptionVols[k];
80	
81	        std::cout << i+1 << "x" << swapLengths[j]
82	                  << std::setprecision(5) << std::noshowpos
83	                  << ": model " << std::setw(7) << io::volatility(implied)
84	                  << ", market " << std::setw(7)
85	                  << io::volatility(swaptionVols[k])
86	                  << " (" << std::setw(7) << std::showpos
87	                  << io::volatility(diff) << std::noshowpos << ")\n";
88	    }
89	}
90	
91	int main(int, char* []) {
92	
93	    try {
94	
95	        std::cout << std::endl;
96	
97	        Date todaysDate(15, February, 2002);
98	        Calendar calendar = TARGET();
99	        Date settlementDate(19, February, 2002);
100	        Settings::instance().evaluationDate() = todaysDate;
101	
102	        // flat yield term structure impling 1x5 swap at 5%
103	        auto flatRate = ext::make_shared<SimpleQuote>(0.04875825);
104	        Handle<YieldTermStructure> rhTermStructure(
105	            ext::make_shared<FlatForward>(
106	                      settlementDate, Handle<Quote>(flatRate),
107	                                      Actual365Fixed()));
108	
109	        // Define the ATM/OTM/ITM swaps
110	        Frequency fixedLegFrequency = Annual;
111	        BusinessDayConvention fixedLegConvention = Unadjusted;
112	        BusinessDayConvention floatingLegConvention = ModifiedFollowing;
113	        DayCounter fixedLegDayCounter = Thirty360(Thirty360::European);
114	        Frequency floatingLegFrequency = Semiannual;
115	        Swap::Type type = Swap::Payer;
116	        Rate dummyFixedRate = 0.03;
117	        auto indexSixMonths = ext::make_shared<Euribor6M>(rhTermStructure);
118	
119	        Date startDate = calendar.advance(settlementDate,1,Years,
120	                                          floatingLegConvention);
121	        Date maturity = calendar.advance(startDate,5,Years,
122	                                         floatingLegConvention);
123	        Schedule fixedSchedule(startDate,maturity,Period(fixedLegFrequency),
124	                               calendar,fixedLegConvention,fixedLegConvention,
125	                               DateGeneration::Forward,false);
126	        Schedule floatSchedule(startDate,maturity,Period(floatingLegFrequency),
127	                               calendar,floatingLegConvention,floatingLegConvention,
128	                               DateGeneration::Forward,false);
129	
130	        auto swap = ext::make_shared<VanillaSwap>(
131	            type, 1000.0,
132	            fixedSchedule, dummyFixedRate, fixedLegDayCounter,
133	            floatSchedule, indexSixMonths, 0.0,
134	            indexSixMonths->dayCounter());
135	        swap->setPricingEngine(ext::make_shared<DiscountingSwapEngine>(rhTermStructure));
136	        Rate fixedATMRate = swap->fairRate();
137	        Rate fixedOTMRate = fixedATMRate * 1.2;
138	        Rate fixedITMRate = fixedATMRate * 0.8;
139	
140	        auto atmSwap = ext::make_shared<VanillaSwap>(
141	            type, 1000.0,
142	            fixedSchedule, fixedATMRate, fixedLegDayCounter,
143	            floatSchedule, indexSixMonths, 0.0,
144	            indexSixMonths->dayCounter());
145	        auto otmSwap = ext::make_shared<VanillaSwap>(
146	            type, 1000.0,
147	            fixedSchedule, fixedOTMRate, fixedLegDayCounter,
148	            floatSchedule, indexSixMonths, 0.0,
149	            indexSixMonths->dayCounter());
150	        auto itmSwap = ext::make_shared<VanillaSwap>(
151	            type, 1000.0,
152	            fixedSchedule, fixedITMRate, fixedLegDayCounter,
153	            floatSchedule, indexSixMonths, 0.0,
154	            indexSixMonths->dayCounter());
155	
156	        // defining the swaptions to be used in model calibration
157	        std::vector<Period> swaptionMaturities;
158	        swaptionMaturities.emplace_back(1, Years);
159	        swaptionMaturities.emplace_back(2, Years);
160	        swaptionMaturities.emplace_back(3, Years);
161	        swaptionMaturities.emplace_back(4, Years);
162	        swaptionMaturities.emplace_back(5, Years);
163	
164	        std::vector<ext::shared_ptr<BlackCalibrationHelper>> swaptions;
165	
166	        // List of times that have to be included in the timegrid
167	        std::list<Time> times;
168	
169	        Size i;
170	        for (i=0; i<numRows; i++) {
171	            Size j = numCols - i -1; // 1x5, 2x4, 3x3, 4x2, 5x1
172	            Size k = i*numCols + j;
173	            auto vol = ext::make_shared<SimpleQuote>(swaptionVols[k]);
174	
175	            swaptions.push_back(ext::make_shared<SwaptionHelper>(
176	                               swaptionMaturities[i],
177	                               Period(swapLengths[j], Years),
178	                               Handle<Quote>(vol),
179	                               indexSixMonths,
180	                               indexSixMonths->tenor(),
181	                               indexSixMonths->dayCounter(),
182	                               indexSixMonths->dayCounter(),
183	                               rhTermStructure));
184	
185	            swaptions.back()->addTimesTo(times);
186	        }
187	
188	        // Building time-grid
189	        TimeGrid grid(times.begin(), times.end(), 30);
190	
191	
192	        // defining the models
193	        auto modelG2 = ext::make_shared<G2>(rhTermStructure);
194	        auto modelHW = ext::make_shared<HullWhite>(rhTermStructure);
195	        auto modelHW2 = ext::make_shared<HullWhite>(rhTermStructure);
196	        auto modelBK = ext::make_shared<BlackKarasinski>(rhTermStructure);
197	
198	
199	        // model calibrations
200	
201	        std::cout << "G2 (analytic formulae) calibration" << std::endl;
202	        for (i=0; i<swaptions.size(); i++)
203	            swaptions[i]->setPricingEngine(ext::make_shared<G2SwaptionEngine>(modelG2, 6.0, 16));
204	
205	        calibrateModel(modelG2, swaptions);
206	        std::cout << "calibrated to:\n"
207	                  << "a     = " << modelG2->params()[0] << ", "
208	                  << "sigma = " << modelG2->params()[1] << "\n"
209	                  << "b     = " << modelG2->params()[2] << ", "
210	                  << "eta   = " << modelG2->params()[3] << "\n"
211	                  << "rho   = " << modelG2->params()[4]
212	                  << std::endl << std::endl;
213	
214	
215	
216	        std::cout << "Hull-White (analytic formulae) calibration" << std::endl;
217	        for (i=0; i<swaptions.size(); i++)
218	            swaptions[i]->setPricingEngine(ext::make_shared<JamshidianSwaptionEngine>(modelHW));
219	
220	        calibrateModel(modelHW, swaptions);
221	        std::cout << "calibrated to:\n"
222	                  << "a = " << modelHW->params()[0] << ", "
223	                  << "sigma = " << modelHW->params()[1]
224	                  << std::endl << std::endl;
225	
226	        std::cout << "Hull-White (numerical) calibration" << std::endl;
227	        for (i=0; i<swaptions.size(); i++)
228	            swaptions[i]->setPricingEngine(ext::make_shared<TreeSwaptionEngine>(modelHW2, grid));
229	
230	        calibrateModel(modelHW2, swaptions);
231	        std::cout << "calibrated to:\n"
232	                  << "a = " << modelHW2->params()[0] << ", "
233	                  << "sigma = " << modelHW2->params()[1]
234	                  << std::endl << std::endl;
235	
236	        std::cout << "Black-Karasinski (numerical) calibration" << std::endl;
237	        for (i=0; i<swaptions.size(); i++)
238	            swaptions[i]->setPricingEngine(ext::make_shared<TreeSwaptionEngine>(modelBK, grid));
239	
240	        calibrateModel(modelBK, swaptions);
241	        std::cout << "calibrated to:\n"
242	                  << "a = " << modelBK->params()[0] << ", "
243	                  << "sigma = " << modelBK->params()[1]
244	                  << std::endl << std::endl;
245	
246	
247	        // ATM Bermudan swaption pricing
248	
249	        std::cout << "Payer bermudan swaption "
250	                  << "struck at " << io::rate(fixedATMRate)
251	                  << " (ATM)" << std::endl;
252	
253	        std::vector<Date> bermudanDates;
254	        const std::vector<ext::shared_ptr<CashFlow>>& leg =
255	            swap->fixedLeg();
256	        for (i=0; i<leg.size(); i++) {
257	            auto coupon = ext::dynamic_pointer_cast<Coupon>(leg[i]);
258	            bermudanDates.push_back(coupon->accrualStartDate());
259	        }
260	
261	        auto bermudanExercise = ext::make_shared<BermudanExercise>(bermudanDates);
262	
263	        Swaption bermudanSwaption(atmSwap, bermudanExercise);
264	
265	        // Do the pricing for each model
266	
267	        // G2 price the European swaption here, it should switch to bermudan
268	        bermudanSwaption.setPricingEngine(ext::make_shared<TreeSwaptionEngine>(modelG2, 50));
269	        std::cout << "G2 (tree):      " << bermudanSwaption.NPV() << std::endl;
270	        bermudanSwaption.setPricingEngine(ext::make_shared<FdG2SwaptionEngine>(modelG2));
271	        std::cout << "G2 (fdm) :      " << bermudanSwaption.NPV() << std::endl;
272	
273	        bermudanSwaption.setPricingEngine(ext::make_shared<TreeSwaptionEngine>(modelHW, 50));
274	        std::cout << "HW (tree):      " << bermudanSwaption.NPV() << std::endl;
275	        bermudanSwaption.setPricingEngine(ext::make_shared<FdHullWhiteSwaptionEngine>(modelHW));
276	        std::cout << "HW (fdm) :      " << bermudanSwaption.NPV() << std::endl;
277	
278	        bermudanSwaption.setPricingEngine(ext::make_shared<TreeSwaptionEngine>(modelHW2, 50));
279	        std::cout << "HW (num, tree): " << bermudanSwaption.NPV() << std::endl;
280	        bermudanSwaption.setPricingEngine(ext::make_shared<FdHullWhiteSwaptionEngine>(modelHW2));
281	        std::cout << "HW (num, fdm) : " << bermudanSwaption.NPV() << std::endl;
282	
283	        bermudanSwaption.setPricingEngine(ext::make_shared<TreeSwaptionEngine>(modelBK, 50));
284	        std::cout << "BK:             " << bermudanSwaption.NPV() << std::endl;
285	
286	
287	        // OTM Bermudan swaption pricing
288	
289	        std::cout << "Payer bermudan swaption "
290	                  << "struck at " << io::rate(fixedOTMRate)
291	                  << " (OTM)" << std::endl;
292	
293	        Swaption otmBermudanSwaption(otmSwap,bermudanExercise);
294	
295	        // Do the pricing for each model
296	        otmBermudanSwaption.setPricingEngine(ext::make_shared<TreeSwaptionEngine>(modelG2, 300));
297	        std::cout << "G2 (tree):       " << otmBermudanSwaption.NPV()
298	                  << std::endl;
299	        otmBermudanSwaption.setPricingEngine(ext::make_shared<FdG2SwaptionEngine>(modelG2));
300	        std::cout << "G2 (fdm) :       " << otmBermudanSwaption.NPV()
301	                  << std::endl;
302	
303	        otmBermudanSwaption.setPricingEngine(ext::make_shared<TreeSwaptionEngine>(modelHW, 50));
304	        std::cout << "HW (tree):       " << otmBermudanSwaption.NPV()
305	                  << std::endl;
306	        otmBermudanSwaption.setPricingEngine(ext::make_shared<FdHullWhiteSwaptionEngine>(modelHW));
307	        std::cout << "HW (fdm) :       " << otmBermudanSwaption.NPV()
308	                  << std::endl;
309	
310	        otmBermudanSwaption.setPricingEngine(ext::make_shared<TreeSwaptionEngine>(modelHW2, 50));
311	        std::cout << "HW (num, tree):  " << otmBermudanSwaption.NPV()
312	                  << std::endl;
313	        otmBermudanSwaption.setPricingEngine(ext::make_shared<FdHullWhiteSwaptionEngine>(modelHW2));
314	        std::cout << "HW (num, fdm):   " << otmBermudanSwaption.NPV()
315	                  << std::endl;
316	
317	        otmBermudanSwaption.setPricingEngine(ext::make_shared<TreeSwaptionEngine>(modelBK, 50));
318	        std::cout << "BK:              " << otmBermudanSwaption.NPV()
319	                  << std::endl;
320	
321	
322	        // ITM Bermudan swaption pricing
323	
324	        std::cout << "Payer bermudan swaption "
325	                  << "struck at " << io::rate(fixedITMRate)
326	                  << " (ITM)" << std::endl;
327	
328	        Swaption itmBermudanSwaption(itmSwap,bermudanExercise);
329	
330	        // Do the pricing for each model
331	        itmBermudanSwaption.setPricingEngine(ext::make_shared<TreeSwaptionEngine>(modelG2, 50));
332	        std::cout << "G2 (tree):       " << itmBermudanSwaption.NPV()
333	                  << std::endl;
334	        itmBermudanSwaption.setPricingEngine(ext::make_shared<FdG2SwaptionEngine>(modelG2));
335	        std::cout << "G2 (fdm) :       " << itmBermudanSwaption.NPV()
336	                  << std::endl;
337	
338	        itmBermudanSwaption.setPricingEngine(ext::make_shared<TreeSwaptionEngine>(modelHW, 50));
339	        std::cout << "HW (tree):       " << itmBermudanSwaption.NPV()
340	                  << std::endl;
341	        itmBermudanSwaption.setPricingEngine(ext::make_shared<FdHullWhiteSwaptionEngine>(modelHW));
342	        std::cout << "HW (fdm) :       " << itmBermudanSwaption.NPV()
343	                  << std::endl;
344	
345	        itmBermudanSwaption.setPricingEngine(ext::make_shared<TreeSwaptionEngine>(modelHW2, 50));
346	        std::cout << "HW (num, tree):  " << itmBermudanSwaption.NPV()
347	                  << std::endl;
348	        itmBermudanSwaption.setPricingEngine(ext::make_shared<FdHullWhiteSwaptionEngine>(modelHW2));
349	        std::cout << "HW (num, fdm) :  " << itmBermudanSwaption.NPV()
350	                  << std::endl;
351	
352	        itmBermudanSwaption.setPricingEngine(ext::make_shared<TreeSwaptionEngine>(modelBK, 50));
353	        std::cout << "BK:              " << itmBermudanSwaption.NPV()
354	                  << std::endl;
355	
356	        return 0;
357	    } catch (std::exception& e) {
358	        std::cerr << e.what() << std::endl;
359	        return 1;
360	    } catch (...) {
361	        std::cerr << "unknown error" << std::endl;
362	        return 1;
363	    }
364	}