QuantLib: a free/open-source library for quantitative finance
fully annotated source code - version 1.38
Loading...
Searching...
No Matches
xabrinterpolation.hpp
Go to the documentation of this file.
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2006 Ferdinando Ametrano
5 Copyright (C) 2007 Marco Bianchetti
6 Copyright (C) 2007 François du Vignaud
7 Copyright (C) 2007 Giorgio Facchinetti
8 Copyright (C) 2006 Mario Pucci
9 Copyright (C) 2006 StatPro Italia srl
10 Copyright (C) 2014 Peter Caspers
11
12 This file is part of QuantLib, a free-software/open-source library
13 for financial quantitative analysts and developers - http://quantlib.org/
14
15 QuantLib is free software: you can redistribute it and/or modify it
16 under the terms of the QuantLib license. You should have received a
17 copy of the license along with this program; if not, please email
18 <quantlib-dev@lists.sf.net>. The license is also available online at
19 <http://quantlib.org/license.shtml>.
20
21 This program is distributed in the hope that it will be useful, but WITHOUT
22 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
23 FOR A PARTICULAR PURPOSE. See the license for more details.
24*/
25
26/*! \file xabrinterpolation.hpp
27 \brief generic interpolation class for sabr style underlying models
28 like the Hagan 2002 expansion, Doust's no arbitrage sabr,
29 Andreasen's zabr expansion for the masses and similar
30*/
31
32#ifndef ql_xabr_interpolation_hpp
33#define ql_xabr_interpolation_hpp
34
45#include <ql/utilities/null.hpp>
46#include <utility>
47
48namespace QuantLib::detail {
49
50template <typename Model> class XABRCoeffHolder {
51 public:
53 const Real& forward,
54 const std::vector<Real>& params,
55 const std::vector<bool>& paramIsFixed,
56 std::vector<Real> addParams)
57 : t_(t), forward_(forward), params_(params), paramIsFixed_(paramIsFixed.size(), false),
58 error_(Null<Real>()), maxError_(Null<Real>()), addParams_(std::move(addParams)) {
59 QL_REQUIRE(t > 0.0, "expiry time must be positive: " << t
60 << " not allowed");
61 QL_REQUIRE(params.size() == Model().dimension(),
62 "wrong number of parameters (" << params.size()
63 << "), should be "
64 << Model().dimension());
65 QL_REQUIRE(paramIsFixed.size() == Model().dimension(),
66 "wrong number of fixed parameters flags ("
67 << paramIsFixed.size() << "), should be "
68 << Model().dimension());
69
70 for (Size i = 0; i < params.size(); ++i) {
71 if (params[i] != Null<Real>())
72 paramIsFixed_[i] = paramIsFixed[i];
73 }
74 Model().defaultValues(params_, paramIsFixed_, forward_, t_, addParams_);
76 }
77 virtual ~XABRCoeffHolder() = default;
78
80 modelInstance_ = Model().instance(t_, forward_, params_, addParams_);
81 }
82
83 /*! Expiry, Forward */
85 const Real &forward_;
86 /*! Parameters */
87 std::vector<Real> params_;
88 std::vector<bool> paramIsFixed_;
89 std::vector<Real> weights_;
90 /*! Interpolation results */
93 /*! Model instance (if required) */
94 ext::shared_ptr<typename Model::type> modelInstance_;
95 /*! additional parameters */
96 std::vector<Real> addParams_;
97};
98
99template <class I1, class I2, typename Model>
101 public XABRCoeffHolder<Model> {
102 public:
103 XABRInterpolationImpl(const I1& xBegin,
104 const I1& xEnd,
105 const I2& yBegin,
106 Time t,
107 const Real& forward,
108 const std::vector<Real>& params,
109 const std::vector<bool>& paramIsFixed,
110 bool vegaWeighted,
111 ext::shared_ptr<EndCriteria> endCriteria,
112 ext::shared_ptr<OptimizationMethod> optMethod,
113 const Real errorAccept,
114 const bool useMaxError,
115 const Size maxGuesses,
116 const std::vector<Real>& addParams = std::vector<Real>(),
118 : Interpolation::templateImpl<I1, I2>(xBegin, xEnd, yBegin, 1),
119 XABRCoeffHolder<Model>(t, forward, params, paramIsFixed, addParams),
120 endCriteria_(std::move(endCriteria)), optMethod_(std::move(optMethod)),
121 errorAccept_(errorAccept), useMaxError_(useMaxError), maxGuesses_(maxGuesses),
122 vegaWeighted_(vegaWeighted), volatilityType_(volatilityType) {
123 // if no optimization method or endCriteria is provided, we provide one
124 if (!optMethod_)
125 optMethod_ = ext::shared_ptr<OptimizationMethod>(
126 new LevenbergMarquardt(1e-8, 1e-8, 1e-8));
127 // optMethod_ = ext::shared_ptr<OptimizationMethod>(new
128 // Simplex(0.01));
129 if (!endCriteria_) {
130 endCriteria_ = ext::make_shared<EndCriteria>(
131 60000, 100, 1e-8, 1e-8, 1e-8);
132 }
133 this->weights_ =
134 std::vector<Real>(xEnd - xBegin, 1.0 / (xEnd - xBegin));
135 }
136
137 void update() override {
138
139 this->updateModelInstance();
140
141 // we should also check that y contains positive values only
142
143 // we must update weights if it is vegaWeighted
144 if (vegaWeighted_) {
145 I1 x = this->xBegin_;
146 I2 y = this->yBegin_;
147 // std::vector<Real>::iterator w = weights_.begin();
148 this->weights_.clear();
149 Real weightsSum = 0.0;
150 for (; x != this->xEnd_; ++x, ++y) {
151 Real stdDev = std::sqrt((*y) * (*y) * this->t_);
152 this->weights_.push_back(Model().weight(*x, this->forward_, stdDev,
153 this->addParams_));
154 weightsSum += this->weights_.back();
155 }
156 // weight normalization
157 auto w = this->weights_.begin();
158 for (; w != this->weights_.end(); ++w)
159 *w /= weightsSum;
160 }
161
162 // there is nothing to optimize
163 if (std::accumulate(this->paramIsFixed_.begin(),
164 this->paramIsFixed_.end(), true,
165 std::logical_and<>())) {
166 this->error_ = interpolationError();
169 return;
170 } else {
171 XABRError costFunction(this);
172
173 Array guess(Model().dimension());
174 for (Size i = 0; i < guess.size(); ++i)
175 guess[i] = this->params_[i];
176
177 Size iterations = 0;
178 Size freeParameters = 0;
179 Real bestError = QL_MAX_REAL;
180 Array bestParameters;
181 for (Size i = 0; i < Model().dimension(); ++i)
182 if (!this->paramIsFixed_[i])
183 ++freeParameters;
184 HaltonRsg halton(freeParameters, 42);
185 EndCriteria::Type tmpEndCriteria;
186 Real tmpInterpolationError;
187
188 do {
189
190 if (iterations > 0) {
191 const auto& s = halton.nextSequence();
192 Model().guess(guess, this->paramIsFixed_, this->forward_,
193 this->t_, s.value, this->addParams_);
194 for (Size i = 0; i < this->paramIsFixed_.size(); ++i)
195 if (this->paramIsFixed_[i])
196 guess[i] = this->params_[i];
197 }
198
199 Array inversedTransformatedGuess(Model().inverse(
200 guess, this->paramIsFixed_, this->params_, this->forward_));
201
202 ProjectedCostFunction constrainedXABRError(
203 costFunction, inversedTransformatedGuess,
204 this->paramIsFixed_);
205
206 Array projectedGuess(
207 constrainedXABRError.project(inversedTransformatedGuess));
208
209 NoConstraint constraint;
210 Problem problem(constrainedXABRError, constraint,
211 projectedGuess);
212 tmpEndCriteria = optMethod_->minimize(problem, *endCriteria_);
213 Array projectedResult(problem.currentValue());
214 Array transfResult(
215 constrainedXABRError.include(projectedResult));
216
217 Array result = Model().direct(transfResult, this->paramIsFixed_,
218 this->params_, this->forward_);
219 tmpInterpolationError = useMaxError_ ? interpolationMaxError()
221
222 if (tmpInterpolationError < bestError) {
223 bestError = tmpInterpolationError;
224 bestParameters = result;
225 this->XABREndCriteria_ = tmpEndCriteria;
226 }
227
228 } while (++iterations < maxGuesses_ &&
229 tmpInterpolationError > errorAccept_);
230
231 for (Size i = 0; i < bestParameters.size(); ++i)
232 this->params_[i] = bestParameters[i];
233
234 this->error_ = interpolationError();
236 }
237 }
238
239 Real value(Real x) const override { return this->modelInstance_->volatility(x, volatilityType_); }
240
241 Real primitive(Real) const override { QL_FAIL("XABR primitive not implemented"); }
242 Real derivative(Real) const override { QL_FAIL("XABR derivative not implemented"); }
243 Real secondDerivative(Real) const override { QL_FAIL("XABR secondDerivative not implemented"); }
244
245 // calculate total squared weighted difference (L2 norm)
247 Real error, totalError = 0.0;
248 I1 x = this->xBegin_;
249 I2 y = this->yBegin_;
250 auto w = this->weights_.begin();
251 for (; x != this->xEnd_; ++x, ++y, ++w) {
252 error = (value(*x) - *y);
253 totalError += error * error * (*w);
254 }
255 return totalError;
256 }
257
258 // calculate weighted differences
260 Array results(this->xEnd_ - this->xBegin_);
261 I1 x = this->xBegin_;
262 Array::iterator r = results.begin();
263 I2 y = this->yBegin_;
264 auto w = this->weights_.begin();
265 for (; x != this->xEnd_; ++x, ++r, ++w, ++y) {
266 *r = (value(*x) - *y) * std::sqrt(*w);
267 }
268 return results;
269 }
270
272 Size n = this->xEnd_ - this->xBegin_;
273 Real squaredError = interpolationSquaredError();
274 return std::sqrt(n * squaredError / (n==1 ? 1 : (n - 1)));
275 }
276
278 Real error, maxError = QL_MIN_REAL;
279 I1 i = this->xBegin_;
280 I2 j = this->yBegin_;
281 for (; i != this->xEnd_; ++i, ++j) {
282 error = std::fabs(value(*i) - *j);
283 maxError = std::max(maxError, error);
284 }
285 return maxError;
286 }
287
288 private:
289 class XABRError : public CostFunction {
290 public:
291 explicit XABRError(XABRInterpolationImpl *xabr) : xabr_(xabr) {}
292
293 Real value(const Array& x) const override {
294 const Array y = Model().direct(x, xabr_->paramIsFixed_,
296 for (Size i = 0; i < xabr_->params_.size(); ++i)
297 xabr_->params_[i] = y[i];
300 }
301
302 Array values(const Array& x) const override {
303 const Array y = Model().direct(x, xabr_->paramIsFixed_,
305 for (Size i = 0; i < xabr_->params_.size(); ++i)
306 xabr_->params_[i] = y[i];
308 return xabr_->interpolationErrors();
309 }
310
311 private:
313 };
314 ext::shared_ptr<EndCriteria> endCriteria_;
315 ext::shared_ptr<OptimizationMethod> optMethod_;
317 const bool useMaxError_;
322};
323
324} // namespace QuantLib
325
326#endif
Black formula.
1-D array used in linear algebra.
Definition: array.hpp:52
Real * iterator
Definition: array.hpp:125
Size size() const
dimension of the array
Definition: array.hpp:483
Cost function abstract class for optimization problem.
Halton low-discrepancy sequence generator.
Definition: haltonrsg.hpp:43
const sample_type & nextSequence() const
Definition: haltonrsg.cpp:56
basic template implementation
templateImpl(const I1 &xBegin, const I1 &xEnd, const I2 &yBegin, const int requiredPoints=2)
base class for 1-D interpolations.
Levenberg-Marquardt optimization method.
No constraint.
Definition: constraint.hpp:79
template class providing a null value for a given type.
Definition: null.hpp:59
Constrained optimization problem.
Definition: problem.hpp:42
const Array & currentValue() const
current value of the local minimum
Definition: problem.hpp:81
Parameterized cost function.
virtual Array include(const Array &projectedParameters) const
returns whole set of parameters corresponding to the set
Definition: projection.cpp:67
virtual Array project(const Array &parameters) const
returns the subset of free parameters corresponding
Definition: projection.cpp:54
ext::shared_ptr< typename Model::type > modelInstance_
XABRCoeffHolder(const Time t, const Real &forward, const std::vector< Real > &params, const std::vector< bool > &paramIsFixed, std::vector< Real > addParams)
virtual ~XABRCoeffHolder()=default
Real value(const Array &x) const override
method to overload to compute the cost function value in x
Array values(const Array &x) const override
method to overload to compute the cost function values in x
ext::shared_ptr< EndCriteria > endCriteria_
XABRInterpolationImpl(const I1 &xBegin, const I1 &xEnd, const I2 &yBegin, Time t, const Real &forward, const std::vector< Real > &params, const std::vector< bool > &paramIsFixed, bool vegaWeighted, ext::shared_ptr< EndCriteria > endCriteria, ext::shared_ptr< OptimizationMethod > optMethod, const Real errorAccept, const bool useMaxError, const Size maxGuesses, const std::vector< Real > &addParams=std::vector< Real >(), VolatilityType volatilityType=VolatilityType::ShiftedLognormal)
ext::shared_ptr< OptimizationMethod > optMethod_
Abstract constraint class.
output manipulators
const DefaultType & t
#define QL_REQUIRE(condition, message)
throw an error if the given pre-condition is not verified
Definition: errors.hpp:117
#define QL_FAIL(message)
throw an error (possibly with file and line information)
Definition: errors.hpp:92
#define QL_MAX_REAL
Definition: qldefines.hpp:176
#define QL_MIN_REAL
Definition: qldefines.hpp:175
Real Time
continuous quantity with 1-year units
Definition: types.hpp:62
QL_REAL Real
real number
Definition: types.hpp:50
std::size_t Size
size of a container
Definition: types.hpp:58
Halton low-discrepancy sequence generator.
base class for 1-D interpolations
Levenberg-Marquardt optimization method.
Abstract optimization method class.
Matrix inverse(const Matrix &m)
Definition: matrix.cpp:44
STL namespace.
null values
ext::shared_ptr< YieldTermStructure > r
Cost function utility.
Simplex optimization method.
volatility types