Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
interpolatedyoycapfloortermpricesurface.hpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2018 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
19/*! \file qle/termstructures/interpolatedyoycapfloortermpricesurface.hpp
20 \brief Interpolated YoY Inflation Cap floor term price surface -
21 extends QuantLib InterpolatedYoYCapFloorTermPriceSurface to allow
22 choice of termstructure directly from YoY swap quotes or from
23 atm swap quotes stripped from cap/floor price surface
24 \ingroup termstructures
25*/
26
27#ifndef quantext_interpolated_yoy_capfloor_term_pricesurface_hpp
28#define quantext_interpolated_yoy_capfloor_term_pricesurface_hpp
29
30#include <ql/experimental/inflation/yoycapfloortermpricesurface.hpp>
32
33namespace QuantExt {
34using namespace QuantLib;
35
36//! Interpolated YoY Inflation Cap floor term price surface
37/*! \ingroup termstructures */
38template <class Interpolator2D, class Interpolator1D>
40public:
42 const Period& yyLag, // observation lag
43 const QuantLib::ext::shared_ptr<YoYInflationIndex>& yii, Rate baseRate,
44 const Handle<YieldTermStructure>& nominal, const DayCounter& dc,
45 const Calendar& cal, const BusinessDayConvention& bdc,
46 const std::vector<Rate>& cStrikes, const std::vector<Rate>& fStrikes,
47 const std::vector<Period>& cfMaturities, const Matrix& cPrice,
48 const Matrix& fPrice,
49 const Interpolator2D& interpolator2d = Interpolator2D(),
50 const Interpolator1D& interpolator1d = Interpolator1D());
51
52 //! inflation term structure interface
53 //@{
54 virtual Date maxDate() const override { return yoy_->maxDate(); }
55 virtual Date baseDate() const override { return yoy_->baseDate(); }
56 //@}
57 virtual Natural fixingDays() const override { return fixingDays_; }
58
59 //! \name YoYCapFloorTermPriceSurface interface
60 //@{
61 virtual std::pair<std::vector<Time>, std::vector<Rate> > atmYoYSwapTimeRates() const override {
62 return atmYoYSwapTimeRates_;
63 }
64 virtual std::pair<std::vector<Date>, std::vector<Rate> > atmYoYSwapDateRates() const override {
65 return atmYoYSwapDateRates_;
66 }
67 virtual QuantLib::ext::shared_ptr<YoYInflationTermStructure> YoYTS() const override {
68 return yoyIndex_->yoyInflationTermStructure().empty() ? yoy_
69 : yoyIndex_->yoyInflationTermStructure().currentLink();
70 }
71
72 virtual Rate price(const Date& d, const Rate k) const override;
73 virtual Real floorPrice(const Date& d, const Rate k) const override;
74 virtual Real capPrice(const Date& d, const Rate k) const override;
75 virtual Rate atmYoYSwapRate(const Date& d, bool extrapolate = true) const override {
76 return atmYoYSwapRateCurve_(timeFromReference(d), extrapolate);
77 }
78 virtual Rate atmYoYRate(const Date& d, const Period& obsLag = Period(-1, Days), bool extrapolate = true) const override {
79 // work in terms of maturity-of-instruments
80 // so ask for rate with observation lag
81 // Third parameter = force linear interpolation of yoy
82 return yoy_->yoyRate(d, obsLag, false, extrapolate);
83 }
84 //@}
85
86 //! \name LazyObject interface
87 //@{
88 void update() override;
89 void performCalculations() const;
90 //@}
91
92 /* For stripping vols from a surface we need a more dense set of maturities than
93 provided by market data i.e. yearly. This provides the option to update the
94 vector of maturities - the interpoator handles the price */
95 void setMaturities(std::vector<Period>& overrideMaturities) { cfMaturities_ = overrideMaturities; }
96
97protected:
98 // create instruments from quotes and bootstrap
99 void calculateYoYTermStructure() const;
100
101 // data for surfaces and curve
102 mutable Matrix cPriceB_;
103 mutable Matrix fPriceB_;
104 mutable Interpolation2D capPrice_, floorPrice_;
105 mutable Interpolator2D interpolator2d_;
106 mutable Interpolation atmYoYSwapRateCurve_;
107 mutable Interpolator1D interpolator1d_;
108};
109
110namespace detail {
112 explicit CloseEnoughComparator(const Real v) : v_(v) {}
113 bool operator()(const Real w) const { return QuantLib::close_enough(v_, w); }
114 Real v_;
115};
116} // namespace detail
117
118// template definitions
119template <class Interpolator2D, class Interpolator1D>
121 Natural fixingDays, const Period& yyLag, const QuantLib::ext::shared_ptr<YoYInflationIndex>& yii, Rate baseRate,
122 const Handle<YieldTermStructure>& nominal, const DayCounter& dc, const Calendar& cal,
123 const BusinessDayConvention& bdc, const std::vector<Rate>& cStrikes, const std::vector<Rate>& fStrikes,
124 const std::vector<Period>& cfMaturities, const Matrix& cPrice, const Matrix& fPrice,
125 const Interpolator2D& interpolator2d, const Interpolator1D& interpolator1d)
126 : YoYCapFloorTermPriceSurface(fixingDays, yyLag, yii, baseRate, nominal, dc, cal, bdc, cStrikes, fStrikes,
127 cfMaturities, cPrice, fPrice),
128 interpolator2d_(interpolator2d), interpolator1d_(interpolator1d) {
130}
131
132template <class I2D, class I1D> void InterpolatedYoYCapFloorTermPriceSurface<I2D, I1D>::update() { notifyObservers(); }
133
135
136 cfMaturityTimes_.clear();
137 for (Size i = 0; i < cfMaturities_.size(); i++) {
138 cfMaturityTimes_.push_back(timeFromReference(yoyOptionDateFromTenor(cfMaturities_[i])));
139 }
140
141 Interpolation2D capPriceTemp, floorPriceTemp;
142 capPriceTemp = interpolator2d_.interpolate(cfMaturityTimes_.begin(), cfMaturityTimes_.end(), cStrikes_.begin(),
143 cStrikes_.end(), cPrice_);
144 capPriceTemp.enableExtrapolation();
145
146 floorPriceTemp = interpolator2d_.interpolate(cfMaturityTimes_.begin(), cfMaturityTimes_.end(), fStrikes_.begin(),
147 fStrikes_.end(), fPrice_);
148 floorPriceTemp.enableExtrapolation();
149
150 // check if we have a valid yoyTS
151 if (yoyIndex_->yoyInflationTermStructure().empty()) {
152 // create a yoyinflation term structure from put/call parity
153 // find the first overlapping strike
154 std::vector<Real> overlappingStrikes;
155 for (Size i = 0; i < fStrikes_.size(); i++) {
156 for (Size j = 0; j < cStrikes_.size(); j++) {
157 if (fStrikes_[i] == cStrikes_[j]) {
158 overlappingStrikes.push_back(fStrikes_[i]);
159 }
160 }
161 }
162 QL_REQUIRE(overlappingStrikes.size(), "No overlapping strikes between caps and floors for "
163 << "yoycapfloortermpricesurface " << yoyIndex_->name());
164
165 // calculate the yoy termstructure from the first overlapping strike
166 // TODO: extend to use all overlapping strike
167
168 // We can get the 1Y fair swap rate from the zero Inflation curve
169 // If the YoY curve is unavailable, a YoY Index built from a ZeroInflationIndex
170 QuantLib::ext::shared_ptr<YoYInflationIndexWrapper> yiiWrapper =
171 QuantLib::ext::dynamic_pointer_cast<YoYInflationIndexWrapper>(yoyIndex_);
172 QuantLib::ext::shared_ptr<ZeroInflationTermStructure> zeroTs =
173 yiiWrapper->zeroIndex()->zeroInflationTermStructure().currentLink();
174 Real fairSwap1Y = zeroTs->zeroRate(yoyOptionDateFromTenor(Period(1, Years)));
175
176 Real k = Null<Real>();
177 if (fairSwap1Y < overlappingStrikes.back()) {
178 for (Size i = 0; i < overlappingStrikes.size(); i++) {
179 if (overlappingStrikes[i] > fairSwap1Y) {
180 k = overlappingStrikes[i];
181 break;
182 }
183 }
184 } else {
185 k = overlappingStrikes.back();
186 }
187
188 for (Size i = 0; i < cfMaturities_.size(); i++) {
189 Time t = cfMaturityTimes_[i];
190 // determine the sum of discount factors
191 Size numYears = (Size)(t + 0.5);
192 Real fairSwap;
193 if (numYears == 1) {
194 fairSwap = fairSwap1Y;
195 } else {
196 Real sumDiscount = 0.0;
197 for (Size j = 0; j < numYears; ++j)
198 sumDiscount += nominalTS_->discount(j + 1.0);
199
200 Real capPrice = capPriceTemp(t, k);
201 Real floorPrice = floorPriceTemp(t, k);
202
203 fairSwap = ((capPrice - floorPrice) / 10000 + k * sumDiscount) / sumDiscount;
204 }
205
206 atmYoYSwapDateRates_.first.push_back(referenceDate() + cfMaturities_[i]);
207 atmYoYSwapTimeRates_.first.push_back(t);
208 atmYoYSwapTimeRates_.second.push_back(fairSwap);
209 atmYoYSwapDateRates_.second.push_back(fairSwap);
210 }
211
212 atmYoYSwapRateCurve_ = interpolator1d_.interpolate(
213 atmYoYSwapTimeRates_.first.begin(), atmYoYSwapTimeRates_.first.end(), atmYoYSwapTimeRates_.second.begin());
214
215 calculateYoYTermStructure();
216
217 } else {
218 yoy_ = yoyIndex_->yoyInflationTermStructure().currentLink();
219 }
220
221 cPriceB_ = Matrix(cfStrikes_.size(), cfMaturities_.size(), Null<Real>());
222 fPriceB_ = Matrix(cfStrikes_.size(), cfMaturities_.size(), Null<Real>());
223
224 for (Size j = 0; j < cfMaturities_.size(); ++j) {
225 Period mat = cfMaturities_[j];
226
227 Time t = cfMaturityTimes_[j];
228 Size numYears = (Size)(t + 0.5);
229 Real sumDiscount = 0.0;
230 for (Size k = 0; k < numYears; ++k)
231 sumDiscount += nominalTS_->discount(k + 1.0);
232
233 Real S = yoy_->yoyRate(yoyOptionDateFromTenor(mat));
234 for (Size i = 0; i < cfStrikes_.size(); ++i) {
235 Real K = cfStrikes_[i];
236 // Real K = std::pow(1.0 + K_quote, mat.length());
237 Size indF = std::find_if(fStrikes_.begin(), fStrikes_.end(), detail::CloseEnoughComparator(cfStrikes_[i])) -
238 fStrikes_.begin();
239 Size indC = std::find_if(cStrikes_.begin(), cStrikes_.end(), detail::CloseEnoughComparator(cfStrikes_[i])) -
240 cStrikes_.begin();
241 bool isFloorStrike = indF < fStrikes_.size();
242 bool isCapStrike = indC < cStrikes_.size();
243 if (isFloorStrike) {
244 fPriceB_[i][j] = fPrice_[indF][j];
245 if (!isCapStrike) {
246 cPriceB_[i][j] = fPrice_[indF][j] + (S - K) * 10000 * sumDiscount;
247 }
248 }
249 if (isCapStrike) {
250 cPriceB_[i][j] = cPrice_[indC][j];
251 if (!isFloorStrike) {
252 fPriceB_[i][j] = cPrice_[indC][j] - (S - K) * 10000 * sumDiscount;
253 }
254 }
255 }
256 }
257
258 // check that all cells are filled
259 for (Size i = 0; i < cPriceB_.rows(); ++i) {
260 for (Size j = 0; j < cPriceB_.columns(); ++j) {
261 QL_REQUIRE(cPriceB_[i][j] != Null<Real>(), "InterpolatedCPICapFloorTermPriceSurface: did not "
262 "fill call price matrix at ("
263 << i << "," << j << "), this is unexpected");
264 QL_REQUIRE(fPriceB_[i][j] != Null<Real>(), "InterpolatedCPICapFloorTermPriceSurface: did not "
265 "fill floor price matrix at ("
266 << i << "," << j << "), this is unexpected");
267 }
268 }
269
270 capPrice_ = interpolator2d_.interpolate(cfMaturityTimes_.begin(), cfMaturityTimes_.end(), cfStrikes_.begin(),
271 cfStrikes_.end(), cPriceB_);
272 capPrice_.enableExtrapolation();
273
274 floorPrice_ = interpolator2d_.interpolate(cfMaturityTimes_.begin(), cfMaturityTimes_.end(), cfStrikes_.begin(),
275 cfStrikes_.end(), fPriceB_);
276 floorPrice_.enableExtrapolation();
277}
278
279template <class I2D, class I1D>
280Rate InterpolatedYoYCapFloorTermPriceSurface<I2D, I1D>::price(const Date& d, const Rate k) const {
281 Rate atm = atmYoYSwapRate(d);
282 return k > atm ? capPrice(d, k) : floorPrice(d, k);
283}
284
285template <class I2D, class I1D>
286Rate InterpolatedYoYCapFloorTermPriceSurface<I2D, I1D>::capPrice(const Date& d, const Rate k) const {
287 Time t = timeFromReference(d);
288 return std::max(0.0, capPrice_(t, k));
289}
290
291template <class I2D, class I1D>
293 Time t = timeFromReference(d);
294 return std::max(0.0, floorPrice_(t, k));
295}
296
297template <class I2D, class I1D>
299
300 // which yoy-swap points to use in building the yoy-fwd curve?
301 // for now pick every year
302 Size nYears = (Size)(0.5 + timeFromReference(referenceDate() + cfMaturities_.back()));
303
304 Handle<YieldTermStructure> nominalH(nominalTS_);
305 std::vector<QuantLib::ext::shared_ptr<BootstrapHelper<YoYInflationTermStructure> > > YYhelpers;
306 for (Size i = 1; i <= nYears; i++) {
307 Date maturity = nominalTS_->referenceDate() + Period(i, Years);
308 Handle<Quote> quote(QuantLib::ext::shared_ptr<Quote>(new SimpleQuote(atmYoYSwapRate(maturity)))); //!
309 QuantLib::ext::shared_ptr<BootstrapHelper<YoYInflationTermStructure> > anInstrument(new YearOnYearInflationSwapHelper(
310 quote, observationLag(), maturity, calendar(), bdc_, dayCounter(), yoyIndex(), nominalH));
311 YYhelpers.push_back(anInstrument);
312 }
313
314 // usually this base rate is known
315 // however for the data to be self-consistent
316 // we pick this as the end of the curve
317 Rate baseYoYRate = atmYoYSwapRate(referenceDate()); //!
318
319 QuantLib::ext::shared_ptr<PiecewiseYoYInflationCurve<I1D>> pYITS(new PiecewiseYoYInflationCurve<I1D>(
320 nominalTS_->referenceDate(), calendar(), dayCounter(), observationLag(), yoyIndex()->frequency(),
321 yoyIndex()->interpolated(), baseYoYRate, YYhelpers));
322 pYITS->recalculate();
323 yoy_ = pYITS; // store
324
325 // check that helpers are repriced
326 const Real eps = 1e-5;
327 for (Size i = 0; i < YYhelpers.size(); i++) {
328 Rate original = atmYoYSwapRate(yoyOptionDateFromTenor(Period(i + 1, Years)));
329 QL_REQUIRE(fabs(YYhelpers[i]->impliedQuote() - original) < eps,
330 "could not reprice helper " << i << ", data " << original << ", implied quote "
331 << YYhelpers[i]->impliedQuote());
332 }
333}
334
335} // namespace QuantExt
336
337#endif
Interpolated YoY Inflation Cap floor term price surface.
virtual std::pair< std::vector< Time >, std::vector< Rate > > atmYoYSwapTimeRates() const override
virtual Real floorPrice(const Date &d, const Rate k) const override
virtual QuantLib::ext::shared_ptr< YoYInflationTermStructure > YoYTS() const override
virtual Rate atmYoYRate(const Date &d, const Period &obsLag=Period(-1, Days), bool extrapolate=true) const override
virtual Real capPrice(const Date &d, const Rate k) const override
virtual std::pair< std::vector< Date >, std::vector< Rate > > atmYoYSwapDateRates() const override
virtual Rate price(const Date &d, const Rate k) const override
InterpolatedYoYCapFloorTermPriceSurface(Natural fixingDays, const Period &yyLag, const QuantLib::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())
virtual Rate atmYoYSwapRate(const Date &d, bool extrapolate=true) const override
virtual Date maxDate() const override
inflation term structure interface
wrapper classes for inflation yoy and interpolation