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 
59 namespace QuantLib {
60 
61 namespace detail {
62 namespace NoArbSabrModel {
63 // parameter bounds
64 const Real beta_min = 0.01;
65 const Real beta_max = 0.99;
66 const Real expiryTime_max = 30.0;
67 const Real sigmaI_min = 0.05;
68 const Real sigmaI_max = 1.00;
69 const Real nu_min = 0.01;
70 const Real nu_max = 0.80;
71 const Real rho_min = -0.99;
72 const 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
76 const Real phiByTau_cutoff = 124.587;
77 // number of mc simulations in tabulated
78 // absorption probabilities
79 const Real nsim = 2500000.0;
80 // small probability used for extrapolation
81 // of beta towards 1
82 const Real tiny_prob = 1E-5;
83 // minimum strike used for normal case integration
84 const Real strike_min = 1E-6;
85 // accuracy and max iterations for
86 // numerical integration
87 const Real i_accuracy = 1E-7;
88 const Size i_max_iterations = 10000;
89 // accuracy when adjusting the model forward
90 // to match the given forward
91 const Real forward_accuracy = 1E-6;
92 // step for searching the model forward
93 // in newton algorithm
94 const Real forward_search_step = 0.0010;
95 // lower bound for density evaluation
96 const Real density_lower_bound = 1E-50;
97 // threshold to identify a zero density
98 const Real density_threshold = 1E-100;
99 }
100 }
101 
102 class 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;
density(const Real strike) const109     Real density(const Real strike) const {
110         return p(strike) * (1 - absProb_) / numericalIntegralOverP_;
111     }
112 
forward() const113     Real forward() const { return externalForward_; }
numericalForward() const114     Real numericalForward() const { return numericalForward_; }
expiryTime() const115     Real expiryTime() const { return expiryTime_; }
alpha() const116     Real alpha() const { return alpha_; }
beta() const117     Real beta() const { return beta_; }
nu() const118     Real nu() const { return nu_; }
rho() const119     Real rho() const { return rho_; }
120 
absorptionProbability() const121     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       friend class integrand;
134       class p_integrand;
135       friend class p_integrand;
136 };
137 
138 namespace detail {
139 
140 extern "C" const unsigned long sabrabsprob[1209600];
141 
142 class D0Interpolator {
143   public:
144     D0Interpolator(Real forward, Real expiryTime, Real alpha, Real beta, Real nu, Real rho);
145     Real operator()() const;
146 
147   private:
148     Real phi(Real d0) const;
149     Real d0(Real phi) const;
150     const Real forward_, expiryTime_, alpha_, beta_, nu_, rho_, gamma_;
151     Real sigmaI_;
152     std::vector<Real> tauG_, sigmaIG_, rhoG_, nuG_, betaG_;
153 };
154 
155 } // namespace detail
156 } // namespace QuantLib
157 
158 #endif
159