33#include <ql/math/comparison.hpp>
34#include <ql/math/interpolations/cubicinterpolation.hpp>
35#include <ql/methods/finitedifferences/meshers/fdmmeshercomposite.hpp>
36#include <ql/quotes/simplequote.hpp>
45 const Handle<YieldTermStructure>& curve,
const std::string& index,
46 const std::string& indexCurrency,
const Handle<BlackScholesModelWrapper>& model,
47 const std::set<Date>& simulationDates,
49 const std::vector<Real>& calibrationStrikes,
const Real mesherEpsilon,
50 const Real mesherScaling,
const Real mesherConcentration,
51 const Size mesherMaxConcentratingPoints,
const bool staticMesher)
52 :
FdBlackScholesBase(stateGridPoints, {currency}, {curve}, {}, {}, {}, {index}, {indexCurrency}, {currency}, model,
53 {}, simulationDates, iborFallbackConfig, calibration, {{index, calibrationStrikes}},
54 mesherEpsilon, mesherScaling, mesherConcentration, mesherMaxConcentratingPoints,
58 const Size stateGridPoints,
const std::vector<std::string>& currencies,
59 const std::vector<Handle<YieldTermStructure>>& curves,
const std::vector<Handle<Quote>>& fxSpots,
60 const std::vector<std::pair<std::string, QuantLib::ext::shared_ptr<InterestRateIndex>>>& irIndices,
61 const std::vector<std::pair<std::string, QuantLib::ext::shared_ptr<ZeroInflationIndex>>>& infIndices,
62 const std::vector<std::string>& indices,
const std::vector<std::string>& indexCurrencies,
63 const std::set<std::string>& payCcys,
const Handle<BlackScholesModelWrapper>& model,
64 const std::map<std::pair<std::string, std::string>, Handle<QuantExt::CorrelationTermStructure>>& correlations,
65 const std::set<Date>& simulationDates,
const IborFallbackConfig& iborFallbackConfig,
const std::string& calibration,
66 const std::map<std::string, std::vector<Real>>& calibrationStrikes,
const Real mesherEpsilon,
67 const Real mesherScaling,
const Real mesherConcentration,
const Size mesherMaxConcentratingPoints,
68 const bool staticMesher)
69 :
ModelImpl(curves.at(0)->dayCounter(), stateGridPoints, currencies, irIndices, infIndices, indices,
70 indexCurrencies, simulationDates, iborFallbackConfig),
71 curves_(curves), fxSpots_(fxSpots), payCcys_(payCcys),
model_(model),
correlations_(correlations),
72 calibration_(calibration),
calibrationStrikes_(calibrationStrikes), mesherEpsilon_(mesherEpsilon),
73 mesherScaling_(mesherScaling), mesherConcentration_(mesherConcentration),
74 mesherMaxConcentratingPoints_(mesherMaxConcentratingPoints), staticMesher_(staticMesher) {
78 QL_REQUIRE(!
model_.empty(),
"model is empty");
79 QL_REQUIRE(!
curves_.empty(),
"no curves given");
81 <<
") does not match number of curves ("
84 "number of currencies (" <<
currencies_.size() <<
") does not match number of fx spots ("
88 "mismatch of processes size (" <<
model_->processes().size() <<
") and number of indices ("
91 for (
auto const& c : payCcys) {
93 "pay ccy '" << c <<
"' not found in currencies list.");
101 registerWith(o.second);
107 if (
model_->processes().size() <= 1)
112 if (
model_->processes().size() == 2) {
114 if (payCcys.size() == 1) {
115 std::string payCcy = *payCcys.begin();
120 mainIndexCcy =
indices_[0].fx()->targetCurrency().code();
123 std::string ccy1 =
indices_[1].fx()->sourceCurrency().code();
124 std::string ccy2 =
indices_[1].fx()->targetCurrency().code();
125 if ((ccy1 == mainIndexCcy && ccy2 == payCcy) || (ccy1 == payCcy && ccy2 == mainIndexCcy)) {
128 currencies.begin(), std::find(currencies.begin(), currencies.end(), mainIndexCcy));
130 std::distance(currencies.begin(), std::find(currencies.begin(), currencies.end(), payCcy));
133 DLOG(
"FdBlackScholesBase model will be run for index '"
144 QL_FAIL(
"FdBlackScholesBase: model does not support multi-dim fd schemes currently.");
150 for (Size i = 0; i <
indices_.size(); ++i)
151 correlation[i][i] = 1.0;
153 IndexInfo inf1(c.first.first), inf2(c.first.second);
158 Size i1 = std::distance(
indices_.begin(), ind1);
159 Size i2 = std::distance(
indices_.begin(), ind2);
160 correlation[i1][i2] = correlation[i2][i1] = c.second->correlation(0.0);
163 TLOG(
"FdBlackScholesBase correlation matrix:");
181 std::vector<Real> times;
205 std::vector<Real> calibrationStrikes;
207 calibrationStrikes.resize(
indices_.size(), Null<Real>());
209 for (Size i = 0; i <
indices_.size(); ++i) {
212 calibrationStrikes.push_back(f->second[0]);
213 TLOG(
"calibration strike for index '" <<
indices_[i] <<
"' is " << f->second[0]);
215 calibrationStrikes.push_back(Null<Real>());
216 TLOG(
"calibration strike for index '" <<
indices_[i] <<
"' is ATMF");
220 QL_FAIL(
"FdBlackScholes: calibration '" <<
calibration_ <<
"' not supported, expected ATM, Deal");
225 std::vector<std::vector<QuantLib::ext::tuple<Real, Real, bool>>> cPoints;
226 for (Size i = 0; i <
indices_.size(); ++i) {
227 cPoints.push_back(std::vector<QuantLib::ext::tuple<Real, Real, bool>>());
231 cPoints.back().push_back(QuantLib::ext::make_tuple(std::log(f->second[j]),
mesherConcentration_,
false));
232 TLOG(
"added critical point at strike " << f->second[j] <<
" with concentration "
241 mesher_ = QuantLib::ext::make_shared<FdmMesherComposite>(QuantLib::ext::make_shared<QuantExt::FdmBlackScholesMesher>(
243 calibrationStrikes[0] == Null<Real>()
246 : calibrationStrikes[0],
252 QuantLib::ext::shared_ptr<QuantExt::FdmQuantoHelper> quantoHelper;
256 quantoHelper = QuantLib::ext::make_shared<QuantExt::FdmQuantoHelper>(
258 *
model_->processes()[1]->blackVolatility(), quantoCorr, Null<Real>(),
model_->processes()[1]->x0(),
false,
263 QuantLib::ext::make_shared<QuantExt::FdmBlackScholesOp>(
mesher_,
model_->processes()[0], calibrationStrikes[0],
false,
264 -
static_cast<Real
>(Null<Real>()), 0, quantoHelper,
false,
true);
268 solver_ = QuantLib::ext::make_shared<FdmBackwardSolver>(
269 operator_, std::vector<QuantLib::ext::shared_ptr<BoundaryCondition<FdmLinearOp>>>(),
nullptr, FdmSchemeDesc::Douglas());
273 auto locations =
mesher_->locations(0);
278 for (Size i = 0; i < calibrationStrikes.size(); ++i) {
280 (calibrationStrikes[i] == Null<Real>() ?
"ATMF" : std::to_string(calibrationStrikes[i]));
283 for (Size i = 0; i <
indices_.size(); ++i) {
288 model_->processes()[i]->dividendYield(), t);
290 Real volatility =
model_->processes()[i]->blackVolatility()->blackVol(
291 t, calibrationStrikes[i] == Null<Real>() ? forward : calibrationStrikes[i]);
304 QL_REQUIRE(indexNo == 0,
"FdBlackScholesBase::getIndexValue(): indexNo (" << indexNo <<
") must be 0");
310 const Date& expiry =
indices_[indexNo].comm(d)->expiryDate();
312 if (expiry != Date())
317 effFwd = std::max(effFwd, d);
326 if (effFwd != Null<Date>()) {
327 auto p =
model_->processes().at(indexNo);
328 res *=
RandomVariable(
size(), p->dividendYield()->discount(effFwd) / p->dividendYield()->discount(d) /
329 (p->riskFreeRate()->discount(effFwd) / p->riskFreeRate()->discount(d)));
341 Date effFixingDate = d;
342 if (fwd != Null<Date>())
345 effFixingDate =
irIndices_.at(indexNo).second->fixingCalendar().adjust(effFixingDate);
350 Date effFixingDate = d;
351 if (fwd != Null<Date>())
357 const Date& start,
const Date& end,
const Real spread,
const Real gearing,
358 const Integer lookback,
const Natural rateCutoff,
359 const Natural fixingDays,
const bool includeSpread,
const Real cap,
360 const Real floor,
const bool nakedOption,
361 const bool localCapFloor)
const {
364 auto index = QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(indexInfo.
irIbor());
365 QL_REQUIRE(index,
"BlackScholesBase::fwdCompAvg(): expected on index for " << indexInput);
367 QL_REQUIRE(cap > 999998.0 && floor < -999998.0,
368 "BlackScholesCGBase:fwdCompAvg(): cap (" << cap <<
") / floor (" << floor <<
") not supported");
369 QuantLib::ext::shared_ptr<QuantLib::FloatingRateCoupon> coupon;
370 QuantLib::ext::shared_ptr<QuantLib::FloatingRateCouponPricer> pricer;
372 coupon = QuantLib::ext::make_shared<QuantExt::AverageONIndexedCoupon>(
373 end, 1.0, start, end, index, gearing, spread, rateCutoff, DayCounter(), lookback * Days, fixingDays);
374 pricer = QuantLib::ext::make_shared<AverageONIndexedCouponPricer>();
376 coupon = QuantLib::ext::make_shared<QuantExt::OvernightIndexedCoupon>(
377 end, 1.0, start, end, index, gearing, spread, Date(), Date(), DayCounter(),
false, includeSpread,
378 lookback * Days, rateCutoff, fixingDays);
379 pricer = QuantLib::ext::make_shared<OvernightIndexedCouponPricer>();
381 coupon->setPricer(pricer);
399 const boost::optional<long>& memSlot,
const RandomVariable& addRegressor1,
402 QL_REQUIRE(!memSlot,
"FdBlackScholesBase::npv(): mem slot not allowed");
403 QL_REQUIRE(!
filter.initialised(),
"FdBlackScholesBase::npv(). filter not allowed");
404 QL_REQUIRE(!addRegressor1.
initialised(),
"FdBlackScholesBase::npv(). addRegressor1 not allowed");
405 QL_REQUIRE(!addRegressor2.
initialised(),
"FdBlackScholesBase::npv(). addRegressor2 not allowed");
409 Real t1 = amount.
time();
422 QL_REQUIRE(t1 != Null<Real>(),
423 "FdBlackScholesBase::npv(): can not roll back amount wiithout time attached (to t0=" << t0 <<
")");
432 QL_REQUIRE(ind0 <= ind1,
"FdBlackScholesBase::npv(): can not roll back from t1= "
433 << t1 <<
" (index " << ind1 <<
") to t0= " << t0 <<
" (" << ind0 <<
")");
442 Array workingArray(amount.
size());
445 for (
int j =
static_cast<int>(ind1) - 1; j >=
static_cast<int>(ind0); --j) {
458 const bool above)
const {
459 QL_FAIL(
"FdBlackScholesBase::getFutureBarrierProb(): not supported");
481 MonotonicCubicNaturalSpline interpolation(x.begin(), x.end(), y.begin());
482 interpolation.enableExtrapolation();
483 return interpolation(
model_->processes()[0]->x0());
487 const std::string& currency)
const {
499 <<
"' in quanto-adjusted FDBlackScholesBase model");
const std::vector< Real > calibrationStrikes_
const std::map< std::pair< std::string, std::string >, Handle< QuantExt::CorrelationTermStructure > > & correlations_
RandomVariable getInfIndexValue(const Size indexNo, const Date &d, const Date &fwd=Null< Date >()) const override
void performCalculations() const override
Size quantoTargetCcyIndex_
void releaseMemory() override
RandomVariable getFutureBarrierProb(const std::string &index, const Date &obsdate1, const Date &obsdate2, const RandomVariable &barrier, const bool above) const override
QuantLib::ext::shared_ptr< FdmLinearOpComposite > operator_
const Real mesherConcentration_
RandomVariable getIrIndexValue(const Size indexNo, const Date &d, const Date &fwd=Null< Date >()) const override
FdBlackScholesBase(const Size stateGridPoints, const std::vector< std::string > ¤cies, const std::vector< Handle< YieldTermStructure > > &curves, const std::vector< Handle< Quote > > &fxSpots, const std::vector< std::pair< std::string, QuantLib::ext::shared_ptr< InterestRateIndex > > > &irIndices, const std::vector< std::pair< std::string, QuantLib::ext::shared_ptr< ZeroInflationIndex > > > &infIndices, const std::vector< std::string > &indices, const std::vector< std::string > &indexCurrencies, const std::set< std::string > &payCcys_, const Handle< BlackScholesModelWrapper > &model, const std::map< std::pair< std::string, std::string >, Handle< QuantExt::CorrelationTermStructure > > &correlations, const std::set< Date > &simulationDates, const IborFallbackConfig &iborFallbackConfig, const std::string &calibration, const std::map< std::string, std::vector< Real > > &calibrationStrikes={}, const Real mesherEpsilon=1E-4, const Real mesherScaling=1.5, const Real mesherConcentration=0.1, const Size mesherMaxConcentratingPoints=9999, const bool staticMesher=false)
RandomVariable npv(const RandomVariable &amount, const Date &obsdate, const Filter &filter, const boost::optional< long > &memSlot, const RandomVariable &addRegressor1, const RandomVariable &addRegressor2) const override
Real getFxSpot(const Size idx) const override
Size quantoSourceCcyIndex_
const Real mesherScaling_
const Date & referenceDate() const override
const std::string & baseCcy() const override
RandomVariable getNumeraire(const Date &s) const override
QuantLib::ext::shared_ptr< FdmBackwardSolver > solver_
Real extractT0Result(const RandomVariable &result) const override
std::set< Date > effectiveSimulationDates_
QuantLib::ext::shared_ptr< FdmMesher > mesher_
RandomVariable underlyingValues_
const std::vector< Handle< Quote > > fxSpots_
RandomVariable pay(const RandomVariable &amount, const Date &obsdate, const Date &paydate, const std::string ¤cy) const override
const Handle< BlackScholesModelWrapper > model_
const std::map< std::string, std::vector< Real > > calibrationStrikes_
RandomVariable getDiscount(const Size idx, const Date &s, const Date &t) const override
const Size mesherMaxConcentratingPoints_
RandomVariable getIndexValue(const Size indexNo, const Date &d, const Date &fwd=Null< Date >()) const override
const Real mesherEpsilon_
const std::map< std::pair< std::string, std::string >, Handle< QuantExt::CorrelationTermStructure > > correlations_
RandomVariable fwdCompAvg(const bool isAvg, const std::string &index, const Date &obsdate, const Date &start, const Date &end, const Real spread, const Real gearing, const Integer lookback, const Natural rateCutoff, const Natural fixingDays, const bool includeSpread, const Real cap, const Real floor, const bool nakedOption, const bool localCapFloor) const override
const std::string calibration_
Real quantoCorrelationMultiplier_
const std::vector< Handle< YieldTermStructure > > curves_
std::vector< Size > positionInTimeGrid_
Matrix getCorrelation() const
bool applyQuantoAdjustment_
QuantLib::ext::shared_ptr< IborIndex > irIbor() const
std::map< std::string, boost::any > additionalResults_
Real timeFromReference(const Date &d) const
virtual Size size() const
const std::vector< std::string > currencies_
std::vector< std::pair< IndexInfo, QuantLib::ext::shared_ptr< ZeroInflationIndex > > > infIndices_
const std::string & baseCcy() const override
std::vector< IndexInfo > indices_
std::vector< std::pair< IndexInfo, QuantLib::ext::shared_ptr< InterestRateIndex > > > irIndices_
RandomVariable pay(const RandomVariable &amount, const Date &obsdate, const Date &paydate, const std::string ¤cy) const override
const std::vector< std::string > indexCurrencies_
SafeStack< ValueType > value
SafeStack< Filter > filter
const QuantLib::ext::shared_ptr< ModelCG > model_
black scholes fd model base class for n underlyings (fx, equity or commodity)
Map text representations to QuantLib/QuantExt types.
#define DLOG(text)
Logging Macro (Level = Debug)
#define TLOGGERSTREAM(text)
#define TLOG(text)
Logging Macro (Level = Data)
Shared utilities for model building and calibration.
RandomVariable exp(RandomVariable x)
Real atmForward(const Real s0, const Handle< YieldTermStructure > &r, const Handle< YieldTermStructure > &q, const Real t)
helper function that computes the atm forward
std::string to_string(const LocationInfo &l)
Serializable Credit Default Swap.
Real at(const Size i) const
bool deterministic() const
void setTime(const Real time)
void copyToArray(QuantLib::Array &array) const
string conversion utilities