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>
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,
45 const Real S = process->x0();
46 QL_REQUIRE(S > 0.0,
"negative or null underlying given");
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()));
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));
60 std::sort(intermediateSteps.begin(), intermediateSteps.end());
62 const Handle<YieldTermStructure> rTS = process->riskFreeRate();
64 const Handle<YieldTermStructure> qTS =
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();
72 Time lastDivTime = 0.0;
73 Real fwd = S + spotAdjustment;
74 Real mi = fwd, ma = fwd;
76 for (Size i = 0; i < intermediateSteps.size(); ++i) {
77 const Time divTime = intermediateSteps[i].first;
78 const Real divAmount = intermediateSteps[i].second;
80 fwd = fwd / rTS->discount(divTime) * rTS->discount(lastDivTime) * qTS->discount(divTime) /
81 qTS->discount(lastDivTime);
83 mi = std::min(mi, fwd);
84 ma = std::max(ma, fwd);
88 mi = std::min(mi, fwd);
89 ma = std::max(ma, fwd);
91 lastDivTime = divTime;
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));
99 Real xMin = std::log(mi) - sigmaSqrtT * normInvEps * scaleFactor;
100 Real xMax = std::log(ma) + sigmaSqrtT * normInvEps * scaleFactor;
102 if (xMinConstraint != Null<Real>()) {
103 xMin = xMinConstraint;
105 if (xMaxConstraint != Null<Real>()) {
106 xMax = xMaxConstraint;
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)
114 cPointsEff.push_back(c);
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])));
125 helper = ext::shared_ptr<Fdm1dMesher>(
new Concentrating1dMesher(xMin, xMax, size, cPointsEff));
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);
135ext::shared_ptr<GeneralizedBlackScholesProcess>
137 const Handle<YieldTermStructure>& qTS, Volatility vol) {
139 return ext::make_shared<GeneralizedBlackScholesProcess>(
141 Handle<BlackVolTermStructure>(ext::shared_ptr<BlackVolTermStructure>(
142 new BlackConstantVol(rTS->referenceDate(), Calendar(), vol, rTS->dayCounter()))));
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 ÷ndSchedule=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