Coverage Report

Created: 2025-11-04 06:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quantlib/ql/methods/finitedifferences/meshers/fdmblackscholesmesher.cpp
Line
Count
Source
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
 <https://www.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
/*! \file fdmblackscholesmesher.cpp
21
    \brief 1-d mesher for the Black-Scholes process (in ln(S))
22
*/
23
24
#include <ql/processes/blackscholesprocess.hpp>
25
#include <ql/termstructures/yieldtermstructure.hpp>
26
#include <ql/termstructures/yield/quantotermstructure.hpp>
27
#include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp>
28
#include <ql/math/distributions/normaldistribution.hpp>
29
#include <ql/methods/finitedifferences/utilities/fdmquantohelper.hpp>
30
#include <ql/methods/finitedifferences/meshers/uniform1dmesher.hpp>
31
#include <ql/methods/finitedifferences/meshers/concentrating1dmesher.hpp>
32
#include <ql/methods/finitedifferences/meshers/fdmblackscholesmesher.hpp>
33
34
namespace QuantLib {
35
36
    FdmBlackScholesMesher::FdmBlackScholesMesher(
37
        Size size,
38
        const ext::shared_ptr<GeneralizedBlackScholesProcess>& process,
39
        Time maturity, Real strike,
40
        Real xMinConstraint, Real xMaxConstraint,
41
        Real eps, Real scaleFactor,
42
        const std::pair<Real, Real>& cPoint,
43
        const DividendSchedule& dividendSchedule,
44
        const ext::shared_ptr<FdmQuantoHelper>& fdmQuantoHelper,
45
        Real spotAdjustment)
46
0
    : Fdm1dMesher(size) {
47
48
0
        const Real S = process->x0();
49
0
        QL_REQUIRE(S > 0.0, "negative or null underlying given");
50
51
0
        std::vector<std::pair<Time, Real> > intermediateSteps;
52
0
        for (const auto& i : dividendSchedule) {
53
0
            const Time t = process->time(i->date());
54
0
            if (t <= maturity && t >= 0.0)
55
0
                intermediateSteps.emplace_back(process->time(i->date()), i->amount());
56
0
        }
57
58
0
        const Size intermediateTimeSteps = std::max<Size>(2, Size(24.0*maturity));
59
0
        for (Size i=0; i < intermediateTimeSteps; ++i)
60
0
            intermediateSteps.emplace_back((i + 1) * (maturity / intermediateTimeSteps), 0.0);
61
62
0
        std::sort(intermediateSteps.begin(), intermediateSteps.end());
63
64
0
        const Handle<YieldTermStructure> rTS = process->riskFreeRate();
65
66
0
        const Handle<YieldTermStructure> qTS =
67
0
            (fdmQuantoHelper) != nullptr ?
68
0
                Handle<YieldTermStructure>(ext::make_shared<QuantoTermStructure>(
69
0
                    process->dividendYield(), process->riskFreeRate(),
70
0
                    Handle<YieldTermStructure>(fdmQuantoHelper->fTS_), process->blackVolatility(),
71
0
                    strike, Handle<BlackVolTermStructure>(fdmQuantoHelper->fxVolTS_),
72
0
                    fdmQuantoHelper->exchRateATMlevel_, fdmQuantoHelper->equityFxCorrelation_)) :
73
0
                process->dividendYield();
74
75
0
        Time lastDivTime = 0.0;
76
0
        Real fwd = S + spotAdjustment;
77
0
        Real mi = fwd, ma = fwd;
78
79
0
        for (auto& intermediateStep : intermediateSteps) {
80
0
            const Time divTime = intermediateStep.first;
81
0
            const Real divAmount = intermediateStep.second;
82
83
0
            fwd = fwd / rTS->discount(divTime) * rTS->discount(lastDivTime)
84
0
                      * qTS->discount(divTime) / qTS->discount(lastDivTime);
85
86
0
            mi  = std::min(mi, fwd); ma = std::max(ma, fwd);
87
88
0
            fwd-= divAmount;
89
90
0
            mi  = std::min(mi, fwd); ma = std::max(ma, fwd);
91
92
0
            lastDivTime = divTime;
93
0
        }
94
95
        // Set the grid boundaries
96
0
        const Real normInvEps = InverseCumulativeNormal()(1-eps);
97
0
        const Real sigmaSqrtT 
98
0
            = process->blackVolatility()->blackVol(maturity, strike)
99
0
                                                        *std::sqrt(maturity);
100
        
101
0
        Real xMin = std::log(mi) - sigmaSqrtT*normInvEps*scaleFactor;
102
0
        Real xMax = std::log(ma) + sigmaSqrtT*normInvEps*scaleFactor;
103
104
0
        if (xMinConstraint != Null<Real>()) {
105
0
            xMin = xMinConstraint;
106
0
        }
107
0
        if (xMaxConstraint != Null<Real>()) {
108
0
            xMax = xMaxConstraint;
109
0
        }
110
111
0
        ext::shared_ptr<Fdm1dMesher> helper;
112
0
        if (   cPoint.first != Null<Real>() 
113
0
            && std::log(cPoint.first) >=xMin && std::log(cPoint.first) <=xMax) {
114
            
115
0
            helper = ext::shared_ptr<Fdm1dMesher>(
116
0
                new Concentrating1dMesher(xMin, xMax, size, 
117
0
                    std::pair<Real,Real>(std::log(cPoint.first),
118
0
                                         cPoint.second)));
119
0
        }
120
0
        else {
121
0
            helper = ext::shared_ptr<Fdm1dMesher>(
122
0
                                        new Uniform1dMesher(xMin, xMax, size));
123
            
124
0
        }
125
        
126
0
        locations_ = helper->locations();
127
0
        for (Size i=0; i < locations_.size(); ++i) {
128
0
            dplus_[i]  = helper->dplus(i);
129
0
            dminus_[i] = helper->dminus(i);
130
0
        }
131
0
    }
132
            
133
    ext::shared_ptr<GeneralizedBlackScholesProcess> 
134
    FdmBlackScholesMesher::processHelper(const Handle<Quote>& s0,
135
                                         const Handle<YieldTermStructure>& rTS,
136
                                         const Handle<YieldTermStructure>& qTS,
137
0
                                         Volatility vol) {
138
        
139
0
        return ext::make_shared<GeneralizedBlackScholesProcess>(
140
            
141
0
                s0, qTS, rTS,
142
0
                Handle<BlackVolTermStructure>(
143
0
                    ext::shared_ptr<BlackVolTermStructure>(
144
0
                        new BlackConstantVol(rTS->referenceDate(),
145
0
                                             Calendar(),
146
0
                                             vol,
147
0
                                             rTS->dayCounter()))));
148
0
    }
149
}
150