/src/quantlib/ql/pricingengines/vanilla/fdblackscholesvanillaengine.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | |
3 | | /* |
4 | | Copyright (C) 2008 Andreas Gaida |
5 | | Copyright (C) 2008, 2009 Ralph Schreyer |
6 | | Copyright (C) 2008, 2009 Klaus Spanderen |
7 | | |
8 | | This file is part of QuantLib, a free-software/open-source library |
9 | | for financial quantitative analysts and developers - http://quantlib.org/ |
10 | | |
11 | | QuantLib is free software: you can redistribute it and/or modify it |
12 | | under the terms of the QuantLib license. You should have received a |
13 | | copy of the license along with this program; if not, please email |
14 | | <quantlib-dev@lists.sf.net>. The license is also available online at |
15 | | <https://www.quantlib.org/license.shtml>. |
16 | | |
17 | | This program is distributed in the hope that it will be useful, but WITHOUT |
18 | | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
19 | | FOR A PARTICULAR PURPOSE. See the license for more details. |
20 | | */ |
21 | | |
22 | | #include <ql/exercise.hpp> |
23 | | #include <ql/methods/finitedifferences/meshers/fdmblackscholesmesher.hpp> |
24 | | #include <ql/methods/finitedifferences/utilities/escroweddividendadjustment.hpp> |
25 | | #include <ql/methods/finitedifferences/meshers/fdmmeshercomposite.hpp> |
26 | | #include <ql/methods/finitedifferences/operators/fdmlinearoplayout.hpp> |
27 | | #include <ql/methods/finitedifferences/solvers/fdmblackscholessolver.hpp> |
28 | | #include <ql/methods/finitedifferences/stepconditions/fdmstepconditioncomposite.hpp> |
29 | | #include <ql/methods/finitedifferences/utilities/fdminnervaluecalculator.hpp> |
30 | | #include <ql/methods/finitedifferences/utilities/fdmescrowedloginnervaluecalculator.hpp> |
31 | | #include <ql/methods/finitedifferences/utilities/fdmquantohelper.hpp> |
32 | | #include <ql/pricingengines/vanilla/fdblackscholesvanillaengine.hpp> |
33 | | #include <ql/processes/blackscholesprocess.hpp> |
34 | | |
35 | | namespace QuantLib { |
36 | | |
37 | | FdBlackScholesVanillaEngine::FdBlackScholesVanillaEngine( |
38 | | ext::shared_ptr<GeneralizedBlackScholesProcess> process, |
39 | | Size tGrid, |
40 | | Size xGrid, |
41 | | Size dampingSteps, |
42 | | const FdmSchemeDesc& schemeDesc, |
43 | | bool localVol, |
44 | | Real illegalLocalVolOverwrite, |
45 | | CashDividendModel cashDividendModel) |
46 | 0 | : process_(std::move(process)), tGrid_(tGrid), xGrid_(xGrid), |
47 | 0 | dampingSteps_(dampingSteps), schemeDesc_(schemeDesc), localVol_(localVol), |
48 | 0 | illegalLocalVolOverwrite_(illegalLocalVolOverwrite), cashDividendModel_(cashDividendModel) { |
49 | 0 | registerWith(process_); |
50 | 0 | } |
51 | | |
52 | | FdBlackScholesVanillaEngine::FdBlackScholesVanillaEngine( |
53 | | ext::shared_ptr<GeneralizedBlackScholesProcess> process, |
54 | | DividendSchedule dividends, |
55 | | Size tGrid, |
56 | | Size xGrid, |
57 | | Size dampingSteps, |
58 | | const FdmSchemeDesc& schemeDesc, |
59 | | bool localVol, |
60 | | Real illegalLocalVolOverwrite, |
61 | | CashDividendModel cashDividendModel) |
62 | 0 | : process_(std::move(process)), dividends_(std::move(dividends)), |
63 | 0 | tGrid_(tGrid), xGrid_(xGrid), dampingSteps_(dampingSteps), schemeDesc_(schemeDesc), |
64 | 0 | localVol_(localVol), illegalLocalVolOverwrite_(illegalLocalVolOverwrite), |
65 | 0 | cashDividendModel_(cashDividendModel) { |
66 | 0 | registerWith(process_); |
67 | 0 | } |
68 | | |
69 | | FdBlackScholesVanillaEngine::FdBlackScholesVanillaEngine( |
70 | | ext::shared_ptr<GeneralizedBlackScholesProcess> process, |
71 | | ext::shared_ptr<FdmQuantoHelper> quantoHelper, |
72 | | Size tGrid, |
73 | | Size xGrid, |
74 | | Size dampingSteps, |
75 | | const FdmSchemeDesc& schemeDesc, |
76 | | bool localVol, |
77 | | Real illegalLocalVolOverwrite, |
78 | | CashDividendModel cashDividendModel) |
79 | 0 | : process_(std::move(process)), |
80 | 0 | tGrid_(tGrid), xGrid_(xGrid), dampingSteps_(dampingSteps), |
81 | 0 | schemeDesc_(schemeDesc), localVol_(localVol), |
82 | 0 | illegalLocalVolOverwrite_(illegalLocalVolOverwrite), quantoHelper_(std::move(quantoHelper)), |
83 | 0 | cashDividendModel_(cashDividendModel) { |
84 | 0 | registerWith(process_); |
85 | 0 | registerWith(quantoHelper_); |
86 | 0 | } |
87 | | |
88 | | FdBlackScholesVanillaEngine::FdBlackScholesVanillaEngine( |
89 | | ext::shared_ptr<GeneralizedBlackScholesProcess> process, |
90 | | DividendSchedule dividends, |
91 | | ext::shared_ptr<FdmQuantoHelper> quantoHelper, |
92 | | Size tGrid, |
93 | | Size xGrid, |
94 | | Size dampingSteps, |
95 | | const FdmSchemeDesc& schemeDesc, |
96 | | bool localVol, |
97 | | Real illegalLocalVolOverwrite, |
98 | | CashDividendModel cashDividendModel) |
99 | 0 | : process_(std::move(process)), dividends_(std::move(dividends)), |
100 | 0 | tGrid_(tGrid), xGrid_(xGrid), dampingSteps_(dampingSteps), |
101 | 0 | schemeDesc_(schemeDesc), localVol_(localVol), |
102 | 0 | illegalLocalVolOverwrite_(illegalLocalVolOverwrite), quantoHelper_(std::move(quantoHelper)), |
103 | 0 | cashDividendModel_(cashDividendModel) { |
104 | 0 | registerWith(process_); |
105 | 0 | registerWith(quantoHelper_); |
106 | 0 | } |
107 | | |
108 | | |
109 | 0 | void FdBlackScholesVanillaEngine::calculate() const { |
110 | | |
111 | | // 0. Cash dividend model |
112 | 0 | const Date exerciseDate = arguments_.exercise->lastDate(); |
113 | 0 | const Time maturity = process_->time(exerciseDate); |
114 | 0 | const Date settlementDate = process_->riskFreeRate()->referenceDate(); |
115 | |
|
116 | 0 | Real spotAdjustment = 0.0; |
117 | 0 | DividendSchedule dividendSchedule = DividendSchedule(); |
118 | |
|
119 | 0 | ext::shared_ptr<EscrowedDividendAdjustment> escrowedDivAdj; |
120 | |
|
121 | 0 | switch (cashDividendModel_) { |
122 | 0 | case Spot: |
123 | 0 | dividendSchedule = dividends_; |
124 | 0 | break; |
125 | 0 | case Escrowed: |
126 | 0 | if (arguments_.exercise->type() != Exercise::European) |
127 | | // add dividend dates as stopping times |
128 | 0 | for (const auto& cf: dividends_) |
129 | 0 | dividendSchedule.push_back( |
130 | 0 | ext::make_shared<FixedDividend>(0.0, cf->date())); |
131 | |
|
132 | 0 | QL_REQUIRE(quantoHelper_ == nullptr, |
133 | 0 | "Escrowed dividend model is not supported for Quanto-Options"); |
134 | | |
135 | 0 | escrowedDivAdj = ext::make_shared<EscrowedDividendAdjustment>( |
136 | 0 | dividends_, |
137 | 0 | process_->riskFreeRate(), |
138 | 0 | process_->dividendYield(), |
139 | 0 | [&](Date d){ return process_->time(d); }, |
140 | 0 | maturity |
141 | 0 | ); |
142 | |
|
143 | 0 | spotAdjustment = |
144 | 0 | escrowedDivAdj->dividendAdjustment(process_->time(settlementDate)); |
145 | |
|
146 | 0 | QL_REQUIRE(process_->x0() + spotAdjustment > 0.0, |
147 | 0 | "spot minus dividends becomes negative"); |
148 | | |
149 | 0 | break; |
150 | 0 | default: |
151 | 0 | QL_FAIL("unknwon cash dividend model"); |
152 | 0 | } |
153 | | |
154 | | // 1. Mesher |
155 | 0 | const ext::shared_ptr<StrikedTypePayoff> payoff = |
156 | 0 | ext::dynamic_pointer_cast<StrikedTypePayoff>(arguments_.payoff); |
157 | |
|
158 | 0 | const ext::shared_ptr<Fdm1dMesher> equityMesher = |
159 | 0 | ext::make_shared<FdmBlackScholesMesher>( |
160 | 0 | xGrid_, process_, maturity, payoff->strike(), |
161 | 0 | Null<Real>(), Null<Real>(), 0.0001, 1.5, |
162 | 0 | std::pair<Real, Real>(payoff->strike(), 0.1), |
163 | 0 | dividendSchedule, quantoHelper_, |
164 | 0 | spotAdjustment); |
165 | | |
166 | 0 | const ext::shared_ptr<FdmMesher> mesher = |
167 | 0 | ext::make_shared<FdmMesherComposite>(equityMesher); |
168 | | |
169 | | // 2. Calculator |
170 | 0 | ext::shared_ptr<FdmInnerValueCalculator> calculator; |
171 | 0 | switch (cashDividendModel_) { |
172 | 0 | case Spot: |
173 | 0 | calculator = ext::make_shared<FdmLogInnerValue>( |
174 | 0 | payoff, mesher, 0); |
175 | 0 | break; |
176 | 0 | case Escrowed: |
177 | 0 | calculator = ext::make_shared<FdmEscrowedLogInnerValueCalculator>( |
178 | 0 | escrowedDivAdj, payoff, mesher, 0); |
179 | 0 | break; |
180 | 0 | default: |
181 | 0 | QL_FAIL("unknwon cash dividend model"); |
182 | 0 | } |
183 | | |
184 | | // 3. Step conditions |
185 | 0 | const ext::shared_ptr<FdmStepConditionComposite> conditions = |
186 | 0 | FdmStepConditionComposite::vanillaComposite( |
187 | 0 | dividendSchedule, arguments_.exercise, mesher, calculator, |
188 | 0 | process_->riskFreeRate()->referenceDate(), |
189 | 0 | process_->riskFreeRate()->dayCounter()); |
190 | | |
191 | | // 4. Boundary conditions |
192 | 0 | const FdmBoundaryConditionSet boundaries; |
193 | | |
194 | | // 5. Solver |
195 | 0 | FdmSolverDesc solverDesc = { mesher, boundaries, conditions, calculator, |
196 | 0 | maturity, tGrid_, dampingSteps_ }; |
197 | |
|
198 | 0 | const ext::shared_ptr<FdmBlackScholesSolver> solver( |
199 | 0 | ext::make_shared<FdmBlackScholesSolver>( |
200 | 0 | Handle<GeneralizedBlackScholesProcess>(process_), |
201 | 0 | payoff->strike(), solverDesc, schemeDesc_, |
202 | 0 | localVol_, illegalLocalVolOverwrite_, |
203 | 0 | Handle<FdmQuantoHelper>(quantoHelper_))); |
204 | |
|
205 | 0 | const Real spot = process_->x0() + spotAdjustment; |
206 | |
|
207 | 0 | results_.value = solver->valueAt(spot); |
208 | 0 | results_.delta = solver->deltaAt(spot); |
209 | 0 | results_.gamma = solver->gammaAt(spot); |
210 | 0 | results_.theta = solver->thetaAt(spot); |
211 | 0 | } |
212 | | |
213 | | MakeFdBlackScholesVanillaEngine::MakeFdBlackScholesVanillaEngine( |
214 | | ext::shared_ptr<GeneralizedBlackScholesProcess> process) |
215 | 0 | : process_(std::move(process)), |
216 | 0 | schemeDesc_(ext::make_shared<FdmSchemeDesc>(FdmSchemeDesc::Douglas())), |
217 | 0 | illegalLocalVolOverwrite_(-Null<Real>()) {} |
218 | | |
219 | | MakeFdBlackScholesVanillaEngine& |
220 | | MakeFdBlackScholesVanillaEngine::withQuantoHelper( |
221 | 0 | const ext::shared_ptr<FdmQuantoHelper>& quantoHelper) { |
222 | 0 | quantoHelper_ = quantoHelper; |
223 | 0 | return *this; |
224 | 0 | } |
225 | | |
226 | | MakeFdBlackScholesVanillaEngine& |
227 | 0 | MakeFdBlackScholesVanillaEngine::withTGrid(Size tGrid) { |
228 | 0 | tGrid_ = tGrid; |
229 | 0 | return *this; |
230 | 0 | } |
231 | | |
232 | | MakeFdBlackScholesVanillaEngine& |
233 | 0 | MakeFdBlackScholesVanillaEngine::withXGrid(Size xGrid) { |
234 | 0 | xGrid_ = xGrid; |
235 | 0 | return *this; |
236 | 0 | } |
237 | | |
238 | | MakeFdBlackScholesVanillaEngine& |
239 | 0 | MakeFdBlackScholesVanillaEngine::withDampingSteps(Size dampingSteps) { |
240 | 0 | dampingSteps_ = dampingSteps; |
241 | 0 | return *this; |
242 | 0 | } |
243 | | |
244 | | MakeFdBlackScholesVanillaEngine& |
245 | | MakeFdBlackScholesVanillaEngine::withFdmSchemeDesc( |
246 | 0 | const FdmSchemeDesc& schemeDesc) { |
247 | 0 | schemeDesc_ = ext::make_shared<FdmSchemeDesc>(schemeDesc); |
248 | 0 | return *this; |
249 | 0 | } |
250 | | |
251 | | MakeFdBlackScholesVanillaEngine& |
252 | 0 | MakeFdBlackScholesVanillaEngine::withLocalVol(bool localVol) { |
253 | 0 | localVol_ = localVol; |
254 | 0 | return *this; |
255 | 0 | } |
256 | | |
257 | | MakeFdBlackScholesVanillaEngine& |
258 | | MakeFdBlackScholesVanillaEngine::withIllegalLocalVolOverwrite( |
259 | 0 | Real illegalLocalVolOverwrite) { |
260 | 0 | illegalLocalVolOverwrite_ = illegalLocalVolOverwrite; |
261 | 0 | return *this; |
262 | 0 | } |
263 | | |
264 | | MakeFdBlackScholesVanillaEngine& |
265 | | MakeFdBlackScholesVanillaEngine::withCashDividends( |
266 | | const std::vector<Date>& dividendDates, |
267 | 0 | const std::vector<Real>& dividendAmounts) { |
268 | 0 | dividends_ = DividendVector(dividendDates, dividendAmounts); |
269 | 0 | return *this; |
270 | 0 | } |
271 | | |
272 | | MakeFdBlackScholesVanillaEngine& |
273 | | MakeFdBlackScholesVanillaEngine::withCashDividendModel( |
274 | 0 | FdBlackScholesVanillaEngine::CashDividendModel cashDividendModel) { |
275 | 0 | cashDividendModel_ = cashDividendModel; |
276 | 0 | return *this; |
277 | 0 | } |
278 | | |
279 | | MakeFdBlackScholesVanillaEngine::operator |
280 | 0 | ext::shared_ptr<PricingEngine>() const { |
281 | 0 | return ext::make_shared<FdBlackScholesVanillaEngine>( |
282 | 0 | process_, |
283 | 0 | dividends_, |
284 | 0 | quantoHelper_, |
285 | 0 | tGrid_, xGrid_, dampingSteps_, |
286 | 0 | *schemeDesc_, |
287 | 0 | localVol_, |
288 | 0 | illegalLocalVolOverwrite_, |
289 | 0 | cashDividendModel_); |
290 | 0 | } |
291 | | |
292 | | } |