23#ifndef quantext_stripped_cpi_volatility_structure_hpp
24#define quantext_stripped_cpi_volatility_structure_hpp
27#include <ql/experimental/inflation/cpicapfloortermpricesurface.hpp>
28#include <ql/math/solvers1d/brent.hpp>
65 const QuantLib::Handle<QuantLib::CPICapFloorTermPriceSurface>& priceSurface,
66 const QuantLib::ext::shared_ptr<QuantLib::ZeroInflationIndex>& zeroIndex,
67 const QuantLib::ext::shared_ptr<QuantExt::CPICapFloorEngine>& engine,
72 const Interpolator2D& interpolator2d = Interpolator2D(),
73 const QuantLib::VolatilityType& volType = QuantLib::ShiftedLognormal,
77 PriceQuotePreference type,
const QuantLib::Handle<QuantLib::CPICapFloorTermPriceSurface>& priceSurface,
78 const QuantLib::ext::shared_ptr<QuantLib::ZeroInflationIndex>& zeroIndex,
79 const bool quotedPricesUseInterpolatedCPIFixings,
80 const QuantLib::ext::shared_ptr<QuantExt::CPICapFloorEngine>& engine,
const QuantLib::Date&
capFloorStartDate = Date(),
84 const Interpolator2D& interpolator2d = Interpolator2D(),
85 const QuantLib::VolatilityType& volType = QuantLib::ShiftedLognormal,
const double displacement = 0.0);
95 QuantLib::Real
minStrike()
const override;
97 QuantLib::Real
maxStrike()
const override;
99 QuantLib::Date
maxDate()
const override;
108 QuantLib::Real
atmStrike(
const QuantLib::Date& maturity,
109 const QuantLib::Period& obsLag = QuantLib::Period(-1, QuantLib::Days))
const override;
112 QuantLib::Volatility
volatilityImpl(QuantLib::Time length, QuantLib::Rate strike)
const override;
114 bool chooseFloor(QuantLib::Real strike, QuantLib::Real atmRate)
const;
119 ObjectiveFunction(QuantLib::Real priceToMatch,
bool useFloor, QuantLib::Real strike, QuantLib::Date startDate,
120 QuantLib::Date maturityDate, QuantLib::Real baseCPI,
121 QuantLib::Handle<QuantLib::CPICapFloorTermPriceSurface> priceSurface,
122 const QuantLib::ext::shared_ptr<QuantLib::ZeroInflationIndex>& zeroIndex,
123 const QuantLib::ext::shared_ptr<QuantExt::CPICapFloorEngine>& engine,
124 const CPI::InterpolationType interpolationType);
126 QuantLib::Real
operator()(QuantLib::Volatility guess)
const;
135 QuantLib::ext::shared_ptr<QuantLib::ZeroInflationIndex>
index_;
136 QuantLib::ext::shared_ptr<QuantExt::CPICapFloorEngine>
engine_;
145 QuantLib::ext::shared_ptr<QuantLib::ZeroInflationIndex>
index_;
146 QuantLib::ext::shared_ptr<QuantExt::CPICapFloorEngine>
engine_;
156 mutable QuantLib::Interpolation2D
vols_;
160template <
class Interpolator2D>
162 PriceQuotePreference type,
const QuantLib::Handle<QuantLib::CPICapFloorTermPriceSurface>& priceSurface,
163 const QuantLib::ext::shared_ptr<QuantLib::ZeroInflationIndex>& index,
const bool quotedPriceUseInterpolatedCPIFixing,
164 const QuantLib::ext::shared_ptr<QuantExt::CPICapFloorEngine>& engine,
165 const QuantLib::Date& capFloorStartDate,
const QuantLib::Real& upperVolBound,
const QuantLib::Real& lowerVolBound,
166 const QuantLib::Real& solverTolerance,
167 const Interpolator2D& interpolator2d,
const QuantLib::VolatilityType& volType,
168 const double displacement)
170 priceSurface->businessDayConvention(), priceSurface->dayCounter(),
171 priceSurface->observationLag(), index->frequency(),
172 quotedPriceUseInterpolatedCPIFixing,
173 capFloorStartDate, volType, displacement),
174 preference_(type), priceSurface_(priceSurface), index_(index),
engine_(engine), upperVolBound_(upperVolBound),
175 lowerVolBound_(lowerVolBound), solverTolerance_(solverTolerance), interpolator2d_(interpolator2d) {
180QL_DEPRECATED_DISABLE_WARNING
181template <
class Interpolator2D>
183 PriceQuotePreference type,
const QuantLib::Handle<QuantLib::CPICapFloorTermPriceSurface>& priceSurface,
184 const QuantLib::ext::shared_ptr<QuantLib::ZeroInflationIndex>& index,
185 const QuantLib::ext::shared_ptr<QuantExt::CPICapFloorEngine>& engine,
186 const QuantLib::Date& capFloorStartDate,
const QuantLib::Real& upperVolBound,
const QuantLib::Real& lowerVolBound,
187 const QuantLib::Real& solverTolerance,
const Interpolator2D& interpolator2d,
188 const QuantLib::VolatilityType& volType,
const double displacement)
190 type, priceSurface, index, index->interpolated(), engine, capFloorStartDate, upperVolBound, lowerVolBound,
191 solverTolerance, interpolator2d, volType, displacement) {}
192QL_DEPRECATED_ENABLE_WARNING
195 strikes_ = priceSurface_->strikes();
196 maturities_ = priceSurface_->maturities();
197 volData_ = QuantLib::Matrix(strikes_.size(), maturities_.size(), QuantLib::Null<QuantLib::Real>());
198 QuantLib::Brent solver;
199 QuantLib::Real guess = (upperVolBound_ + lowerVolBound_) / 2.0;
200 QuantLib::Date startDate = capFloorStartDate();
201 QuantLib::Date underlyingBaseDate =
204 for (QuantLib::Size i = 0; i < strikes_.size(); i++) {
205 for (QuantLib::Size j = 0; j < maturities_.size(); j++) {
207 QuantLib::Date maturityDate = optionDateFromTenor(maturities_[j]);
208 QuantLib::Date fixDate =
212 Time timeToMaturity = dayCounter().yearFraction(underlyingBaseDate, fixDate);
213 QuantLib::Real atmRate = std::pow(I1 / baseCPI, 1 / timeToMaturity) - 1.0;
215 bool useFloor = chooseFloor(strikes_[i], atmRate);
218 QuantLib::Real priceToMatch = useFloor ? priceSurface_->floorPrice(maturities_[j], strikes_[i])
219 : priceSurface_->capPrice(maturities_[j], strikes_[i]);
221 auto interpolationType =
222 indexIsInterpolated() ? CPI::InterpolationType::Linear : CPI::InterpolationType::Flat;
223 ObjectiveFunction func(priceToMatch, useFloor, strikes_[i], startDate, maturityDate, baseCPI,
224 priceSurface_, index_,
engine_, interpolationType);
225 QuantLib::Real found = solver.solve(func, solverTolerance_, guess, lowerVolBound_, upperVolBound_);
226 volData_[i][j] = found;
227 }
catch (std::exception& e) {
228 QL_FAIL(
"failed to find implied vol for "
229 << (useFloor ?
"Floor" :
"Cap") <<
" with strike " << strikes_[i] <<
" and maturity "
230 << maturities_[j] <<
", because: " << e.what() <<
" "
231 << QuantLib::io::iso_date(startDate + maturities_[j]) <<
" " << maturityDate);
236 maturityTimes_.clear();
237 for (QuantLib::Size i = 0; i < maturities_.size(); i++) {
238 QuantLib::Date d = optionDateFromTenor(maturities_[i]);
239 maturityTimes_.push_back(fixingTime(d));
242 vols_ = interpolator2d_.interpolate(maturityTimes_.begin(), maturityTimes_.end(), strikes_.begin(), strikes_.end(),
244 vols_.enableExtrapolation();
247template <
class Interpolator2D>
249 if (preference_ ==
Floor) {
250 if (strike <= priceSurface_->floorStrikes().back())
256 if (preference_ ==
Cap) {
257 if (strike < priceSurface_->capStrikes().front())
267 if (strike <= priceSurface_->floorStrikes().back() && strike < priceSurface_->capStrikes().front())
270 else if (strike > priceSurface_->floorStrikes().back() && strike >= priceSurface_->capStrikes().front())
273 else if (strike <= priceSurface_->floorStrikes().back() && strike >= priceSurface_->capStrikes().front()) {
275 if (strike < atmRate)
281 }
else if (strike > priceSurface_->floorStrikes().back() && strike < priceSurface_->capStrikes().front()) {
283 if (strike < atmRate)
288 QL_FAIL(
"case not covered in StrippedCPIVolatilitySurface: strike="
289 << strike <<
" maxFloorStrike=" << priceSurface_->floorStrikes().back()
290 <<
" minCapStrike=" << priceSurface_->capStrikes().front() <<
" atm=" << atmRate);
296 return strikes_.front() - QL_EPSILON;
300 return strikes_.back() + QL_EPSILON;
304 QuantLib::Date today = QuantLib::Settings::instance().evaluationDate();
305 return today + maturities_.back();
308template <
class Interpolator2D>
310 QuantLib::Rate strike)
const {
311 return vols_(length, strike);
314template <
class Interpolator2D>
316 QuantLib::Real priceToMatch,
bool useFloor, QuantLib::Real strike, QuantLib::Date startDate,
317 QuantLib::Date maturityDate, QuantLib::Real baseCPI,
318 QuantLib::Handle<QuantLib::CPICapFloorTermPriceSurface> priceSurface,
319 const QuantLib::ext::shared_ptr<QuantLib::ZeroInflationIndex>& zeroIndex,
320 const QuantLib::ext::shared_ptr<QuantExt::CPICapFloorEngine>& engine,
const CPI::InterpolationType interpolationType)
321 : priceToMatch_(priceToMatch), useFloor_(useFloor), strike_(strike), startDate_(startDate),
322 maturityDate_(maturityDate), baseCPI_(baseCPI), priceSurface_(priceSurface), index_(zeroIndex),
engine_(engine),
323 interpolationType_(interpolationType),
326 startDate_, baseCPI_, maturityDate_, priceSurface_->calendar(),
327 priceSurface_->businessDayConvention(), priceSurface_->calendar(),
328 priceSurface_->businessDayConvention(), strike_, index_,
329 priceSurface_->observationLag(), interpolationType)) {
336template <
class Interpolator2D>
340 QL_DEPRECATED_DISABLE_WARNING
341 bool isInterpolated = interpolationType_ == CPI::InterpolationType::Linear ||
342 (interpolationType_ == CPI::InterpolationType::AsIndex &&
index_->interpolated());
343 QL_DEPRECATED_ENABLE_WARNING
345 QuantLib::ext::shared_ptr<QuantExt::ConstantCPIVolatility> vol = QuantLib::ext::make_shared<QuantExt::ConstantCPIVolatility>(
350 engine_->setVolatility(QuantLib::Handle<QuantLib::CPIVolatilitySurface>(vol));
352 QuantLib::Real npv = cpiCapFloor_.NPV();
353 return priceToMatch_ - npv;
356template <
class Interpolator2D>
358 const QuantLib::Period& obsLag)
const {
359 QuantLib::Period lag = obsLag == -1 * QuantLib::Days ? observationLag() : obsLag;
363 double atm = forwardCPI / baseCPI;
365 QuantLib::inflationYearFraction(frequency(), indexIsInterpolated(), dayCounter(),
baseDate(), fixingDate);
366 return std::pow(atm, 1.0 / ttm) - 1.0;
QuantLib::ext::shared_ptr< PricingEngine > engine_
double displacement() const
Returns the displacement for lognormal volatilities.
QuantLib::Date baseDate() const override
base date will be in the past
QuantLib::Date capFloorStartDate() const
QuantLib::Real priceToMatch_
ObjectiveFunction(QuantLib::Real priceToMatch, bool useFloor, QuantLib::Real strike, QuantLib::Date startDate, QuantLib::Date maturityDate, QuantLib::Real baseCPI, QuantLib::Handle< QuantLib::CPICapFloorTermPriceSurface > priceSurface, const QuantLib::ext::shared_ptr< QuantLib::ZeroInflationIndex > &zeroIndex, const QuantLib::ext::shared_ptr< QuantExt::CPICapFloorEngine > &engine, const CPI::InterpolationType interpolationType)
QuantLib::CPICapFloor cpiCapFloor_
QuantLib::Handle< QuantLib::CPICapFloorTermPriceSurface > priceSurface_
QuantLib::Date lastAvailableFixingDate_
QuantLib::Real operator()(QuantLib::Volatility guess) const
QuantLib::ext::shared_ptr< QuantLib::ZeroInflationIndex > index_
QuantLib::ext::shared_ptr< QuantExt::CPICapFloorEngine > engine_
QuantLib::Date startDate_
CPI::InterpolationType interpolationType_
QuantLib::Date maturityDate_
Stripped zero inflation volatility structure.
Interpolator2D interpolator2d_
QuantLib::Matrix volData_
QL_DEPRECATED StrippedCPIVolatilitySurface(PriceQuotePreference type, const QuantLib::Handle< QuantLib::CPICapFloorTermPriceSurface > &priceSurface, const QuantLib::ext::shared_ptr< QuantLib::ZeroInflationIndex > &zeroIndex, const QuantLib::ext::shared_ptr< QuantExt::CPICapFloorEngine > &engine, const QuantLib::Date &capFloorStartDate=Date(), const QuantLib::Real &upperVolBound=StrippedCPIVolSurfaceDefaultValues::upperVolBound, const QuantLib::Real &lowerVolBound=StrippedCPIVolSurfaceDefaultValues::lowerVolBound, const QuantLib::Real &solverTolerance=StrippedCPIVolSurfaceDefaultValues::solverTolerance, const Interpolator2D &interpolator2d=Interpolator2D(), const QuantLib::VolatilityType &volType=QuantLib::ShiftedLognormal, const double displacement=0.0)
void performCalculations() const
const std::vector< QuantLib::Period > & maturities()
const std::vector< QuantLib::Real > & strikes()
bool computeTimeToExpiryFromLastAvailableFixingDate_
QuantLib::Interpolation2D vols_
std::vector< QuantLib::Time > maturityTimes_
QuantLib::Real minStrike() const override
the minimum strike for which the term structure can return vols
const QuantLib::Matrix & volData()
QuantLib::Real solverTolerance_
std::vector< QuantLib::Rate > strikes_
QuantLib::Handle< QuantLib::CPICapFloorTermPriceSurface > priceSurface_
std::vector< QuantLib::Period > maturities_
bool chooseFloor(QuantLib::Real strike, QuantLib::Real atmRate) const
QuantLib::Real upperVolBound_
QuantLib::Real maxStrike() const override
the maximum strike for which the term structure can return vols
QuantLib::Real lowerVolBound_
PriceQuotePreference preference_
QuantLib::Date maxDate() const override
maximum date for which the term structure can return vols
QuantLib::ext::shared_ptr< QuantLib::ZeroInflationIndex > index_
QuantLib::ext::shared_ptr< QuantExt::CPICapFloorEngine > engine_
QuantLib::Real atmStrike(const QuantLib::Date &maturity, const QuantLib::Period &obsLag=QuantLib::Period(-1, QuantLib::Days)) const override
QuantLib::Volatility volatilityImpl(QuantLib::Time length, QuantLib::Rate strike) const override
Constant CPI Volatility Surface.
CPI cap/floor engine using the Black pricing formula and interpreting the volatility data as lognorma...
interpolated correlation term structure
some inflation related utilities.
QuantLib::Date fixingDate(const QuantLib::Date &d, const QuantLib::Period obsLag, const QuantLib::Frequency freq, bool interpolated)
QuantLib::Rate cpiFixing(const QuantLib::ext::shared_ptr< QuantLib::ZeroInflationIndex > &index, const QuantLib::Date &maturity, const QuantLib::Period &obsLag, bool interpolated)
Computes a CPI fixing giving an zeroIndex, with interpolation if needed.
static constexpr QuantLib::Real upperVolBound
static constexpr QuantLib::Real lowerVolBound
static constexpr QuantLib::Real solverTolerance