Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
strippedoptionletadapter.hpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2019 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/strippedoptionletadapter.hpp
20 \brief Convert a StrippedOptionletBase in to an OptionletVolatilityStructure
21 \ingroup termstructures
22*/
23
24#ifndef quantext_stripped_optionlet_adapter_h
25#define quantext_stripped_optionlet_adapter_h
26
27#include <algorithm>
28#include <ql/math/interpolation.hpp>
29#include <ql/termstructures/interpolatedcurve.hpp>
30#include <ql/termstructures/volatility/flatsmilesection.hpp>
31#include <ql/termstructures/volatility/interpolatedsmilesection.hpp>
32#include <ql/termstructures/volatility/optionlet/optionletvolatilitystructure.hpp>
33#include <ql/termstructures/volatility/optionlet/strippedoptionletbase.hpp>
34#include <ql/utilities/dataformatters.hpp>
35#include <vector>
36
37namespace QuantExt {
38
39/*! Adapter class for turning a StrippedOptionletBase into an OptionletVolatilityStructure.
40
41 The class takes two template parameters indicating the interpolation in the time and strike direction respectively.
42
43 The class can take a QuantLib::StrippedOptionletBase that has only one strike column. In this case, the strike
44 interpolation is ignored and the volatility at one of the pillar tenors, and any strike, is merely the passed
45 in volatility. In this case, the smile sections are flat. All of this enables the StrippedOptionletAdapter to
46 represent a stripped ATM optionlet curve. The single strike in the QuantLib::StrippedOptionletBase is ignored.
47
48 \ingroup termstructures
49*/
50template <class TimeInterpolator, class SmileInterpolator>
51class StrippedOptionletAdapter : public QuantLib::OptionletVolatilityStructure, public QuantLib::LazyObject {
52
53public:
54 /*! Constructor that does not take a reference date. The settlement days is derived from \p sob and the term
55 structure will be a \e moving term structure.
56 */
57 StrippedOptionletAdapter(const QuantLib::ext::shared_ptr<QuantLib::StrippedOptionletBase>& sob,
58 const TimeInterpolator& ti = TimeInterpolator(),
59 const SmileInterpolator& si = SmileInterpolator());
60
61 /*! Constructor taking an explicit \p referenceDate and the term structure will therefore be not \e moving.
62 */
63 StrippedOptionletAdapter(const QuantLib::Date& referenceDate,
64 const QuantLib::ext::shared_ptr<QuantLib::StrippedOptionletBase>& sob,
65 const TimeInterpolator& ti = TimeInterpolator(),
66 const SmileInterpolator& si = SmileInterpolator());
67
68 //! \name TermStructure interface
69 //@{
70 QuantLib::Date maxDate() const override;
71 //@}
72
73 //! \name VolatilityTermStructure interface
74 //@{
75 QuantLib::Rate minStrike() const override;
76 QuantLib::Rate maxStrike() const override;
77 //@}
78
79 //! \name OptionletVolatilityStructure interface
80 //@{
81 QuantLib::VolatilityType volatilityType() const override;
82 QuantLib::Real displacement() const override;
83 //@}
84
85 //! \name LazyObject interface
86 //@{
87 void update() override;
88 void performCalculations() const override;
89 //@}
90
91 //! \name Observer interface
92 //@{
93 void deepUpdate() override;
94 //@}
95
96 //! \name Inspectors
97 //@{
98 QuantLib::ext::shared_ptr<QuantLib::StrippedOptionletBase> optionletBase() const;
99 //@}
100
101protected:
102 //! \name OptionletVolatilityStructure interface
103 //@{
104 QuantLib::ext::shared_ptr<QuantLib::SmileSection> smileSectionImpl(QuantLib::Time optionTime) const override;
105 QuantLib::Volatility volatilityImpl(QuantLib::Time length, QuantLib::Rate strike) const override;
106 //@}
107
108private:
109 //! Base optionlet object that provides the stripped optionlet volatilities
110 QuantLib::ext::shared_ptr<QuantLib::StrippedOptionletBase> optionletBase_;
111
112 //! The interpolation object in the time direction
113 TimeInterpolator ti_;
114
115 //! The interpolation object in the strike direction
116 SmileInterpolator si_;
117
118 /*! The optionlet volatility vs strike section at each optionlet fixing date
119 It is \c mutable so that we can call \c enableExtrapolation in \c performCalculations.
120 */
121 mutable std::vector<QuantLib::Interpolation> strikeSections_;
122
123 //! Flag that indicates if optionletBase_ has only one strike for all option tenors
125
126 //! Method to populate oneStrike_ on initialisation
127 void populateOneStrike();
128};
129
130template <class TimeInterpolator, class SmileInterpolator>
132 const QuantLib::ext::shared_ptr<QuantLib::StrippedOptionletBase>& sob, const TimeInterpolator& ti,
133 const SmileInterpolator& si)
134 : OptionletVolatilityStructure(sob->settlementDays(), sob->calendar(), sob->businessDayConvention(),
135 sob->dayCounter()),
136 optionletBase_(sob), ti_(ti), si_(si), strikeSections_(optionletBase_->optionletMaturities()) {
137 registerWith(optionletBase_);
139}
140
141template <class TimeInterpolator, class SmileInterpolator>
143 const QuantLib::Date& referenceDate, const QuantLib::ext::shared_ptr<QuantLib::StrippedOptionletBase>& sob,
144 const TimeInterpolator& ti, const SmileInterpolator& si)
145 : OptionletVolatilityStructure(referenceDate, sob->calendar(), sob->businessDayConvention(), sob->dayCounter()),
146 optionletBase_(sob), ti_(ti), si_(si), strikeSections_(optionletBase_->optionletMaturities()) {
147 registerWith(optionletBase_);
149}
150
151template <class TimeInterpolator, class SmileInterpolator>
153 return optionletBase_->optionletFixingDates().back();
154}
155
156template <class TimeInterpolator, class SmileInterpolator>
158
159 // If only one strike
160 if (oneStrike_) {
161 if (volatilityType() == QuantLib::ShiftedLognormal) {
162 return displacement() > 0.0 ? -displacement() : 0.0;
163 } else {
164 return QL_MIN_REAL;
165 }
166 }
167
168 // Return the minimum strike over all optionlet tenors
169 QuantLib::Rate minStrike = optionletBase_->optionletStrikes(0).front();
170 for (QuantLib::Size i = 1; i < optionletBase_->optionletMaturities(); ++i) {
171 minStrike = std::min(optionletBase_->optionletStrikes(i).front(), minStrike);
172 }
173 return minStrike;
174}
175
176template <class TimeInterpolator, class SmileInterpolator>
178
179 // If only one strike, there is no max strike
180 if (oneStrike_) {
181 return QL_MAX_REAL;
182 }
183
184 // Return the maximum strike over all optionlet tenors
185 QuantLib::Rate maxStrike = optionletBase_->optionletStrikes(0).back();
186 for (QuantLib::Size i = 1; i < optionletBase_->optionletMaturities(); ++i) {
187 maxStrike = std::max(optionletBase_->optionletStrikes(i).back(), maxStrike);
188 }
189 return maxStrike;
190}
191
192template <class TimeInterpolator, class SmileInterpolator>
194 return optionletBase_->volatilityType();
195}
196
197template <class TimeInterpolator, class SmileInterpolator>
199 return optionletBase_->displacement();
200}
201
202template <class TimeInterpolator, class SmileInterpolator>
204
205 // Need this or some tests with ObservationMode::Mode::Disable fail
206 // e.g. */SensitivityAnalysisTest/testPortfolioSensitivityDisableObs
207 optionletBase_->update();
208
209 TermStructure::update();
210 LazyObject::update();
211}
212
213template <class TimeInterpolator, class SmileInterpolator>
215
216 // Some localised typedefs and using declarations to make the code more readable
217 using QuantLib::Rate;
218 using QuantLib::Size;
219 using QuantLib::Volatility;
220 using std::vector;
221
222 // If only one strike, no strike section to update
223 if (oneStrike_) {
224 return;
225 }
226
227 for (Size i = 0; i < optionletBase_->optionletMaturities(); ++i) {
228 const vector<Rate>& strikes = optionletBase_->optionletStrikes(i);
229 const vector<Volatility>& vols = optionletBase_->optionletVolatilities(i);
230 strikeSections_[i] = si_.interpolate(strikes.begin(), strikes.end(), vols.begin());
231 // Extrapolation can be enabled here. Range checks are performed in the volatility methods.
232 strikeSections_[i].enableExtrapolation();
233 }
234}
235
236template <class TimeInterpolator, class SmileInterpolator>
238 optionletBase_->update();
239 update();
240}
241
242template <class TimeInterpolator, class SmileInterpolator>
243inline QuantLib::ext::shared_ptr<QuantLib::StrippedOptionletBase>
245 return optionletBase_;
246}
247
248template <class TimeInterpolator, class SmileInterpolator>
249inline QuantLib::ext::shared_ptr<QuantLib::SmileSection>
251
252 // Some localised typedefs and using declarations to make the code more readable
253 using QuantLib::Null;
254 using QuantLib::Rate;
255 using QuantLib::Real;
256 using QuantLib::Size;
257 using QuantLib::Volatility;
258 using QuantLib::io::ordinal;
259 using std::equal;
260 using std::sqrt;
261 using std::vector;
262
263 // Leave ATM rate as Null<Real>() for now but could interpolate optionletBase_->atmOptionletRates()?
264 Real atmRate = Null<Real>();
265
266 // If one strike, return a flat smile section
267 if (oneStrike_) {
268 Volatility vol = volatility(optionTime, optionletBase_->optionletStrikes(0)[0], true);
269 return QuantLib::ext::make_shared<QuantLib::FlatSmileSection>(optionTime, vol, optionletBase_->dayCounter(), atmRate,
270 volatilityType(), displacement());
271 }
272
273 /* we choose the strikes from the first fixing time for interpolation
274 - if only fixed strikes are used, they are the same for all times anyway
275 - if atm is used in addition, the first time's strikes are a superset of all others, i.e. the densest */
276 const vector<Rate>& strikes = optionletBase_->optionletStrikes(0);
277
278 // Store standard deviation at each strike
279 vector<Real> stdDevs;
280 for (Size i = 0; i < strikes.size(); i++) {
281 stdDevs.push_back(sqrt(blackVariance(optionTime, strikes[i], true)));
282 }
283
284 // Return the smile section.
285 return QuantLib::ext::make_shared<QuantLib::InterpolatedSmileSection<SmileInterpolator> >(
286 optionTime, strikes, stdDevs, atmRate, si_, optionletBase_->dayCounter(), volatilityType(), displacement());
287}
288
289template <class TimeInterpolator, class SmileInterpolator>
290inline QuantLib::Volatility
292 QuantLib::Rate strike) const {
293
294 // Some localised typedefs and using declarations to make the code more readable
295 using QuantLib::Interpolation;
296 using QuantLib::Size;
297 using QuantLib::Time;
298 using QuantLib::Volatility;
299 using std::vector;
300
301 calculate();
302
303 vector<Volatility> vols(optionletBase_->optionletMaturities());
304 for (Size i = 0; i < optionletBase_->optionletMaturities(); ++i) {
305 vols[i] = oneStrike_ ? optionletBase_->optionletVolatilities(i)[0] : strikeSections_[i](strike);
306 }
307
308 vector<Time> fixingTimes = optionletBase_->optionletFixingTimes();
309 Interpolation ti = ti_.interpolate(fixingTimes.begin(), fixingTimes.end(), vols.begin());
310
311 // Extrapolation can be enabled at this level. The range checks will have already been performed in
312 // the public OptionletVolatilityStructure::volatility method that calls this `Impl`
313 ti.enableExtrapolation();
314
315 return ti(optionTime);
316}
317
318template <class TimeInterpolator, class SmileInterpolator>
320 oneStrike_ = true;
321 for (QuantLib::Size i = 0; i < optionletBase_->optionletMaturities(); ++i) {
322 if (optionletBase_->optionletStrikes(i).size() > 1) {
323 oneStrike_ = false;
324 return;
325 }
326 }
327}
328
329} // namespace QuantExt
330
331#endif
QuantLib::Real displacement() const override
TimeInterpolator ti_
The interpolation object in the time direction.
StrippedOptionletAdapter(const QuantLib::ext::shared_ptr< QuantLib::StrippedOptionletBase > &sob, const TimeInterpolator &ti=TimeInterpolator(), const SmileInterpolator &si=SmileInterpolator())
void populateOneStrike()
Method to populate oneStrike_ on initialisation.
QuantLib::ext::shared_ptr< QuantLib::StrippedOptionletBase > optionletBase_
Base optionlet object that provides the stripped optionlet volatilities.
QuantLib::VolatilityType volatilityType() const override
bool oneStrike_
Flag that indicates if optionletBase_ has only one strike for all option tenors.
SmileInterpolator si_
The interpolation object in the strike direction.
QuantLib::ext::shared_ptr< QuantLib::SmileSection > smileSectionImpl(QuantLib::Time optionTime) const override
QuantLib::Date maxDate() const override
QuantLib::ext::shared_ptr< QuantLib::StrippedOptionletBase > optionletBase() const
QuantLib::Rate minStrike() const override
QuantLib::Rate maxStrike() const override
std::vector< QuantLib::Interpolation > strikeSections_
QuantLib::Volatility volatilityImpl(QuantLib::Time length, QuantLib::Rate strike) const override
RandomVariable sqrt(RandomVariable x)
vector< Real > strikes