Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
optioninterpolator2d.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 blackvariancesurfacesparse.hpp
20 \brief Black volatility surface modeled as variance surface
21 */
22
23#ifndef quantext_option_interpolator_2d_hpp
24#define quantext_option_interpolator_2d_hpp
25
26#include <ql/math/interpolation.hpp>
27#include <ql/patterns/observable.hpp>
28#include <ql/time/date.hpp>
29#include <ql/time/daycounters/actual365fixed.hpp>
30
32
33namespace QuantExt {
34
36 explicit CloseEnoughComparator(const QuantLib::Real v) : v_(v) {}
37 bool operator()(const QuantLib::Real w) const { return QuantLib::close_enough(v_, w); }
38 QuantLib::Real v_;
39};
40
41//! Option surface interpolator base
43
44public:
45 // Destructor
47 // default Constructor
49
50 //! virtual access methods
51 virtual QuantLib::Real getValue(QuantLib::Time t, QuantLib::Real strike) const = 0;
52 virtual QuantLib::Real getValue(QuantLib::Date d, QuantLib::Real strike) const = 0;
53
54 const QuantLib::Date& referenceDate() const { return referenceDate_; }
55 std::vector<QuantLib::Time> times() const { return times_; };
56 std::vector<QuantLib::Date> expiries() const { return expiries_; };
57 std::vector<std::vector<QuantLib::Real> > strikes() const { return strikes_; };
58 std::vector<std::vector<QuantLib::Real> > values() const { return values_; };
59
60protected:
61 std::vector<QuantLib::Date> expiries_; // expiries
62 std::vector<QuantLib::Time> times_; // times
63 std::vector<std::vector<QuantLib::Real> > strikes_; // strikes for each expiry
64 std::vector<std::vector<QuantLib::Real> > values_;
65 QuantLib::Date referenceDate_;
66};
67
68//! Option surface interpolator
69//! \ingroup interpolators
70template <class InterpolatorStrike, class InterpolatorExpiry>
72
73public:
74 //! OptionInterpolator2d default Constructor
75 OptionInterpolator2d(const QuantLib::Date& referenceDate, const QuantLib::DayCounter& dayCounter,
76 bool lowerStrikeConstExtrap = true, bool upperStrikeConstExtrap = true,
77 const InterpolatorStrike& interpolatorStrike = InterpolatorStrike(),
78 const InterpolatorExpiry& interpolatorExpiry = InterpolatorExpiry(),
79 const QuantLib::Date& baseDate = QuantLib::Date())
81 lowerStrikeConstExtrap_(lowerStrikeConstExtrap), upperStrikeConstExtrap_(upperStrikeConstExtrap),
82 interpolatorStrike_(interpolatorStrike), interpolatorExpiry_(interpolatorExpiry), initialised_(false),
83 baseDate_(baseDate == QuantLib::Date() ? referenceDate : baseDate){};
84
85 //! OptionInterpolator2d Constructor with dates
86 OptionInterpolator2d(const QuantLib::Date& referenceDate, const QuantLib::DayCounter& dayCounter,
87 const std::vector<QuantLib::Date>& dates, const std::vector<QuantLib::Real>& strikes,
88 const std::vector<QuantLib::Real>& values, bool lowerStrikeConstExtrap = true,
89 bool upperStrikeConstExtrap = true,
90 const InterpolatorStrike& interpolatorStrike = InterpolatorStrike(),
91 const InterpolatorExpiry& interpolatorExpiry = InterpolatorExpiry(),
92 const QuantLib::Date& baseDate = QuantLib::Date());
93
94 //! OptionInterpolator2d Constructor with Tenors
95 OptionInterpolator2d(const QuantLib::Date& referenceDate, const QuantLib::Calendar& calendar,
96 const QuantLib::BusinessDayConvention& bdc, const QuantLib::DayCounter& dayCounter,
97 const std::vector<QuantLib::Period>& tenors, const std::vector<QuantLib::Real>& strikes,
98 const std::vector<QuantLib::Real>& values, bool lowerStrikeConstExtrap = true,
99 bool upperStrikeConstExtrap = true,
100 const InterpolatorStrike& interpolatorStrike = InterpolatorStrike(),
101 const InterpolatorExpiry& interpolatorExpiry = InterpolatorExpiry(),
102 const QuantLib::Date& baseDate = QuantLib::Date());
103
104 /* delete copy and copy assignment operators because of the stored Interpolation objects, which would
105 still point to the source object's data after the copy */
108
109 //! Initialise
110 void initialise(const std::vector<QuantLib::Date>& dates, const std::vector<QuantLib::Real>& strikes,
111 const std::vector<QuantLib::Real>& values);
112 void initialise(const std::vector<QuantLib::Period>& tenors, const std::vector<QuantLib::Real>& strikes,
113 const std::vector<QuantLib::Real>& values, const QuantLib::Calendar& calendar,
114 const QuantLib::BusinessDayConvention& bdc);
115
116 //! \name Getters
117 //@{
118 std::vector<QuantLib::Time> times() const;
119 std::vector<QuantLib::Date> expiries() const;
120 std::vector<std::vector<QuantLib::Real> > strikes() const;
121 std::vector<std::vector<QuantLib::Real> > values() const;
122 QuantLib::DayCounter dayCounter() const { return dayCounter_; }
123 QuantLib::Real getValue(QuantLib::Time t, QuantLib::Real strike) const override;
124 QuantLib::Real getValue(QuantLib::Date d, QuantLib::Real strike) const override;
125 //@}
126
127protected:
128 std::vector<QuantLib::Interpolation> interpolations_; // strike interpolations for each expiry
129
130private:
131 QuantLib::DayCounter dayCounter_;
132 QuantLib::Real getValueForStrike(QuantLib::Real strike, const std::vector<QuantLib::Real>& strks,
133 const std::vector<QuantLib::Real>& vars,
134 const QuantLib::Interpolation& intrp) const;
137 InterpolatorStrike interpolatorStrike_;
138 InterpolatorExpiry interpolatorExpiry_;
140 QuantLib::Date baseDate_;
141
142};
143
144// template definitions
145template <class InterpolatorStrike, class InterpolatorExpiry>
147 const QuantLib::Date& referenceDate, const QuantLib::DayCounter& dayCounter,
148 const std::vector<QuantLib::Date>& dates, const std::vector<QuantLib::Real>& strikes,
149 const std::vector<QuantLib::Real>& values, bool lowerStrikeConstExtrap, bool upperStrikeConstExtrap,
150 const InterpolatorStrike& interpolatorStrike,
151 const InterpolatorExpiry& interpolatorExpiry,
152 const QuantLib::Date& baseDate)
153 : OptionInterpolatorBase(referenceDate), dayCounter_(dayCounter), lowerStrikeConstExtrap_(lowerStrikeConstExtrap),
154 upperStrikeConstExtrap_(upperStrikeConstExtrap), interpolatorStrike_(interpolatorStrike),
155 interpolatorExpiry_(interpolatorExpiry), initialised_(false),
156 baseDate_(baseDate == QuantLib::Date() ? referenceDate : baseDate) {
157
158 initialise(dates, strikes, values);
159};
160
161template <class InterpolatorStrike, class InterpolatorExpiry>
163 const QuantLib::Date& referenceDate, const QuantLib::Calendar& calendar,
164 const QuantLib::BusinessDayConvention& bdc, const QuantLib::DayCounter& dayCounter,
165 const std::vector<QuantLib::Period>& tenors, const std::vector<QuantLib::Real>& strikes,
166 const std::vector<QuantLib::Real>& values, bool lowerStrikeConstExtrap, bool upperStrikeConstExtrap, const InterpolatorStrike& interpolatorStrike,
167 const InterpolatorExpiry& interpolatorExpiry, const QuantLib::Date& baseDate)
168 : OptionInterpolatorBase(referenceDate), dayCounter_(dayCounter), lowerStrikeConstExtrap_(lowerStrikeConstExtrap),
169 upperStrikeConstExtrap_(upperStrikeConstExtrap), interpolatorStrike_(interpolatorStrike),
170 interpolatorExpiry_(interpolatorExpiry), initialised_(false),
171 baseDate_(baseDate == QuantLib::Date() ? referenceDate : baseDate) {
172
173 initialise(tenors, strikes, values, calendar, bdc);
174}
175
176template <class IS, class IE>
177void OptionInterpolator2d<IS, IE>::initialise(const std::vector<QuantLib::Date>& dates,
178 const std::vector<QuantLib::Real>& strikes,
179 const std::vector<QuantLib::Real>& values) {
180 using QuantLib::Date;
181 using QuantLib::Interpolation;
182 using QuantLib::Real;
183 using QuantLib::Size;
184 using QuantLib::Time;
185 using std::pair;
186 using std::set;
187 using std::vector;
188 QL_REQUIRE((strikes.size() == dates.size()) && (dates.size() == values.size()),
189 "dates, strikes and values vectors not of equal size.");
190
191 // first get uniques dates and sort
192 set<Date> datesSet(dates.begin(), dates.end());
193 expiries_ = vector<Date>(datesSet.begin(), datesSet.end());
194 vector<bool> dateDone(expiries_.size(), false);
195 times_ = vector<Time>(expiries_.size());
196 interpolations_ = vector<Interpolation>(expiries_.size());
197 values_ = vector<vector<Real> >(expiries_.size());
198 strikes_ = vector<vector<Real> >(expiries_.size());
199
200 // Populate expiry info. (Except interpolation obj members)
201 for (Size i = 0; i < dates.size(); i++) {
202 vector<Date>::iterator found = find(expiries_.begin(), expiries_.end(), dates[i]);
203 QL_REQUIRE(found != expiries_.end(), "Date should already be loaded" << dates[i]);
204 Size ii;
205 ii = distance(expiries_.begin(), found); // index of expiry
206
207 if (!dateDone[ii]) {
208 // add expiry data if not found
209 QL_REQUIRE(dates[i] >= referenceDate_,
210 "Expiry date:" << dates[i] << " before asof date: " << referenceDate_);
211 times_[ii] = dayCounter_.yearFraction(referenceDate_, dates[i]);
212 strikes_[ii].push_back(strikes[i]);
213 values_[ii].push_back(values[i]);
214 dateDone[ii] = true;
215 } else {
216 // expiry found => add if strike not found
217 Real tmpStrike = strikes[i];
218 vector<Real>::iterator fnd =
219 find_if(strikes_[ii].begin(), strikes_[ii].end(), CloseEnoughComparator(tmpStrike));
220 if (fnd == strikes_[ii].end()) {
221 // add strike/var pairs if strike not found for this expiry
222 strikes_[ii].push_back(strikes[i]);
223 values_[ii].push_back(values[i]);
224 }
225 }
226 }
227
228 // check on strikes and values size
229 for (Size i = 0; i < expiries_.size(); i++)
230 QL_REQUIRE(strikes_[i].size() == values_[i].size(),
231 "different number of variances and strikes for date: " << expiries_[i]);
232
233 // set expiries' interpolations.
234 for (Size i = 0; i < expiries_.size(); i++) {
235 // sort strikes within this expiry
236 vector<pair<Real, Real> > tmpPairs(strikes_[i].size());
237 vector<Real> sortedStrikes;
238 vector<Real> sortedVals;
239 for (Size j = 0; j < strikes_[i].size(); j++) {
240 tmpPairs[j] = pair<Real, Real>(strikes_[i][j], values_[i][j]);
241 }
242 sort(tmpPairs.begin(), tmpPairs.end()); // sorts according to first. (strikes)
243 for (vector<pair<Real, Real> >::iterator it = tmpPairs.begin(); it != tmpPairs.end(); it++) {
244 sortedStrikes.push_back(it->first);
245 sortedVals.push_back(it->second);
246 }
247 strikes_[i] = sortedStrikes;
248 values_[i] = sortedVals;
249
250 // set interpolation
251 if (strikes_[i].size() == 1) {
252 interpolations_[i] = Constant().interpolate(values_[i].front());
253 } else {
254 interpolations_[i] =
255 interpolatorStrike_.interpolate(strikes_[i].begin(), strikes_[i].end(), values_[i].begin());
256 }
257 interpolations_[i].enableExtrapolation();
258 }
259 initialised_ = true;
260}
261
262template <class IS, class IE>
263void OptionInterpolator2d<IS, IE>::initialise(const std::vector<QuantLib::Period>& tenors,
264 const std::vector<QuantLib::Real>& strikes,
265 const std::vector<QuantLib::Real>& values,
266 const QuantLib::Calendar& calendar,
267 const QuantLib::BusinessDayConvention& bdc) {
268
269 std::vector<QuantLib::Date> dates;
270 for (auto t : tenors)
271 dates.push_back(calendar.advance(referenceDate(), t, bdc));
272
273 initialise(dates, strikes, values);
274}
275
276template <class IS, class IE>
277QuantLib::Real OptionInterpolator2d<IS, IE>::getValueForStrike(QuantLib::Real strike,
278 const std::vector<QuantLib::Real>& strks,
279 const std::vector<QuantLib::Real>& vars,
280 const QuantLib::Interpolation& intrp) const {
281 QL_REQUIRE(!strks.empty(), "OptionInterpolator2d: no strikes given");
282 QL_REQUIRE(strks.size() == vars.size(), "OptionInterpolator2d: strikes size ("
283 << strks.size() << ") does not match vars size (" << vars.size()
284 << ")");
285 QuantLib::Real retVar;
286 if (strike > strks.back() && upperStrikeConstExtrap_) {
287 retVar = vars.back(); // force flat extrapolate far strike if requested
288 } else if (strike < strks.front() && lowerStrikeConstExtrap_) {
289 retVar = vars.front(); // force flat extrapolate near strike if requested
290 } else {
291 retVar = intrp(strike); // interpolate between strikes or extrap with interpolator default
292 }
293 return retVar;
294}
295
296template <class IS, class IE>
297QuantLib::Real OptionInterpolator2d<IS, IE>::getValue(QuantLib::Time t, QuantLib::Real strike) const {
298 using QuantLib::Interpolation;
299 using QuantLib::Real;
300 using QuantLib::Size;
301 using QuantLib::Time;
302 using std::vector;
303 Time baseTime = dayCounter_.yearFraction(referenceDate_, baseDate_);
304 QL_REQUIRE(initialised_, "No data provided to OptionInterpolator2d");
305 QL_REQUIRE(t >= baseTime, "Variance requested for date before base date: " << baseDate_);
306 if (QuantLib::close_enough(t,baseTime)) {
307 // requested at reference date
308 QL_REQUIRE(!values_.empty(), "OptionInterpolator2d: no expiries given");
309 QL_REQUIRE(!values_.front().empty(), "OptionInterpolator2d: no value for first expiry given");
310 return values_[0][0];
311 } else {
312 QL_REQUIRE(!expiries_.empty(), "OptionInterpolator2d: no expiry given");
313 if (expiries_.size() == 1) {
314 return getValueForStrike(strike, strikes_[0], values_[0], interpolations_[0]);
315 }
316 // ind1 and ind2 two expiries on either side of requested time.
317 Size ind1, ind2;
318 if (t <= times_.front()) {
319 // near end of expiries, use first 2 strikes
320 ind1 = 0;
321 ind2 = 1;
322 } else if (t > times_.back()) {
323 // far end of expiries, use last 2
324 ind1 = times_.size() - 2;
325 ind2 = times_.size() - 1;
326 } else {
327 // requested between existing expiries (interpolate between expiries)
328 ind2 = distance(times_.begin(), lower_bound(times_.begin(), times_.end(), t));
329 ind1 = (ind2 != 0) ? ind2 - 1 : 0;
330 }
331 // interpolate between expiries
332 vector<Real> tmpVars(2);
333 vector<Time> xAxis;
334 xAxis.push_back(times_[ind1]);
335 xAxis.push_back(times_[ind2]);
336
337 tmpVars[0] = getValueForStrike(strike, strikes_[ind1], values_[ind1], interpolations_[ind1]);
338 tmpVars[1] = getValueForStrike(strike, strikes_[ind2], values_[ind2], interpolations_[ind2]);
339 Interpolation interp = interpolatorExpiry_.interpolate(xAxis.begin(), xAxis.end(), tmpVars.begin());
340 // linear extrapolation of expiries in case t > time_.back() above.
341 interp.enableExtrapolation(true);
342 return interp(t);
343 }
344}
345
346template <class IS, class IE>
347QuantLib::Real OptionInterpolator2d<IS, IE>::getValue(QuantLib::Date d, QuantLib::Real strike) const {
348 QL_REQUIRE(initialised_, "No data provided to OptionInterpolator2d");
349 QL_REQUIRE(d >= baseDate_, "Variance requested for date before reference date: " << baseDate_);
350 QuantLib::Real valueReturn;
351
352 std::vector<QuantLib::Date>::const_iterator it = find(expiries_.begin(), expiries_.end(), d);
353 // if the date matches one of the expiries get the value on that day, otherwise use time interpolation
354 if (it != expiries_.end()) {
355 QuantLib::Size dis = distance(expiries_.begin(), it);
356 valueReturn = getValueForStrike(strike, strikes_[dis], values_[dis], interpolations_[dis]);
357 } else {
358 QuantLib::Time t = dayCounter_.yearFraction(referenceDate_, d);
359 valueReturn = getValue(t, strike);
360 }
361 return valueReturn;
362}
363
364template <class IS, class IE> std::vector<QuantLib::Time> OptionInterpolator2d<IS, IE>::times() const {
365 QL_REQUIRE(initialised_, "No data provided to OptionInterpolator2d");
367}
368
369template <class IS, class IE> std::vector<QuantLib::Date> OptionInterpolator2d<IS, IE>::expiries() const {
370 QL_REQUIRE(initialised_, "No data provided to OptionInterpolator2d");
372}
373
374template <class IS, class IE> std::vector<std::vector<QuantLib::Real> > OptionInterpolator2d<IS, IE>::strikes() const {
375 QL_REQUIRE(initialised_, "No data provided to OptionInterpolator2d");
377}
378
379template <class IS, class IE> std::vector<std::vector<QuantLib::Real> > OptionInterpolator2d<IS, IE>::values() const {
380 QL_REQUIRE(initialised_, "No data provided to OptionInterpolator2d");
382}
383
384} // namespace QuantExt
385
386#endif
Constant-interpolation factory and traits
QuantLib::Interpolation interpolate(const Real &y) const
std::vector< QuantLib::Date > expiries() const
std::vector< QuantLib::Interpolation > interpolations_
OptionInterpolator2d & operator=(const OptionInterpolator2d &)=delete
OptionInterpolator2d(const OptionInterpolator2d &)=delete
QuantLib::Real getValueForStrike(QuantLib::Real strike, const std::vector< QuantLib::Real > &strks, const std::vector< QuantLib::Real > &vars, const QuantLib::Interpolation &intrp) const
std::vector< std::vector< QuantLib::Real > > strikes() const
OptionInterpolator2d(const QuantLib::Date &referenceDate, const QuantLib::Calendar &calendar, const QuantLib::BusinessDayConvention &bdc, const QuantLib::DayCounter &dayCounter, const std::vector< QuantLib::Period > &tenors, const std::vector< QuantLib::Real > &strikes, const std::vector< QuantLib::Real > &values, bool lowerStrikeConstExtrap=true, bool upperStrikeConstExtrap=true, const InterpolatorStrike &interpolatorStrike=InterpolatorStrike(), const InterpolatorExpiry &interpolatorExpiry=InterpolatorExpiry(), const QuantLib::Date &baseDate=QuantLib::Date())
OptionInterpolator2d Constructor with Tenors.
void initialise(const std::vector< QuantLib::Period > &tenors, const std::vector< QuantLib::Real > &strikes, const std::vector< QuantLib::Real > &values, const QuantLib::Calendar &calendar, const QuantLib::BusinessDayConvention &bdc)
std::vector< std::vector< QuantLib::Real > > values() const
void initialise(const std::vector< QuantLib::Date > &dates, const std::vector< QuantLib::Real > &strikes, const std::vector< QuantLib::Real > &values)
Initialise.
OptionInterpolator2d(const QuantLib::Date &referenceDate, const QuantLib::DayCounter &dayCounter, bool lowerStrikeConstExtrap=true, bool upperStrikeConstExtrap=true, const InterpolatorStrike &interpolatorStrike=InterpolatorStrike(), const InterpolatorExpiry &interpolatorExpiry=InterpolatorExpiry(), const QuantLib::Date &baseDate=QuantLib::Date())
OptionInterpolator2d default Constructor.
QuantLib::Real getValue(QuantLib::Date d, QuantLib::Real strike) const override
QuantLib::DayCounter dayCounter() const
OptionInterpolator2d(const QuantLib::Date &referenceDate, const QuantLib::DayCounter &dayCounter, const std::vector< QuantLib::Date > &dates, const std::vector< QuantLib::Real > &strikes, const std::vector< QuantLib::Real > &values, bool lowerStrikeConstExtrap=true, bool upperStrikeConstExtrap=true, const InterpolatorStrike &interpolatorStrike=InterpolatorStrike(), const InterpolatorExpiry &interpolatorExpiry=InterpolatorExpiry(), const QuantLib::Date &baseDate=QuantLib::Date())
OptionInterpolator2d Constructor with dates.
QuantLib::Real getValue(QuantLib::Time t, QuantLib::Real strike) const override
virtual access methods
std::vector< QuantLib::Time > times() const
Option surface interpolator base.
std::vector< QuantLib::Date > expiries() const
std::vector< std::vector< QuantLib::Real > > strikes_
virtual QuantLib::Real getValue(QuantLib::Date d, QuantLib::Real strike) const =0
std::vector< std::vector< QuantLib::Real > > strikes() const
OptionInterpolatorBase(const QuantLib::Date &referenceDate)
std::vector< std::vector< QuantLib::Real > > values() const
std::vector< QuantLib::Time > times_
std::vector< QuantLib::Date > expiries_
virtual QuantLib::Real getValue(QuantLib::Time t, QuantLib::Real strike) const =0
virtual access methods
const QuantLib::Date & referenceDate() const
std::vector< std::vector< QuantLib::Real > > values_
std::vector< QuantLib::Time > times() const
flat interpolation decorator
CloseEnoughComparator(const QuantLib::Real v)
bool operator()(const QuantLib::Real w) const
vector< Real > strikes