Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
inflationcapfloorvolcurve.cpp
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
23
24#include <ql/experimental/inflation/interpolatedyoyoptionletstripper.hpp>
25#include <ql/math/comparison.hpp>
26#include <ql/math/interpolations/bilinearinterpolation.hpp>
28#include <ql/math/matrix.hpp>
29#include <ql/termstructures/volatility/capfloor/capfloortermvolcurve.hpp>
30#include <ql/time/daycounters/actual365fixed.hpp>
31
36
40
41using namespace QuantLib;
42using namespace QuantExt;
43using namespace std;
44
45namespace ore {
46namespace data {
47
49 const Loader& loader, const CurveConfigurations& curveConfigs,
50 map<string, QuantLib::ext::shared_ptr<YieldCurve>>& yieldCurves,
51 map<string, QuantLib::ext::shared_ptr<InflationCurve>>& inflationCurves) {
52 try {
53 const QuantLib::ext::shared_ptr<InflationCapFloorVolatilityCurveConfig>& config =
54 curveConfigs.inflationCapFloorVolCurveConfig(spec.curveConfigID());
55
56 auto it = yieldCurves.find(config->yieldTermStructure());
57 if (it != yieldCurves.end()) {
58 discountCurve_ = it->second->handle();
59 } else {
60 QL_FAIL("The yield term structure, " << config->yieldTermStructure()
61 << ", required in the building "
62 "of the curve, "
63 << spec.name() << ", was not found.");
64 }
65
66 switch (config->quoteType()) {
68 buildFromPrices(asof, spec, loader, config, yieldCurves, inflationCurves);
69 break;
71 buildFromVolatilities(asof, spec, loader, config, yieldCurves, inflationCurves);
72 break;
73 default:
74 QL_FAIL("unexpected quote type");
75 }
76
77 } catch (std::exception& e) {
78 QL_FAIL("inflation cap/floor vol curve building failed :" << e.what());
79 } catch (...) {
80 QL_FAIL("inflation cap/floor vol curve building failed: unknown error");
81 }
82}
83
85 Date asof, InflationCapFloorVolatilityCurveSpec spec, const Loader& loader,
86 const QuantLib::ext::shared_ptr<InflationCapFloorVolatilityCurveConfig>& config,
87 map<string, QuantLib::ext::shared_ptr<YieldCurve>>& yieldCurves,
88 map<string, QuantLib::ext::shared_ptr<InflationCurve>>& inflationCurves) {
89
90 DLOG("Build InflationCapFloorVolCurve " << spec.name() << " from vols");
91
92 // Volatility type
94 VolatilityType quoteVolatilityType;
95
96 switch (config->volatilityType()) {
99 quoteVolatilityType = ShiftedLognormal;
100 break;
103 quoteVolatilityType = Normal;
104 break;
107 quoteVolatilityType = ShiftedLognormal;
108 break;
109 default:
110 QL_FAIL("unexpected volatility type");
111 }
112
113 // Read in quotes matrix
114 DLOG("Read quotes matrix");
115 vector<Period> tenors = parseVectorOfValues<Period>(config->tenors(), &parsePeriod);
116 vector<double> strikes = parseVectorOfValues<Real>(config->strikes(), &parseReal);
117 QL_REQUIRE(!strikes.empty(), "Strikes should not be empty - expect a cap matrix");
118 Matrix vols(tenors.size(), strikes.size());
119 vector<vector<bool>> found(tenors.size(), vector<bool>(strikes.size()));
120 Size remainingQuotes = tenors.size() * strikes.size();
121 Size quotesRead = 0;
122
123 // Quotes index can differ from the index for which we are building the surface.
124 string quoteIndex = config->quoteIndex().empty() ? config->index() : config->quoteIndex();
125
126 // We take the first capfloor shift quote that we find in the file matching the
127 // currency and index tenor
128
129 std::ostringstream ss1;
131 Wildcard w1(ss1.str());
132 auto data1 = loader.get(w1, asof);
133
134 std::ostringstream ss2;
136 Wildcard w2(ss2.str());
137 auto data2 = loader.get(w2, asof);
138
139 data1.merge(data2);
140
141 for (const auto& md : data1) {
142 QL_REQUIRE(md->asofDate() == asof, "MarketDatum asofDate '" << md->asofDate() << "' <> asof '" << asof << "'");
143
144 QuantLib::ext::shared_ptr<InflationCapFloorQuote> q;
145
147 q = QuantLib::ext::dynamic_pointer_cast<ZcInflationCapFloorQuote>(md);
148 } else {
149 q = QuantLib::ext::dynamic_pointer_cast<YyInflationCapFloorQuote>(md);
150 }
151
152 if (q && q->index() == quoteIndex && q->quoteType() == volatilityType) {
153
154 quotesRead++;
155
156 Real strike = parseReal(q->strike());
157 Size i = std::find(tenors.begin(), tenors.end(), q->term()) - tenors.begin();
158 Size j = std::find_if(strikes.begin(), strikes.end(),
159 [&strike](const double& s) { return close_enough(s, strike); }) -
160 strikes.begin();
161
162 if (i < tenors.size() && j < strikes.size()) {
163 vols[i][j] = q->quote()->value();
164
165 if (!found[i][j]) {
166 found[i][j] = true;
167 --remainingQuotes;
168 }
169 }
170 }
171 }
172
173 LOG("InflationCapFloorVolCurve: read " << quotesRead << " vols");
174
175 // Check that we have all the data we need
176 size_t filledValues = 0;
177 if (remainingQuotes != 0) {
178 // Fill missing quotes
179 for (size_t i = 0; i < tenors.size(); ++i) {
180 std::vector<double> xs;
181 std::vector<double> ys;
182 std::vector<size_t> missingIds;
183 for (size_t j = 0; j < strikes.size(); ++j) {
184 if (found[i][j]) {
185 xs.push_back(strikes[j]);
186 ys.push_back(vols[i][j]);
187 } else {
188 missingIds.push_back(j);
189 }
190 }
191 if (!missingIds.empty() && xs.size() >= 1) {
192 if (xs.size() == 1) {
193 xs.push_back(xs.front() + 0.01);
194 ys.push_back(ys.front());
195 }
196 auto interpolation = LinearFlat().interpolate(xs.begin(), xs.end(), ys.begin());
197 for (auto j : missingIds) {
198 auto value = interpolation(strikes[j], true);
199
200 WLOG("vol for cap floor price surface, strike " << strikes[j] << ", term " << tenors[i]
201 << ", not found. Replace NULL with " << value);
202 vols[i][j] = value;
203 filledValues++;
204 }
205 }
206 }
207 }
208
209 if (remainingQuotes - filledValues != 0){
210
211 ostringstream m;
212 m << "Not all quotes found for spec " << spec << endl;
213 if (remainingQuotes != 0) {
214 m << "Found vol data (*) and missing data (.):" << std::endl;
215 for (Size i = 0; i < tenors.size(); ++i) {
216 for (Size j = 0; j < strikes.size(); ++j) {
217 m << (found[i][j] ? "*" : ".");
218 }
219 if (i < tenors.size() - 1)
220 m << endl;
221 }
222 }
223 DLOGGERSTREAM(m.str());
224 QL_FAIL("could not build inflation cap/floor vol curve");
225 }
226
228
229 // Non-ATM cap/floor volatility surface
230 QuantLib::ext::shared_ptr<QuantLib::CapFloorTermVolSurface> capVol =
231 QuantLib::ext::make_shared<QuantLib::CapFloorTermVolSurface>(0, config->calendar(), config->businessDayConvention(),
232 tenors, strikes, vols, config->dayCounter());
233
234 QuantLib::ext::shared_ptr<YoYInflationIndex> index;
235 auto it2 = inflationCurves.find(config->indexCurve());
236 if (it2 != inflationCurves.end()) {
237 QuantLib::ext::shared_ptr<InflationTermStructure> ts = it2->second->inflationTermStructure();
238 // Check if the Index curve is a YoY curve - if not it must be a zero curve
239 QuantLib::ext::shared_ptr<YoYInflationTermStructure> yyTs =
240 QuantLib::ext::dynamic_pointer_cast<YoYInflationTermStructure>(ts);
241 QL_REQUIRE(yyTs, "YoY Inflation curve required for vol surface " << index->name());
242 index = QuantLib::ext::make_shared<QuantExt::YoYInflationIndexWrapper>(
243 parseZeroInflationIndex(config->index(), Handle<ZeroInflationTermStructure>()),
244 true, Handle<YoYInflationTermStructure>(yyTs));
245 }
246
247 QuantLib::ext::shared_ptr<YoYInflationOptionletVolStripper> volStripper =
248 QuantLib::ext::make_shared<YoYInflationOptionletVolStripper>(capVol, index, discountCurve_, quoteVolatilityType);
249 yoyVolSurface_ = volStripper->yoyInflationCapFloorVolSurface();
250
251 } else if (config->type() == InflationCapFloorVolatilityCurveConfig::Type::ZC) {
252
253 DLOG("Building InflationCapFloorVolatilityCurveConfig::Type::ZC");
254 std::vector<std::vector<Handle<Quote>>> quotes(tenors.size(),
255 std::vector<Handle<Quote>>(strikes.size(), Handle<Quote>()));
256 for (Size i = 0; i < tenors.size(); ++i) {
257 for (Size j = 0; j < strikes.size(); ++j) {
258 QuantLib::ext::shared_ptr<SimpleQuote> q(new SimpleQuote(vols[i][j]));
259 quotes[i][j] = Handle<Quote>(q);
260 }
261 }
262
263 DLOG("Building zero inflation index");
264 QuantLib::ext::shared_ptr<ZeroInflationIndex> index;
265 auto it2 = inflationCurves.find(config->indexCurve());
266 if (it2 == inflationCurves.end()) {
267 QL_FAIL("The zero inflation curve, " << config->indexCurve()
268 << ", required in building the inflation cap floor vol surface "
269 << spec.name() << ", was not found");
270 } else {
271 QuantLib::ext::shared_ptr<ZeroInflationTermStructure> ts =
272 QuantLib::ext::dynamic_pointer_cast<ZeroInflationTermStructure>(it2->second->inflationTermStructure());
273 QL_REQUIRE(ts,
274 "inflation term structure " << config->indexCurve() << " was expected to be zero, but is not");
275 index = parseZeroInflationIndex(config->index(), Handle<ZeroInflationTermStructure>(ts));
276 }
277
278 DLOG("Building surface");
279 Date startDate = Date();
280 const QuantLib::ext::shared_ptr<Conventions>& conventions = InstrumentConventions::instance().conventions();
281 bool interpolated = false;
282 if (!config->conventions().empty() && conventions->has(config->conventions())) {
283 QuantLib::ext::shared_ptr<InflationSwapConvention> conv =
284 QuantLib::ext::dynamic_pointer_cast<InflationSwapConvention>(conventions->get(config->conventions()));
285 startDate = getStartAndLag(asof, *conv).first;
286 interpolated = conv->interpolated();
287 }
288
289 cpiVolSurface_ = QuantLib::ext::make_shared<InterpolatedCPIVolatilitySurface<Bilinear>>(
290 tenors, strikes, quotes, index, interpolated, config->settleDays(), config->calendar(),
291 config->businessDayConvention(), config->dayCounter(), config->observationLag(), startDate, Bilinear(),
292 quoteVolatilityType, 0.0);
293 if (config->extrapolate())
294 cpiVolSurface_->enableExtrapolation();
295 DLOG("Building surface done");
296 } else {
297 QL_FAIL("InflationCapFloorVolatilityCurveConfig::Type not covered");
298 }
299}
300
302 const Loader& loader,
303 const QuantLib::ext::shared_ptr<InflationCapFloorVolatilityCurveConfig>& config,
304 map<string, QuantLib::ext::shared_ptr<YieldCurve>>& yieldCurves,
305 map<string, QuantLib::ext::shared_ptr<InflationCurve>>& inflationCurves) {
306
307 DLOG("Build InflationCapFloorVolCurve " << spec.name() << " from prices");
308
309 QL_REQUIRE((config->type() == InflationCapFloorVolatilityCurveConfig::Type::ZC) ||
311 "Inflation cap floor pricevolatility surfaces must be of type 'ZC' or 'YY'");
312
313 // Volatility type
314 VolatilityType quoteVolatilityType;
315
316 switch (config->volatilityType()) {
318 quoteVolatilityType = ShiftedLognormal;
319 break;
321 quoteVolatilityType = Normal;
322 break;
324 quoteVolatilityType = ShiftedLognormal;
325 break;
326 default:
327 QL_FAIL("unexpected volatility type: '" << config->volatilityType() << "'");
328 }
329
330 // Required by QuantLib price surface constructors but apparently not used
331 std::vector<Period> terms = parseVectorOfValues<Period>(config->tenors(), &parsePeriod);
332 std::vector<Real> capStrikes = parseVectorOfValues<Real>(config->capStrikes(), &parseReal);
333 std::vector<Real> floorStrikes = parseVectorOfValues<Real>(config->floorStrikes(), &parseReal);
334
335 Matrix cPrice(capStrikes.size(), capStrikes.size() == 0 ? 0 : terms.size(), Null<Real>()),
336 fPrice(floorStrikes.size(), floorStrikes.size() == 0 ? 0 : terms.size(), Null<Real>());
337
338 // Quotes index can differ from the index for which we are building the surface.
339 string quoteIndex = config->quoteIndex().empty() ? config->index() : config->quoteIndex();
340
341 // We loop over all market data, looking for quotes that match the configuration
342
343 std::ostringstream ss1;
345 Wildcard w1(ss1.str());
346 auto data1 = loader.get(w1, asof);
347
348 std::ostringstream ss2;
350 Wildcard w2(ss2.str());
351 auto data2 = loader.get(w2, asof);
352
353 data1.merge(data2);
354
355 for (const auto& md : data1) {
356 QL_REQUIRE(md->asofDate() == asof, "MarketDatum asofDate '" << md->asofDate() << "' <> asof '" << asof << "'");
357
358 QuantLib::ext::shared_ptr<InflationCapFloorQuote> q;
359
361 q = QuantLib::ext::dynamic_pointer_cast<ZcInflationCapFloorQuote>(md);
362 } else {
363 q = QuantLib::ext::dynamic_pointer_cast<YyInflationCapFloorQuote>(md);
364 }
365
366 if (q && q->index() == quoteIndex && md->quoteType() == MarketDatum::QuoteType::PRICE) {
367 auto it1 = std::find(terms.begin(), terms.end(), q->term());
368 Real strike = parseReal(q->strike());
369 Size strikeIdx = Null<Size>();
370 if (q->isCap()) {
371 for (Size i = 0; i < capStrikes.size(); ++i) {
372 if (close_enough(capStrikes[i], strike))
373 strikeIdx = i;
374 }
375 } else {
376 for (Size i = 0; i < floorStrikes.size(); ++i) {
377 if (close_enough(floorStrikes[i], strike))
378 strikeIdx = i;
379 }
380 }
381 if (it1 != terms.end() && strikeIdx != Null<Size>()) {
382 if (q->isCap()) {
383 cPrice[strikeIdx][it1 - terms.begin()] = q->quote()->value();
384 } else {
385 fPrice[strikeIdx][it1 - terms.begin()] = q->quote()->value();
386 }
387 }
388 }
389 }
390
391 ostringstream capStrikesString, floorStrikesString;
392 for (Size i = 0; i < floorStrikes.size(); ++i)
393 floorStrikesString << floorStrikes[i] << ",";
394 for (Size i = 0; i < capStrikes.size(); ++i)
395 capStrikesString << capStrikes[i] << ",";
396 DLOG("Building inflation cap floor price surface:");
397 DLOG("Cap Strikes are: " << capStrikesString.str());
398 DLOG("Floor Strikes are: " << floorStrikesString.str());
399 DLOGGERSTREAM("Cap Price Matrix:\n" << cPrice << "Floor Price Matrix:\n" << fPrice);
400
402 // ZC Curve
403 QuantLib::ext::shared_ptr<ZeroInflationIndex> index;
404 auto it2 = inflationCurves.find(config->indexCurve());
405 if (it2 == inflationCurves.end()) {
406 QL_FAIL("The zero inflation curve, " << config->indexCurve()
407 << ", required in building the inflation cap floor price surface "
408 << spec.name() << ", was not found");
409 } else {
410 QuantLib::ext::shared_ptr<ZeroInflationTermStructure> ts =
411 QuantLib::ext::dynamic_pointer_cast<ZeroInflationTermStructure>(it2->second->inflationTermStructure());
412 QL_REQUIRE(ts,
413 "inflation term structure " << config->indexCurve() << " was expected to be zero, but is not");
414 index = parseZeroInflationIndex(config->index(), Handle<ZeroInflationTermStructure>(ts));
415 }
416 QuantLib::ext::shared_ptr<QuantExt::CPICapFloorEngine> engine;
417
418 bool isLogNormalVol = quoteVolatilityType == QuantLib::ShiftedLognormal;
419
420 if (isLogNormalVol) {
421 engine = QuantLib::ext::make_shared<QuantExt::CPIBlackCapFloorEngine>(
422 discountCurve_, QuantLib::Handle<QuantLib::CPIVolatilitySurface>(),
423 config->useLastAvailableFixingDate());
424 } else {
425 engine = QuantLib::ext::make_shared<QuantExt::CPIBachelierCapFloorEngine>(
426 discountCurve_, QuantLib::Handle<QuantLib::CPIVolatilitySurface>(),
427 config->useLastAvailableFixingDate());
428 }
429
430 try {
431 const QuantLib::ext::shared_ptr<Conventions>& conventions = InstrumentConventions::instance().conventions();
432 Date startDate = Date();
433 bool interpolated = false;
434 if (!config->conventions().empty() && conventions->has(config->conventions())) {
435 QuantLib::ext::shared_ptr<InflationSwapConvention> conv =
436 QuantLib::ext::dynamic_pointer_cast<InflationSwapConvention>(conventions->get(config->conventions()));
437 startDate = getStartAndLag(asof, *conv).first;
438 interpolated = conv->interpolated();
439 }
440 QuantLib::ext::shared_ptr<QuantExt::CPIPriceVolatilitySurface<Linear, Linear>> cpiCapFloorVolSurface;
441
442 // We ignore missing prices and convert all available prices to vols and interpolate misisng vols linear and
443 // extrapolate them flat
444 bool ignoreMissingPrices = true;
445
446 cpiCapFloorVolSurface = QuantLib::ext::make_shared<QuantExt::CPIPriceVolatilitySurface<Linear, Linear>>(
447 QuantExt::PriceQuotePreference::CapFloor, config->observationLag(), config->calendar(),
448 config->businessDayConvention(), config->dayCounter(), index, discountCurve_, capStrikes, floorStrikes,
449 terms, cPrice, fPrice, engine, interpolated, startDate, ignoreMissingPrices, true, true,
453
454 // cast
455 cpiVolSurface_ = cpiCapFloorVolSurface;
456
457 cpiVolSurface_->enableExtrapolation();
458
459 for (Size i = 0; i < cpiCapFloorVolSurface->strikes().size(); ++i) {
460 for (Size j = 0; j < cpiCapFloorVolSurface->maturities().size(); ++j) {
461 DLOG("Implied CPI CapFloor BlackVol,strike," << cpiCapFloorVolSurface->strikes()[i] << ",maturity,"
462 << cpiCapFloorVolSurface->maturities()[j] << ",index,"
463 << index->name() << ",Vol,"
464 << cpiCapFloorVolSurface->volData()[i][j]);
465 if (cpiCapFloorVolSurface->missingValues()[i][j]) {
466 WLOG("Implied CPI CapFloor Surface, price misisng for strike "
467 << cpiCapFloorVolSurface->strikes()[i] << ", maturity, "
468 << cpiCapFloorVolSurface->maturities()[j] << ",index," << index->name()
469 << ", ignore missing point and try interpolate the missing vol.")
470 }
471 if (cpiCapFloorVolSurface->pricesFailedToConvert()[i][j]) {
472 WLOG("Implied CPI CapFloor Surface, couldn't imply vol from price for strike "
473 << cpiCapFloorVolSurface->strikes()[i] << ", maturity, "
474 << cpiCapFloorVolSurface->maturities()[j] << ",index," << index->name()
475 << "ignore missing point and try to interpolate the missing vol.");
476 }
477 }
478 }
479 DLOG("CPIVolSurfaces built for spec " << spec.name());
480 } catch (std::exception& e) {
481 QL_FAIL("Building CPIVolSurfaces failed for spec " << spec.name() << ": " << e.what());
482 }
483 }
485
486 for (Size j = 0; j < terms.size(); ++j) {
487 for (Size i = 0; i < capStrikes.size(); ++i)
488 QL_REQUIRE(cPrice[i][j] != Null<Real>(), "quote for cap floor price surface, type cap, strike "
489 << capStrikes[i] << ", term " << terms[j]
490 << ", not found.");
491 for (Size i = 0; i < floorStrikes.size(); ++i)
492 QL_REQUIRE(fPrice[i][j] != Null<Real>(), "quote for cap floor price surface, type floor, strike "
493 << floorStrikes[i] << ", term " << terms[j]
494 << ", not found.");
495 }
496
497 // The strike grids have some minimum requirements which we fulfill here at
498 // least technically; note that the extrapolated prices will not be sensible,
499 // instead only the given strikes for the given option type may be sensible
500 // in the end
501
502 static const Real largeStrike = 1.0;
503 static const Real largeStrikeFactor = 0.99;
504
505 Size addFloor = 0, addCap = 0;
506 if (floorStrikes.size() == 0) {
507 floorStrikes.push_back(-largeStrike);
508 floorStrikes.push_back(-(largeStrike * largeStrikeFactor));
509 addFloor = 2;
510 }
511 if (floorStrikes.size() == 1) {
512 floorStrikes.insert(floorStrikes.begin(), -largeStrike);
513 addFloor = 1;
514 }
515 if (capStrikes.size() == 0) {
516 capStrikes.push_back(largeStrike * largeStrikeFactor);
517 capStrikes.push_back(largeStrike);
518 addCap = 2;
519 }
520 if (capStrikes.size() == 1) {
521 capStrikes.push_back(largeStrike);
522 addCap = 1;
523 }
524 if (addFloor > 0) {
525 Matrix tmp(fPrice.rows() + addFloor, terms.size(), 1E-10);
526 for (Size i = addFloor; i < fPrice.rows() + addFloor; ++i) {
527 for (Size j = 0; j < fPrice.columns(); ++j) {
528 tmp[i][j] = fPrice[i - addFloor][j];
529 }
530 }
531 fPrice = tmp;
532 }
533 if (addCap > 0) {
534 Matrix tmp(cPrice.rows() + addCap, terms.size(), 1E-10);
535 for (Size i = 0; i < cPrice.rows(); ++i) {
536 for (Size j = 0; j < cPrice.columns(); ++j) {
537 tmp[i][j] = cPrice[i][j];
538 }
539 }
540 cPrice = tmp;
541 }
542
543 QuantLib::ext::shared_ptr<YoYInflationIndex> index;
544 auto it2 = inflationCurves.find(config->indexCurve());
545 if (it2 == inflationCurves.end()) {
546 QL_FAIL("The inflation curve, " << config->indexCurve()
547 << ", required in building the inflation cap floor price surface "
548 << spec.name() << ", was not found");
549 } else {
550 QuantLib::ext::shared_ptr<InflationTermStructure> ts = it2->second->inflationTermStructure();
551 // Check if the Index curve is a YoY curve - if not it must be a zero curve
552 QuantLib::ext::shared_ptr<YoYInflationTermStructure> yyTs =
553 QuantLib::ext::dynamic_pointer_cast<YoYInflationTermStructure>(ts);
554
555 if (yyTs) {
556 useMarketYoyCurve_ = true;
557 index = QuantLib::ext::make_shared<QuantExt::YoYInflationIndexWrapper>(
558 parseZeroInflationIndex(config->index(), Handle<ZeroInflationTermStructure>()),
559 true, Handle<YoYInflationTermStructure>(yyTs));
560 } else {
561 useMarketYoyCurve_ = false;
562 QuantLib::ext::shared_ptr<ZeroInflationTermStructure> zeroTs =
563 QuantLib::ext::dynamic_pointer_cast<ZeroInflationTermStructure>(ts);
564 QL_REQUIRE(zeroTs,
565 "Inflation term structure " << config->indexCurve() << "must be of type YoY or Zero");
566 index = QuantLib::ext::make_shared<QuantExt::YoYInflationIndexWrapper>(
567 parseZeroInflationIndex(config->index(), Handle<ZeroInflationTermStructure>(zeroTs)),
568 true, Handle<YoYInflationTermStructure>());
569 }
570 }
571 // Required by the QL pricesurface but not used
572 Rate startRate = 0.0;
573 // Build the term structure
574 QuantLib::ext::shared_ptr<QuantExt::InterpolatedYoYCapFloorTermPriceSurface<QuantLib::Bilinear, QuantLib::Linear>>
575 yoySurface = QuantLib::ext::make_shared<
577 0, config->observationLag(), index, startRate, discountCurve_, config->dayCounter(), config->calendar(),
578 config->businessDayConvention(), capStrikes, floorStrikes, terms, cPrice, fPrice);
579
580 std::vector<Period> optionletTerms = {yoySurface->maturities().front()};
581 while (optionletTerms.back() != terms.back()) {
582 optionletTerms.push_back(optionletTerms.back() + Period(1, Years));
583 }
584 yoySurface->setMaturities(optionletTerms);
585 surface_ = yoySurface;
586
587 QuantLib::ext::shared_ptr<InterpolatedYoYOptionletStripper<QuantLib::Linear>> yoyStripper =
588 QuantLib::ext::make_shared<InterpolatedYoYOptionletStripper<QuantLib::Linear>>();
589
590 // Create an empty volatility surface to pass to the engine
591 QuantLib::ext::shared_ptr<QuantLib::YoYOptionletVolatilitySurface> ovs =
592 QuantLib::ext::dynamic_pointer_cast<QuantLib::YoYOptionletVolatilitySurface>(
593 QuantLib::ext::make_shared<QuantLib::ConstantYoYOptionletVolatility>(
594 0.0, yoySurface->settlementDays(), yoySurface->calendar(), yoySurface->businessDayConvention(),
595 yoySurface->dayCounter(), yoySurface->observationLag(), yoySurface->frequency(),
596 yoySurface->indexIsInterpolated()));
597 Handle<QuantLib::YoYOptionletVolatilitySurface> hovs(ovs);
598
599 // create a yoy Index from the surfaces termstructure
600 yoyTs_ = yoySurface->YoYTS();
601 QuantLib::ext::shared_ptr<YoYInflationIndex> yoyIndex = index->clone(Handle<YoYInflationTermStructure>(yoyTs_));
602
603 QuantLib::ext::shared_ptr<YoYInflationBachelierCapFloorEngine> cfEngine =
604 QuantLib::ext::make_shared<YoYInflationBachelierCapFloorEngine>(yoyIndex, hovs, discountCurve_);
605
606 yoyVolSurface_ = QuantLib::ext::make_shared<QuantExt::KInterpolatedYoYOptionletVolatilitySurface<Linear>>(
607 yoySurface->settlementDays(), yoySurface->calendar(), yoySurface->businessDayConvention(),
608 yoySurface->dayCounter(), yoySurface->observationLag(), yoySurface, cfEngine, yoyStripper, 0, Linear(),
609 VolatilityType::Normal);
610 }
611}
612
613} // namespace data
614} // namespace ore
void setMaturities(std::vector< Period > &overrideMaturities)
Interpolation interpolate(const I1 &xBegin, const I1 &xEnd, const I2 &yBegin) const
Container class for all Curve Configurations.
const std::string & curveConfigID() const
Definition: curvespec.hpp:83
string name() const
returns the unique curve name
Definition: curvespec.hpp:78
QuantLib::ext::shared_ptr< InflationTermStructure > surface_
const InflationCapFloorVolatilityCurveSpec & spec() const
void buildFromVolatilities(Date asof, InflationCapFloorVolatilityCurveSpec spec, const Loader &loader, const QuantLib::ext::shared_ptr< InflationCapFloorVolatilityCurveConfig > &config, map< string, QuantLib::ext::shared_ptr< YieldCurve > > &yieldCurves, map< string, QuantLib::ext::shared_ptr< InflationCurve > > &inflationCurves)
void buildFromPrices(Date asof, InflationCapFloorVolatilityCurveSpec spec, const Loader &loader, const QuantLib::ext::shared_ptr< InflationCapFloorVolatilityCurveConfig > &config, map< string, QuantLib::ext::shared_ptr< YieldCurve > > &yieldCurves, map< string, QuantLib::ext::shared_ptr< InflationCurve > > &inflationCurves)
QuantLib::ext::shared_ptr< QuantExt::YoYOptionletVolatilitySurface > yoyVolSurface_
QuantLib::ext::shared_ptr< YoYInflationTermStructure > yoyTs_
QuantLib::ext::shared_ptr< QuantLib::CPIVolatilitySurface > cpiVolSurface_
Inflation cap floor volatility description.
Definition: curvespec.hpp:331
Market data loader base class.
Definition: loader.hpp:47
virtual QuantLib::ext::shared_ptr< MarketDatum > get(const std::string &name, const QuantLib::Date &d) const
get quote by its unique name, throws if not existent, override in derived classes for performance
Definition: loader.cpp:24
QuoteType
Supported market quote types.
SafeStack< ValueType > value
QuantLib::ext::shared_ptr< ZeroInflationIndex > parseZeroInflationIndex(const string &s, const Handle< ZeroInflationTermStructure > &h)
Convert std::string to QuantLib::ZeroInflationIndex.
Period parsePeriod(const string &s)
Convert text to QuantLib::Period.
Definition: parsers.cpp:171
Real parseReal(const string &s)
Convert text to Real.
Definition: parsers.cpp:112
Map text representations to QuantLib/QuantExt types.
Wrapper class for building YoY Inflation CapFloor volatility structures.
Classes and functions for log message handling.
@ data
Definition: log.hpp:77
#define LOG(text)
Logging Macro (Level = Notice)
Definition: log.hpp:552
#define DLOG(text)
Logging Macro (Level = Debug)
Definition: log.hpp:554
#define WLOG(text)
Logging Macro (Level = Warning)
Definition: log.hpp:550
#define DLOGGERSTREAM(text)
Definition: log.hpp:632
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
VolatilityType volatilityType(CapFloorVolatilityCurveConfig::VolatilityType type)
Imply QuantLib::VolatilityType from CapFloorVolatilityCurveConfig::VolatilityType.
std::pair< QuantLib::Date, QuantLib::Period > getStartAndLag(const QuantLib::Date &asof, const InflationSwapConvention &conv)
Serializable Credit Default Swap.
Definition: namespaces.docs:23
static constexpr QuantLib::Real upperVolBound
static constexpr QuantLib::Real lowerVolBound
static constexpr QuantLib::Real solverTolerance
vector< Real > strikes
vector< string > curveConfigs