24#include <ql/math/distributions/gammadistribution.hpp>
25#include <ql/pricingengines/vanilla/analytich1hwengine.hpp>
29 class AnalyticH1HWEngine::Fj_Helper {
32 Fj_Helper(
const Handle<HestonModel>& hestonModel,
33 const ext::shared_ptr<HullWhite>& hullWhiteModel,
36 std::complex<Real> operator()(
Real u)
const;
45 const Real lambda_, eta_;
46 const Real v0_, kappa_, theta_, gamma_;
52 AnalyticH1HWEngine::Fj_Helper::Fj_Helper(
53 const Handle<HestonModel>& hestonModel,
54 const ext::shared_ptr<HullWhite>& hullWhiteModel,
57 lambda_(hullWhiteModel->a()),
58 eta_ (hullWhiteModel->sigma()),
59 v0_ (hestonModel->v0()),
60 kappa_ (hestonModel->kappa()),
61 theta_ (hestonModel->theta()),
62 gamma_ (hestonModel->sigma()),
63 d_ (4.0*kappa_*theta_/(gamma_*gamma_)),
68 Real AnalyticH1HWEngine::Fj_Helper::c(Time t)
const {
69 return gamma_*gamma_/(4*kappa_)*(1.0-std::exp(-kappa_*t));
72 Real AnalyticH1HWEngine::Fj_Helper::lambda(Time t)
const {
73 return 4.0*kappa_*v0_*std::exp(-kappa_*t)
74 /(gamma_*gamma_*(1.0-std::exp(-kappa_*t)));
77 Real AnalyticH1HWEngine::Fj_Helper::LambdaApprox(Time t)
const {
78 return std::sqrt( c(t)*(lambda(t)-1.0)
79 + c(t)*d_*(1.0 + 1.0/(2.0*(d_+lambda(t)))));
82 Real AnalyticH1HWEngine::Fj_Helper::Lambda(Time t)
const {
83 const GammaFunction
g = GammaFunction();
84 const Size maxIter = 1000;
85 const Real lambdaT = lambda(t);
92 s=std::exp(k*std::log(0.5*lambdaT) +
g.logValue(0.5*(1+d_)+k)
93 -
g.logValue(k+1) -
g.logValue(0.5*d_+k));
95 }
while (s > std::numeric_limits<float>::epsilon() && ++i < maxIter);
97 QL_REQUIRE(i < maxIter,
"can not calculate Lambda");
99 retVal *= std::sqrt(2*c(t)) * std::exp(-0.5*lambdaT);
103 std::complex<Real> AnalyticH1HWEngine::Fj_Helper::operator()(Real u)
const {
105 const Real gamma2 = gamma_*gamma_;
108 if (8.0*kappa_*theta_/gamma2 > 1.0) {
109 a = std::sqrt(theta_-gamma2/(8.0*kappa_));
110 b = std::sqrt(v0_) - a;
111 c =-std::log((LambdaApprox(1.0)-a)/b);
114 a = std::sqrt(gamma2/(2.0*kappa_))
115 *std::exp( GammaFunction().logValue(0.5*(d_+1.0))
116 - GammaFunction().logValue(0.5*d_));
119 const Time t2 = 1.0/kappa_;
121 const Real Lambda_t1 = std::sqrt(v0_);
122 const Real Lambda_t2 = Lambda(t2);
124 c = std::log((Lambda_t2-a)/(Lambda_t1-a))/(t1-t2);
125 b = std::exp(c*t1)*(Lambda_t1-a);
128 const std::complex<Real> I4 =
129 -1.0 / lambda_ * std::complex<Real>(u * u, ((j_ == 1U) ? -u : u)) *
130 (b / c * (1.0 - std::exp(-c * term_)) + a * term_ +
131 a / lambda_ * (std::exp(-lambda_ * term_) - 1.0) +
132 b / (c - lambda_) * std::exp(-c * term_) * (1.0 - std::exp(-term_ * (lambda_ - c))));
134 return eta_*rhoSr_*I4;
138 AnalyticH1HWEngine::AnalyticH1HWEngine(
139 const ext::shared_ptr<HestonModel>& model,
140 const ext::shared_ptr<HullWhite>& hullWhiteModel,
144 QL_REQUIRE(
rhoSr_ >= 0.0,
"Fourier integration is not stable if "
145 "the equity interest rate correlation is negative");
149 const ext::shared_ptr<HestonModel>& model,
150 const ext::shared_ptr<HullWhite>& hullWhiteModel,
153 relTolerance, maxEvaluations),
AnalyticH1HWEngine(const ext::shared_ptr< HestonModel > &model, const ext::shared_ptr< HullWhite > &hullWhiteModel, Real rhoSr, Size integrationOrder=144)
std::complex< Real > addOnTerm(Real phi, Time t, Size j) const override
Analytic Heston engine incl. stochastic interest rates.
std::complex< Real > addOnTerm(Real phi, Time t, Size j) const override
const ext::shared_ptr< HullWhite > hullWhiteModel_
Handle< HestonModel > model_
Real Time
continuous quantity with 1-year units
std::size_t Size
size of a container