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