hasquant-0.7.0.0: cbits/qlPricingEngineAux.cpp
// this file intentionally does not contain any references to wrappers, only vanilla QuantLib is used here
#include <ql/pricingengines/all.hpp>
#include <ql/pricingengines/vanilla/binomialengine.hpp>
#include <ql/pricingengines/barrier/binomialbarrierengine.hpp>
#include <ql/experimental/barrieroption/binomialdoublebarrierengine.hpp>
#include <ql/experimental/barrieroption/mcdoublebarrierengine.hpp>
#include <ql/experimental/callablebonds/blackcallablebondengine.hpp>
#include <ql/experimental/callablebonds/treecallablebondengine.hpp>
#include <ql/pricingengines/bond/binomialconvertibleengine.hpp>
#include <ql/experimental/lattices/extendedbinomialtree.hpp>
#include <ql/experimental/math/zigguratrng.hpp>
#include <ql/methods/finitedifferences/expliciteuler.hpp>
#include <ql/methods/finitedifferences/impliciteuler.hpp>
#include <ql/pricingengines/vanilla/fdblackscholesvanillaengine.hpp>
#include <ql/instruments/dividendschedule.hpp>
#include <ql/methods/montecarlo/pathgenerator.hpp>
#include <ql/methods/montecarlo/multipathgenerator.hpp>
#include <ql/experimental/exoticoptions/mchimalayaengine.hpp>
#include <ql/experimental/exoticoptions/mcpagodaengine.hpp>
#include <ql/experimental/exoticoptions/mceverestengine.hpp>
#include <ql/pricingengines/forward/mcforwardeuropeanbsengine.hpp>
#include <ql/pricingengines/forward/mcforwardeuropeanhestonengine.hpp>
#include <ql/pricingengines/basket/mceuropeanbasketengine.hpp>
#include <ql/pricingengines/basket/mcamericanbasketengine.hpp>
#include <ql/pricingengines/asian/mc_discr_arith_av_price_heston.hpp>
#include <ql/math/statistics/incrementalstatistics.hpp>
namespace hasquant {
#include "qlEnumObjects.h"
}
using QuantLib::ext::shared_ptr;
#include "qlPricingEngineAux.h"
using namespace QuantLib;
// ---------------------------------------------------------------------------------------------
// Trait dispatchers.
//
// Each engine is selected by one or two runtime traits. Dispatchers call a generic lambda with
// an empty `Tag<T>` per axis, so each constructor is written once and recovers types through
// `typename decltype(r)::type`.
//
// Every dispatcher takes its return type as an explicit leading template argument
// (`dispatchRngStat<PricingEngine*>(...)`) rather than deducing it with a trailing
// `-> decltype(make(Tag<PseudoRandom>()))`. That is not a style choice. A trailing return type is
// an *unevaluated* operand, so the probe call it names is the first instantiation of the lambda
// for that tag -- and clang then emits the engine's constructor but never marks its vtable used,
// leaving `~Engine()` and its thunks undefined. It links as a missing
// `..MCPagodaEngine<..,Statistics>..D0Ev` at dlopen time, and *only* for the exact tag named in
// the probe (`Statistics` here), which is why it looks like a QuantLib packaging problem rather
// than a bug in this file. Keep the explicit `Ret`; do not "simplify" it back to decltype.
template <class T> struct Tag { using type = T; };
template <class Ret, class F>
Ret dispatchTree(int tree, F&& make) {
switch (tree) {
case hasquant::JarrowRudd: return make(Tag<JarrowRudd>());
case hasquant::CoxRossRubinstein: return make(Tag<CoxRossRubinstein>());
case hasquant::AdditiveEQPBinomialTree: return make(Tag<AdditiveEQPBinomialTree>());
case hasquant::Trigeorgis: return make(Tag<Trigeorgis>());
case hasquant::Tian: return make(Tag<Tian>());
case hasquant::LeisenReimer: return make(Tag<LeisenReimer>());
case hasquant::Joshi4: return make(Tag<Joshi4>());
case hasquant::ExtendedJarrowRudd: return make(Tag<ExtendedJarrowRudd>());
case hasquant::ExtendedCoxRossRubinstein: return make(Tag<ExtendedCoxRossRubinstein>());
case hasquant::ExtendedAdditiveEQPBinomialTree: return make(Tag<ExtendedAdditiveEQPBinomialTree>());
case hasquant::ExtendedTrigeorgis: return make(Tag<ExtendedTrigeorgis>());
case hasquant::ExtendedTian: return make(Tag<ExtendedTian>());
case hasquant::ExtendedLeisenReimer: return make(Tag<ExtendedLeisenReimer>());
case hasquant::ExtendedJoshi4: return make(Tag<ExtendedJoshi4>());
}
QL_FAIL("Unknown Binomial Tree "<< tree);
}
template <class Ret, class F>
Ret dispatchRng(int rngtrait, F&& make) {
switch (rngtrait) {
case hasquant::PseudoRandom: return make(Tag<PseudoRandom>());
case hasquant::PoissonPseudoRandom: return make(Tag<PoissonPseudoRandom>());
case hasquant::LowDiscrepancy: return make(Tag<LowDiscrepancy>());
case hasquant::Ziggurat: return make(Tag<Ziggurat>());
}
QL_FAIL("Unknown RNG "<< rngtrait);
}
template <class Ret, class F>
Ret dispatchStat(int stattrait, F&& make) {
switch (stattrait) {
case hasquant::Statistics: return make(Tag<QuantLib::Statistics>());
case hasquant::GaussianStatistics: return make(Tag<QuantLib::GaussianStatistics>());
case hasquant::GeneralStatistics: return make(Tag<QuantLib::GeneralStatistics>());
case hasquant::IncrementalStatistics: return make(Tag<QuantLib::IncrementalStatistics>());
}
QL_FAIL("Unknown Statistics "<< stattrait);
}
// The shared RNG x Statistics dispatch used by every templated Monte Carlo engine in this file.
template <class Ret, class F>
Ret dispatchRngStat(int rngtrait, int stattrait, F&& make) {
return dispatchRng<Ret>(rngtrait, [&](auto r) {
return dispatchStat<Ret>(stattrait, [&](auto st) { return make(r, st); });
});
}
// ---------------------------------------------------------------------------------------------
PricingEngine* qlBinomialVanillaEngineAux(int tree, const shared_ptr<GeneralizedBlackScholesProcess> process, unsigned timeSteps) {
return dispatchTree<PricingEngine*>(tree, [&](auto t) {
return new BinomialVanillaEngine<typename decltype(t)::type>(process, timeSteps);
});
}
PricingEngine* qlBinomialConvertibleEngineAux(int tree, const shared_ptr<GeneralizedBlackScholesProcess> process, unsigned timeSteps, const Handle<Quote>& cs, DividendSchedule d) {
return dispatchTree<PricingEngine*>(tree, [&](auto t) {
return new BinomialConvertibleEngine<typename decltype(t)::type>(process, timeSteps, cs, d);
});
}
PricingEngine* qlBinomialBarrierEngineAux(int tree, const shared_ptr<GeneralizedBlackScholesProcess> process, unsigned timeSteps, unsigned maxTimeSteps) {
return dispatchTree<PricingEngine*>(tree, [&](auto t) {
return new BinomialBarrierEngine<typename decltype(t)::type, DiscretizedBarrierOption>(process, timeSteps, maxTimeSteps);
});
}
PricingEngine* qlBinomialDoubleBarrierEngineAux(int tree, const shared_ptr<GeneralizedBlackScholesProcess> process, unsigned timeSteps) {
return dispatchTree<PricingEngine*>(tree, [&](auto t) {
return new BinomialDoubleBarrierEngine<typename decltype(t)::type>(process, timeSteps);
});
}
PricingEngine* qlMCDoubleBarrierEngineAux(int rngtrait, int stattrait, const shared_ptr<GeneralizedBlackScholesProcess> process, unsigned timeSteps, unsigned timeStepsPerYear, int brownianBridge, int antitheticVariate, unsigned requiredSamples, double requiredTolerance, unsigned maxSamples, unsigned seed) {
return dispatchRngStat<PricingEngine*>(rngtrait, stattrait, [&](auto r, auto st) {
return new MCDoubleBarrierEngine<typename decltype(r)::type, typename decltype(st)::type>(process, timeSteps, timeStepsPerYear, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed);
});
}
PricingEngine* qlMCVarianceSwapEngine1Aux(int rngtrait, int stattrait, const shared_ptr<GeneralizedBlackScholesProcess> process, unsigned timeSteps, unsigned timeStepsPerYear, int brownianBridge, int antitheticVariate, unsigned requiredSamples, double requiredTolerance, unsigned maxSamples, unsigned seed) {
return dispatchRngStat<PricingEngine*>(rngtrait, stattrait, [&](auto r, auto st) {
return new MCVarianceSwapEngine<typename decltype(r)::type, typename decltype(st)::type>(process, timeSteps, timeStepsPerYear, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed);
});
}
PricingEngine* qlMCHestonHullWhiteEngine1Aux(int rngtrait, int stattrait, const shared_ptr<HybridHestonHullWhiteProcess> process, unsigned timeSteps, unsigned timeStepsPerYear, int antitheticVariate, int controlVariate, unsigned requiredSamples, double requiredTolerance, unsigned maxSamples, unsigned seed) {
return dispatchRngStat<PricingEngine*>(rngtrait, stattrait, [&](auto r, auto st) {
return new MCHestonHullWhiteEngine<typename decltype(r)::type, typename decltype(st)::type>(process, timeSteps, timeStepsPerYear, antitheticVariate, controlVariate, requiredSamples, requiredTolerance, maxSamples, seed);
});
}
PricingEngine* qlMCAmericanEngine1Aux(int rngtrait, int stattrait, const shared_ptr<GeneralizedBlackScholesProcess> process, unsigned timeSteps, unsigned timeStepsPerYear, int antitheticVariate, int controlVariate, unsigned requiredSamples, double requiredTolerance, unsigned maxSamples, unsigned seed, unsigned polynomOrder, LsmBasisSystem::PolynomialType polynomType, unsigned nCalibrationSamples, ext::optional<bool> antitheticVariateCalibration, unsigned seedCalibration) {
return dispatchRngStat<PricingEngine*>(rngtrait, stattrait, [&](auto r, auto st) {
return new MCAmericanEngine<typename decltype(r)::type, typename decltype(st)::type>(process, timeSteps, timeStepsPerYear, antitheticVariate, controlVariate, requiredSamples, requiredTolerance, maxSamples, seed, polynomOrder, polynomType, nCalibrationSamples, antitheticVariateCalibration, seedCalibration);
});
}
PricingEngine* qlMCBarrierEngine1Aux(int rngtrait, int stattrait, const shared_ptr<GeneralizedBlackScholesProcess> process, unsigned timeSteps, unsigned timeStepsPerYear, int brownianBridge, int antitheticVariate, unsigned requiredSamples, double requiredTolerance, unsigned maxSamples, int isBiased, unsigned seed) {
return dispatchRngStat<PricingEngine*>(rngtrait, stattrait, [&](auto r, auto st) {
return new MCBarrierEngine<typename decltype(r)::type, typename decltype(st)::type>(process, timeSteps, timeStepsPerYear, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, isBiased, seed);
});
}
PricingEngine* qlMCDigitalEngine1Aux(int rngtrait, int stattrait, const shared_ptr<GeneralizedBlackScholesProcess> x0, unsigned timeSteps, unsigned timeStepsPerYear, int brownianBridge, int antitheticVariate, unsigned requiredSamples, double requiredTolerance, unsigned maxSamples, unsigned seed) {
return dispatchRngStat<PricingEngine*>(rngtrait, stattrait, [&](auto r, auto st) {
return new MCDigitalEngine<typename decltype(r)::type, typename decltype(st)::type>(x0, timeSteps, timeStepsPerYear, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed);
});
}
PricingEngine* qlMCForwardEuropeanBSEngine1Aux(int rngtrait, int stattrait, const shared_ptr<GeneralizedBlackScholesProcess> process, unsigned timeSteps, unsigned timeStepsPerYear, int brownianBridge, int antitheticVariate, unsigned requiredSamples, double requiredTolerance, unsigned maxSamples, unsigned seed) {
return dispatchRngStat<PricingEngine*>(rngtrait, stattrait, [&](auto r, auto st) {
return new MCForwardEuropeanBSEngine<typename decltype(r)::type, typename decltype(st)::type>(process, timeSteps, timeStepsPerYear, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed);
});
}
PricingEngine* qlMCForwardEuropeanHestonEngine1Aux(int rngtrait, int stattrait, const shared_ptr<HestonProcess> process, unsigned timeSteps, unsigned timeStepsPerYear, int antitheticVariate, unsigned requiredSamples, double requiredTolerance, unsigned maxSamples, unsigned seed, int controlVariate) {
return dispatchRngStat<PricingEngine*>(rngtrait, stattrait, [&](auto r, auto st) {
return new MCForwardEuropeanHestonEngine<typename decltype(r)::type, typename decltype(st)::type>(process, timeSteps, timeStepsPerYear, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed, controlVariate);
});
}
PricingEngine* qlMCDiscreteArithmeticAPEngine1Aux(int rngtrait, int stattrait, const shared_ptr<GeneralizedBlackScholesProcess> process, int brownianBridge, int antitheticVariate, int controlVariate, unsigned requiredSamples, double requiredTolerance, unsigned maxSamples, unsigned seed) {
return dispatchRngStat<PricingEngine*>(rngtrait, stattrait, [&](auto r, auto st) {
return new MCDiscreteArithmeticAPEngine<typename decltype(r)::type, typename decltype(st)::type>(process, brownianBridge, antitheticVariate, controlVariate, requiredSamples, requiredTolerance, maxSamples, seed);
});
}
PricingEngine* qlMCDiscreteArithmeticASEngine1Aux(int rngtrait, int stattrait, const shared_ptr<GeneralizedBlackScholesProcess> process, int brownianBridge, int antitheticVariate, unsigned requiredSamples, double requiredTolerance, unsigned maxSamples, unsigned seed) {
return dispatchRngStat<PricingEngine*>(rngtrait, stattrait, [&](auto r, auto st) {
return new MCDiscreteArithmeticASEngine<typename decltype(r)::type, typename decltype(st)::type>(process, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed);
});
}
PricingEngine* qlMCDiscreteGeometricAPEngine1Aux(int rngtrait, int stattrait, const shared_ptr<GeneralizedBlackScholesProcess> process, int brownianBridge, int antitheticVariate, unsigned requiredSamples, double requiredTolerance, unsigned maxSamples, unsigned seed) {
return dispatchRngStat<PricingEngine*>(rngtrait, stattrait, [&](auto r, auto st) {
return new MCDiscreteGeometricAPEngine<typename decltype(r)::type, typename decltype(st)::type>(process, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed);
});
}
PricingEngine* qlMCDiscreteArithmeticAPHestonEngine1Aux(int rngtrait, int stattrait, const shared_ptr<HestonProcess> process, int antitheticVariate, unsigned requiredSamples, double requiredTolerance, unsigned maxSamples, unsigned seed, unsigned timeSteps, unsigned timeStepsPerYear, int controlVariate) {
return dispatchRngStat<PricingEngine*>(rngtrait, stattrait, [&](auto r, auto st) {
return new MCDiscreteArithmeticAPHestonEngine<typename decltype(r)::type, typename decltype(st)::type>(process, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed, timeSteps, timeStepsPerYear, controlVariate);
});
}
PricingEngine* qlMCDiscreteGeometricAPHestonEngine1Aux(int rngtrait, int stattrait, const shared_ptr<HestonProcess> process, int antitheticVariate, unsigned requiredSamples, double requiredTolerance, unsigned maxSamples, unsigned seed, unsigned timeSteps, unsigned timeStepsPerYear) {
return dispatchRngStat<PricingEngine*>(rngtrait, stattrait, [&](auto r, auto st) {
return new MCDiscreteGeometricAPHestonEngine<typename decltype(r)::type, typename decltype(st)::type>(process, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed, timeSteps, timeStepsPerYear);
});
}
PricingEngine* qlMCEuropeanEngine1Aux(int rngtrait, int stattrait, const shared_ptr<GeneralizedBlackScholesProcess> process, unsigned timeSteps, unsigned timeStepsPerYear, int brownianBridge, int antitheticVariate, unsigned requiredSamples, double requiredTolerance, unsigned maxSamples, unsigned seed) {
return dispatchRngStat<PricingEngine*>(rngtrait, stattrait, [&](auto r, auto st) {
return new MCEuropeanEngine<typename decltype(r)::type, typename decltype(st)::type>(process, timeSteps, timeStepsPerYear, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed);
});
}
PricingEngine* qlMCEuropeanGJRGARCHEngine1Aux(int rngtrait, int stattrait, const shared_ptr<GJRGARCHProcess> x0, unsigned timeSteps, unsigned timeStepsPerYear, int antitheticVariate, unsigned requiredSamples, double requiredTolerance, unsigned maxSamples, unsigned seed) {
return dispatchRngStat<PricingEngine*>(rngtrait, stattrait, [&](auto r, auto st) {
return new MCEuropeanGJRGARCHEngine<typename decltype(r)::type, typename decltype(st)::type>(x0, timeSteps, timeStepsPerYear, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed);
});
}
PricingEngine* qlMCEuropeanHestonEngine1Aux(int rngtrait, int stattrait, const shared_ptr<HestonProcess> x0, unsigned timeSteps, unsigned timeStepsPerYear, int antitheticVariate, unsigned requiredSamples, double requiredTolerance, unsigned maxSamples, unsigned seed) {
return dispatchRngStat<PricingEngine*>(rngtrait, stattrait, [&](auto r, auto st) {
return new MCEuropeanHestonEngine<typename decltype(r)::type, typename decltype(st)::type>(x0, timeSteps, timeStepsPerYear, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed);
});
}
PricingEngine* qlMCHullWhiteCapFloorEngine1Aux(int rngtrait, int stattrait, shared_ptr<HullWhite> model, int brownianBridge, int antitheticVariate, unsigned requiredSamples, double requiredTolerance, unsigned maxSamples, unsigned seed) {
return dispatchRngStat<PricingEngine*>(rngtrait, stattrait, [&](auto r, auto st) {
return new MCHullWhiteCapFloorEngine<typename decltype(r)::type, typename decltype(st)::type>(model, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed);
});
}
PricingEngine* qlMCHimalayaEngine1Aux(int rngtrait, int stattrait, const shared_ptr<StochasticProcessArray> processes, int brownianBridge, int antitheticVariate, unsigned requiredSamples, double requiredTolerance, unsigned maxSamples, unsigned seed) {
return dispatchRngStat<PricingEngine*>(rngtrait, stattrait, [&](auto r, auto st) {
return new MCHimalayaEngine<typename decltype(r)::type, typename decltype(st)::type>(processes, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed);
});
}
PricingEngine* qlMCPagodaEngine1Aux(int rngtrait, int stattrait, const shared_ptr<StochasticProcessArray> processes, int brownianBridge, int antitheticVariate, unsigned requiredSamples, double requiredTolerance, unsigned maxSamples, unsigned seed) {
return dispatchRngStat<PricingEngine*>(rngtrait, stattrait, [&](auto r, auto st) {
return new MCPagodaEngine<typename decltype(r)::type, typename decltype(st)::type>(processes, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed);
});
}
PricingEngine* qlMCEverestEngine1Aux(int rngtrait, int stattrait, const shared_ptr<StochasticProcessArray> processes, unsigned timeSteps, unsigned timeStepsPerYear, int brownianBridge, int antitheticVariate, unsigned requiredSamples, double requiredTolerance, unsigned maxSamples, unsigned seed) {
return dispatchRngStat<PricingEngine*>(rngtrait, stattrait, [&](auto r, auto st) {
return new MCEverestEngine<typename decltype(r)::type, typename decltype(st)::type>(processes, timeSteps, timeStepsPerYear, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed);
});
}
PricingEngine* qlMCEuropeanBasketEngine1Aux(int rngtrait, int stattrait, const shared_ptr<StochasticProcessArray> processes, unsigned timeSteps, unsigned timeStepsPerYear, int brownianBridge, int antitheticVariate, unsigned requiredSamples, double requiredTolerance, unsigned maxSamples, unsigned seed) {
return dispatchRngStat<PricingEngine*>(rngtrait, stattrait, [&](auto r, auto st) {
return new MCEuropeanBasketEngine<typename decltype(r)::type, typename decltype(st)::type>(processes, timeSteps, timeStepsPerYear, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed);
});
}
PricingEngine* qlMCPerformanceEngine1Aux(int rngtrait, int stattrait, const shared_ptr<GeneralizedBlackScholesProcess> process, int brownianBridge, int antitheticVariate, unsigned requiredSamples, double requiredTolerance, unsigned maxSamples, unsigned seed) {
return dispatchRngStat<PricingEngine*>(rngtrait, stattrait, [&](auto r, auto st) {
return new MCPerformanceEngine<typename decltype(r)::type, typename decltype(st)::type>(process, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed);
});
}
// MCLookbackEngine<I,RNG,S> is templated over the lookback option type I as well as RNG/S -- I is
// not a runtime "trait" (it fixes the whole option/engine-base pair, not a policy struct chosen
// among siblings), so each of the four already-bound lookback option types gets its own dispatcher
// over the RNG x Statistics axes only, mirroring the four separate analytic lookback engine shims.
PricingEngine* qlMCLookbackFixedEngineAux(int rngtrait, int stattrait, const shared_ptr<GeneralizedBlackScholesProcess> process, unsigned timeSteps, unsigned timeStepsPerYear, int brownianBridge, int antitheticVariate, unsigned requiredSamples, double requiredTolerance, unsigned maxSamples, unsigned seed) {
return dispatchRngStat<PricingEngine*>(rngtrait, stattrait, [&](auto r, auto st) {
return new MCLookbackEngine<ContinuousFixedLookbackOption, typename decltype(r)::type, typename decltype(st)::type>(process, timeSteps, timeStepsPerYear, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed);
});
}
PricingEngine* qlMCLookbackFloatingEngineAux(int rngtrait, int stattrait, const shared_ptr<GeneralizedBlackScholesProcess> process, unsigned timeSteps, unsigned timeStepsPerYear, int brownianBridge, int antitheticVariate, unsigned requiredSamples, double requiredTolerance, unsigned maxSamples, unsigned seed) {
return dispatchRngStat<PricingEngine*>(rngtrait, stattrait, [&](auto r, auto st) {
return new MCLookbackEngine<ContinuousFloatingLookbackOption, typename decltype(r)::type, typename decltype(st)::type>(process, timeSteps, timeStepsPerYear, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed);
});
}
PricingEngine* qlMCLookbackPartialFixedEngineAux(int rngtrait, int stattrait, const shared_ptr<GeneralizedBlackScholesProcess> process, unsigned timeSteps, unsigned timeStepsPerYear, int brownianBridge, int antitheticVariate, unsigned requiredSamples, double requiredTolerance, unsigned maxSamples, unsigned seed) {
return dispatchRngStat<PricingEngine*>(rngtrait, stattrait, [&](auto r, auto st) {
return new MCLookbackEngine<ContinuousPartialFixedLookbackOption, typename decltype(r)::type, typename decltype(st)::type>(process, timeSteps, timeStepsPerYear, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed);
});
}
PricingEngine* qlMCLookbackPartialFloatingEngineAux(int rngtrait, int stattrait, const shared_ptr<GeneralizedBlackScholesProcess> process, unsigned timeSteps, unsigned timeStepsPerYear, int brownianBridge, int antitheticVariate, unsigned requiredSamples, double requiredTolerance, unsigned maxSamples, unsigned seed) {
return dispatchRngStat<PricingEngine*>(rngtrait, stattrait, [&](auto r, auto st) {
return new MCLookbackEngine<ContinuousPartialFloatingLookbackOption, typename decltype(r)::type, typename decltype(st)::type>(process, timeSteps, timeStepsPerYear, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed);
});
}
// MCAmericanBasketEngine is templated <RNG> only upstream (its base MCLongstaffSchwartzEngine<BasketOption::engine,
// MultiVariate,RNG> never forwards a second template argument), so unlike every other engine in this file it has no
// S axis to expose -- not a gap, a real upstream limitation. See CLAUDE.md/PricingEngine.chs for the note.
PricingEngine* qlMCAmericanBasketEngine1Aux(int rngtrait, const shared_ptr<StochasticProcessArray> processes, unsigned timeSteps, unsigned timeStepsPerYear, int brownianBridge, int antitheticVariate, unsigned requiredSamples, double requiredTolerance, unsigned maxSamples, unsigned seed, unsigned nCalibrationSamples, unsigned polynomialOrder, LsmBasisSystem::PolynomialType polynomialType) {
return dispatchRng<PricingEngine*>(rngtrait, [&](auto r) {
return new MCAmericanBasketEngine<typename decltype(r)::type>(processes, timeSteps, timeStepsPerYear, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed, nCalibrationSamples, polynomialOrder, polynomialType);
});
}
PricingEngine* qlFdBlackScholesVanillaEngineAux(const shared_ptr<GeneralizedBlackScholesProcess> process, unsigned tGrid, unsigned xGrid, unsigned dampingSteps, const FdmSchemeDesc &fdScheme, bool localVol, double illegalLocalVolOverwrite, int cashDividendModel) {return new FdBlackScholesVanillaEngine(process, tGrid, xGrid, dampingSteps, fdScheme, localVol, illegalLocalVolOverwrite, (FdBlackScholesVanillaEngine::CashDividendModel)cashDividendModel);}
class PolymorphicPathGenerator {
private:
using PseudoRandomPathGenerator = MultiPathGenerator<PseudoRandom::rsg_type>;
using SobolPathGenerator = MultiPathGenerator<LowDiscrepancy::rsg_type>;
using PoissonPathGenerator = MultiPathGenerator<PoissonPseudoRandom::rsg_type>;
using ZigguratPathGenerator = MultiPathGenerator<Ziggurat::rsg_type>;
public:
PolymorphicPathGenerator(int rngtrait, const shared_ptr<StochasticProcess> p, const TimeGrid &t, unsigned seed, unsigned dim, bool brownianBridge) {
init(rngtrait, p, t, seed, dim, brownianBridge, SobolRsg::Jaeckel);
}
PolymorphicPathGenerator(SobolRsg::DirectionIntegers dir, const shared_ptr<StochasticProcess> p, const TimeGrid &t, unsigned seed, unsigned dim, bool brownianBridge) {
init(hasquant::LowDiscrepancy, p, t, seed, dim, brownianBridge, dir);
}
const Sample<MultiPath>& next() const {return _next();}
const Sample<MultiPath>& antithetic() const {return _antithetic();}
private:
void init(int rngtrait, const shared_ptr<StochasticProcess> p, const TimeGrid &t, unsigned seed, unsigned dim, bool brownianBridge, SobolRsg::DirectionIntegers dir) {
switch (rngtrait) {
case hasquant::PseudoRandom:
_pseudoRandom = std::unique_ptr<PseudoRandomPathGenerator>(new PseudoRandomPathGenerator(p, t, PseudoRandom::rsg_type(PseudoRandom::ursg_type(dim, PseudoRandom::urng_type(seed))), brownianBridge));
_next = std::bind(static_cast<const Sample<MultiPath>& (PseudoRandomPathGenerator::*)() const>(&PseudoRandomPathGenerator::next), _pseudoRandom.get());
_antithetic = std::bind(&PseudoRandomPathGenerator::antithetic, _pseudoRandom.get());
break;
case hasquant::PoissonPseudoRandom:
_poisson = std::unique_ptr<PoissonPathGenerator>(new PoissonPathGenerator(p, t, PoissonPseudoRandom::rsg_type(PoissonPseudoRandom::ursg_type(dim, PoissonPseudoRandom::urng_type(seed))), brownianBridge));
_next = std::bind(static_cast<const Sample<MultiPath>& (PoissonPathGenerator::*)() const>(&PoissonPathGenerator::next), _poisson.get());
_antithetic = std::bind(&PoissonPathGenerator::antithetic, _poisson.get());
break;
case hasquant::LowDiscrepancy:
_sobol = std::unique_ptr<SobolPathGenerator>(new SobolPathGenerator(p, t, LowDiscrepancy::rsg_type(SobolRsg(dim, seed, dir)), brownianBridge));
_next = std::bind(static_cast<const Sample<MultiPath>& (SobolPathGenerator::*)() const>(&SobolPathGenerator::next), _sobol.get());
_antithetic = std::bind(&SobolPathGenerator::antithetic, _sobol.get());
break;
case hasquant::Ziggurat:
_ziggurat = std::unique_ptr<ZigguratPathGenerator>(new ZigguratPathGenerator(p, t, Ziggurat::rsg_type(dim, ZigguratRng(seed)), brownianBridge));
_next = std::bind(static_cast<const Sample<MultiPath>& (ZigguratPathGenerator::*)() const>(&ZigguratPathGenerator::next), _ziggurat.get());
_antithetic = std::bind(&ZigguratPathGenerator::antithetic, _ziggurat.get());
break;
default:
QL_FAIL("Unknown RNG "<< rngtrait);
}
}
std::unique_ptr<PseudoRandomPathGenerator> _pseudoRandom;
std::unique_ptr<SobolPathGenerator> _sobol;
std::unique_ptr<PoissonPathGenerator> _poisson;
std::unique_ptr<ZigguratPathGenerator> _ziggurat;
std::function<const Sample<MultiPath>& ()> _next;
std::function<const Sample<MultiPath>& ()> _antithetic;
};
PolymorphicPathGenerator* qlPathGeneratorAux(int rngtrait, const shared_ptr<StochasticProcess> p, const TimeGrid &grid, unsigned seed, unsigned dim, bool brownianBridge) {
return new PolymorphicPathGenerator(rngtrait, p, grid, seed, dim, brownianBridge);
}
PolymorphicPathGenerator* qlSobolPathGeneratorAux(SobolRsg::DirectionIntegers dir, const shared_ptr<StochasticProcess> p, const TimeGrid &grid, unsigned seed, unsigned dim, bool brownianBridge) {
return new PolymorphicPathGenerator(dir, p, grid, seed, dim, brownianBridge);
}
// The gaussian sequence generator that PolymorphicPathGenerator's MultiPathGenerator merely
// consumes, lifted out so Haskell can drive its own SDE evolution with no callback in the hot
// loop -- shape 1 of CLAUDE.md's "coarsen the language-boundary crossing" bullet, the same trick
// lsmRegress plays on LongstaffSchwartzPathPricer. Same four-way RngTrait switch and the same
// SobolRsg::DirectionIntegers overload as PolymorphicPathGenerator above, deliberately: the two
// construct their rsg identically, so a Haskell-evolved path can be compared draw-for-draw
// against pathGenerator's own.
class PolymorphicGaussianRsg {
private:
using PseudoRandomRsg = PseudoRandom::rsg_type;
using SobolRsgType = LowDiscrepancy::rsg_type;
using PoissonRsg = PoissonPseudoRandom::rsg_type;
using ZigguratRsg = Ziggurat::rsg_type;
public:
PolymorphicGaussianRsg(int rngtrait, unsigned dim, unsigned seed) {
init(rngtrait, dim, seed, SobolRsg::Jaeckel);
}
PolymorphicGaussianRsg(SobolRsg::DirectionIntegers dir, unsigned dim, unsigned seed) {
init(hasquant::LowDiscrepancy, dim, seed, dir);
}
const Sample<std::vector<Real> >& nextSequence() const {return _next();}
const Sample<std::vector<Real> >& lastSequence() const {return _last();}
unsigned dimension() const {return _dimension();}
private:
void init(int rngtrait, unsigned dim, unsigned seed, SobolRsg::DirectionIntegers dir) {
switch (rngtrait) {
case hasquant::PseudoRandom:
_pseudoRandom.reset(new PseudoRandomRsg(PseudoRandom::ursg_type(dim, PseudoRandom::urng_type(seed))));
bind(_pseudoRandom.get());
break;
case hasquant::PoissonPseudoRandom:
_poisson.reset(new PoissonRsg(PoissonPseudoRandom::ursg_type(dim, PoissonPseudoRandom::urng_type(seed))));
bind(_poisson.get());
break;
case hasquant::LowDiscrepancy:
_sobol.reset(new SobolRsgType(SobolRsg(dim, seed, dir)));
bind(_sobol.get());
break;
case hasquant::Ziggurat:
_ziggurat.reset(new ZigguratRsg(dim, ZigguratRng(seed)));
bind(_ziggurat.get());
break;
default:
QL_FAIL("Unknown RNG "<< rngtrait);
}
}
template <class Rsg> void bind(Rsg* r) {
_next = [r]() -> const Sample<std::vector<Real> >& {return r->nextSequence();};
_last = [r]() -> const Sample<std::vector<Real> >& {return r->lastSequence();};
_dimension = [r]() {return (unsigned)r->dimension();};
}
std::unique_ptr<PseudoRandomRsg> _pseudoRandom;
std::unique_ptr<SobolRsgType> _sobol;
std::unique_ptr<PoissonRsg> _poisson;
std::unique_ptr<ZigguratRsg> _ziggurat;
std::function<const Sample<std::vector<Real> >& ()> _next;
std::function<const Sample<std::vector<Real> >& ()> _last;
std::function<unsigned ()> _dimension;
};
PolymorphicGaussianRsg* qlGaussianRsgAux(int rngtrait, unsigned dimension, unsigned seed) {
return new PolymorphicGaussianRsg(rngtrait, dimension, seed);
}
PolymorphicGaussianRsg* qlSobolGaussianRsgAux(SobolRsg::DirectionIntegers dir, unsigned dimension, unsigned seed) {
return new PolymorphicGaussianRsg(dir, dimension, seed);
}
void qlFreePolymorphicGaussianRsgAux(PolymorphicGaussianRsg* g) {delete g;}
const Sample<std::vector<Real> >& qlGaussianRsgNextSequenceAux(PolymorphicGaussianRsg* g) {return g->nextSequence();}
const Sample<std::vector<Real> >& qlGaussianRsgLastSequenceAux(PolymorphicGaussianRsg* g) {return g->lastSequence();}
unsigned qlGaussianRsgDimensionAux(PolymorphicGaussianRsg* g) {return g->dimension();}
void qlFreePolymorphicPathGeneratorAux(PolymorphicPathGenerator *p) {delete p;}
const Sample<MultiPath>& qlPathGeneratorNextAux(PolymorphicPathGenerator *p) {return p->next();}
const Sample<MultiPath>& qlPathGeneratorAntitheticAux(PolymorphicPathGenerator *p) {return p->antithetic();}
/* vim: set ft=cpp ff=unix ts=8 sts=2 sw=2 et: */