53 ext::shared_ptr<Fdm1dMesher> varianceMesher(
54 const SquareRootProcessRNDCalculator& rnd,
56 Real v0,
const HestonSLVFokkerPlanckFdmParams& params) {
58 std::vector<std::tuple<Real, Real, bool> > cPoints;
60 const Real v0Density = params.v0Density;
61 const Real upperBoundDensity = params.vUpperBoundDensity;
62 const Real lowerBoundDensity = params.vLowerBoundDensity;
64 Real lowerBound = Null<Real>(), upperBound = -Null<Real>();
66 for (
Size i=0; i <= 10; ++i) {
67 const Time t = t0 + i/10.0*(t1-t0);
68 lowerBound = std::min(
69 lowerBound, rnd.invcdf(params.vLowerEps,
t));
70 upperBound = std::max(
71 upperBound, rnd.invcdf(1.0-params.vUpperEps,
t));
74 lowerBound = std::max(lowerBound, params.vMin);
75 switch (params.trafoType) {
78 lowerBound = std::log(lowerBound);
79 upperBound = std::log(upperBound);
81 const Real v0Center = std::log(
v0);
84 std::make_tuple(lowerBound, lowerBoundDensity,
false),
85 std::make_tuple(v0Center, v0Density,
true),
86 std::make_tuple(upperBound, upperBoundDensity,
false)
89 return ext::make_shared<Concentrating1dMesher>(
90 lowerBound, upperBound, vGrid, cPoints, 1e-8);
97 std::make_tuple(lowerBound, lowerBoundDensity,
false),
98 std::make_tuple(v0Center, v0Density,
true),
99 std::make_tuple(upperBound, upperBoundDensity,
false)
102 return ext::make_shared<Concentrating1dMesher>(
103 lowerBound, upperBound, vGrid, cPoints, 1e-8);
110 std::make_tuple(lowerBound, lowerBoundDensity,
false),
111 std::make_tuple(v0Center, v0Density,
true),
112 std::make_tuple(upperBound, upperBoundDensity,
false)
115 return ext::make_shared<Concentrating1dMesher>(
116 lowerBound, upperBound, vGrid, cPoints, 1e-8);
119 QL_FAIL(
"transformation type is not implemented");
123 Real integratePDF(
const Array& p,
124 const ext::shared_ptr<FdmMesherComposite>& mesher,
129 return FdmMesherIntegral(
130 mesher, DiscreteSimpsonIntegral()).integrate(p);
134 for (
const auto& iter : *mesher->layout()) {
135 const Size idx = iter.index();
136 const Real nu = mesher->location(iter, 1);
138 tp[idx] = p[idx]*std::pow(
nu,
alpha-1);
141 return FdmMesherIntegral(
142 mesher, DiscreteSimpsonIntegral()).integrate(tp);
149 const ext::shared_ptr<FdmMesherComposite>& mesher,
152 return p/integratePDF(p, mesher, trafoType,
alpha);
156 template <
class Interpolator>
159 const ext::shared_ptr<FdmMesherComposite>& oldMesher,
160 const ext::shared_ptr<FdmMesherComposite>& newMesher,
161 const Interpolator& interp = Interpolator()) {
163 QL_REQUIRE( oldMesher->layout()->size() == newMesher->layout()->size()
164 && oldMesher->layout()->size() == p.size(),
165 "inconsistent mesher or vector size given");
167 Matrix m(oldMesher->layout()->dim()[1], oldMesher->layout()->dim()[0]);
168 for (
Size i=0; i < m.rows(); ++i) {
169 std::copy(p.begin() + i*m.columns(),
170 p.begin() + (i+1)*m.columns(), m.row_begin(i));
172 const Interpolation2D interpol = interp.interpolate(
173 oldMesher->getFdm1dMeshers()[0]->locations().begin(),
174 oldMesher->getFdm1dMeshers()[0]->locations().end(),
175 oldMesher->getFdm1dMeshers()[1]->locations().begin(),
176 oldMesher->getFdm1dMeshers()[1]->locations().end(), m);
178 Array pNew(p.size());
179 for (
const auto& iter : *newMesher->layout()) {
180 const Real x = newMesher->location(iter, 0);
181 const Real v = newMesher->location(iter, 1);
183 if ( x > interpol.xMax() || x < interpol.xMin()
184 ||
v > interpol.yMax() ||
v < interpol.yMin() ) {
185 pNew[iter.index()] = 0;
188 pNew[iter.index()] = interpol(x,
v);
197 virtual ~FdmScheme() =
default;
198 virtual void step(Array& a,
Time t) = 0;
199 virtual void setStep(
Time dt) = 0;
203 class FdmSchemeWrapper :
public FdmScheme {
205 explicit FdmSchemeWrapper(T* scheme)
208 void step(Array& a,
Time t)
override {
scheme_->step(a,
t); }
209 void setStep(
Time dt)
override {
scheme_->setStep(dt); }
215 ext::shared_ptr<FdmScheme> fdmSchemeFactory(
216 const FdmSchemeDesc desc,
217 const ext::shared_ptr<FdmLinearOpComposite>& op) {
221 return ext::shared_ptr<FdmScheme>(
222 new FdmSchemeWrapper<HundsdorferScheme>(
223 new HundsdorferScheme(desc.theta, desc.mu, op)));
225 return ext::shared_ptr<FdmScheme>(
226 new FdmSchemeWrapper<DouglasScheme>(
227 new DouglasScheme(desc.theta, op)));
229 return ext::shared_ptr<FdmScheme>(
230 new FdmSchemeWrapper<CraigSneydScheme>(
231 new CraigSneydScheme(desc.theta, desc.mu, op)));
233 return ext::shared_ptr<FdmScheme>(
234 new FdmSchemeWrapper<ModifiedCraigSneydScheme>(
235 new ModifiedCraigSneydScheme(
236 desc.theta, desc.mu, op)));
238 return ext::shared_ptr<FdmScheme>(
239 new FdmSchemeWrapper<ImplicitEulerScheme>(
240 new ImplicitEulerScheme(op)));
242 return ext::shared_ptr<FdmScheme>(
243 new FdmSchemeWrapper<ExplicitEulerScheme>(
244 new ExplicitEulerScheme(op)));
246 QL_FAIL(
"Unknown scheme type");
256 std::vector<Date> mandatoryDates,
257 const Real mixingFactor)
258 : localVol_(
std::move(localVol)), hestonModel_(
std::move(hestonModel)), endDate_(endDate),
259 params_(params), mandatoryDates_(
std::move(mandatoryDates)),
260 mixingFactor_(mixingFactor), logging_(logging) {
274 ext::shared_ptr<LocalVolTermStructure>
286 const ext::shared_ptr<Quote> spot
288 const ext::shared_ptr<YieldTermStructure> rTS
290 const ext::shared_ptr<YieldTermStructure> qTS
304 const Date referenceDate = rTS->referenceDate();
309 "reference date must be smaller than final calibration date");
312 "final calibration maturity exceeds local volatility surface");
319 std::vector<Time> times(1, tIdx);
323 const Time dt = maxDt*decayFactor + minDt*(1.0-decayFactor);
325 times.push_back(std::min(
T, tIdx+=dt));
329 times.push_back(dc.
yearFraction(referenceDate, mandatoryDate));
332 const ext::shared_ptr<TimeGrid> timeGrid(
333 new TimeGrid(times.begin(), times.end()));
343 const std::vector<Size> rescaleSteps
352 std::vector<ext::shared_ptr<Fdm1dMesher> > xMesher, vMesher;
353 xMesher.reserve(timeGrid->size());
354 vMesher.reserve(timeGrid->size());
356 xMesher.push_back(localVolRND.
mesher(0.0));
357 vMesher.push_back(ext::make_shared<Predefined1dMesher>(
358 std::vector<Real>(vGrid,
v0)));
361 for (
Size i=1; i < timeGrid->size(); ++i) {
362 xMesher.push_back(localVolRND.
mesher(timeGrid->at(i)));
364 if ((rescaleIdx < rescaleSteps.size())
365 && (i == rescaleSteps[rescaleIdx])) {
367 vMesher.push_back(varianceMesher(squareRootRnd,
368 timeGrid->at(rescaleSteps[rescaleIdx-1]),
369 (rescaleIdx < rescaleSteps.size())
370 ? timeGrid->at(rescaleSteps[rescaleIdx])
375 vMesher.push_back(vMesher.back());
379 ext::shared_ptr<FdmMesherComposite> mesher
380 = ext::make_shared<FdmMesherComposite>(
381 xMesher.at(1), vMesher.at(1));
384 =
localVol_->localVol(0.0, spot->value())/std::sqrt(
v0);
386 ext::shared_ptr<Matrix> L(
new Matrix(xGrid, timeGrid->size()));
389 std::fill(L->column_begin(0),L->column_end(0), l0);
390 std::fill(L->column_begin(1),L->column_end(1), l0);
393 std::vector<ext::shared_ptr<std::vector<Real> > > vStrikes(
396 for (
Size i=0; i < timeGrid->size(); ++i) {
397 vStrikes[i] = ext::make_shared<std::vector<Real> >(xGrid);
398 if (xMesher[i]->locations().front()
399 == xMesher[i]->locations().back()) {
400 std::fill(vStrikes[i]->begin(), vStrikes[i]->end(),
401 std::exp(xMesher[i]->locations().front()));
404 std::transform(xMesher[i]->locations().begin(),
405 xMesher[i]->locations().end(),
406 vStrikes[i]->begin(),
407 [](
Real x) ->
Real {
return std::exp(x); });
411 const ext::shared_ptr<FixedLocalVolSurface> leverageFct(
414 ext::shared_ptr<FdmLinearOpComposite> hestonFwdOp(
421 const LogEntry entry = { timeGrid->at(1),
422 ext::make_shared<Array>(p), mesher };
426 for (
Size i=2; i < times.size(); ++i) {
427 const Time t = timeGrid->at(i);
428 const Time dt =
t - timeGrid->at(i-1);
430 if ( mesher->getFdm1dMeshers()[0] != xMesher[i]
431 || mesher->getFdm1dMeshers()[1] != vMesher[i]) {
432 const ext::shared_ptr<FdmMesherComposite> newMesher(
435 p = reshapePDF<Bilinear>(p, mesher, newMesher);
438 p = rescalePDF(p, mesher, trafoType,
alpha);
440 hestonFwdOp = ext::shared_ptr<FdmLinearOpComposite>(
447 Array(mesher->getFdm1dMeshers()[0]->locations().begin(),
448 mesher->getFdm1dMeshers()[0]->locations().end())));
450 mesher->getFdm1dMeshers()[1]->locations().begin(),
451 mesher->getFdm1dMeshers()[1]->locations().end());
460 const ext::shared_ptr<FdmScheme> fdmScheme(
461 fdmSchemeFactory(fdmSchemeDesc, hestonFwdOp));
465 for (
Size k=0; k < vGrid; ++k)
466 pSlice[k] = pn[j + k*xGrid];
478 const Real scale = pInt/vpInt;
481 const Real l = (scale >= 0.0)
484 (*L)[j][i] = std::min(50.0, std::max(0.001, l));
486 leverageFct->setInterpolation(
Linear());
489 const Real sLowerBound = std::max(x.
front(),
490 std::exp(localVolRND.
invcdf(
492 const Real sUpperBound = std::min(x.
back(),
493 std::exp(localVolRND.
invcdf(
496 const Real lowerL = leverageFct->localVol(
t, sLowerBound);
497 const Real upperL = leverageFct->localVol(
t, sUpperBound);
500 if (x[j] < sLowerBound)
501 std::fill(L->row_begin(j)+i,
502 std::min(L->row_begin(j)+i+1, L->row_end(j)),
504 else if (x[j] > sUpperBound)
505 std::fill(L->row_begin(j)+i,
506 std::min(L->row_begin(j)+i+1, L->row_end(j)),
511 leverageFct->setInterpolation(
Linear());
515 fdmScheme->setStep(dt);
516 fdmScheme->step(pn,
t);
519 p = rescalePDF(p, mesher, trafoType,
alpha);
523 = {
t, ext::make_shared<Array>(p), mesher };
bilinear interpolation between discrete points
1-D array used in linear algebra.
Size size() const
dimension of the array
Time yearFraction(const Date &, const Date &, const Date &refPeriodStart=Date(), const Date &refPeriodEnd=Date()) const
Returns the period between two dates as a fraction of year.
Array get(Time t, Algorithm algorithm) const
Shared handle to an observable.
ext::shared_ptr< LocalVolTermStructure > leverageFunction() const
void performCalculations() const override
HestonSLVFDMModel(Handle< LocalVolTermStructure > localVol, Handle< HestonModel > hestonModel, const Date &endDate, HestonSLVFokkerPlanckFdmParams params, bool logging=false, std::vector< Date > mandatoryDates=std::vector< Date >(), Real mixingFactor=1.0)
const std::list< LogEntry > & logEntries() const
const HestonSLVFokkerPlanckFdmParams params_
ext::shared_ptr< LocalVolTermStructure > leverageFunction_
std::list< LogEntry > logEntries_
const Handle< LocalVolTermStructure > localVol_
const Handle< HestonModel > hestonModel_
const std::vector< Date > mandatoryDates_
ext::shared_ptr< HestonProcess > hestonProcess() const
ext::shared_ptr< LocalVolTermStructure > localVol() const
virtual void calculate() const
Linear-interpolation factory and traits
std::vector< Size > rescaleTimeSteps() const
ext::shared_ptr< Fdm1dMesher > mesher(Time t) const
Real invcdf(Real p, Time t) const override
Matrix used in linear algebra.
template class providing a null value for a given type.
std::pair< iterator, bool > registerWith(const ext::shared_ptr< Observable > &)
One-dimensional grid mesher concentrating around critical points.
Craig-Sneyd operator splitting.
integrals on non uniform grids
Douglas operator splitting.
#define QL_REQUIRE(condition, message)
throw an error if the given pre-condition is not verified
#define QL_FAIL(message)
throw an error (possibly with file and line information)
Heston Fokker-Planck forward operator.
memory layout of a fdm linear operator
FdmMesher which is a composite of Fdm1dMesher.
mesher based integral over target function.
Local volatility surface based on fixed values plus interpolation.
Real Time
continuous quantity with 1-year units
Real Volatility
volatility
std::size_t Size
size of a container
Heston model for the stochastic volatility of an asset.
const std::unique_ptr< T > scheme_
Heston stochastic local volatility model.
Hundsdorfer operator splitting.
local volatility risk neutral terminal density calculation
Local volatility term structure base class.
modified Craig-Sneyd operator splitting
Array Pow(const Array &v, Real alpha)
Array Exp(const Array &v)
normal, cumulative and inverse cumulative distributions
ext::shared_ptr< YieldTermStructure > r
ext::shared_ptr< BlackVolTermStructure > v
One-dimensional mesher build from a given set of points.
risk neutral terminal density calculator for the square root process
static FdmSchemeDesc ImplicitEuler()
FdmSquareRootFwdOp::TransformationType trafoType
Size maxIntegrationIterations
FdmHestonGreensFct::Algorithm greensAlgorithm
Size predictionCorretionSteps