1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2020 Lew Wei Hao
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
21#include <ql/methods/finitedifferences/meshers/fdmblackscholesmesher.hpp>
22#include <ql/methods/finitedifferences/meshers/fdmmeshercomposite.hpp>
23#include <ql/methods/finitedifferences/meshers/fdmsimpleprocess1dmesher.hpp>
24#include <ql/methods/finitedifferences/operators/fdmlinearoplayout.hpp>
25#include <ql/methods/finitedifferences/solvers/fdmcirsolver.hpp>
26#include <ql/methods/finitedifferences/stepconditions/fdmstepconditioncomposite.hpp>
27#include <ql/methods/finitedifferences/utilities/fdminnervaluecalculator.hpp>
28#include <ql/pricingengines/vanilla/fdcirvanillaengine.hpp>
29#include <ql/processes/blackscholesprocess.hpp>
30#include <ql/processes/coxingersollrossprocess.hpp>
31#include <utility>
32
33namespace QuantLib {
34
35 FdCIRVanillaEngine::FdCIRVanillaEngine(
36 ext::shared_ptr<CoxIngersollRossProcess> cirProcess,
37 ext::shared_ptr<GeneralizedBlackScholesProcess> bsProcess,
38 Size tGrid,
39 Size xGrid,
40 Size rGrid,
41 Size dampingSteps,
42 const Real rho,
43 const FdmSchemeDesc& schemeDesc,
44 ext::shared_ptr<FdmQuantoHelper> quantoHelper)
45 : bsProcess_(std::move(bsProcess)), cirProcess_(std::move(cirProcess)),
46 quantoHelper_(std::move(quantoHelper)), explicitDividends_(false),
47 tGrid_(tGrid), xGrid_(xGrid), rGrid_(rGrid), dampingSteps_(dampingSteps),
48 rho_(rho), schemeDesc_(schemeDesc) {}
49
50 FdCIRVanillaEngine::FdCIRVanillaEngine(
51 ext::shared_ptr<CoxIngersollRossProcess> cirProcess,
52 ext::shared_ptr<GeneralizedBlackScholesProcess> bsProcess,
53 DividendSchedule dividends,
54 Size tGrid,
55 Size xGrid,
56 Size rGrid,
57 Size dampingSteps,
58 const Real rho,
59 const FdmSchemeDesc& schemeDesc,
60 ext::shared_ptr<FdmQuantoHelper> quantoHelper)
61 : bsProcess_(std::move(bsProcess)), cirProcess_(std::move(cirProcess)),
62 quantoHelper_(std::move(quantoHelper)), dividends_(std::move(dividends)),
63 explicitDividends_(true),
64 tGrid_(tGrid), xGrid_(xGrid), rGrid_(rGrid), dampingSteps_(dampingSteps), rho_(rho),
65 schemeDesc_(schemeDesc) {}
66
67 FdmSolverDesc FdCIRVanillaEngine::getSolverDesc(Real) const {
68
69 // dividends will eventually be moved out of arguments, but for now we need the switch
70 QL_DEPRECATED_DISABLE_WARNING
71 const DividendSchedule& passedDividends = explicitDividends_ ? dividends_ : arguments_.cashFlow;
72 QL_DEPRECATED_ENABLE_WARNING
73
74 const ext::shared_ptr<StrikedTypePayoff> payoff =
75 ext::dynamic_pointer_cast<StrikedTypePayoff>(r: arguments_.payoff);
76 const Time maturity = bsProcess_->time(arguments_.exercise->lastDate());
77
78 // The short rate mesher
79 const ext::shared_ptr<Fdm1dMesher> shortRateMesher(
80 new FdmSimpleProcess1dMesher(rGrid_, cirProcess_, maturity, tGrid_));
81
82 // The equity mesher
83 const ext::shared_ptr<Fdm1dMesher> equityMesher(
84 new FdmBlackScholesMesher(
85 xGrid_, bsProcess_, maturity, payoff->strike(),
86 Null<Real>(), Null<Real>(), 0.0001, 1.5,
87 std::pair<Real, Real>(payoff->strike(), 0.1),
88 passedDividends, quantoHelper_,
89 0.0));
90
91 const ext::shared_ptr<FdmMesher> mesher(
92 new FdmMesherComposite(equityMesher, shortRateMesher));
93
94 // Calculator
95 const ext::shared_ptr<FdmInnerValueCalculator> calculator(
96 new FdmLogInnerValue(arguments_.payoff, mesher, 0));
97
98 // Step conditions
99 const ext::shared_ptr<FdmStepConditionComposite> conditions =
100 FdmStepConditionComposite::vanillaComposite(
101 schedule: passedDividends, exercise: arguments_.exercise,
102 mesher, calculator,
103 refDate: bsProcess_->riskFreeRate()->referenceDate(),
104 dayCounter: bsProcess_->riskFreeRate()->dayCounter());
105
106 // Boundary conditions
107 const FdmBoundaryConditionSet boundaries;
108
109 // Solver
110 FdmSolverDesc solverDesc = { .mesher: mesher, .bcSet: boundaries, .condition: conditions,
111 .calculator: calculator, .maturity: maturity,
112 .timeSteps: tGrid_, .dampingSteps: dampingSteps_ };
113
114 return solverDesc;
115 }
116
117 void FdCIRVanillaEngine::calculate() const {
118 const ext::shared_ptr<StrikedTypePayoff> payoff =
119 ext::dynamic_pointer_cast<StrikedTypePayoff>(r: arguments_.payoff);
120
121 ext::shared_ptr<FdmCIRSolver> solver(new FdmCIRSolver(
122 Handle<CoxIngersollRossProcess>(cirProcess_),
123 Handle<GeneralizedBlackScholesProcess>(bsProcess_),
124 getSolverDesc(1.5), schemeDesc_,
125 rho_, payoff->strike()));
126
127 const Real r0 = cirProcess_->x0();
128 const Real spot = bsProcess_->x0();
129
130 results_.value = solver->valueAt(s: spot, v: r0);
131 results_.delta = solver->deltaAt(s: spot, v: r0);
132 results_.gamma = solver->gammaAt(s: spot, v: r0);
133 results_.theta = solver->thetaAt(s: spot, v: r0);
134 }
135
136 MakeFdCIRVanillaEngine::MakeFdCIRVanillaEngine(
137 ext::shared_ptr<CoxIngersollRossProcess> cirProcess,
138 ext::shared_ptr<GeneralizedBlackScholesProcess> bsProcess,
139 const Real rho)
140 : cirProcess_(std::move(cirProcess)), bsProcess_(std::move(bsProcess)), rho_(rho),
141 schemeDesc_(ext::make_shared<FdmSchemeDesc>(args: FdmSchemeDesc::ModifiedHundsdorfer())) {}
142
143 MakeFdCIRVanillaEngine& MakeFdCIRVanillaEngine::withQuantoHelper(
144 const ext::shared_ptr<FdmQuantoHelper>& quantoHelper) {
145 quantoHelper_ = quantoHelper;
146 return *this;
147 }
148
149 MakeFdCIRVanillaEngine&
150 MakeFdCIRVanillaEngine::withTGrid(Size tGrid) {
151 tGrid_ = tGrid;
152 return *this;
153 }
154
155 MakeFdCIRVanillaEngine&
156 MakeFdCIRVanillaEngine::withXGrid(Size xGrid) {
157 xGrid_ = xGrid;
158 return *this;
159 }
160
161 MakeFdCIRVanillaEngine&
162 MakeFdCIRVanillaEngine::withRGrid(Size rGrid) {
163 rGrid_ = rGrid;
164 return *this;
165 }
166
167 MakeFdCIRVanillaEngine&
168 MakeFdCIRVanillaEngine::withDampingSteps(Size dampingSteps) {
169 dampingSteps_ = dampingSteps;
170 return *this;
171 }
172
173 MakeFdCIRVanillaEngine&
174 MakeFdCIRVanillaEngine::withFdmSchemeDesc(
175 const FdmSchemeDesc& schemeDesc) {
176 schemeDesc_ = ext::make_shared<FdmSchemeDesc>(args: schemeDesc);
177 return *this;
178 }
179
180 MakeFdCIRVanillaEngine&
181 MakeFdCIRVanillaEngine::withCashDividends(
182 const std::vector<Date>& dividendDates,
183 const std::vector<Real>& dividendAmounts) {
184 dividends_ = DividendVector(dividendDates, dividends: dividendAmounts);
185 explicitDividends_ = true;
186 return *this;
187 }
188
189 MakeFdCIRVanillaEngine::operator
190 ext::shared_ptr<PricingEngine>() const {
191 if (explicitDividends_) {
192 return ext::make_shared<FdCIRVanillaEngine>(
193 args: cirProcess_,
194 args: bsProcess_,
195 args: dividends_,
196 args: tGrid_, args: xGrid_, args: rGrid_, args: dampingSteps_,
197 args: rho_,
198 args&: *schemeDesc_,
199 args: quantoHelper_);
200 } else {
201 return ext::make_shared<FdCIRVanillaEngine>(
202 args: cirProcess_,
203 args: bsProcess_,
204 args: tGrid_, args: xGrid_, args: rGrid_, args: dampingSteps_,
205 args: rho_,
206 args&: *schemeDesc_,
207 args: quantoHelper_);
208 }
209 }
210
211}
212

source code of quantlib/ql/pricingengines/vanilla/fdcirvanillaengine.cpp