Coverage Report

Created: 2026-08-14 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quantlib/ql/processes/hestonslvprocess.cpp
Line
Count
Source
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2015 Johannes Göttker-Schnetmann
5
 Copyright (C) 2015 Klaus Spanderen
6
7
 This file is part of QuantLib, a free-software/open-source library
8
 for financial quantitative analysts and developers - http://quantlib.org/
9
10
 QuantLib is free software: you can redistribute it and/or modify it
11
 under the terms of the QuantLib license.  You should have received a
12
 copy of the license along with this program; if not, please email
13
 <quantlib-dev@lists.sf.net>. The license is also available online at
14
 <https://www.quantlib.org/license.shtml>.
15
16
 This program is distributed in the hope that it will be useful, but WITHOUT
17
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18
 FOR A PARTICULAR PURPOSE.  See the license for more details.
19
*/
20
21
/*! \file hestonslvprocess.cpp
22
    \brief Heston stochastic local volatility process
23
*/
24
25
#include <ql/processes/hestonslvprocess.hpp>
26
#include <ql/math/distributions/normaldistribution.hpp>
27
#include <ql/methods/finitedifferences/utilities/squarerootprocessrndcalculator.hpp>
28
#include <utility>
29
30
namespace QuantLib {
31
32
    HestonSLVProcess::HestonSLVProcess(const ext::shared_ptr<HestonProcess>& hestonProcess,
33
                                       ext::shared_ptr<LocalVolTermStructure> leverageFct,
34
                                       const Real mixingFactor)
35
0
    : mixingFactor_(mixingFactor), hestonProcess_(hestonProcess),
36
0
      leverageFct_(std::move(leverageFct)) {
37
0
        registerWith(hestonProcess);
38
0
        setParameters();
39
0
    };
40
41
0
    void HestonSLVProcess::update() {
42
0
        setParameters();
43
0
        StochasticProcess::update();
44
0
    }
45
46
0
    Array HestonSLVProcess::drift(Time t, const Array& x) const {
47
0
        Array tmp(2);
48
49
0
        const Volatility vol =
50
0
           std::max(1e-8, std::sqrt(x[1])*leverageFct_->localVol(t, x[0], true));
51
52
0
        tmp[0] = riskFreeRate()->forwardRate(t, t, Continuous).rate()
53
0
               - dividendYield()->forwardRate(t, t, Continuous).rate()
54
0
               - 0.5*vol*vol;
55
56
0
        tmp[1] = kappa_*(theta_ - x[1]);
57
58
0
        return tmp;
59
0
    }
60
61
0
    Matrix HestonSLVProcess::diffusion(Time t, const Array& x) const {
62
63
0
        const Real vol =
64
0
            std::max(1e-8, std::sqrt(x[1])*leverageFct_->localVol(t, x[0], true));
65
66
0
        const Real sigma2 = mixedSigma_ * std::sqrt(x[1]);
67
0
        const Real sqrhov = std::sqrt(1.0 - rho_*rho_);
68
69
0
        Matrix tmp(2,2);
70
0
        tmp[0][0] = vol;          tmp[0][1] = 0.0;
71
0
        tmp[1][0] = rho_*sigma2;  tmp[1][1] = sqrhov*sigma2;
72
73
0
        return tmp;
74
0
    }
75
76
    Array HestonSLVProcess::evolve(
77
0
        Time t0, const Array& x0, Time dt, const Array& dw) const {
78
0
        Array retVal(2);
79
80
0
        const Real ex = std::exp(-kappa_*dt);
81
82
0
        const Real m  =  theta_+(x0[1]-theta_)*ex;
83
0
        const Real s2 =  x0[1]*mixedSigma_*mixedSigma_*ex/kappa_*(1-ex)
84
0
                       + theta_*mixedSigma_*mixedSigma_/(2*kappa_)*(1-ex)*(1-ex);
85
0
        const Real psi = s2/(m*m);
86
87
0
        if (psi < 1.5) {
88
0
            const Real b2 = 2/psi-1+std::sqrt(2/psi*(2/psi-1));
89
0
            const Real b  = std::sqrt(b2);
90
0
            const Real a  = m/(1+b2);
91
92
0
            retVal[1] = a*(b+dw[1])*(b+dw[1]);
93
0
        }
94
0
        else {
95
0
            const Real p = (psi-1)/(psi+1);
96
0
            const Real beta = (1-p)/m;
97
0
            const Real u = CumulativeNormalDistribution()(dw[1]);
98
99
0
            retVal[1] = ((u <= p) ? Real(0.0) : std::log((1-p)/(1-u))/beta);
100
0
        }
101
102
0
        const Real mu = riskFreeRate()->forwardRate(t0, t0+dt, Continuous).rate()
103
0
             - dividendYield()->forwardRate(t0, t0+dt, Continuous).rate();
104
105
0
        const Real rho1 = std::sqrt(1-rho_*rho_);
106
107
0
        const Volatility l_0 = leverageFct_->localVol(t0, x0[0], true);
108
0
        const Real v_0 = 0.5*(x0[1]+retVal[1])*l_0*l_0;
109
110
0
        retVal[0] = x0[0]*std::exp(mu*dt - 0.5*v_0*dt
111
0
            + rho_/mixedSigma_*l_0 * (
112
0
                  retVal[1] - kappa_*theta_*dt
113
0
                  + 0.5*(x0[1]+retVal[1])*kappa_*dt - x0[1])
114
0
            + rho1*std::sqrt(v_0*dt)*dw[0]);
115
116
0
        return retVal;
117
0
    }
118
119
0
    void HestonSLVProcess::setParameters() {
120
0
        v0_    = hestonProcess_->v0();
121
0
        kappa_ = hestonProcess_->kappa();
122
0
        theta_ = hestonProcess_->theta();
123
0
        sigma_ = hestonProcess_->sigma();
124
0
        rho_   = hestonProcess_->rho();
125
0
        mixedSigma_ = mixingFactor_ * sigma_;
126
0
    }
127
128
}