22#include <ql/errors.hpp>
23#include <ql/math/comparison.hpp>
24#include <ql/math/integrals/gausslobattointegral.hpp>
32 alpha = std::max(alpha, 1E-5);
35 else if (rho > 1 - 1E-5)
40 Real zeta = nu / alpha * (forward - strike);
41 Real x = std::log((std::sqrt(1.0 - 2.0 * rho * zeta + zeta * zeta) - rho + zeta) / (1.0 - rho));
43 Real vol = alpha * f * (1.0 + expiryTime * (2.0 - 3.0 * rho * rho) * nu * nu / 24.0);
44 QL_REQUIRE(std::isfinite(vol),
"normalSabrVolatility: computed invalid vol for strike="
45 << strike <<
", forward=" << forward <<
", expiryTime=" << expiryTime
46 <<
", alpha=" << alpha <<
", nu=" << nu <<
", rho=" << rho);
47 return std::max(vol, 0.00001);
51 return std::max(atmVol / (1.0 + expiryTime * (2.0 - 3.0 * rho * rho) * nu * nu / 24.0), 0.00001);
56Real deltaR(
const Real t) {
return std::exp(t / 8.0) - (3072.0 + t * (384.0 + t * (24.0 + t))) / 3072.0; }
58Real g(
const Real s) {
return s / std::tanh(s) - 1.0; }
60Real R(
const Real t,
const Real s) {
64 return (3072.0 + t * (384.0 + t * (24.0 + t))) / 3072.0 - t * (2688.0 + t * (80.0 + 21.0 * t)) / 322560.0 * s2 +
65 t * (2816.0 - t * (88.0 + 63.0 * t)) / 3548160.0 * s4;
71 return 1.0 + 3.0 * t * gval / (8.0 * s2) - (5.0 * t2 * (-8.0 * s2 + gval * (24.0 + 3.0 * gval))) / (128.0 * s4) +
72 (35.0 * t3 * (-40.0 * s2 + gval * (120 + gval * (24.0 + 3.0 * gval)))) / (1024.0 * s6);
75Real G(
const Real t,
const Real s) {
76 return std::sqrt(std::sinh(s) / s) * std::exp(-s * s / (2.0 * t) - t / 8.0) * (R(t, s) + deltaR(t));
84 nu = std::max(nu, 1E-6);
87 else if (rho > 1 - 1E-5)
93 Real k = (strike - forward) / V0 + rho;
94 Real rhobar = std::sqrt(1.0 - rho * rho);
95 Real arg = (-rho * k + std::sqrt(k * k + rhobar * rhobar)) / (rhobar * rhobar);
96 QL_REQUIRE(arg > 1.0 - 1E-12,
"invalid arg (" << arg <<
"), must be >= 1");
97 Real s0 = std::acosh(std::max(1.0, arg));
99 auto integrand = [k, rho, nu, expiryTime](
const Real s) {
100 Real tmp = (k - rho * std::cosh(s));
101 Real arg = std::sinh(s) * std::sinh(s) - tmp * tmp;
102 QL_REQUIRE(arg > -1E-12,
"invalid arg (" << arg <<
"), must be >= 0 (tmp=" << tmp <<
")");
103 return G(nu * nu * expiryTime, s) / std::sinh(s) * std::sqrt(std::max(0.0, arg));
106 Real lowerBound = std::max(s0, 1E-12);
107 Real upperBound = std::max(1.5 * s0, 1.0);
108 while (integrand(upperBound) > 1E-12)
111 GaussLobattoIntegral gl(10000, 1E-8);
112 Real price = V0 / M_PI * gl(integrand, lowerBound, upperBound);
113 price += std::max(forward - strike, 0.0);
implied bachelier volatility based on Jaeckel, Implied Normal Volatility, 2017
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
Real normalFreeBoundarySabrVolatility(Rate strike, Rate forward, Time expiryTime, Real alpha, Real nu, Real rho)
Real exactBachelierImpliedVolatility(Option::Type optionType, Real strike, Real forward, Real tte, Real bachelierPrice, Real discount)
Real normalSabrVolatility(Rate strike, Rate forward, Time expiryTime, Real alpha, Real nu, Real rho)
Real normalFreeBoundarySabrPrice(Rate strike, Rate forward, Time expiryTime, Real alpha, Real nu, Real rho)
Real normalSabrAlphaFromAtmVol(Rate forward, Time expiryTime, Real atmVol, Real nu, Real rho)
normal SABR model implied volatility approximation