32 class AnalyticPTDHestonEngine::Fj_Helper {
35 const Handle<PiecewiseTimeDependentHestonModel>& model,
45 std::vector<Rate> r_, q_;
46 const ext::shared_ptr<YieldTermStructure> qTS_;
47 const Handle<PiecewiseTimeDependentHestonModel> model_;
49 const TimeGrid timeGrid_;
52 AnalyticPTDHestonEngine::Fj_Helper::Fj_Helper(
53 const Handle<PiecewiseTimeDependentHestonModel>& model,
59 x_ (
std::log(model->s0())),
60 sx_(
std::log(strike)),
61 r_(model->timeGrid().size()-1),
62 q_(model->timeGrid().size()-1),
64 timeGrid_(model->timeGrid()){
66 for (Size i=0; i <timeGrid_.size()-1; ++i) {
67 const Time begin = std::min(term_, timeGrid_[i]);
68 const Time end = std::min(term_, timeGrid_[i+1]);
69 r_[i] = model->riskFreeRate()
70 ->forwardRate(begin, end, Continuous, NoFrequency).rate();
71 q_[i] = model->dividendYield()
72 ->forwardRate(begin, end, Continuous, NoFrequency).rate();
76 Real AnalyticPTDHestonEngine::Fj_Helper::operator()(Real phi)
const {
80 phi = std::max(
Real(std::numeric_limits<float>::epsilon()), phi);
82 std::complex<Real> D = 0.0;
83 std::complex<Real> C = 0.0;
85 for (Size i=timeGrid_.size()-1; i > 0; --i) {
86 const Time begin = timeGrid_[i-1];
88 const Time end = std::min(term_, timeGrid_[i]);
89 const Time tau = end-begin;
90 const Time t = 0.5*(end+begin);
101 const std::complex<Real> t1 = t0+std::complex<Real>(0, -rpsig);
102 const std::complex<Real>
d = std::sqrt(t1*t1 - sigma2*phi
103 *std::complex<Real>(-phi, (j_== 1)? 1 : -1));
104 const std::complex<Real>
g = (t1-
d)/(t1+
d);
105 const std::complex<Real> gt
106 = (t1-
d - D*sigma2)/(t1+
d - D*sigma2);
108 D = (t1+
d)/sigma2*(g-gt*std::exp(-
d*tau))
109 /(1.0-gt*std::exp(-
d*tau));
111 const std::complex<Real> lng
112 = std::log((1.0 - gt*std::exp(-
d*tau))/(1.0 - gt));
115 + std::complex<Real>(0.0, phi*(r_[i-1]-q_[i-1])*tau) + C;
118 return std::exp(v0_*D+C+std::complex<Real>(0.0, phi*(
x_ - sx_))).imag()
122 class AnalyticPTDHestonEngine::AP_Helper {
124 AP_Helper(Time term, Real s0, Real strike, Real ratio,
126 const AnalyticPTDHestonEngine*
const enginePtr)
130 sx_(
std::log(strike)),
131 dd_(
x_-
std::log(ratio)),
132 enginePtr_(enginePtr) {
133 QL_REQUIRE(enginePtr !=
nullptr,
"pricing engine required");
136 Real operator()(Real u)
const {
137 const std::complex<Real> z(u, -0.5);
139 const std::complex<Real> phiBS
140 = std::exp(-0.5*sigmaBS_*sigmaBS_*term_
141 *(z*z + std::complex<Real>(-z.imag(), z.real())));
143 return (std::exp(std::complex<Real>(0.0, u*(dd_-sx_)))
144 * (phiBS - enginePtr_->chF(z, term_)) / (u*u + 0.25)).real();
151 const AnalyticPTDHestonEngine*
const enginePtr_;
155 std::complex<Real> AnalyticPTDHestonEngine::lnChF(
156 const std::complex<Real>& z,
Time T)
const {
158 const Real v0 = model_->v0();
160 std::complex<Real> D = 0.0;
161 std::complex<Real> C = 0.0;
163 const TimeGrid& timeGrid = model_->timeGrid();
164 const Time lastModelTime = timeGrid.
back();
167 "maturity (" <<
T <<
") is too large, "
168 "time grid is bounded by " << lastModelTime);
170 const Size lastI = std::distance(timeGrid.
begin(),
171 std::lower_bound(timeGrid.
begin(), timeGrid.
end(),
T));
173 for (
Integer i=lastI-1; i >= 0; --i) {
174 const Time begin = timeGrid[i];
175 const Time end = std::min(
T, timeGrid[i+1]);
176 const Time tau = end - begin;
178 const Time t = 0.5*(end+begin);
186 const std::complex<Real> k
189 const std::complex<Real>
d = std::sqrt(
190 k*k + (z*z + std::complex<Real>(-z.imag(), z.real()))*sigma2);
192 const std::complex<Real> g = (k-
d)/(k+
d);
194 const std::complex<Real> gt = (k-
d-D*sigma2)/(k+
d-D*sigma2);
197 - 2.0*std::log((1.0-gt*std::exp(-
d*tau))/(1.0-gt)));
199 D = (k+
d)/sigma2 * (g - gt*std::exp(-
d*tau))
200 /(1.0 - gt*std::exp(-
d*tau));
206 std::complex<Real> AnalyticPTDHestonEngine::chF(
207 const std::complex<Real>& z,
Time T)
const {
208 return std::exp(lnChF(z,
T));
211 AnalyticPTDHestonEngine::AnalyticPTDHestonEngine(
212 const ext::shared_ptr<PiecewiseTimeDependentHestonModel>& model,
213 Size integrationOrder)
221 andersenPiterbargEpsilon_(
Null<
Real>()) {
225 const ext::shared_ptr<PiecewiseTimeDependentHestonModel>& model,
226 Real relTolerance,
Size maxEvaluations)
233 relTolerance,
Null<
Real>(), maxEvaluations))),
234 andersenPiterbargEpsilon_(
Null<
Real>()) {
238 const ext::shared_ptr<PiecewiseTimeDependentHestonModel>& model,
241 Real andersenPiterbargEpsilon)
248 andersenPiterbargEpsilon_(andersenPiterbargEpsilon) {
255 "not an European option");
258 ext::shared_ptr<PlainVanillaPayoff>
payoff =
259 ext::dynamic_pointer_cast<PlainVanillaPayoff>(
arguments_.payoff);
264 QL_REQUIRE(spotPrice > 0.0,
"negative or null underlying given");
268 =
model_->riskFreeRate()->dayCounter().yearFraction(
269 model_->riskFreeRate()->referenceDate(),
272 QL_REQUIRE(term < model_->timeGrid().back() ||
274 "maturity (" << term <<
") is too large, time grid is bounded by "
275 <<
model_->timeGrid().back());
277 const Real riskFreeDiscount =
model_->riskFreeRate()->discount(
279 const Real dividendDiscount =
model_->dividendYield()->discount(
284 QL_REQUIRE(timeGrid.
size() > 1,
"at least two model points needed");
287 Real kappaAvg = 0.0, thetaAvg = 0.0, sigmaAvg=0.0, rhoAvg = 0.0;
289 for (
Size i=1; i <=
n; ++i) {
290 const Time t = 0.5*(timeGrid[i-1] + timeGrid[i]);
296 kappaAvg/=
n; thetaAvg/=
n; sigmaAvg/=
n; rhoAvg/=
n;
302 const Real c_inf = std::min(0.2, std::max(0.0001,
303 std::sqrt(1.0-
squared(rhoAvg))/sigmaAvg))
304 *(
v0 + kappaAvg*thetaAvg*term);
314 switch (
payoff->optionType())
317 results_.value = spotPrice*dividendDiscount*(p1+0.5)
318 - strike*riskFreeDiscount*(p2+0.5);
321 results_.value = spotPrice*dividendDiscount*(p1-0.5)
322 - strike*riskFreeDiscount*(p2-0.5);
325 QL_FAIL(
"unknown option type");
331 "maturity (" << term <<
") is too large, "
332 "time grid is bounded by " << timeGrid.
back());
334 const Time t05 = 0.5*timeGrid.
at(1);
336 const std::complex<Real> D_u_inf =
341 const Size lastI = std::distance(timeGrid.
begin(),
342 std::lower_bound(timeGrid.
begin(), timeGrid.
end(), term));
344 std::complex<Real> C_u_inf(0.0, 0.0);
345 for (
Size i=0; i < lastI; ++i) {
346 const Time begin = timeGrid[i];
347 const Time end = std::min(term, timeGrid[i+1]);
348 const Time tau = end - begin;
349 const Time t = 0.5*(end+begin);
357 *std::complex<Real>(std::sqrt(1-
rho*
rho),
rho);
360 const Real ratio = riskFreeDiscount/dividendDiscount;
362 const Real fwdPrice = spotPrice / ratio;
365 *
M_PI/(std::sqrt(strike*fwdPrice)*riskFreeDiscount);
367 const Real c_inf = -(C_u_inf + D_u_inf*
v0).real();
369 const ext::function<
Real()> uM = [=](){
374 = (1-std::exp(-kappaAvg*term))*(
v0-thetaAvg)
375 /(kappaAvg*term) + thetaAvg;
379 fwdPrice, std::sqrt(vAvg*term),
380 riskFreeDiscount).
value();
383 AP_Helper(term, spotPrice, strike,
384 ratio, std::sqrt(vAvg),
this),uM)
385 * std::sqrt(strike * fwdPrice)*riskFreeDiscount/
M_PI;
388 switch (
payoff->optionType())
395 - riskFreeDiscount*(fwdPrice - strike);
398 QL_FAIL(
"unknown option type");
404 QL_FAIL(
"unknown complex log formula");
analytic piecewise time dependent Heston-model engine
Black-formula calculator class.
static Real andersenPiterbargIntegrationLimit(Real c_inf, Real epsilon, Real v0, Real t)
const Real andersenPiterbargEpsilon_
Size numberOfEvaluations() const
void calculate() const override
AnalyticPTDHestonEngine(const ext::shared_ptr< PiecewiseTimeDependentHestonModel > &model, Real relTolerance, Size maxEvaluations)
const ComplexLogFormula cpxLog_
const ext::shared_ptr< Integration > integration_
Black 1976 calculator class.
Base class for some pricing engine on a particular model.
Handle< PiecewiseTimeDependentHestonModel > model_
template class providing a null value for a given type.
Piecewise time dependent Heston model.
const_iterator begin() const
const_iterator end() const
Vanilla option (no discrete dividends, no barriers) on a single asset.
#define QL_REQUIRE(condition, message)
throw an error if the given pre-condition is not verified
#define QL_FAIL(message)
throw an error (possibly with file and line information)
Real Time
continuous quantity with 1-year units
Real Volatility
volatility
QL_INTEGER Integer
integer number
std::size_t Size
size of a container
ext::shared_ptr< QuantLib::Payoff > payoff
functionals and combinators not included in the STL
bool close_enough(const Quantity &m1, const Quantity &m2, Size n)
Payoffs for various options.