1 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 
3 /*
4  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 StatPro Italia srl
5  Copyright (C) 2009, 2015 Ferdinando Ametrano
6  Copyright (C) 2015 Paolo Mazzocchi
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 /*! \file zerocurve.hpp
23     \brief interpolated zero-rates structure
24 */
25 
26 #ifndef quantlib_zero_curve_hpp
27 #define quantlib_zero_curve_hpp
28 
29 #include <ql/termstructures/yield/zeroyieldstructure.hpp>
30 #include <ql/termstructures/interpolatedcurve.hpp>
31 #include <ql/math/interpolations/linearinterpolation.hpp>
32 #include <ql/interestrate.hpp>
33 #include <ql/math/comparison.hpp>
34 #include <ql/utilities/dataformatters.hpp>
35 #include <utility>
36 
37 namespace QuantLib {
38 
39     //! YieldTermStructure based on interpolation of zero rates
40     /*! \ingroup yieldtermstructures */
41     template <class Interpolator>
42     class InterpolatedZeroCurve : public ZeroYieldStructure,
43                                   protected InterpolatedCurve<Interpolator> {
44       public:
45         // constructor
46         InterpolatedZeroCurve(
47             const std::vector<Date>& dates,
48             const std::vector<Rate>& yields,
49             const DayCounter& dayCounter,
50             const Calendar& calendar = Calendar(),
51             const std::vector<Handle<Quote> >& jumps =
52                                                 std::vector<Handle<Quote> >(),
53             const std::vector<Date>& jumpDates = std::vector<Date>(),
54             const Interpolator& interpolator = Interpolator(),
55             Compounding compounding = Continuous,
56             Frequency frequency = Annual);
57         InterpolatedZeroCurve(
58             const std::vector<Date>& dates,
59             const std::vector<Rate>& yields,
60             const DayCounter& dayCounter,
61             const Calendar& calendar,
62             const Interpolator& interpolator,
63             Compounding compounding = Continuous,
64             Frequency frequency = Annual);
65         InterpolatedZeroCurve(
66             const std::vector<Date>& dates,
67             const std::vector<Rate>& yields,
68             const DayCounter& dayCounter,
69             const Interpolator& interpolator,
70             Compounding compounding = Continuous,
71             Frequency frequency = Annual);
72         //! \name TermStructure interface
73         //@{
74         Date maxDate() const;
75         //@}
76         //! \name other inspectors
77         //@{
78         const std::vector<Time>& times() const;
79         const std::vector<Date>& dates() const;
80         const std::vector<Real>& data() const;
81         const std::vector<Rate>& zeroRates() const;
82         std::vector<std::pair<Date, Real> > nodes() const;
83         //@}
84 
85       protected:
86         explicit InterpolatedZeroCurve(
87             const DayCounter&,
88             const Interpolator& interpolator = Interpolator());
89         InterpolatedZeroCurve(
90             const Date& referenceDate,
91             const DayCounter&,
92             const std::vector<Handle<Quote> >& jumps = std::vector<Handle<Quote> >(),
93             const std::vector<Date>& jumpDates = std::vector<Date>(),
94             const Interpolator& interpolator = Interpolator());
95         InterpolatedZeroCurve(
96             Natural settlementDays,
97             const Calendar&,
98             const DayCounter&,
99             const std::vector<Handle<Quote> >& jumps = std::vector<Handle<Quote> >(),
100             const std::vector<Date>& jumpDates = std::vector<Date>(),
101             const Interpolator& interpolator = Interpolator());
102 
103         /*! \deprecated Passing jumps without a reference date never worked correctly.
104                         Use one of the other constructors instead.
105                         Deprecated in version 1.19.
106         */
107         QL_DEPRECATED
108         InterpolatedZeroCurve(
109             const DayCounter&,
110             const std::vector<Handle<Quote> >& jumps,
111             const std::vector<Date>& jumpDates = std::vector<Date>(),
112             const Interpolator& interpolator = Interpolator());
113 
114         //! \name ZeroYieldStructure implementation
115         //@{
116         Rate zeroYieldImpl(Time t) const;
117         //@}
118         mutable std::vector<Date> dates_;
119       private:
120         void initialize(const Compounding& compounding, const Frequency& frequency);
121     };
122 
123     //! Term structure based on linear interpolation of zero yields
124     /*! \ingroup yieldtermstructures */
125     typedef InterpolatedZeroCurve<Linear> ZeroCurve;
126 
127 
128     // inline definitions
129 
130     template <class T>
maxDate() const131     inline Date InterpolatedZeroCurve<T>::maxDate() const {
132         if (this->maxDate_ != Date())
133            return this->maxDate_;
134         return dates_.back();
135     }
136 
137     template <class T>
times() const138     inline const std::vector<Time>& InterpolatedZeroCurve<T>::times() const {
139         return this->times_;
140     }
141 
142     template <class T>
dates() const143     inline const std::vector<Date>& InterpolatedZeroCurve<T>::dates() const {
144         return dates_;
145     }
146 
147     template <class T>
148     inline const std::vector<Real>&
data() const149     InterpolatedZeroCurve<T>::data() const {
150         return this->data_;
151     }
152 
153     template <class T>
154     inline const std::vector<Rate>&
zeroRates() const155     InterpolatedZeroCurve<T>::zeroRates() const {
156         return this->data_;
157     }
158 
159     template <class T>
160     inline std::vector<std::pair<Date, Real> >
nodes() const161     InterpolatedZeroCurve<T>::nodes() const {
162         std::vector<std::pair<Date, Real> > results(dates_.size());
163         for (Size i=0; i<dates_.size(); ++i)
164             results[i] = std::make_pair(dates_[i], this->data_[i]);
165         return results;
166     }
167 
168     #ifndef __DOXYGEN__
169 
170     // template definitions
171 
172     template <class T>
zeroYieldImpl(Time t) const173     Rate InterpolatedZeroCurve<T>::zeroYieldImpl(Time t) const {
174         if (t <= this->times_.back())
175             return this->interpolation_(t, true);
176 
177         // flat fwd extrapolation
178         Time tMax = this->times_.back();
179         Rate zMax = this->data_.back();
180         Rate instFwdMax = zMax + tMax * this->interpolation_.derivative(tMax);
181         return (zMax * tMax + instFwdMax * (t-tMax)) / t;
182     }
183 
184     template <class T>
InterpolatedZeroCurve(const DayCounter & dayCounter,const T & interpolator)185     InterpolatedZeroCurve<T>::InterpolatedZeroCurve(
186                                     const DayCounter& dayCounter,
187                                     const T& interpolator)
188     : ZeroYieldStructure(dayCounter), InterpolatedCurve<T>(interpolator) {}
189 
190     template <class T>
InterpolatedZeroCurve(const Date & referenceDate,const DayCounter & dayCounter,const std::vector<Handle<Quote>> & jumps,const std::vector<Date> & jumpDates,const T & interpolator)191     InterpolatedZeroCurve<T>::InterpolatedZeroCurve(
192                                     const Date& referenceDate,
193                                     const DayCounter& dayCounter,
194                                     const std::vector<Handle<Quote> >& jumps,
195                                     const std::vector<Date>& jumpDates,
196                                     const T& interpolator)
197     : ZeroYieldStructure(referenceDate, Calendar(), dayCounter, jumps, jumpDates),
198       InterpolatedCurve<T>(interpolator) {}
199 
200     template <class T>
InterpolatedZeroCurve(Natural settlementDays,const Calendar & calendar,const DayCounter & dayCounter,const std::vector<Handle<Quote>> & jumps,const std::vector<Date> & jumpDates,const T & interpolator)201     InterpolatedZeroCurve<T>::InterpolatedZeroCurve(
202                                     Natural settlementDays,
203                                     const Calendar& calendar,
204                                     const DayCounter& dayCounter,
205                                     const std::vector<Handle<Quote> >& jumps,
206                                     const std::vector<Date>& jumpDates,
207                                     const T& interpolator)
208     : ZeroYieldStructure(settlementDays, calendar, dayCounter, jumps, jumpDates),
209       InterpolatedCurve<T>(interpolator) {}
210 
211 #if defined(__GNUC__)
212 #pragma GCC diagnostic push
213 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
214 #endif
215 #if defined(__clang__)
216 #pragma clang diagnostic push
217 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
218 #endif
219 #if defined(QL_PATCH_MSVC)
220 #pragma warning(push)
221 #pragma warning(disable:4996)
222 #endif
223 
224     template <class T>
InterpolatedZeroCurve(const DayCounter & dayCounter,const std::vector<Handle<Quote>> & jumps,const std::vector<Date> & jumpDates,const T & interpolator)225     InterpolatedZeroCurve<T>::InterpolatedZeroCurve(
226                                     const DayCounter& dayCounter,
227                                     const std::vector<Handle<Quote> >& jumps,
228                                     const std::vector<Date>& jumpDates,
229                                     const T& interpolator)
230     : ZeroYieldStructure(dayCounter, jumps, jumpDates),
231       InterpolatedCurve<T>(interpolator) {}
232 
233 #if defined(QL_PATCH_MSVC)
234 #pragma warning(pop)
235 #endif
236 #if defined(__clang__)
237 #pragma clang diagnostic pop
238 #endif
239 #if defined(__GNUC__)
240 #pragma GCC diagnostic pop
241 #endif
242 
243     template <class T>
InterpolatedZeroCurve(const std::vector<Date> & dates,const std::vector<Rate> & yields,const DayCounter & dayCounter,const Calendar & calendar,const std::vector<Handle<Quote>> & jumps,const std::vector<Date> & jumpDates,const T & interpolator,Compounding compounding,Frequency frequency)244     InterpolatedZeroCurve<T>::InterpolatedZeroCurve(
245                                     const std::vector<Date>& dates,
246                                     const std::vector<Rate>& yields,
247                                     const DayCounter& dayCounter,
248                                     const Calendar& calendar,
249                                     const std::vector<Handle<Quote> >& jumps,
250                                     const std::vector<Date>& jumpDates,
251                                     const T& interpolator,
252                                     Compounding compounding,
253                                     Frequency frequency)
254     : ZeroYieldStructure(dates.at(0), calendar, dayCounter, jumps, jumpDates),
255       InterpolatedCurve<T>(std::vector<Time>(), yields, interpolator),
256       dates_(dates)
257     {
258         initialize(compounding,frequency);
259     }
260 
261     template <class T>
InterpolatedZeroCurve(const std::vector<Date> & dates,const std::vector<Rate> & yields,const DayCounter & dayCounter,const Calendar & calendar,const T & interpolator,Compounding compounding,Frequency frequency)262     InterpolatedZeroCurve<T>::InterpolatedZeroCurve(
263                                                const std::vector<Date>& dates,
264                                                const std::vector<Rate>& yields,
265                                                const DayCounter& dayCounter,
266                                                const Calendar& calendar,
267                                                const T& interpolator,
268                                                Compounding compounding,
269                                                Frequency frequency)
270     : ZeroYieldStructure(dates.at(0), calendar, dayCounter),
271       InterpolatedCurve<T>(std::vector<Time>(), yields, interpolator),
272       dates_(dates)
273     {
274         initialize(compounding,frequency);
275     }
276 
277     template <class T>
InterpolatedZeroCurve(const std::vector<Date> & dates,const std::vector<Rate> & yields,const DayCounter & dayCounter,const T & interpolator,Compounding compounding,Frequency frequency)278     InterpolatedZeroCurve<T>::InterpolatedZeroCurve(
279                                                const std::vector<Date>& dates,
280                                                const std::vector<Rate>& yields,
281                                                const DayCounter& dayCounter,
282                                                const T& interpolator,
283                                                Compounding compounding,
284                                                Frequency frequency)
285     : ZeroYieldStructure(dates.at(0), Calendar(), dayCounter),
286       InterpolatedCurve<T>(std::vector<Time>(), yields, interpolator),
287       dates_(dates)
288     {
289         initialize(compounding,frequency);
290     }
291 
292     #endif
293 
294     template <class T>
initialize(const Compounding & compounding,const Frequency & frequency)295     void InterpolatedZeroCurve<T>::initialize(const Compounding& compounding,
296                                               const Frequency& frequency)
297     {
298         QL_REQUIRE(dates_.size() >= T::requiredPoints,
299                    "not enough input dates given");
300         QL_REQUIRE(this->data_.size() == dates_.size(),
301                    "dates/data count mismatch");
302 
303         this->times_.resize(dates_.size());
304         this->times_[0] = 0.0;
305         if (compounding != Continuous) {
306             // We also have to convert the first rate.
307             // The first time is 0.0, so we can't use it.
308             // We fall back to about one day.
309             Time dt = 1.0/365;
310             InterestRate r(this->data_[0], dayCounter(), compounding, frequency);
311             this->data_[0] = r.equivalentRate(Continuous, NoFrequency, dt);
312         }
313 
314         for (Size i=1; i<dates_.size(); ++i) {
315             QL_REQUIRE(dates_[i] > dates_[i-1],
316                        "invalid date (" << dates_[i] << ", vs "
317                        << dates_[i-1] << ")");
318             this->times_[i] = dayCounter().yearFraction(dates_[0], dates_[i]);
319             QL_REQUIRE(!close(this->times_[i],this->times_[i-1]),
320                        "two dates correspond to the same time "
321                        "under this curve's day count convention");
322 
323             // adjusting zero rates to match continuous compounding
324             if (compounding != Continuous)
325             {
326                 InterestRate r(this->data_[i], dayCounter(), compounding, frequency);
327                 this->data_[i] = r.equivalentRate(Continuous, NoFrequency, this->times_[i]);
328             }
329         }
330 
331         this->interpolation_ =
332             this->interpolator_.interpolate(this->times_.begin(),
333                                             this->times_.end(),
334                                             this->data_.begin());
335         this->interpolation_.update();
336     }
337 
338 }
339 
340 #endif
341