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