1	/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3	/*!
4	 Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl
5	 Copyright (C) 2003, 2004, 2005, 2006, 2007 StatPro Italia srl
6	 Copyright (C) 2004 Ferdinando Ametrano
7	 Copyright (C) 2018 Jose Garcia
8	
9	 This file is part of QuantLib, a free-software/open-source library
10	 for financial quantitative analysts and developers - http://quantlib.org/
11	
12	 QuantLib is free software: you can redistribute it and/or modify it
13	 under the terms of the QuantLib license.  You should have received a
14	 copy of the license along with this program; if not, please email
15	 <quantlib-dev@lists.sf.net>. The license is also available online at
16	 <http://quantlib.org/license.shtml>.
17	
18	 This program is distributed in the hope that it will be useful, but WITHOUT
19	 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20	 FOR A PARTICULAR PURPOSE.  See the license for more details.
21	*/
22	
23	/*  This example shows how to set up a term structure with OIS discounting
24	    and then price a simple 5 year swap.
25	
26	    Example based on market data in paper by F. M. Ametrano and M. Bianchetti,
27	    Everything You Always Wanted to Know About Multiple Interest Rate Curve Boostrapping
28	    but Were Afraid to Ask (April 2, 2013).
29	    http://ssrn.com/abstract=2219548
30	    Eonia curve was taken from Figure 25 and Euribor 6m from figure 31.
31	*/
32	
33	#include <ql/qldefines.hpp>
34	#if !defined(BOOST_ALL_NO_LIB) && defined(BOOST_MSVC)
35	#include <ql/auto_link.hpp>
36	#endif
37	#include <ql/termstructures/yield/piecewiseyieldcurve.hpp>
38	#include <ql/termstructures/yieldtermstructure.hpp>
39	#include <ql/termstructures/yield/ratehelpers.hpp>
40	#include <ql/termstructures/yield/oisratehelper.hpp>
41	#include <ql/pricingengines/swap/discountingswapengine.hpp>
42	#include <ql/indexes/ibor/eonia.hpp>
43	#include <ql/indexes/ibor/euribor.hpp>
44	#include <ql/time/imm.hpp>
45	#include <ql/time/calendars/target.hpp>
46	#include <ql/time/daycounters/actual360.hpp>
47	#include <ql/time/daycounters/thirty360.hpp>
48	#include <ql/time/daycounters/actualactual.hpp>
49	#include <ql/math/interpolations/cubicinterpolation.hpp>
50	#include <ql/math/interpolations/loginterpolation.hpp>
51	
52	#include <iostream>
53	#include <iomanip>
54	
55	using namespace QuantLib;
56	
57	int main(int, char* []) {
58	
59	    try {
60	
61	        std::cout << std::endl;
62	
63	        /*************************
64	         ***  GLOBAL SETTINGS  ***
65	         *************************/
66	
67	        Calendar calendar = TARGET();
68	
69	        Date todaysDate(11, December, 2012);
70	        Settings::instance().evaluationDate() = todaysDate;
71	        todaysDate = Settings::instance().evaluationDate();
72	
73	        Integer fixingDays = 2;
74	        Date settlementDate = calendar.advance(todaysDate, fixingDays, Days);
75	        // must be a business day
76	        settlementDate = calendar.adjust(settlementDate);
77	
78	
79	        std::cout << "Today: " << todaysDate.weekday()
80	                  << ", " << todaysDate << std::endl;
81	
82	        std::cout << "Settlement date: " << settlementDate.weekday()
83	                  << ", " << settlementDate << std::endl;
84	
85	        /*********************
86	        **   EONIA CURVE    **
87	        *********************/
88	
89	        DayCounter termStructureDayCounter = Actual365Fixed();
90	        std::vector<ext::shared_ptr<RateHelper>> eoniaInstruments;
91	
92	        auto eonia = ext::make_shared<Eonia>();
93	
94	        // a SimpleQuote instance stores a value which can be manually changed;
95	        // other Quote subclasses could read the value from a database
96	        // or some kind of data feed.
97	
98	        // RateHelpers are built from the quotes, together with
99	        // other info depending on the instrument.  Quotes are passed in
100	        // relinkable handles which could be relinked to some other
101	        // data source later.
102	
103	        // deposits
104	
105	        std::map<Natural, ext::shared_ptr<Quote>> depoQuotes = {
106	            // settlement days, quote
107	            {0, ext::make_shared<SimpleQuote>(0.0004)},
108	            {1, ext::make_shared<SimpleQuote>(0.0004)},
109	            {2, ext::make_shared<SimpleQuote>(0.0004)}
110	        };
111	
112	        DayCounter depositDayCounter = Actual360();
113	
114	        for (const auto& q : depoQuotes) {
115	            auto settlementDays = q.first;
116	            auto quote = q.second;
117	            auto helper = ext::make_shared<DepositRateHelper>(
118	                Handle<Quote>(quote),
119	                1 * Days, settlementDays,
120	                calendar, Following,
121	                false, depositDayCounter);
122	            eoniaInstruments.push_back(helper);
123	        }
124	
125	        // short-term OIS
126	
127	        std::map<Period, ext::shared_ptr<Quote>> shortOisQuotes = {
128	            {1 * Weeks, ext::make_shared<SimpleQuote>(0.00070)},
129	            {2 * Weeks, ext::make_shared<SimpleQuote>(0.00069)},
130	            {3 * Weeks, ext::make_shared<SimpleQuote>(0.00078)},
131	            {1 * Months, ext::make_shared<SimpleQuote>(0.00074)}
132	        };
133	
134	        for (const auto& q : shortOisQuotes) {
135	            auto tenor = q.first;
136	            auto quote = q.second;
137	            auto helper = ext::make_shared<OISRateHelper>(
138	                2, tenor, Handle<Quote>(quote), eonia);
139	            eoniaInstruments.push_back(helper);
140	        }
141	
142	        // Dated OIS
143		
144	        std::map<std::pair<Date, Date>, ext::shared_ptr<Quote>> datedOisQuotes = {
145	            {{Date(16, January, 2013), Date(13, February, 2013)}, ext::make_shared<SimpleQuote>( 0.000460)},
146	            {{Date(13, February, 2013), Date(13, March, 2013)}, ext::make_shared<SimpleQuote>( 0.000160)},
147	            {{Date(13, March, 2013), Date(10, April, 2013)}, ext::make_shared<SimpleQuote>(-0.000070)},
148	            {{Date(10, April, 2013), Date(8, May, 2013)}, ext::make_shared<SimpleQuote>(-0.000130)},
149	            {{Date(8, May, 2013), Date(12, June, 2013)}, ext::make_shared<SimpleQuote>(-0.000140)},
150	        };
151	
152	        for (const auto& q : datedOisQuotes) {
153	            auto startDate = q.first.first;
154	            auto endDate = q.first.second;
155	            auto quote = q.second;
156	            auto helper = ext::make_shared<DatedOISRateHelper>(
157	                startDate, endDate, Handle<Quote>(quote), eonia);
158	            eoniaInstruments.push_back(helper);
159	        }
160	
161	        // long-term OIS
162	
163	        std::map<Period, ext::shared_ptr<Quote>> longOisQuotes = {
164	            {15 * Months, ext::make_shared<SimpleQuote>(0.00002)},
165	            {18 * Months, ext::make_shared<SimpleQuote>(0.00008)},
166	            {21 * Months, ext::make_shared<SimpleQuote>(0.00021)},
167	            {2 * Years, ext::make_shared<SimpleQuote>(0.00036)},
168	            {3 * Years, ext::make_shared<SimpleQuote>(0.00127)},
169	            {4 * Years, ext::make_shared<SimpleQuote>(0.00274)},
170	            {5 * Years, ext::make_shared<SimpleQuote>(0.00456)},
171	            {6 * Years, ext::make_shared<SimpleQuote>(0.00647)},
172	            {7 * Years, ext::make_shared<SimpleQuote>(0.00827)},
173	            {8 * Years, ext::make_shared<SimpleQuote>(0.00996)},
174	            {9 * Years, ext::make_shared<SimpleQuote>(0.01147)},
175	            {10 * Years, ext::make_shared<SimpleQuote>(0.0128)},
176	            {11 * Years, ext::make_shared<SimpleQuote>(0.01404)},
177	            {12 * Years, ext::make_shared<SimpleQuote>(0.01516)},
178	            {15 * Years, ext::make_shared<SimpleQuote>(0.01764)},
179	            {20 * Years, ext::make_shared<SimpleQuote>(0.01939)},
180	            {25 * Years, ext::make_shared<SimpleQuote>(0.02003)},
181	            {30 * Years, ext::make_shared<SimpleQuote>(0.02038)}
182	        };
183	
184	        for (const auto& q : longOisQuotes) {
185	            auto tenor = q.first;
186	            auto quote = q.second;
187	            auto helper = ext::make_shared<OISRateHelper>(
188	                2, tenor, Handle<Quote>(quote), eonia);
189	            eoniaInstruments.push_back(helper);
190	        }
191	
192	        // curve
193	
194	        auto eoniaTermStructure = ext::make_shared<PiecewiseYieldCurve<Discount, Cubic>>(
195	                todaysDate, eoniaInstruments, termStructureDayCounter);
196	
197	        eoniaTermStructure->enableExtrapolation();
198	
199	        // This curve will be used for discounting cash flows
200	        RelinkableHandle<YieldTermStructure> discountingTermStructure;
201	        discountingTermStructure.linkTo(eoniaTermStructure);
202	
203	
204	        /**************************
205	        **    EURIBOR 6M CURVE   **
206	        ***************************/
207	
208	        std::vector<ext::shared_ptr<RateHelper>> euribor6MInstruments;
209	
210	        auto euribor6M = ext::make_shared<Euribor6M>();
211	
212	        // deposits
213	
214	        auto d6MRate = ext::make_shared<SimpleQuote>(0.00312);
215	
216	        auto d6M = ext::make_shared<DepositRateHelper>(
217	            Handle<Quote>(d6MRate),
218	            6 * Months, 3,
219	            calendar, Following,
220	            false, depositDayCounter);
221	
222	        euribor6MInstruments.push_back(d6M);
223	
224	        // FRAs
225	
226	        std::map<Natural, ext::shared_ptr<Quote>> fraQuotes = {
227	            {1, ext::make_shared<SimpleQuote>(0.002930)},
228	            {2, ext::make_shared<SimpleQuote>(0.002720)},
229	            {3, ext::make_shared<SimpleQuote>(0.002600)},
230	            {4, ext::make_shared<SimpleQuote>(0.002560)},
231	            {5, ext::make_shared<SimpleQuote>(0.002520)},
232	            {6, ext::make_shared<SimpleQuote>(0.002480)},
233	            {7, ext::make_shared<SimpleQuote>(0.002540)},
234	            {8, ext::make_shared<SimpleQuote>(0.002610)},
235	            {9, ext::make_shared<SimpleQuote>(0.002670)},
236	            {10, ext::make_shared<SimpleQuote>(0.002790)},
237	            {11, ext::make_shared<SimpleQuote>(0.002910)},
238	            {12, ext::make_shared<SimpleQuote>(0.003030)},
239	            {13, ext::make_shared<SimpleQuote>(0.003180)},
240	            {14, ext::make_shared<SimpleQuote>(0.003350)},
241	            {15, ext::make_shared<SimpleQuote>(0.003520)},
242	            {16, ext::make_shared<SimpleQuote>(0.003710)},
243	            {17, ext::make_shared<SimpleQuote>(0.003890)},
244	            {18, ext::make_shared<SimpleQuote>(0.004090)}
245	        };
246	
247	        for (const auto& q : fraQuotes) {
248	            auto monthsToStart = q.first;
249		            auto quote = q.second;
250	            auto helper = ext::make_shared<FraRateHelper>(
251	                Handle<Quote>(quote),
252	                monthsToStart, euribor6M);
253	            euribor6MInstruments.push_back(helper);
254	        }
255	
256	        // swaps
257	
258	        std::map<Period, ext::shared_ptr<Quote>> swapQuotes = {
259	            {3 * Years, ext::make_shared<SimpleQuote>(0.004240)},
260	            {4 * Years, ext::make_shared<SimpleQuote>(0.005760)},
261	            {5 * Years, ext::make_shared<SimpleQuote>(0.007620)},
262	            {6 * Years, ext::make_shared<SimpleQuote>(0.009540)},
263	            {7 * Years, ext::make_shared<SimpleQuote>(0.011350)},
264	            {8 * Years, ext::make_shared<SimpleQuote>(0.013030)},
265	            {9 * Years, ext::make_shared<SimpleQuote>(0.014520)},
266	            {10 * Years, ext::make_shared<SimpleQuote>(0.015840)},
267	            {12 * Years, ext::make_shared<SimpleQuote>(0.018090)},
268	            {15 * Years, ext::make_shared<SimpleQuote>(0.020370)},
269	            {20 * Years, ext::make_shared<SimpleQuote>(0.021870)},
270	            {25 * Years, ext::make_shared<SimpleQuote>(0.022340)},
271	            {30 * Years, ext::make_shared<SimpleQuote>(0.022560)},
272	            {35 * Years, ext::make_shared<SimpleQuote>(0.022950)},
273	            {40 * Years, ext::make_shared<SimpleQuote>(0.023480)},
274	            {50 * Years, ext::make_shared<SimpleQuote>(0.024210)},
275	            {60 * Years, ext::make_shared<SimpleQuote>(0.024630)}
276	        };
277	
278	        Frequency swFixedLegFrequency = Annual;
279	        BusinessDayConvention swFixedLegConvention = Unadjusted;
280	        DayCounter swFixedLegDayCounter = Thirty360(Thirty360::European);
281	
282	        for (const auto& q : swapQuotes) {
283	            auto tenor = q.first;
284	            auto quote = q.second;
285	            auto helper = ext::make_shared<SwapRateHelper>(
286	                Handle<Quote>(quote), tenor,
287	                calendar, swFixedLegFrequency,
288	                swFixedLegConvention, swFixedLegDayCounter,
289	                euribor6M,
290	                Handle<Quote>(), 0 * Days,
291	                discountingTermStructure); // the Eonia curve is used for discounting
292	            euribor6MInstruments.push_back(helper);
293	        }
294	
295	        // If needed, it's possible to change the tolerance; the default is 1.0e-12.
296	        // The tolerance is passed in an explicit bootstrap object. Depending on
297	        // the bootstrap algorithm, it's possible to pass other parameters.
298	        double tolerance = 1.0e-15;
299	        auto euribor6MTermStructure = ext::make_shared<PiecewiseYieldCurve<Discount, Cubic>>(
300	                settlementDate, euribor6MInstruments,
301	                termStructureDayCounter,
302	                PiecewiseYieldCurve<Discount, Cubic>::bootstrap_type(tolerance));
303	
304	        // This curve will be used for forward-rate forecasting
305	
306	        RelinkableHandle<YieldTermStructure> forecastingTermStructure;
307	        forecastingTermStructure.linkTo(euribor6MTermStructure);
308	
309	        /*********************
310	        * SWAPS TO BE PRICED *
311	        **********************/
312	
313	        // constant nominal 1,000,000 Euro
314	        Real nominal = 1000000.0;
315	        // fixed leg
316	        Frequency fixedLegFrequency = Annual;
317	        BusinessDayConvention fixedLegConvention = Unadjusted;
318	        BusinessDayConvention floatingLegConvention = ModifiedFollowing;
319	        DayCounter fixedLegDayCounter = Thirty360(Thirty360::European);
320	        Rate fixedRate = 0.007;
321	        DayCounter floatingLegDayCounter = Actual360();
322	
323	        // floating leg
324	        Frequency floatingLegFrequency = Semiannual;
325	        auto euriborIndex = ext::make_shared<Euribor6M>(forecastingTermStructure);
326	        Spread spread = 0.0;
327	
328	        Integer lengthInYears = 5;
329	        Swap::Type swapType = Swap::Payer;
330	
331	        Date maturity = settlementDate + lengthInYears*Years;
332	        Schedule fixedSchedule(settlementDate, maturity,
333	                               Period(fixedLegFrequency),
334	                               calendar, fixedLegConvention,
335	                               fixedLegConvention,
336	                               DateGeneration::Forward, false);
337	        Schedule floatSchedule(settlementDate, maturity,
338	                               Period(floatingLegFrequency),
339	                               calendar, floatingLegConvention,
340	                               floatingLegConvention,
341	                               DateGeneration::Forward, false);
342	        VanillaSwap spot5YearSwap(swapType, nominal,
343	            fixedSchedule, fixedRate, fixedLegDayCounter,
344	            floatSchedule, euriborIndex, spread,
345	            floatingLegDayCounter);
346	
347	        Date fwdStart = calendar.advance(settlementDate, 1, Years);
348	        Date fwdMaturity = fwdStart + lengthInYears*Years;
349	        Schedule fwdFixedSchedule(fwdStart, fwdMaturity,
350	                                  Period(fixedLegFrequency),
351	                                  calendar, fixedLegConvention,
352	                                  fixedLegConvention,
353	                                  DateGeneration::Forward, false);
354	        Schedule fwdFloatSchedule(fwdStart, fwdMaturity,
355	                                  Period(floatingLegFrequency),
356	                                  calendar, floatingLegConvention,
357	                                  floatingLegConvention,
358	                                  DateGeneration::Forward, false);
359	        VanillaSwap oneYearForward5YearSwap(swapType, nominal,
360	            fwdFixedSchedule, fixedRate, fixedLegDayCounter,
361	            fwdFloatSchedule, euriborIndex, spread,
362	            floatingLegDayCounter);
363	
364	
365	        /***************
366	        * SWAP PRICING *
367	        ****************/
368	
369	        // utilities for formatting the report
370	
371	        std::ostringstream s1;
372	        s1 << "5-years swap paying " << std::setprecision(2) << io::rate(fixedRate);
373	        std::string case1 = s1.str();
374	
375	        std::ostringstream s2;
376	        s2 << "5-years, 1-year forward swap paying " << std::setprecision(2) << io::rate(fixedRate);
377	        std::string case2 = s2.str();
378	
379	        std::vector<std::string> headers(4);
380	        headers[0] = std::string(std::max(case1.size(), case2.size()) + 1, ' ');
381	        headers[1] = "net present value";
382	        headers[2] = "fair spread";
383	        headers[3] = "fair fixed rate";
384	        std::string separator = " | ";
385	        std::string header = headers[0] + separator + headers[1] + separator + headers[2] + separator + headers[3];
386	        Size width = header.size();
387	        std::string rule(width, '-'), dblrule(width, '=');
388	
389	        // calculations
390	
391	        auto s5yRate = swapQuotes[5 * Years];
392	
393	        std::cout << dblrule << std::endl;
394	        std::cout << " With 5-year market swap-rate = "
395	                  << std::setprecision(2) << io::rate(s5yRate->value())
396	                  << std::endl;
397	        std::cout << rule << std::endl;
398	
399	        std::cout << header << std::endl;
400		        std::cout << rule << std::endl;
401	
402	        Real NPV;
403	        Rate fairRate;
404	        Spread fairSpread;
405	
406	        auto swapEngine = ext::make_shared<DiscountingSwapEngine>(discountingTermStructure);
407	
408	        spot5YearSwap.setPricingEngine(swapEngine);
409	        oneYearForward5YearSwap.setPricingEngine(swapEngine);
410	
411	        NPV = spot5YearSwap.NPV();
412	        fairSpread = spot5YearSwap.fairSpread();
413	        fairRate = spot5YearSwap.fairRate();
414	
415	        std::cout << std::setw(headers[0].size())
416	                  << case1 << separator;
417	        std::cout << std::setw(headers[1].size())
418	                  << std::fixed << std::setprecision(2) << NPV << separator;
419	        std::cout << std::setw(headers[2].size())
420	                  << io::rate(fairSpread) << separator;
421	        std::cout << std::setw(headers[3].size())
422	                  << io::rate(fairRate);
423	        std::cout << std::endl;
424	
425	        std::cout << rule << std::endl;
426	
427	        // let's check that the 5 years swap has been correctly re-priced
428	        QL_REQUIRE(std::fabs(fairRate-s5yRate->value())<1e-8,
429	                   "5-years swap mispriced by "
430	                   << io::rate(std::fabs(fairRate-s5yRate->value())));
431	
432	        // now let's price the 1Y forward 5Y swap
433	
434	        NPV = oneYearForward5YearSwap.NPV();
435	        fairSpread = oneYearForward5YearSwap.fairSpread();
436	        fairRate = oneYearForward5YearSwap.fairRate();
437	
438	        std::cout << std::setw(headers[0].size())
439	                  << case2 << separator;
440	        std::cout << std::setw(headers[1].size())
441	                  << std::fixed << std::setprecision(2) << NPV << separator;
442	        std::cout << std::setw(headers[2].size())
443	                  << io::rate(fairSpread) << separator;
444	        std::cout << std::setw(headers[3].size())
445	                  << io::rate(fairRate);
446	        std::cout << std::endl;
447	
448	        // now let's say that the 5-years swap rate goes up to 0.90%.
449	        // A smarter market element--say, connected to a data source-- would
450	        // notice the change itself. Since we're using SimpleQuotes,
451	        // we'll have to change the value manually--which forces us to
452	        // downcast the handle and use the SimpleQuote
453	        // interface. In any case, the point here is that a change in the
454	        // value contained in the Quote triggers a new bootstrapping
455	        // of the curve and a repricing of the swap.
456	
457	        auto fiveYearsRate = ext::dynamic_pointer_cast<SimpleQuote>(s5yRate);
458	        fiveYearsRate->setValue(0.0090);
459	
460	        std::cout << dblrule << std::endl;
461	        std::cout << " With 5-year market swap-rate = "
462	                  << io::rate(s5yRate->value()) << std::endl;
463	        std::cout << rule << std::endl;
464	
465	        std::cout << header << std::endl;
466	        std::cout << rule << std::endl;
467	
468	        // now get the updated results
469	
470	        NPV = spot5YearSwap.NPV();
471	        fairSpread = spot5YearSwap.fairSpread();
472	        fairRate = spot5YearSwap.fairRate();
473	
474	        std::cout << std::setw(headers[0].size())
475	                  << case1 << separator;
476	        std::cout << std::setw(headers[1].size())
477	                  << std::fixed << std::setprecision(2) << NPV << separator;
478	        std::cout << std::setw(headers[2].size())
479	                  << io::rate(fairSpread) << separator;
480	        std::cout << std::setw(headers[3].size())
481	                  << io::rate(fairRate);
482	        std::cout << std::endl;
483	
484	        QL_REQUIRE(std::fabs(fairRate-s5yRate->value())<1e-8,
485	                   "5-years swap mispriced!");
486	
487	        std::cout << rule << std::endl;
488	
489	        // the 1Y forward 5Y swap doesn't change;
490	        // it depends on the 1-year and 6-years rates, which didn't move
491	
492	        NPV = oneYearForward5YearSwap.NPV();
493	        fairSpread = oneYearForward5YearSwap.fairSpread();
494	        fairRate = oneYearForward5YearSwap.fairRate();
495	
496	        std::cout << std::setw(headers[0].size())
497	                  << case2 << separator;
498	        std::cout << std::setw(headers[1].size())
499	                  << std::fixed << std::setprecision(2) << NPV << separator;
500	        std::cout << std::setw(headers[2].size())
501	                  << io::rate(fairSpread) << separator;
502	        std::cout << std::setw(headers[3].size())
503	                  << io::rate(fairRate);
504	        std::cout << std::endl;
505	
506	        std::cout << dblrule << std::endl;
507	
508	        return 0;
509	
510	    } catch (std::exception& e) {
511	        std::cerr << e.what() << std::endl;
512	        return 1;
513	    } catch (...) {
514	        std::cerr << "unknown error" << std::endl;
515	        return 1;
516	    }
517	}