1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2014 Peter Caspers
5
6 This file is part of QuantLib, a free-software/open-source library
7 for financial quantitative analysts and developers - http://quantlib.org/
8
9 QuantLib is free software: you can redistribute it and/or modify it
10 under the terms of the QuantLib license. You should have received a
11 copy of the license along with this program; if not, please email
12 <quantlib-dev@lists.sf.net>. The license is also available online at
13 <http://quantlib.org/license.shtml>.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the license for more details.
18*/
19
20/*! \file noarbsabr.hpp
21 \brief No-arbitrage SABR
22
23 Reference: Paul Doust, No-arbitrage SABR,
24 The Journal of Computational Finance (3–31)
25 Volume 15/Number 3, Spring 2012
26
27 The parameters are bounded as follows (see also below)
28
29 beta [0.01, 0.99]
30 expiryTime (0.0, 30.0]
31 sigmaI = alpha*forward^(beta-1) [0.05, 1.0]
32 nu [0.0001, 0.8]
33 rho [-0.99, 0.99]
34
35 As suggested in the paper, d0 is interpolated (linearly)
36 in phi space. For beta > 0.9 phi is extrapolated to a
37 value corresponding to d0 = tiny_prob = 1E-5 at beta = 1.
38 For tau < 0.25 phi is extrapolated flat.
39 For rho outside [-0.75, 0.75] phi is extrapolated linearly.
40
41 There are some parameter sets that are admissable, yet do
42 not allow for the adjustment procedure as suggested in the
43 paper to force the model implied forward to the correct
44 value. In this case, no adjustment is done, leading to a
45 model implied forward different from the desired one.
46 This situation can be identified by comparing forward()
47 and numericalForward().
48*/
49
50#ifndef quantlib_noarb_sabr
51#define quantlib_noarb_sabr
52
53#include <ql/qldefines.hpp>
54#include <ql/types.hpp>
55#include <ql/math/integrals/gausslobattointegral.hpp>
56
57#include <vector>
58
59namespace QuantLib {
60
61namespace detail {
62namespace NoArbSabrModel {
63// parameter bounds
64const Real beta_min = 0.01;
65const Real beta_max = 0.99;
66const Real expiryTime_max = 30.0;
67const Real sigmaI_min = 0.05;
68const Real sigmaI_max = 1.00;
69const Real nu_min = 0.01;
70const Real nu_max = 0.80;
71const Real rho_min = -0.99;
72const Real rho_max = 0.99;
73// cutoff for phi(d0) / tau
74// if beta = 0.99, d0 is below 1E-14 for
75// bigger values than this
76const Real phiByTau_cutoff = 124.587;
77// number of mc simulations in tabulated
78// absorption probabilities
79const Real nsim = 2500000.0;
80// small probability used for extrapolation
81// of beta towards 1
82const Real tiny_prob = 1E-5;
83// minimum strike used for normal case integration
84const Real strike_min = 1E-6;
85// accuracy and max iterations for
86// numerical integration
87const Real i_accuracy = 1E-7;
88const Size i_max_iterations = 10000;
89// accuracy when adjusting the model forward
90// to match the given forward
91const Real forward_accuracy = 1E-6;
92// step for searching the model forward
93// in newton algorithm
94const Real forward_search_step = 0.0010;
95// lower bound for density evaluation
96const Real density_lower_bound = 1E-50;
97// threshold to identify a zero density
98const Real density_threshold = 1E-100;
99}
100}
101
102class NoArbSabrModel {
103
104 public:
105 NoArbSabrModel(Real expiryTime, Real forward, Real alpha, Real beta, Real nu, Real rho);
106
107 Real optionPrice(Real strike) const;
108 Real digitalOptionPrice(Real strike) const;
109 Real density(const Real strike) const {
110 return p(f: strike) * (1 - absProb_) / numericalIntegralOverP_;
111 }
112
113 Real forward() const { return externalForward_; }
114 Real numericalForward() const { return numericalForward_; }
115 Real expiryTime() const { return expiryTime_; }
116 Real alpha() const { return alpha_; }
117 Real beta() const { return beta_; }
118 Real nu() const { return nu_; }
119 Real rho() const { return rho_; }
120
121 Real absorptionProbability() const { return absProb_; }
122
123 private:
124 Real p(Real f) const;
125 Real forwardError(Real forward) const;
126 const Real expiryTime_, externalForward_;
127 const Real alpha_, beta_, nu_, rho_;
128 Real absProb_, fmin_, fmax_;
129 mutable Real forward_, numericalIntegralOverP_;
130 mutable Real numericalForward_;
131 ext::shared_ptr<GaussLobattoIntegral> integrator_;
132 class integrand;
133 class p_integrand;
134};
135
136namespace detail {
137
138extern "C" const unsigned long sabrabsprob[1209600];
139
140class D0Interpolator {
141 public:
142 D0Interpolator(Real forward, Real expiryTime, Real alpha, Real beta, Real nu, Real rho);
143 Real operator()() const;
144
145 private:
146 Real phi(Real d0) const;
147 Real d0(Real phi) const;
148 const Real forward_, expiryTime_, alpha_, beta_, nu_, rho_, gamma_;
149 Real sigmaI_;
150 std::vector<Real> tauG_, sigmaIG_, rhoG_, nuG_, betaG_;
151};
152
153} // namespace detail
154} // namespace QuantLib
155
156#endif
157

source code of quantlib/ql/experimental/volatility/noarbsabr.hpp