QuantLib: a free/open-source library for quantitative finance
Fully annotated sources - version 1.32
Loading...
Searching...
No Matches
yoycapfloortermpricesurface.hpp
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2009 Chris Kenyon
5 Copyright (C) 2009 Bernd Engelmann
6
7 This file is part of QuantLib, a free-software/open-source library
8 for financial quantitative analysts and developers - http://quantlib.org/
9
10 QuantLib is free software: you can redistribute it and/or modify it
11 under the terms of the QuantLib license. You should have received a
12 copy of the license along with this program; if not, please email
13 <quantlib-dev@lists.sf.net>. The license is also available online at
14 <http://quantlib.org/license.shtml>.
15
16 This program is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 FOR A PARTICULAR PURPOSE. See the license for more details.
19*/
20
25#ifndef quantlib_yoy_capfloor_term_price_surface_hpp
26#define quantlib_yoy_capfloor_term_price_surface_hpp
27
28#include <ql/indexes/inflationindex.hpp>
29#include <ql/termstructures/inflation/piecewiseyoyinflationcurve.hpp>
30#include <ql/termstructures/inflation/inflationhelpers.hpp>
31#include <ql/experimental/inflation/polynomial2Dspline.hpp>
32#include <cmath>
33
34namespace QuantLib {
35
37
43 public:
45 const Period& yyLag,
46 const ext::shared_ptr<YoYInflationIndex>& yii,
49 const DayCounter& dc,
50 const Calendar& cal,
51 const BusinessDayConvention& bdc,
52 const std::vector<Rate>& cStrikes,
53 const std::vector<Rate>& fStrikes,
54 const std::vector<Period>& cfMaturities,
55 const Matrix& cPrice,
56 const Matrix& fPrice);
57
58 bool indexIsInterpolated() const;
59
61
62 virtual std::pair<std::vector<Time>, std::vector<Rate> >
64 virtual std::pair<std::vector<Date>, std::vector<Rate> >
66
68 virtual ext::shared_ptr<YoYInflationTermStructure> YoYTS() const = 0;
70 ext::shared_ptr<YoYInflationIndex> yoyIndex() const { return yoyIndex_; }
71
73
81 virtual Natural fixingDays() const {return fixingDays_;}
82 virtual Real price(const Date& d, Rate k) const = 0;
83 virtual Real capPrice(const Date& d, Rate k) const = 0;
84 virtual Real floorPrice(const Date& d, Rate k) const = 0;
85 virtual Rate atmYoYSwapRate(const Date &d,
86 bool extrapolate = true) const = 0;
87 virtual Rate atmYoYRate(const Date &d,
88 const Period &obsLag = Period(-1,Days),
89 bool extrapolate = true) const = 0;
90
91 virtual Real price(const Period& d, Rate k) const;
92 virtual Real capPrice(const Period& d, Rate k) const;
93 virtual Real floorPrice(const Period& d, Rate k) const;
94 virtual Rate atmYoYSwapRate(const Period &d,
95 bool extrapolate = true) const;
96 virtual Rate atmYoYRate(const Period &d,
97 const Period &obsLag = Period(-1,Days),
98 bool extrapolate = true) const;
99
100 virtual std::vector<Rate> strikes() const {return cfStrikes_;}
101 virtual std::vector<Rate> capStrikes() const {return cStrikes_;}
102 virtual std::vector<Rate> floorStrikes() const {return fStrikes_;}
103 virtual std::vector<Period> maturities() const {return cfMaturities_;}
104 virtual Rate minStrike() const {return cfStrikes_.front();};
105 virtual Rate maxStrike() const {return cfStrikes_.back();};
106 virtual Date minMaturity() const {return referenceDate()+cfMaturities_.front();}// \TODO deal with index interpolation
107 virtual Date maxMaturity() const {return referenceDate()+cfMaturities_.back();}
109
110 virtual Date yoyOptionDateFromTenor(const Period& p) const;
111
112 protected:
113 virtual bool checkStrike(Rate K) {
114 return ( minStrike() <= K && K <= maxStrike() );
115 }
116 virtual bool checkMaturity(const Date& d) {
117 return ( minMaturity() <= d && d <= maxMaturity() );
118 }
119
120 // defaults, mostly used for building yoy-fwd curve from put-call parity
121 // ext::shared_ptr<YieldTermStructure> nominal_;
122 // Period lag_;
123 // Calendar cal_;
126 ext::shared_ptr<YoYInflationIndex> yoyIndex_;
128 // data
129 std::vector<Rate> cStrikes_;
130 std::vector<Rate> fStrikes_;
131 std::vector<Period> cfMaturities_;
132 mutable std::vector<Real> cfMaturityTimes_;
136 // constructed
137 mutable std::vector<Rate> cfStrikes_;
138 mutable ext::shared_ptr<YoYInflationTermStructure> yoy_;
139 mutable std::pair<std::vector<Time>, std::vector<Rate> > atmYoYSwapTimeRates_;
140 mutable std::pair<std::vector<Date>, std::vector<Rate> > atmYoYSwapDateRates_;
141 };
142
143
144 template<class Interpolator2D, class Interpolator1D>
147 public:
150 const Period &yyLag, // observation lag
151 const ext::shared_ptr<YoYInflationIndex>& yii,
153 const Handle<YieldTermStructure> &nominal,
154 const DayCounter &dc,
155 const Calendar &cal,
156 const BusinessDayConvention &bdc,
157 const std::vector<Rate> &cStrikes,
158 const std::vector<Rate> &fStrikes,
159 const std::vector<Period> &cfMaturities,
160 const Matrix &cPrice,
161 const Matrix &fPrice,
162 const Interpolator2D &interpolator2d = Interpolator2D(),
163 const Interpolator1D &interpolator1d = Interpolator1D());
164
166
167 Date maxDate() const override { return yoy_->maxDate(); }
168 Date baseDate() const override { return yoy_->baseDate(); }
170 Natural fixingDays() const override { return fixingDays_; }
171
173
174 std::pair<std::vector<Time>, std::vector<Rate> > atmYoYSwapTimeRates() const override {
176 }
177 std::pair<std::vector<Date>, std::vector<Rate> > atmYoYSwapDateRates() const override {
179 }
180 ext::shared_ptr<YoYInflationTermStructure> YoYTS() const override { return yoy_; }
181 Rate price(const Date& d, Rate k) const override;
182 Real floorPrice(const Date& d, Rate k) const override;
183 Real capPrice(const Date& d, Rate k) const override;
184 Rate atmYoYSwapRate(const Date& d, bool extrapolate = true) const override {
185 return atmYoYSwapRateCurve_(timeFromReference(d),extrapolate);
186 }
188 const Period& obsLag = Period(-1, Days),
189 bool extrapolate = true) const override {
190 // work in terms of maturity-of-instruments
191 // so ask for rate with observation lag
192 // Third parameter = force linear interpolation of yoy
193 return yoy_->yoyRate(d, obsLag, false, extrapolate);
194 }
196
198
199 void update() override;
200 void performCalculations() const;
202
203 protected:
205 void intersect() const;
207 public:
209 Real operator()(Rate guess) const;
210 protected:
211 const Time t_;
212 const Interpolation2D &a_, &b_; // work on references
213 };
214
216 void calculateYoYTermStructure() const;
217
218 // data for surfaces and curve
219 mutable std::vector<Rate> cStrikesB_;
220 mutable std::vector<Rate> fStrikesB_;
225 mutable Interpolator2D interpolator2d_;
228 };
229
230
231 // inline definitions
232
235 }
236
237 // template definitions
238
239 #ifndef __DOXYGEN__
240
241 template<class I2D, class I1D>
244 Natural fixingDays,
245 const Period &yyLag,
246 const ext::shared_ptr<YoYInflationIndex>& yii,
247 Rate baseRate,
248 const Handle<YieldTermStructure> &nominal,
249 const DayCounter &dc,
250 const Calendar &cal,
251 const BusinessDayConvention &bdc,
252 const std::vector<Rate> &cStrikes,
253 const std::vector<Rate> &fStrikes,
254 const std::vector<Period> &cfMaturities,
255 const Matrix &cPrice,
256 const Matrix &fPrice,
257 const I2D &interpolator2d,
258 const I1D &interpolator1d)
259 : YoYCapFloorTermPriceSurface(fixingDays, yyLag, yii,
260 baseRate, nominal, dc, cal, bdc,
261 cStrikes, fStrikes, cfMaturities,
262 cPrice, fPrice),
263 interpolator2d_(interpolator2d), interpolator1d_(interpolator1d) {
264 performCalculations();
265 }
266
267 #endif
268
269 template<class I2D, class I1D>
271 update() {
272 notifyObservers();
273 }
274
275
276 template<class I2D, class I1D>
278 performCalculations() const {
279 // calculate all the useful things
280 // ... first the intersection of the cap and floor surfs
281 intersect();
282
283 // ... then the yoy term structure, which requires instruments
284 // and a bootstrap
285 calculateYoYTermStructure();
286 }
287
288
289 template<class I2D, class I1D>
292 const Interpolation2D &a,
293 const Interpolation2D &b)
294 : t_(t), a_(a), b_(b) {
295 // do nothing more
296 }
297
298
299 template<class I2D, class I1D>
301 price(const Date &d, const Rate k) const {
302 Rate atm = atmYoYSwapRate(d);
303 return k > atm ? capPrice(d,k): floorPrice(d,k);
304 }
305
306
307 template<class I2D, class I1D>
309 capPrice(const Date &d, const Rate k) const {
310 Time t = timeFromReference(d);
311 return capPrice_(t,k);
312 }
313
314
315 template<class I2D, class I1D>
317 floorPrice(const Date &d, const Rate k) const {
318 Time t = timeFromReference(d);
319 return floorPrice_(t,k);
320 }
321
322
323 template<class I2D, class I1D>
325 operator()(Rate guess) const {
326 // allow extrapolation because the overlap is typically insufficient
327 // looking for a zero
328 return ( a_(t_,guess,true) - b_(t_,guess,true) );
329 }
330
331
332 template<class I2D, class I1D>
334 intersect() const {
335
336
337 // TODO: define the constants outside the code
338 const Real maxSearchRange = 0.0201;
339 const Real maxExtrapolationMaturity = 5.01;
340 const Real searchStep = 0.0050;
341 const Real intrinsicValueAddOn = 0.001;
342
343 std::vector<bool> validMaturity(cfMaturities_.size(),false);
344
345 cfMaturityTimes_.clear();
346 for (Size i=0; i<cfMaturities_.size();i++) {
349 }
350
351 capPrice_ = interpolator2d_.interpolate(
353 cStrikes_.begin(), cStrikes_.end(),
354 cPrice_
355 );
357
358 floorPrice_ = interpolator2d_.interpolate(
360 fStrikes_.begin(), fStrikes_.end(),
361 fPrice_
362 );
364
365 atmYoYSwapDateRates_.first.clear();
366 atmYoYSwapDateRates_.second.clear();
367 atmYoYSwapTimeRates_.first.clear();
368 atmYoYSwapTimeRates_.second.clear();
369 Brent solver;
370 Real solverTolerance_ = 1e-7;
371 Real lo,hi,guess;
372 std::vector<Real> minSwapRateIntersection(cfMaturityTimes_.size());
373 std::vector<Real> maxSwapRateIntersection(cfMaturityTimes_.size());
374 std::vector<Time> tmpSwapMaturities;
375 std::vector<Rate> tmpSwapRates;
376 for (Size i = 0; i < cfMaturities_.size(); i++) {
377 Time t = cfMaturityTimes_[i];
378 // determine the sum of discount factors
379 Size numYears = (Size)std::lround(t);
380 Real sumDiscount = 0.0;
381 for (Size j=0; j<numYears; ++j)
382 sumDiscount += nominalTS_->discount(j + 1.0);
383 // determine the minimum value of the ATM swap point
384 Real tmpMinSwapRateIntersection = -1.e10;
385 Real tmpMaxSwapRateIntersection = 1.e10;
386 for (Size j=0; j<fStrikes_.size(); ++j) {
388 Real minSwapRate = fStrikes_[j] - price / (sumDiscount * 10000);
389 if (minSwapRate > tmpMinSwapRateIntersection)
390 tmpMinSwapRateIntersection = minSwapRate;
391 }
392 for (Size j=0; j<cStrikes_.size(); ++j) {
394 Real maxSwapRate = cStrikes_[j] + price / (sumDiscount * 10000);
395 if (maxSwapRate < tmpMaxSwapRateIntersection)
396 tmpMaxSwapRateIntersection = maxSwapRate;
397 }
398 maxSwapRateIntersection[i] = tmpMaxSwapRateIntersection;
399 minSwapRateIntersection[i] = tmpMinSwapRateIntersection;
400
401 // find the interval where the intersection lies
402 bool trialsExceeded = false;
403 int numTrials = (int)(maxSearchRange / searchStep);
404 if ( floorPrice_(t,fStrikes_.back()) > capPrice_(t,fStrikes_.back()) ) {
405 int counter = 1;
406 bool stop = false;
407 Real strike = 0.0;
408 while (!stop) {
409 strike = fStrikes_.back() - counter * searchStep;
410 if (floorPrice_(t, strike) < capPrice_(t, strike))
411 stop = true;
412 counter++;
413 if (counter == numTrials + 1) {
414 if (!stop) {
415 stop = true;
416 trialsExceeded = true;
417 }
418 }
419 }
420 lo = strike;
421 hi = strike + searchStep;
422 } else {
423 int counter = 1;
424 bool stop = false;
425 Real strike = 0.0;
426 while (!stop) {
427 strike = fStrikes_.back() + counter * searchStep;
428 if (floorPrice_(t, strike) > capPrice_(t, strike))
429 stop = true;
430 counter++;
431 if (counter == numTrials + 1) {
432 if (!stop) {
433 stop = true;
434 trialsExceeded = true;
435 }
436 }
437 }
438 lo = strike - searchStep;
439 hi = strike;
440 }
441
442 guess = (hi+lo)/2.0;
443 Rate kI = -999.999;
444
445 if (!trialsExceeded) {
446 try{
447 kI = solver.solve( ObjectiveFunction(t, capPrice_, floorPrice_), solverTolerance_, guess, lo, hi );
448 } catch( std::exception &e) {
449 QL_FAIL("cap/floor intersection finding failed at t = " << t << ", error msg: "<< e.what());
450 }
451 // error message if kI is economically nonsensical (only if t is large)
452 if (kI <= minSwapRateIntersection[i]) {
453 if (t > maxExtrapolationMaturity)
454 QL_FAIL("cap/floor intersection finding failed at t = " << t <<
455 ", error msg: intersection value is below the arbitrage free lower bound "
456 << minSwapRateIntersection[i]);
457 }
458 else
459 {
460 tmpSwapMaturities.push_back(t);
461 tmpSwapRates.push_back(kI);
462 validMaturity[i] = true;
463 }
464 }
465 else
466 {
467 // error message if t is too large
468 if (t > maxExtrapolationMaturity)
469 QL_FAIL("cap/floor intersection finding failed at t = " << t <<
470 ", error msg: no interection found inside the admissible range");
471 }
472 }
473
474 // extrapolation of swap rates if necessary
475 //Polynomial2D tmpInterpol;
476 //Interpolation interpol = tmpInterpol.interpolate(tmpSwapMaturities.begin(), tmpSwapMaturities.end(), tmpSwapRates.begin());
477 //interpol.enableExtrapolation();
478 int counter = 0;
479 for (Size i=0; i<cfMaturities_.size(); ++i) {
480 if ( !validMaturity[i] ) {
483 // atmYoYSwapRates_->second.push_back(interpol((*cfMaturities_)[i]));
484 // Heuristic: overwrite the the swap rate with a value that guarantees that the
485 // intrinsic value of all options is lower than the price
486 Real newSwapRate = minSwapRateIntersection[i] + intrinsicValueAddOn;
487 if (newSwapRate > maxSwapRateIntersection[i])
488 newSwapRate = 0.5 * (minSwapRateIntersection[i] + maxSwapRateIntersection[i]);
489 atmYoYSwapTimeRates_.second.push_back(newSwapRate);
490 atmYoYSwapDateRates_.second.push_back(newSwapRate);
491 } else {
492 atmYoYSwapTimeRates_.first.push_back(tmpSwapMaturities[counter]);
493 atmYoYSwapTimeRates_.second.push_back(tmpSwapRates[counter]);
494 atmYoYSwapDateRates_.first.push_back(
496 atmYoYSwapDateRates_.second.push_back(tmpSwapRates[counter]);
497 counter++;
498 }
499 }
500
501 // create the swap curve using the factory
503 interpolator1d_.interpolate(atmYoYSwapTimeRates_.first.begin(),
504 atmYoYSwapTimeRates_.first.end(),
505 atmYoYSwapTimeRates_.second.begin());
506 }
507
508
509 template<class I2D, class I1D>
512
513 // which yoy-swap points to use in building the yoy-fwd curve?
514 // for now pick every year
515 Size nYears = (Size)std::lround(timeFromReference(referenceDate()+cfMaturities_.back()));
516
517 std::vector<ext::shared_ptr<BootstrapHelper<YoYInflationTermStructure> > > YYhelpers;
518 for (Size i=1; i<=nYears; i++) {
519 Date maturity = nominalTS_->referenceDate() + Period(i,Years);
520 Handle<Quote> quote(ext::shared_ptr<Quote>(
521 new SimpleQuote( atmYoYSwapRate( maturity ) )));
522 ext::shared_ptr<BootstrapHelper<YoYInflationTermStructure> >
523 anInstrument(
525 quote, observationLag(), maturity,
527 yoyIndex(), nominalTS_));
528 YYhelpers.push_back (anInstrument);
529 }
530
531 // usually this base rate is known
532 // however for the data to be self-consistent
533 // we pick this as the end of the curve
534 Rate baseYoYRate = atmYoYSwapRate( referenceDate() );
535
536 // Linear is OK because we have every year
537 ext::shared_ptr<PiecewiseYoYInflationCurve<Linear> > pYITS(
539 nominalTS_->referenceDate(),
541 yoyIndex()->interpolated(), baseYoYRate,
542 YYhelpers));
543 pYITS->recalculate();
544 yoy_ = pYITS; // store
545
546 // check that helpers are repriced
547 const Real eps = 1e-5;
548 for (Size i=0; i<YYhelpers.size(); i++) {
550 QL_REQUIRE(fabs(YYhelpers[i]->impliedQuote() - original) <eps,
551 "could not reprice helper "<< i
552 << ", data " << original
553 << ", implied quote " << YYhelpers[i]->impliedQuote()
554 );
555 }
556 }
557
558}
559
560
561#endif
Brent 1-D solver
Definition: brent.hpp:37
calendar class
Definition: calendar.hpp:61
Concrete date class.
Definition: date.hpp:125
day counter class
Definition: daycounter.hpp:44
void enableExtrapolation(bool b=true)
enable extrapolation in subsequent calls
Shared handle to an observable.
Definition: handle.hpp:41
Interface for inflation term structures.
ObjectiveFunction(Time t, const Interpolation2D &, const Interpolation2D &)
Rate atmYoYRate(const Date &d, const Period &obsLag=Period(-1, Days), bool extrapolate=true) const override
Real capPrice(const Date &d, Rate k) const override
Real floorPrice(const Date &d, Rate k) const override
std::pair< std::vector< Date >, std::vector< Rate > > atmYoYSwapDateRates() const override
Rate atmYoYSwapRate(const Date &d, bool extrapolate=true) const override
ext::shared_ptr< YoYInflationTermStructure > YoYTS() const override
derived from yoy swap rates
std::pair< std::vector< Time >, std::vector< Rate > > atmYoYSwapTimeRates() const override
atm yoy swaps from put-call parity on cap/floor data
InterpolatedYoYCapFloorTermPriceSurface(Natural fixingDays, const Period &yyLag, const ext::shared_ptr< YoYInflationIndex > &yii, Rate baseRate, const Handle< YieldTermStructure > &nominal, const DayCounter &dc, const Calendar &cal, const BusinessDayConvention &bdc, const std::vector< Rate > &cStrikes, const std::vector< Rate > &fStrikes, const std::vector< Period > &cfMaturities, const Matrix &cPrice, const Matrix &fPrice, const Interpolator2D &interpolator2d=Interpolator2D(), const Interpolator1D &interpolator1d=Interpolator1D())
Date maxDate() const override
inflation term structure interface
void intersect() const
intersection of cap and floor price surfaces at given strikes
void calculateYoYTermStructure() const
mess of making it, i.e. create instruments from quotes and bootstrap
base class for 2-D interpolations.
base class for 1-D interpolations.
Matrix used in linear algebra.
Definition: matrix.hpp:41
Piecewise year-on-year inflation term structure.
market element returning a stored value
Definition: simplequote.hpp:33
Real solve(const F &f, Real accuracy, Real guess, Real step) const
Definition: solver1d.hpp:84
virtual const Date & referenceDate() const
the date at which discount = 1.0 and/or variance = 0.0
virtual Calendar calendar() const
the calendar used for reference and/or option date calculation
Time timeFromReference(const Date &date) const
date/time conversion
virtual DayCounter dayCounter() const
the day counter used for date/time conversion
Year-on-year inflation-swap bootstrap helper.
Abstract base class, inheriting from InflationTermStructure.
virtual Real price(const Date &d, Rate k) const =0
virtual std::vector< Rate > strikes() const
virtual Rate atmYoYRate(const Date &d, const Period &obsLag=Period(-1, Days), bool extrapolate=true) const =0
virtual std::vector< Rate > floorStrikes() const
virtual ext::shared_ptr< YoYInflationTermStructure > YoYTS() const =0
derived from yoy swap rates
virtual Real capPrice(const Date &d, Rate k) const =0
ext::shared_ptr< YoYInflationIndex > yoyIndex() const
index yoy is based on
std::pair< std::vector< Time >, std::vector< Rate > > atmYoYSwapTimeRates_
virtual BusinessDayConvention businessDayConvention() const
inspectors
virtual std::vector< Period > maturities() const
std::pair< std::vector< Date >, std::vector< Rate > > atmYoYSwapDateRates_
virtual Rate atmYoYSwapRate(const Date &d, bool extrapolate=true) const =0
ext::shared_ptr< YoYInflationTermStructure > yoy_
virtual Real floorPrice(const Date &d, Rate k) const =0
virtual std::pair< std::vector< Date >, std::vector< Rate > > atmYoYSwapDateRates() const =0
virtual std::vector< Rate > capStrikes() const
ext::shared_ptr< YoYInflationIndex > yoyIndex_
virtual std::pair< std::vector< Time >, std::vector< Rate > > atmYoYSwapTimeRates() const =0
atm yoy swaps from put-call parity on cap/floor data
virtual Date yoyOptionDateFromTenor(const Period &p) const
BusinessDayConvention
Business Day conventions.
Real Time
continuous quantity with 1-year units
Definition: types.hpp:62
QL_REAL Real
real number
Definition: types.hpp:50
unsigned QL_INTEGER Natural
positive integer
Definition: types.hpp:43
Real Rate
interest rates
Definition: types.hpp:70
std::size_t Size
size of a container
Definition: types.hpp:58
Definition: any.hpp:35