Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
sabrstrippedoptionletadapter.hpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2024 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/sabrstrippedoptionletadapter.hpp
20 \brief Convert a StrippedOptionletBase in to an OptionletVolatilityStructure using a SABR model
21 \ingroup termstructures
22*/
23
24#ifndef quantext_stripped_optionlet_adapter_sabr_h
25#define quantext_stripped_optionlet_adapter_sabr_h
26
28
29#include <ql/math/interpolation.hpp>
30#include <ql/termstructures/interpolatedcurve.hpp>
31#include <ql/termstructures/volatility/flatsmilesection.hpp>
32#include <ql/termstructures/volatility/interpolatedsmilesection.hpp>
33#include <ql/termstructures/volatility/optionlet/optionletvolatilitystructure.hpp>
34#include <ql/termstructures/volatility/optionlet/strippedoptionletbase.hpp>
35#include <ql/utilities/dataformatters.hpp>
36
37#include <algorithm>
38#include <vector>
39
40namespace QuantExt {
41
42template <class TimeInterpolator>
43class SabrStrippedOptionletAdapter : public QuantLib::OptionletVolatilityStructure, public QuantLib::LazyObject {
44
45public:
46 /*! Constructor that does not take a reference date. The settlement days is derived from \p sob and the term
47 structure will be a \e moving term structure.
48 */
49 SabrStrippedOptionletAdapter(const QuantLib::ext::shared_ptr<QuantLib::StrippedOptionletBase>& sob,
51 const TimeInterpolator& ti = TimeInterpolator(),
52 const boost::optional<QuantLib::VolatilityType> outputVolatilityType = boost::none,
53 const std::vector<std::vector<std::pair<Real, bool>>>& initialModelParameters = {},
54 const QuantLib::Size maxCalibrationAttempts = 10,
55 const QuantLib::Real exitEarlyErrorThreshold = 0.005,
56 const QuantLib::Real maxAcceptableError = 0.05);
57
58 /*! Constructor taking an explicit \p referenceDate and the term structure will therefore be not \e moving.
59 */
60 SabrStrippedOptionletAdapter(const QuantLib::Date& referenceDate,
61 const QuantLib::ext::shared_ptr<QuantLib::StrippedOptionletBase>& sob,
63 const TimeInterpolator& ti = TimeInterpolator(),
64 const boost::optional<QuantLib::VolatilityType> outputVolatilityType = boost::none,
65 const std::vector<std::vector<std::pair<Real, bool>>>& initialModelParameters = {},
66 const QuantLib::Size maxCalibrationAttempts = 10,
67 const QuantLib::Real exitEarlyErrorThreshold = 0.005,
68 const QuantLib::Real maxAcceptableError = 0.05);
69
70 //! \name TermStructure interface
71 //@{
72 QuantLib::Date maxDate() const override;
73 //@}
74
75 //! \name VolatilityTermStructure interface
76 //@{
77 QuantLib::Rate minStrike() const override;
78 QuantLib::Rate maxStrike() const override;
79 //@}
80
81 //! \name OptionletVolatilityStructure interface
82 //@{
83 QuantLib::VolatilityType volatilityType() const override;
84 QuantLib::Real displacement() const override;
85 //@}
86
87 //! \name LazyObject interface
88 //@{
89 void update() override;
90 void performCalculations() const override;
91 //@}
92
93 //! \name Observer interface
94 //@{
95 void deepUpdate() override;
96 //@}
97
98 //! \name Inspectors
99 //@{
100 QuantLib::ext::shared_ptr<QuantLib::StrippedOptionletBase> optionletBase() const;
101 QuantLib::ext::shared_ptr<QuantExt::ParametricVolatility> parametricVolatility() const {
103 }
104 //@}
105
106protected:
107 //! \name OptionletVolatilityStructure interface
108 //@{
109 QuantLib::ext::shared_ptr<QuantLib::SmileSection> smileSectionImpl(QuantLib::Time optionTime) const override;
110 QuantLib::Volatility volatilityImpl(QuantLib::Time length, QuantLib::Rate strike) const override;
111 //@}
112
113private:
114 //! Base optionlet object that provides the stripped optionlet volatilities
115 QuantLib::ext::shared_ptr<QuantLib::StrippedOptionletBase> optionletBase_;
116
117 //! The interpolation object in the time direction
118 TimeInterpolator ti_;
119
120 //! SABR specific inputs
122 boost::optional<QuantLib::VolatilityType> outputVolatilityType_;
123 std::vector<std::vector<std::pair<Real, bool>>> initialModelParameters_;
126 QuantLib::Real maxAcceptableError_;
127
128 //! State
129 mutable std::map<Real, QuantLib::ext::shared_ptr<ParametricVolatilitySmileSection>> cache_;
130 mutable QuantLib::ext::shared_ptr<ParametricVolatility> parametricVolatility_;
131 mutable std::unique_ptr<FlatExtrapolation> atmInterpolation_;
132};
133
134template <class TimeInterpolator>
136 const QuantLib::ext::shared_ptr<QuantLib::StrippedOptionletBase>& sob,
137 const QuantExt::SabrParametricVolatility::ModelVariant modelVariant, const TimeInterpolator& ti,
138 const boost::optional<QuantLib::VolatilityType> outputVolatilityType,
139 const std::vector<std::vector<std::pair<Real, bool>>>& initialModelParameters,
140 const QuantLib::Size maxCalibrationAttempts, const QuantLib::Real exitEarlyErrorThreshold,
141 const QuantLib::Real maxAcceptableError)
142 : OptionletVolatilityStructure(sob->settlementDays(), sob->calendar(), sob->businessDayConvention(),
143 sob->dayCounter()),
144 optionletBase_(sob), ti_(ti), modelVariant_(modelVariant), outputVolatilityType_(outputVolatilityType),
145 initialModelParameters_(initialModelParameters), maxCalibrationAttempts_(maxCalibrationAttempts),
146 exitEarlyErrorThreshold_(exitEarlyErrorThreshold), maxAcceptableError_(maxAcceptableError) {
147 registerWith(optionletBase_);
148}
149
150template <class TimeInterpolator>
152 const QuantLib::Date& referenceDate, const QuantLib::ext::shared_ptr<QuantLib::StrippedOptionletBase>& sob,
153 const QuantExt::SabrParametricVolatility::ModelVariant modelVariant, const TimeInterpolator& ti,
154 const boost::optional<QuantLib::VolatilityType> outputVolatilityType,
155 const std::vector<std::vector<std::pair<Real, bool>>>& initialModelParameters,
156 const QuantLib::Size maxCalibrationAttempts, const QuantLib::Real exitEarlyErrorThreshold,
157 const QuantLib::Real maxAcceptableError)
158 : OptionletVolatilityStructure(referenceDate, sob->calendar(), sob->businessDayConvention(), sob->dayCounter()),
159 optionletBase_(sob), ti_(ti), modelVariant_(modelVariant), outputVolatilityType_(outputVolatilityType),
160 initialModelParameters_(initialModelParameters), maxCalibrationAttempts_(maxCalibrationAttempts),
161 exitEarlyErrorThreshold_(exitEarlyErrorThreshold), maxAcceptableError_(maxAcceptableError) {
162 registerWith(optionletBase_);
163}
164
165template <class TimeInterpolator>
167 return Date::maxDate();
168}
169
170template <class TimeInterpolator>
172 return -QL_MAX_REAL;
173}
174
175template <class TimeInterpolator>
177 return QL_MAX_REAL;
178}
179
180template <class TimeInterpolator>
182 return optionletBase_->volatilityType();
183}
184
185template <class TimeInterpolator>
187 return optionletBase_->displacement();
188}
189
190template <class TimeInterpolator> inline void SabrStrippedOptionletAdapter<TimeInterpolator>::update() {
191 optionletBase_->update();
192 TermStructure::update();
193 LazyObject::update();
194}
195
196template <class TimeInterpolator>
198 cache_.clear();
199
200 atmInterpolation_ = std::make_unique<FlatExtrapolation>(QuantLib::ext::make_shared<LinearInterpolation>(
201 this->optionletBase()->optionletFixingTimes().begin(), this->optionletBase()->optionletFixingTimes().end(),
202 this->optionletBase()->atmOptionletRates().begin()));
203 atmInterpolation_->enableExtrapolation();
204 atmInterpolation_->update();
205
206 std::vector<ParametricVolatility::MarketSmile> marketSmiles;
207 std::map<std::pair<QuantLib::Real, QuantLib::Real>, std::vector<std::pair<Real, bool>>> modelParameters;
208 QL_REQUIRE(initialModelParameters_.empty() || initialModelParameters_.size() == 1 ||
209 initialModelParameters_.size() == this->optionletBase()->optionletFixingTimes().size(),
210 "SabrStrippedOptionletAdapter: initial model parameters must be empty or their size ("
211 << initialModelParameters_.size()
212 << ") must be 1 or it must match the number of optionlet fixing times ("
213 << this->optionletBase()->optionletFixingTimes().size() << ")");
214 for (Size i = 0; i < this->optionletBase()->optionletFixingTimes().size(); ++i) {
215 Real forward = atmInterpolation_->operator()(this->optionletBase()->optionletFixingTimes()[i]);
216 marketSmiles.push_back(ParametricVolatility::MarketSmile{this->optionletBase()->optionletFixingTimes()[i],
217 Null<Real>(),
218 forward,
219 displacement(),
220 {},
221 this->optionletBase()->optionletStrikes(i),
222 this->optionletBase()->optionletVolatilities(i)});
223 if (!initialModelParameters_.empty()) {
224 modelParameters[std::make_pair(this->optionletBase()->optionletFixingTimes()[i], Null<Real>())] =
225 initialModelParameters_.size() == 1 ? initialModelParameters_.front() : initialModelParameters_[i];
226 }
227 }
228
229 parametricVolatility_ = QuantLib::ext::make_shared<SabrParametricVolatility>(
230 modelVariant_, marketSmiles, ParametricVolatility::MarketModelType::Black76,
231 volatilityType() == QuantLib::Normal ? ParametricVolatility::MarketQuoteType::NormalVolatility
233 Handle<YieldTermStructure>(), modelParameters, maxCalibrationAttempts_, exitEarlyErrorThreshold_,
234 maxAcceptableError_);
235}
236
237template <class TimeInterpolator> inline void SabrStrippedOptionletAdapter<TimeInterpolator>::deepUpdate() {
238 optionletBase_->update();
239 update();
240}
241
242template <class TimeInterpolator>
243inline QuantLib::ext::shared_ptr<QuantLib::StrippedOptionletBase>
245 return optionletBase_;
246}
247
248template <class TimeInterpolator>
249inline QuantLib::ext::shared_ptr<QuantLib::SmileSection>
251 calculate();
252 if (auto c = cache_.find(optionTime); c != cache_.end()) {
253 return c->second;
254 }
255 Real forward = atmInterpolation_->operator()(optionTime);
256 QuantLib::VolatilityType outVolType = outputVolatilityType_ ? *outputVolatilityType_ : volatilityType();
257 auto tmp = QuantLib::ext::make_shared<ParametricVolatilitySmileSection>(
258 optionTime, Null<Real>(), forward, parametricVolatility_,
259 outVolType == QuantLib::Normal ? ParametricVolatility::MarketQuoteType::NormalVolatility
261 cache_[optionTime] = tmp;
262 return tmp;
263}
264
265template <class TimeInterpolator>
266inline QuantLib::Volatility
267SabrStrippedOptionletAdapter<TimeInterpolator>::volatilityImpl(QuantLib::Time optionTime, QuantLib::Rate strike) const {
268 return smileSectionImpl(optionTime)->volatility(strike);
269}
270
271} // namespace QuantExt
272
273#endif
std::unique_ptr< FlatExtrapolation > atmInterpolation_
TimeInterpolator ti_
The interpolation object in the time direction.
QuantLib::ext::shared_ptr< QuantExt::ParametricVolatility > parametricVolatility() const
std::map< Real, QuantLib::ext::shared_ptr< ParametricVolatilitySmileSection > > cache_
State.
std::vector< std::vector< std::pair< Real, bool > > > initialModelParameters_
QuantLib::ext::shared_ptr< QuantLib::StrippedOptionletBase > optionletBase_
Base optionlet object that provides the stripped optionlet volatilities.
boost::optional< QuantLib::VolatilityType > outputVolatilityType_
QuantExt::SabrParametricVolatility::ModelVariant modelVariant_
SABR specific inputs.
QuantLib::VolatilityType volatilityType() const override
QuantLib::ext::shared_ptr< QuantLib::SmileSection > smileSectionImpl(QuantLib::Time optionTime) const override
QuantLib::ext::shared_ptr< QuantLib::StrippedOptionletBase > optionletBase() const
QuantLib::ext::shared_ptr< ParametricVolatility > parametricVolatility_
SabrStrippedOptionletAdapter(const QuantLib::ext::shared_ptr< QuantLib::StrippedOptionletBase > &sob, const QuantExt::SabrParametricVolatility::ModelVariant modelVariant, const TimeInterpolator &ti=TimeInterpolator(), const boost::optional< QuantLib::VolatilityType > outputVolatilityType=boost::none, const std::vector< std::vector< std::pair< Real, bool > > > &initialModelParameters={}, const QuantLib::Size maxCalibrationAttempts=10, const QuantLib::Real exitEarlyErrorThreshold=0.005, const QuantLib::Real maxAcceptableError=0.05)
QuantLib::Volatility volatilityImpl(QuantLib::Time length, QuantLib::Rate strike) const override