QuantLib: a free/open-source library for quantitative finance
fully annotated source code - version 1.34
Loading...
Searching...
No Matches
cpicapfloortermpricesurface.hpp
Go to the documentation of this file.
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2010, 2011 Chris Kenyon
5
6 This file is part of QuantLib, a free-software/open-source library
7 for financial quantitative analysts and developers - http://quantlib.org/
8
9 QuantLib is free software: you can redistribute it and/or modify it
10 under the terms of the QuantLib license. You should have received a
11 copy of the license along with this program; if not, please email
12 <quantlib-dev@lists.sf.net>. The license is also available online at
13 <http://quantlib.org/license.shtml>.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the license for more details.
18*/
19
20/*! \file cpicapfloortermpricesurface.hpp
21 \brief cpi inflation cap and floor term price structure.
22*/
23
24#ifndef quantlib_cpi_capfloor_term_price_surface_hpp
25#define quantlib_cpi_capfloor_term_price_surface_hpp
26
32
33
34namespace QuantLib {
35
36 //! Provides cpi cap/floor prices by interpolation and put/call parity (not cap/floor/swap* parity).
37 /*! The inflation index MUST contain a ZeroInflationTermStructure as
38 this is used to create ATM. Unlike YoY price surfaces we
39 assume that 1) an ATM ZeroInflationTermStructure is available
40 and 2) that it is safe to use it. This is supported by the
41 fact that no stripping is required for CPI cap/floors as they
42 only give one flow.
43
44 cpi cap/floors have a single (one) flow (unlike nominal
45 caps) because they observe cumulative inflation up to
46 their maturity. Options are on CPI(T)/CPI(0) but strikes
47 are quoted for yearly average inflation, so require transformation
48 via (1+quote)^T to obtain actual strikes. These are consistent
49 with ZCIIS quoting conventions.
50
51 The observationLag is that for the referenced instrument prices.
52 Strikes are as-quoted not as-used.
53 */
55 public:
58 Real baseRate, // avoids an uncontrolled crash if index has no TS
60 const Calendar& cal, // calendar in index may not be useful
61 const BusinessDayConvention& bdc,
62 const DayCounter& dc,
63 ext::shared_ptr<ZeroInflationIndex> zii,
64 CPI::InterpolationType interpolationType,
66 const std::vector<Rate>& cStrikes,
67 const std::vector<Rate>& fStrikes,
68 const std::vector<Period>& cfMaturities,
69 const Matrix& cPrice,
70 const Matrix& fPrice);
71
72 //! \name InflationTermStructure interface
73 //@{
74 virtual Period observationLag() const;
75 virtual Frequency frequency() const;
76 virtual Date baseDate() const;
77 virtual Rate baseRate() const;
78 //@}
79
80 //! inspectors
81 /*! \note you don't know if price() is a cap or a floor
82 without checking the ZeroInflation ATM level.
83 */
84 //@{
85 virtual Real nominal() const;
87 ext::shared_ptr<ZeroInflationIndex> zeroInflationIndex() const { return zii_; }
88 //@}
89
90 Rate atmRate(Date maturity) const;
91
92 //! \warning you MUST remind the compiler in any descendants with the using:: mechanism
93 //! because you overload the names
94 //! remember that the strikes use the quoting convention
95 //@{
96 virtual Real price(const Period &d, Rate k) const;
97 virtual Real capPrice(const Period &d, Rate k) const;
98 virtual Real floorPrice(const Period &d, Rate k) const;
99 virtual Real price(const Date &d, Rate k) const = 0;
100 virtual Real capPrice(const Date &d, Rate k) const = 0;
101 virtual Real floorPrice(const Date &d, Rate k) const = 0;
102 //@}
103
104 virtual std::vector<Rate> strikes() const {return cfStrikes_;}
105 virtual std::vector<Rate> capStrikes() const {return cStrikes_;}
106 virtual std::vector<Rate> floorStrikes() const {return fStrikes_;}
107 virtual std::vector<Period> maturities() const {return cfMaturities_;}
108
109 virtual const Matrix &capPrices() const { return cPrice_; }
110 virtual const Matrix &floorPrices() const { return fPrice_; }
111
112 virtual Rate minStrike() const {return cfStrikes_.front();};
113 virtual Rate maxStrike() const {return cfStrikes_.back();};
114 virtual Date minDate() const {return referenceDate()+cfMaturities_.front();}// \TODO deal with index interpolation
115 Date maxDate() const override { return referenceDate() + cfMaturities_.back(); }
116 //@}
117
118 virtual Date cpiOptionDateFromTenor(const Period& p) const;
119
120 protected:
121 virtual bool checkStrike(Rate K) {
122 return ( minStrike() <= K && K <= maxStrike() );
123 }
124 virtual bool checkMaturity(const Date& d) {
125 return ( minDate() <= d && d <= maxDate() );
126 }
127
128 ext::shared_ptr<ZeroInflationIndex> zii_;
131 // data
132 std::vector<Rate> cStrikes_;
133 std::vector<Rate> fStrikes_;
134 std::vector<Period> cfMaturities_;
135 mutable std::vector<Real> cfMaturityTimes_;
138 // constructed
139 mutable std::vector<Rate> cfStrikes_;
140 private:
145 };
146
147
148
149 template<class Interpolator2D>
152 public:
154 Rate startRate,
155 const Period &observationLag,
156 const Calendar &cal,
157 const BusinessDayConvention &bdc,
158 const DayCounter &dc,
159 const ext::shared_ptr<ZeroInflationIndex>& zii,
160 CPI::InterpolationType interpolationType,
162 const std::vector<Rate> &cStrikes,
163 const std::vector<Rate> &fStrikes,
164 const std::vector<Period> &cfMaturities,
165 const Matrix &cPrice,
166 const Matrix &fPrice,
167 const Interpolator2D &interpolator2d = Interpolator2D());
168
169 //! \name LazyObject interface
170 //@{
171 void performCalculations() const;
172 //@}
173
174 //! required to allow for method hiding
175 //@{
179 //@}
180
181 //! remember that the strikes use the quoting convention
182 //@{
183 Real price(const Date& d, Rate k) const override;
184 Real capPrice(const Date& d, Rate k) const override;
185 Real floorPrice(const Date& d, Rate k) const override;
186 //@}
187
188 protected:
189
190 // data for surfaces and curve
194 mutable Interpolator2D interpolator2d_;
195 };
196
197
198 // template definitions, for some reason DOXYGEN doesn't like the first one
199
200 #ifndef __DOXYGEN__
201
202 template<class Interpolator2D>
205 Rate startRate,
206 const Period &observationLag,
207 const Calendar &cal,
208 const BusinessDayConvention &bdc,
209 const DayCounter &dc,
210 const ext::shared_ptr<ZeroInflationIndex>& zii,
211 CPI::InterpolationType interpolationType,
213 const std::vector<Rate> &cStrikes,
214 const std::vector<Rate> &fStrikes,
215 const std::vector<Period> &cfMaturities,
216 const Matrix &cPrice,
217 const Matrix &fPrice,
218 const Interpolator2D &interpolator2d)
219 : CPICapFloorTermPriceSurface(nominal, startRate, observationLag, cal, bdc, dc,
220 zii, interpolationType, yts, cStrikes, fStrikes,
221 cfMaturities, cPrice, fPrice),
222 interpolator2d_(interpolator2d) {
224 }
225
226 #endif
227
228 //! set up the interpolations for capPrice_ and floorPrice_
229 //! since we know ATM, and we have single flows,
230 //! we can use put/call parity to extend the surfaces
231 //! across all strikes
232 template<class I2D>
234 performCalculations() const {
235
236 cPriceB_ =
237 Matrix(cfStrikes_.size(), cfMaturities_.size(), Null<Real>());
238 fPriceB_ =
239 Matrix(cfStrikes_.size(), cfMaturities_.size(), Null<Real>());
240
241 Handle<YieldTermStructure> yts = nominalTS_;
242 QL_REQUIRE(!yts.empty(), "Yts is empty!!!");
243
244 for (Size j = 0; j < cfMaturities_.size(); ++j) {
245 Period mat = cfMaturities_[j];
246 Real df = yts->discount(cpiOptionDateFromTenor(mat));
247 Real atm_quote = atmRate(cpiOptionDateFromTenor(mat));
248 Real atm = std::pow(1.0 + atm_quote, mat.length());
249 Real S = atm * df;
250 for (Size i = 0; i < cfStrikes_.size(); ++i) {
251 Real K_quote = cfStrikes_[i];
252 Real K = std::pow(1.0 + K_quote, mat.length());
253 auto close = [k = cfStrikes_[i]](Real x){ return close_enough(x, k); };
254 Size indF = std::find_if(fStrikes_.begin(), fStrikes_.end(), close) - fStrikes_.begin();
255 Size indC = std::find_if(cStrikes_.begin(), cStrikes_.end(), close) - cStrikes_.begin();
256 bool isFloorStrike = indF < fStrikes_.size();
257 bool isCapStrike = indC < cStrikes_.size();
258 if (isFloorStrike) {
259 fPriceB_[i][j] = fPrice_[indF][j];
260 if (!isCapStrike) {
261 cPriceB_[i][j] = fPrice_[indF][j] + S - K * df;
262 }
263 }
264 if (isCapStrike) {
265 cPriceB_[i][j] = cPrice_[indC][j];
266 if (!isFloorStrike) {
267 fPriceB_[i][j] = cPrice_[indC][j] + K * df - S;
268 }
269 }
270 }
271 }
272
273 // check that all cells are filled
274 for (Size i = 0; i < cPriceB_.rows(); ++i) {
275 for (Size j = 0; j < cPriceB_.columns(); ++j) {
276 QL_REQUIRE(cPriceB_[i][j] != Null<Real>(),
277 "InterpolatedCPICapFloorTermPriceSurface: did not "
278 "fill call price matrix at ("
279 << i << "," << j << "), this is unexpected");
280 QL_REQUIRE(fPriceB_[i][j] != Null<Real>(),
281 "InterpolatedCPICapFloorTermPriceSurface: did not "
282 "fill floor price matrix at ("
283 << i << "," << j << "), this is unexpected");
284 }
285 }
286
287 cfMaturityTimes_.clear();
288 for (Size i=0; i<cfMaturities_.size();i++) {
289 cfMaturityTimes_.push_back(timeFromReference(cpiOptionDateFromTenor(cfMaturities_[i])));
290 }
291
292 capPrice_ = interpolator2d_.interpolate(cfMaturityTimes_.begin(),cfMaturityTimes_.end(),
293 cfStrikes_.begin(), cfStrikes_.end(),
294 cPriceB_
295 );
296 capPrice_.enableExtrapolation();
297
298 floorPrice_ = interpolator2d_.interpolate(cfMaturityTimes_.begin(),cfMaturityTimes_.end(),
299 cfStrikes_.begin(), cfStrikes_.end(),
300 fPriceB_
301 );
302 floorPrice_.enableExtrapolation();
303 }
304
305 //! remember that the strike uses the quoting convention
306 template<class I2D>
308 price(const Date &d, Rate k) const {
309
310 Rate atm = atmRate(d);
311 return k > atm ? capPrice(d,k): floorPrice(d,k);
312 }
313
314 //! remember that the strike uses the quoting convention
315 template<class I2D>
317 capPrice(const Date &d, Rate k) const {
318 Time t = timeFromReference(d);
319 return capPrice_(t,k);
320 }
321
322 //! remember that the strike uses the quoting convention
323 template<class I2D>
325 floorPrice(const Date &d, Rate k) const {
326 Time t = timeFromReference(d);
327 return floorPrice_(t,k);
328 }
329
330 // inline definitions
331
333 return observationLag_;
334 }
335
337 return zeroInflationIndex()->frequency();
338 }
339
341 return zeroInflationIndex()->zeroInflationTermStructure()->baseDate();
342 }
343
345 return baseRate_;
346 }
347
349 return nominal_;
350 }
351
354 return bdc_;
355 }
356
357}
358
359#endif
Provides cpi cap/floor prices by interpolation and put/call parity (not cap/floor/swap* parity).
virtual Real price(const Date &d, Rate k) const =0
virtual std::vector< Rate > strikes() const
virtual Date cpiOptionDateFromTenor(const Period &p) const
virtual std::vector< Rate > floorStrikes() const
virtual Real capPrice(const Date &d, Rate k) const =0
virtual std::vector< Period > maturities() const
Date maxDate() const override
the latest date for which the curve can return values
virtual Real capPrice(const Period &d, Rate k) const
ext::shared_ptr< ZeroInflationIndex > zeroInflationIndex() const
ext::shared_ptr< ZeroInflationIndex > zii_
virtual Real floorPrice(const Date &d, Rate k) const =0
virtual Real price(const Period &d, Rate k) const
virtual BusinessDayConvention businessDayConvention() const
virtual Real floorPrice(const Period &d, Rate k) const
virtual std::vector< Rate > capStrikes() const
calendar class
Definition: calendar.hpp:61
Concrete date class.
Definition: date.hpp:125
day counter class
Definition: daycounter.hpp:44
Shared handle to an observable.
Definition: handle.hpp:41
bool empty() const
checks if the contained shared pointer points to anything
Definition: handle.hpp:191
InterpolatedCPICapFloorTermPriceSurface(Real nominal, Rate startRate, const Period &observationLag, const Calendar &cal, const BusinessDayConvention &bdc, const DayCounter &dc, const ext::shared_ptr< ZeroInflationIndex > &zii, CPI::InterpolationType interpolationType, const Handle< YieldTermStructure > &yts, 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())
Real capPrice(const Date &d, Rate k) const override
remember that the strike uses the quoting convention
Real floorPrice(const Date &d, Rate k) const override
remember that the strike uses the quoting convention
Real price(const Date &d, Rate k) const override
remember that the strikes use the quoting convention
base class for 2-D interpolations.
Matrix used in linear algebra.
Definition: matrix.hpp:41
template class providing a null value for a given type.
Definition: null.hpp:76
Integer length() const
Definition: period.hpp:50
Basic term-structure functionality.
virtual const Date & referenceDate() const
the date at which discount = 1.0 and/or variance = 0.0
const DefaultType & t
#define QL_REQUIRE(condition, message)
throw an error if the given pre-condition is not verified
Definition: errors.hpp:117
Date d
Frequency
Frequency of events.
Definition: frequency.hpp:37
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
Real Rate
interest rates
Definition: types.hpp:70
std::size_t Size
size of a container
Definition: types.hpp:58
base classes for inflation indexes
Base classes for inflation term structures.
abstract base classes for 2-D interpolations
base class for 1-D interpolations
Definition: any.hpp:35
bool close(const Quantity &m1, const Quantity &m2, Size n)
Definition: quantity.cpp:163
bool close_enough(const Quantity &m1, const Quantity &m2, Size n)
Definition: quantity.cpp:182
polynomial interpolation in the y-direction, spline interpolation x-direction
InterpolationType
when you observe an index, how do you interpolate between fixings?