Coverage Report

Created: 2025-09-04 07:11

/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
}