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