Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
fdmblackscholesmesher.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2020 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
19/*! \file fdmblackscholesmesher.cpp
20 \brief 1-d mesher for the Black-Scholes process (in ln(S))
21*/
22
24
25#include <ql/math/distributions/normaldistribution.hpp>
26#include <ql/methods/finitedifferences/meshers/concentrating1dmesher.hpp>
27#include <ql/methods/finitedifferences/meshers/uniform1dmesher.hpp>
28#include <ql/methods/finitedifferences/utilities/fdmquantohelper.hpp>
29#include <ql/processes/blackscholesprocess.hpp>
30#include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp>
31#include <ql/termstructures/yield/quantotermstructure.hpp>
32#include <ql/termstructures/yieldtermstructure.hpp>
33
34namespace QuantExt {
35
36FdmBlackScholesMesher::FdmBlackScholesMesher(Size size, const ext::shared_ptr<GeneralizedBlackScholesProcess>& process,
37 Time maturity, Real strike, Real xMinConstraint, Real xMaxConstraint,
38 Real eps, Real scaleFactor,
39 const std::vector<QuantLib::ext::tuple<Real, Real, bool>>& cPoints,
40 const DividendSchedule& dividendSchedule,
41 const ext::shared_ptr<FdmQuantoHelper>& fdmQuantoHelper,
42 Real spotAdjustment)
43 : Fdm1dMesher(size) {
44
45 const Real S = process->x0();
46 QL_REQUIRE(S > 0.0, "negative or null underlying given");
47
48 std::vector<std::pair<Time, Real>> intermediateSteps;
49 for (Size i = 0; i < dividendSchedule.size(); ++i) {
50 const Time t = process->time(dividendSchedule[i]->date());
51 if (t <= maturity && t >= 0.0)
52 intermediateSteps.push_back(
53 std::make_pair(process->time(dividendSchedule[i]->date()), dividendSchedule[i]->amount()));
54 }
55
56 const Size intermediateTimeSteps = std::max<Size>(2, Size(24.0 * maturity));
57 for (Size i = 0; i < intermediateTimeSteps; ++i)
58 intermediateSteps.push_back(std::make_pair((i + 1) * (maturity / intermediateTimeSteps), 0.0));
59
60 std::sort(intermediateSteps.begin(), intermediateSteps.end());
61
62 const Handle<YieldTermStructure> rTS = process->riskFreeRate();
63
64 const Handle<YieldTermStructure> qTS =
65 (fdmQuantoHelper)
66 ? Handle<YieldTermStructure>(ext::make_shared<QuantoTermStructure>(
67 process->dividendYield(), process->riskFreeRate(), Handle<YieldTermStructure>(fdmQuantoHelper->fTS_),
68 process->blackVolatility(), strike, Handle<BlackVolTermStructure>(fdmQuantoHelper->fxVolTS_),
69 fdmQuantoHelper->exchRateATMlevel_, fdmQuantoHelper->equityFxCorrelation_))
70 : process->dividendYield();
71
72 Time lastDivTime = 0.0;
73 Real fwd = S + spotAdjustment;
74 Real mi = fwd, ma = fwd;
75
76 for (Size i = 0; i < intermediateSteps.size(); ++i) {
77 const Time divTime = intermediateSteps[i].first;
78 const Real divAmount = intermediateSteps[i].second;
79
80 fwd = fwd / rTS->discount(divTime) * rTS->discount(lastDivTime) * qTS->discount(divTime) /
81 qTS->discount(lastDivTime);
82
83 mi = std::min(mi, fwd);
84 ma = std::max(ma, fwd);
85
86 fwd -= divAmount;
87
88 mi = std::min(mi, fwd);
89 ma = std::max(ma, fwd);
90
91 lastDivTime = divTime;
92 }
93
94 // Set the grid boundaries, avoid too narrow grid due to vol close to zero (floor vol at 1%)
95 const Real normInvEps = InverseCumulativeNormal()(1 - eps);
96 const Real sigmaSqrtT =
97 std::max(1.0E-2, process->blackVolatility()->blackVol(maturity, strike) * std::sqrt(maturity));
98
99 Real xMin = std::log(mi) - sigmaSqrtT * normInvEps * scaleFactor;
100 Real xMax = std::log(ma) + sigmaSqrtT * normInvEps * scaleFactor;
101
102 if (xMinConstraint != Null<Real>()) {
103 xMin = xMinConstraint;
104 }
105 if (xMaxConstraint != Null<Real>()) {
106 xMax = xMaxConstraint;
107 }
108
109 // filter cPoints on [xmin, xmax]
110 std::vector<QuantLib::ext::tuple<Real, Real, bool>> cPointsEff;
111 for (auto const& c : cPoints) {
112 if (QuantLib::ext::get<0>(c) == Null<Real>() || QuantLib::ext::get<0>(c) < xMin || QuantLib::ext::get<0>(c) > xMax)
113 continue;
114 cPointsEff.push_back(c);
115 }
116
117 ext::shared_ptr<Fdm1dMesher> helper;
118 if (cPointsEff.empty()) {
119 helper = ext::shared_ptr<Fdm1dMesher>(new Uniform1dMesher(xMin, xMax, size));
120 } else if (cPointsEff.size() == 1) {
121 helper = ext::shared_ptr<Fdm1dMesher>(new Concentrating1dMesher(
122 xMin, xMax, size, std::make_pair(QuantLib::ext::get<0>(cPointsEff[0]), QuantLib::ext::get<1>(cPointsEff[0])),
123 QuantLib::ext::get<2>(cPointsEff[0])));
124 } else {
125 helper = ext::shared_ptr<Fdm1dMesher>(new Concentrating1dMesher(xMin, xMax, size, cPointsEff));
126 }
127
128 locations_ = helper->locations();
129 for (Size i = 0; i < locations_.size(); ++i) {
130 dplus_[i] = helper->dplus(i);
131 dminus_[i] = helper->dminus(i);
132 }
133}
134
135ext::shared_ptr<GeneralizedBlackScholesProcess>
136FdmBlackScholesMesher::processHelper(const Handle<Quote>& s0, const Handle<YieldTermStructure>& rTS,
137 const Handle<YieldTermStructure>& qTS, Volatility vol) {
138
139 return ext::make_shared<GeneralizedBlackScholesProcess>(
140 s0, qTS, rTS,
141 Handle<BlackVolTermStructure>(ext::shared_ptr<BlackVolTermStructure>(
142 new BlackConstantVol(rTS->referenceDate(), Calendar(), vol, rTS->dayCounter()))));
143}
144} // namespace QuantExt
FdmBlackScholesMesher(Size size, const ext::shared_ptr< GeneralizedBlackScholesProcess > &process, Time maturity, Real strike, Real xMinConstraint=Null< Real >(), Real xMaxConstraint=Null< Real >(), Real eps=0.0001, Real scaleFactor=1.5, const std::vector< QuantLib::ext::tuple< Real, Real, bool > > &cPoints={}, const DividendSchedule &dividendSchedule=DividendSchedule(), const ext::shared_ptr< FdmQuantoHelper > &fdmQuantoHelper=ext::shared_ptr< FdmQuantoHelper >(), Real spotAdjustment=0.0)
static ext::shared_ptr< GeneralizedBlackScholesProcess > processHelper(const Handle< Quote > &s0, const Handle< YieldTermStructure > &rTS, const Handle< YieldTermStructure > &qTS, Volatility vol)
extended version of the QuantLib class, see the documentation for details
QuantLib::BootstrapHelper< QuantLib::OptionletVolatilityStructure > helper