QuantLib: a free/open-source library for quantitative finance
Fully annotated sources - version 1.32
Loading...
Searching...
No Matches
fdhestonhullwhitevanillaengine.cpp
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2009 Klaus Spanderen
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#include <ql/methods/finitedifferences/meshers/fdmblackscholesmesher.hpp>
21#include <ql/methods/finitedifferences/meshers/fdmblackscholesmultistrikemesher.hpp>
22#include <ql/methods/finitedifferences/meshers/fdmhestonvariancemesher.hpp>
23#include <ql/methods/finitedifferences/meshers/fdmmeshercomposite.hpp>
24#include <ql/methods/finitedifferences/meshers/fdmsimpleprocess1dmesher.hpp>
25#include <ql/methods/finitedifferences/meshers/uniform1dmesher.hpp>
26#include <ql/methods/finitedifferences/operators/fdmlinearoplayout.hpp>
27#include <ql/methods/finitedifferences/stepconditions/fdmstepconditioncomposite.hpp>
28#include <ql/methods/finitedifferences/utilities/fdminnervaluecalculator.hpp>
29#include <ql/pricingengines/vanilla/analytichestonengine.hpp>
30#include <ql/pricingengines/vanilla/fdhestonhullwhitevanillaengine.hpp>
31#include <ql/pricingengines/vanilla/fdhestonvanillaengine.hpp>
32#include <utility>
33
34namespace QuantLib {
35
36 QL_DEPRECATED_DISABLE_WARNING
37
39 const ext::shared_ptr<HestonModel>& hestonModel,
40 ext::shared_ptr<HullWhiteProcess> hwProcess,
41 Real corrEquityShortRate,
42 Size tGrid,
43 Size xGrid,
44 Size vGrid,
45 Size rGrid,
46 Size dampingSteps,
47 bool controlVariate,
48 const FdmSchemeDesc& schemeDesc)
51 DividendVanillaOption::results>(hestonModel),
52 hwProcess_(std::move(hwProcess)), explicitDividends_(false),
53 corrEquityShortRate_(corrEquityShortRate), tGrid_(tGrid),
54 xGrid_(xGrid), vGrid_(vGrid), rGrid_(rGrid), dampingSteps_(dampingSteps),
55 schemeDesc_(schemeDesc), controlVariate_(controlVariate) {}
56
58 const ext::shared_ptr<HestonModel>& hestonModel,
59 ext::shared_ptr<HullWhiteProcess> hwProcess,
60 DividendSchedule dividends,
61 Real corrEquityShortRate,
62 Size tGrid,
63 Size xGrid,
64 Size vGrid,
65 Size rGrid,
66 Size dampingSteps,
67 bool controlVariate,
68 const FdmSchemeDesc& schemeDesc)
71 DividendVanillaOption::results>(hestonModel),
72 hwProcess_(std::move(hwProcess)), dividends_(std::move(dividends)), explicitDividends_(true),
73 corrEquityShortRate_(corrEquityShortRate), tGrid_(tGrid),
74 xGrid_(xGrid), vGrid_(vGrid), rGrid_(rGrid), dampingSteps_(dampingSteps),
75 schemeDesc_(schemeDesc), controlVariate_(controlVariate) {}
76
77 QL_DEPRECATED_ENABLE_WARNING
78
80
81 // dividends will eventually be moved out of arguments, but for now we need the switch
82 QL_DEPRECATED_DISABLE_WARNING
83 const DividendSchedule& passedDividends = explicitDividends_ ? dividends_ : arguments_.cashFlow;
84 QL_DEPRECATED_ENABLE_WARNING
85
86 // 1. cache lookup for precalculated results
87 for (auto& cachedArgs2result : cachedArgs2results_) {
88 if (cachedArgs2result.first.exercise->type() == arguments_.exercise->type() &&
89 cachedArgs2result.first.exercise->dates() == arguments_.exercise->dates()) {
90 ext::shared_ptr<PlainVanillaPayoff> p1 =
91 ext::dynamic_pointer_cast<PlainVanillaPayoff>(
92 arguments_.payoff);
93 ext::shared_ptr<PlainVanillaPayoff> p2 =
94 ext::dynamic_pointer_cast<PlainVanillaPayoff>(cachedArgs2result.first.payoff);
95
96 if ((p1 != nullptr) && p1->strike() == p2->strike() &&
97 p1->optionType() == p2->optionType()) {
98 QL_REQUIRE(passedDividends.empty(),
99 "multiple strikes engine does not work with discrete dividends");
100 results_ = cachedArgs2result.second;
101 return;
102 }
103 }
104 }
105
106 // 2. Mesher
107 const ext::shared_ptr<HestonProcess> hestonProcess=model_->process();
108 const Time maturity=hestonProcess->time(arguments_.exercise->lastDate());
109
110 // 2.1 The variance mesher
111 const Size tGridMin = 5;
112 const ext::shared_ptr<FdmHestonVarianceMesher> varianceMesher(
113 new FdmHestonVarianceMesher(vGrid_, hestonProcess,
114 maturity,std::max(tGridMin,tGrid_/50)));
115
116 // 2.2 The equity mesher
117 const ext::shared_ptr<StrikedTypePayoff> payoff =
118 ext::dynamic_pointer_cast<StrikedTypePayoff>(arguments_.payoff);
119 QL_REQUIRE(payoff, "wrong payoff type given");
120
121 ext::shared_ptr<Fdm1dMesher> equityMesher;
122 if (strikes_.empty()) {
123 equityMesher = ext::shared_ptr<Fdm1dMesher>(
125 xGrid_,
127 hestonProcess->s0(), hestonProcess->dividendYield(),
128 hestonProcess->riskFreeRate(),
129 varianceMesher->volaEstimate()),
130 maturity, payoff->strike(),
131 Null<Real>(), Null<Real>(), 0.0001, 1.5,
132 std::pair<Real, Real>(payoff->strike(), 0.1),
133 passedDividends));
134 }
135 else {
136 QL_REQUIRE(passedDividends.empty(),
137 "multiple strikes engine does not work with discrete dividends");
138 equityMesher = ext::shared_ptr<Fdm1dMesher>(
140 xGrid_,
142 hestonProcess->s0(), hestonProcess->dividendYield(),
143 hestonProcess->riskFreeRate(),
144 varianceMesher->volaEstimate()),
145 maturity, strikes_, 0.0001, 1.5,
146 std::pair<Real, Real>(payoff->strike(), 0.075)));
147 }
148
149 //2.3 The short rate mesher
150 const ext::shared_ptr<OrnsteinUhlenbeckProcess> ouProcess(
152 const ext::shared_ptr<Fdm1dMesher> shortRateMesher(
153 new FdmSimpleProcess1dMesher(rGrid_, ouProcess, maturity));
154
155 const ext::shared_ptr<FdmMesher> mesher(
156 new FdmMesherComposite(equityMesher, varianceMesher,
157 shortRateMesher));
158
159 // 3. Calculator
160 const ext::shared_ptr<FdmInnerValueCalculator> calculator(
161 new FdmLogInnerValue(arguments_.payoff, mesher, 0));
162
163 // 4. Step conditions
164 const ext::shared_ptr<FdmStepConditionComposite> conditions =
166 passedDividends, arguments_.exercise,
167 mesher, calculator,
168 hestonProcess->riskFreeRate()->referenceDate(),
169 hestonProcess->riskFreeRate()->dayCounter());
170
171 // 5. Boundary conditions
172 const FdmBoundaryConditionSet boundaries;
173
174 // 6. Solver
175 const FdmSolverDesc solverDesc = { mesher, boundaries, conditions,
176 calculator, maturity,
178
179 const ext::shared_ptr<FdmHestonHullWhiteSolver> solver(
183 solverDesc, schemeDesc_));
184
185 const Real spot = hestonProcess->s0()->value();
186 const Real v0 = hestonProcess->v0();
187 results_.value = solver->valueAt(spot, v0, 0);
188 results_.delta = solver->deltaAt(spot, v0, 0, spot*0.01);
189 results_.gamma = solver->gammaAt(spot, v0, 0, spot*0.01);
190 results_.theta = solver->thetaAt(spot, v0, 0);
191
192 cachedArgs2results_.resize(strikes_.size());
193 for (Size i=0; i < strikes_.size(); ++i) {
194 cachedArgs2results_[i].first.exercise = arguments_.exercise;
195 cachedArgs2results_[i].first.payoff =
196 ext::make_shared<PlainVanillaPayoff>(
197 payoff->optionType(), strikes_[i]);
198 const Real d = payoff->strike()/strikes_[i];
199
200 QL_DEPRECATED_DISABLE_WARNING
202 results = cachedArgs2results_[i].second;
203 QL_DEPRECATED_ENABLE_WARNING
204 results.value = solver->valueAt(spot*d, v0, 0)/d;
205 results.delta = solver->deltaAt(spot*d, v0, 0, spot*d*0.01);
206 results.gamma = solver->gammaAt(spot*d, v0, 0, spot*d*0.01)*d;
207 results.theta = solver->thetaAt(spot*d, v0, 0)/d;
208 }
209
210 if (controlVariate_) {
211 ext::shared_ptr<PricingEngine> analyticEngine(
212 new AnalyticHestonEngine(*model_, 164));
213 ext::shared_ptr<Exercise> exercise(
214 new EuropeanExercise(arguments_.exercise->lastDate()));
215
216 VanillaOption option(payoff, exercise);
217 option.setPricingEngine(analyticEngine);
218 Real analyticNPV = option.NPV();
219
220 ext::shared_ptr<FdHestonVanillaEngine> fdEngine(
223 schemeDesc_));
224 fdEngine->enableMultipleStrikesCaching(strikes_);
225 option.setPricingEngine(fdEngine);
226
227 Real fdNPV = option.NPV();
228 results_.value += analyticNPV - fdNPV;
229 for (Size i=0; i < strikes_.size(); ++i) {
230 VanillaOption controlVariateOption(
231 ext::shared_ptr<StrikedTypePayoff>(
232 new PlainVanillaPayoff(payoff->optionType(),
233 strikes_[i])), exercise);
234 controlVariateOption.setPricingEngine(analyticEngine);
235 analyticNPV = controlVariateOption.NPV();
236
237 controlVariateOption.setPricingEngine(fdEngine);
238 fdNPV = controlVariateOption.NPV();
239 cachedArgs2results_[i].second.value += analyticNPV - fdNPV;
240 }
241 }
242 }
243
245 cachedArgs2results_.clear();
246 QL_DEPRECATED_DISABLE_WARNING
250 QL_DEPRECATED_ENABLE_WARNING
251 }
252
254 const std::vector<Real>& strikes) {
255 strikes_ = strikes;
256 update();
257 }
258
259}
analytic Heston-model engine based on Fourier transform
Single-asset vanilla option (no barriers) with discrete dividends.
European exercise.
Definition: exercise.hpp:96
FdHestonHullWhiteVanillaEngine(const ext::shared_ptr< HestonModel > &model, ext::shared_ptr< HullWhiteProcess > hwProcess, Real corrEquityShortRate, Size tGrid=50, Size xGrid=100, Size vGrid=40, Size rGrid=20, Size dampingSteps=0, bool controlVariate=true, const FdmSchemeDesc &schemeDesc=FdmSchemeDesc::Hundsdorfer())
const ext::shared_ptr< HullWhiteProcess > hwProcess_
QL_DEPRECATED_DISABLE_WARNING std::vector< std::pair< DividendVanillaOption::arguments, DividendVanillaOption::results > > cachedArgs2results_
void enableMultipleStrikesCaching(const std::vector< Real > &strikes)
Finite-differences Heston vanilla option engine.
static ext::shared_ptr< GeneralizedBlackScholesProcess > processHelper(const Handle< Quote > &s0, const Handle< YieldTermStructure > &rTS, const Handle< YieldTermStructure > &qTS, Volatility vol)
static ext::shared_ptr< FdmStepConditionComposite > vanillaComposite(const DividendSchedule &schedule, const ext::shared_ptr< Exercise > &exercise, const ext::shared_ptr< FdmMesher > &mesher, const ext::shared_ptr< FdmInnerValueCalculator > &calculator, const Date &refDate, const DayCounter &dayCounter)
Base class for some pricing engine on a particular model.
Shared handle to an observable.
Definition: handle.hpp:41
Heston model for the stochastic volatility of an asset.
Definition: hestonmodel.hpp:42
Real NPV() const
returns the net present value of the instrument.
Definition: instrument.hpp:167
void setPricingEngine(const ext::shared_ptr< PricingEngine > &)
set the pricing engine to be used.
Definition: instrument.cpp:35
template class providing a null value for a given type.
Definition: null.hpp:76
Ornstein-Uhlenbeck process class.
Plain-vanilla payoff.
Definition: payoffs.hpp:105
Vanilla option (no discrete dividends, no barriers) on a single asset.
Real Time
continuous quantity with 1-year units
Definition: types.hpp:62
QL_REAL Real
real number
Definition: types.hpp:50
std::size_t Size
size of a container
Definition: types.hpp:58
Definition: any.hpp:35
std::vector< ext::shared_ptr< Dividend > > DividendSchedule
OperatorTraits< FdmLinearOp >::bc_set FdmBoundaryConditionSet
STL namespace.