33 QuantLib::ext::shared_ptr<QuantExt::CrossAssetModel> model,
34 QuantLib::ext::shared_ptr<QuantExt::MultiPathGeneratorBase> pathGenerator,
35 QuantLib::ext::shared_ptr<ScenarioFactory> scenarioFactory, QuantLib::ext::shared_ptr<ScenarioSimMarketParameters> simMarketConfig,
36 Date today, QuantLib::ext::shared_ptr<DateGrid> grid, QuantLib::ext::shared_ptr<ore::data::Market> initMarket,
37 const std::string& configuration)
39 scenarioFactory_(scenarioFactory), simMarketConfig_(simMarketConfig), initMarket_(initMarket),
40 configuration_(configuration) {
42 LOG(
"CrossAssetModelScenarioGenerator ctor called");
44 QL_REQUIRE(initMarket != NULL,
"CrossAssetScenarioGenerator: initMarket is null");
45 QL_REQUIRE(
timeGrid_.size() ==
dates_.size() + 1,
"date/time grid size mismatch");
49 DayCounter dc =
model_->irModel(0)->termStructure()->dayCounter();
50 n_ccy_ =
model_->components(CrossAssetModel::AssetType::IR);
51 n_eq_ =
model_->components(CrossAssetModel::AssetType::EQ);
52 n_inf_ =
model_->components(CrossAssetModel::AssetType::INF);
53 n_cr_ =
model_->components(CrossAssetModel::AssetType::CR);
54 n_com_ =
model_->components(CrossAssetModel::AssetType::COM);
62 for (Size j = 0; j <
model_->components(CrossAssetModel::AssetType::IR); j++) {
63 std::string ccy =
model_->parametrizations()[j]->currency().code();
66 for (Size k = 0; k < n_ten; k++)
75 for (Size k = 0; k < n_ten; ++k) {
83 for (Size j = 0; j < n_curves; ++j) {
85 Size n_ten =
ten_yc_.back().size();
86 for (Size k = 0; k < n_ten; ++k) {
94 for (Size j = 0; j <
n_com_; j++) {
98 for (Size k = 0; k < n_ten; k++)
105 for (Size k = 0; k <
n_ccy_ - 1; k++) {
106 const string& foreign =
model_->parametrizations()[k + 1]->currency().code();
107 const string& domestic =
model_->parametrizations()[0]->currency().code();
113 DLOG(
"CrossAssetModel is simulating FX vols");
114 QL_REQUIRE(
model_->modelType(CrossAssetModel::AssetType::IR, 0) == CrossAssetModel::ModelType::LGM1F,
115 "Simulation of FX vols is only supported for LGM1F ir model type.");
119 DLOG(
"Set up CrossAssetModelImpliedFxVolTermStructures for " << pair);
120 QL_REQUIRE(pair.size() == 6,
"Invalid ccypair " << pair);
121 const string& domestic = pair.substr(0, 3);
122 const string& foreign = pair.substr(3);
123 QL_REQUIRE(domestic ==
model_->parametrizations()[0]->currency().code(),
"Only DOM-FOR fx vols supported");
125 QL_REQUIRE(index > 0,
"Invalid index for ccy " << foreign <<
" should be > 0");
127 DLOG(
"Pair " << pair <<
" index " << index);
129 fxVols_.push_back(QuantLib::ext::make_shared<CrossAssetModelImpliedFxVolTermStructure>(
model_, index - 1));
130 DLOG(
"Set up CrossAssetModelImpliedFxVolTermStructures for " << pair <<
" done");
135 Size n_eq =
model_->components(CrossAssetModel::AssetType::EQ);
137 for (Size k = 0; k < n_eq; k++) {
138 const string& eqName =
model_->eqbs(k)->name();
144 DLOG(
"CrossAssetModel is simulating EQ vols");
145 QL_REQUIRE(
model_->modelType(CrossAssetModel::AssetType::IR, 0) == CrossAssetModel::ModelType::LGM1F,
146 "Simulation of EQ vols is only supported for LGM1F ir model type.");
150 DLOG(
"Set up CrossAssetModelImpliedEqVolTermStructures for " << equityName);
151 Size eqIndex = model->eqIndex(equityName);
153 DLOG(
"EQ Vol Name = " << equityName <<
", index = " << eqIndex);
155 eqVols_.push_back(QuantLib::ext::make_shared<CrossAssetModelImpliedEqVolTermStructure>(
model_, eqIndex));
156 DLOG(
"Set up CrossAssetModelImpliedEqVolTermStructures for " << equityName <<
" done");
161 Size n_inf =
model_->components(CrossAssetModel::AssetType::INF);
164 for (Size j = 0; j < n_inf; ++j) {
171 for (Size j = 0; j < n_zeroinf; ++j) {
174 for (Size k = 0; k < n_ten; ++k) {
184 for (Size j = 0; j < n_yoyinf; ++j) {
187 for (Size k = 0; k < n_ten; ++k) {
196 Size n_cr =
model_->components(CrossAssetModel::AssetType::CR);
198 for (Size j = 0; j <
model_->components(CrossAssetModel::AssetType::CR); j++) {
199 std::string cr_name =
model_->cr(j)->name();
201 Size n_ten =
ten_dfc_.back().size();
202 for (Size k = 0; k < n_ten; k++) {
210 ostringstream numStr;
225 for (Size j = 0; j <
n_ccy_; ++j) {
226 curves_.push_back(QuantLib::ext::make_shared<QuantExt::ModelImpliedYieldTermStructure>(
model_->irModel(j), dc,
true));
232 Handle<YieldTermStructure> fts = index->forwardingTermStructure();
233 auto impliedFwdCurve = QuantLib::ext::make_shared<ModelImpliedYtsFwdFwdCorrected>(
234 model_->irModel(
model_->ccyIndex(index->currency())), fts, dc,
false);
236 indices_.push_back(index->clone(Handle<YieldTermStructure>(impliedFwdCurve)));
243 auto impliedYieldCurve =
244 QuantLib::ext::make_shared<ModelImpliedYtsFwdFwdCorrected>(
model_->irModel(
model_->ccyIndex(ccy)), yts, dc,
false);
249 for (Size j = 0; j <
n_com_; ++j) {
250 QuantLib::ext::shared_ptr<CommodityModel> cm =
model_->comModel(j);
251 auto pts = QuantLib::ext::make_shared<QuantExt::ModelImpliedPriceTermStructure>(
model_->comModel(j), dc,
true);
263 auto ccyIdx =
model_->ccyIndex(
model_->inf(idx)->currency());
264 auto mt =
model_->modelType(CrossAssetModel::AssetType::INF, idx);
265 QL_REQUIRE(mt == CrossAssetModel::ModelType::DK || mt == CrossAssetModel::ModelType::JY,
266 "CrossAssetModelScenarioGenerator: expected inflation model to be JY or DK.");
267 QuantLib::ext::shared_ptr<ZeroInflationModelTermStructure> ts;
270 if (mt == CrossAssetModel::ModelType::DK) {
271 ts = QuantLib::ext::make_shared<DkImpliedZeroInflationTermStructure>(
274 ts = QuantLib::ext::make_shared<JyImpliedZeroInflationTermStructure>(
model_, idx);
275 QL_REQUIRE(
model_->modelType(CrossAssetModel::AssetType::IR, 0) == CrossAssetModel::ModelType::LGM1F,
276 "Simulation of INF JY model is only supported for LGM1F ir model type.");
284 auto ccyIdx =
model_->ccyIndex(
model_->inf(idx)->currency());
285 auto mt =
model_->modelType(CrossAssetModel::AssetType::INF, idx);
286 QL_REQUIRE(mt == CrossAssetModel::ModelType::DK || mt == CrossAssetModel::ModelType::JY,
287 "CrossAssetModelScenarioGenerator: expected inflation model to be JY or DK.");
288 QuantLib::ext::shared_ptr<YoYInflationModelTermStructure> ts;
289 if (mt == CrossAssetModel::ModelType::DK) {
290 ts = QuantLib::ext::make_shared<DkImpliedYoYInflationTermStructure>(
293 ts = QuantLib::ext::make_shared<JyImpliedYoYInflationTermStructure>(
296 QL_REQUIRE(
model_->modelType(CrossAssetModel::AssetType::IR, 0) == CrossAssetModel::ModelType::LGM1F,
297 "Simulation of INF DK or JY model for YoY curves is only supported for LGM1F ir model type.");
301 for (Size j = 0; j <
n_cr_; ++j) {
302 if (
model_->modelType(CrossAssetModel::AssetType::CR, j) == CrossAssetModel::ModelType::LGM1F) {
303 lgmDefaultCurves_.push_back(QuantLib::ext::make_shared<QuantExt::LgmImpliedDefaultTermStructure>(
305 cirppDefaultCurves_.push_back(QuantLib::ext::shared_ptr<QuantExt::CirppImpliedDefaultTermStructure>());
306 }
else if (
model_->modelType(CrossAssetModel::AssetType::CR, j) == CrossAssetModel::ModelType::CIRPP) {
307 lgmDefaultCurves_.push_back(QuantLib::ext::shared_ptr<QuantExt::LgmImpliedDefaultTermStructure>());
309 QuantLib::ext::make_shared<QuantExt::CirppImpliedDefaultTermStructure>(
model_->crcirppModel(j), j));
313 LOG(
"CrossAssetModelScenarioGenerator ctor done");
317void copyPathToArray(
const MultiPath& p, Size t, Size a, Array& target) {
318 for (Size k = 0; k < target.size(); ++k)
319 target[k] = p[a + k][t];
324 std::vector<QuantLib::ext::shared_ptr<Scenario>> scenarios(
dates_.size());
325 QL_REQUIRE(
pathGenerator_ !=
nullptr,
"CrossAssetModelScenarioGenerator::nextPath(): pathGenerator is null");
327 DayCounter dc =
model_->irModel(0)->termStructure()->dayCounter();
329 std::vector<Array> ir_state(
n_ccy_);
330 for (Size j = 0; j <
n_ccy_; ++j)
331 ir_state[j] = Array(
model_->irModel(j)->n());
333 Array ir_state_aux(
model_->irModel(0)->n_aux());
339 std::vector<Size> yieldCurveCcyIdx(
n_curves_);
343 for (Size i = 0; i <
dates_.size(); i++) {
349 copyPathToArray(sample.value, i + 1,
model_->pIdx(CrossAssetModel::AssetType::IR, 0), ir_state[0]);
350 copyPathToArray(sample.value, i + 1,
model_->pIdx(CrossAssetModel::AssetType::IR, 0) + ir_state[0].size(),
352 for (Size j = 1; j <
n_ccy_; ++j)
353 copyPathToArray(sample.value, i + 1,
model_->pIdx(CrossAssetModel::AssetType::IR, j), ir_state[j]);
356 scenarios[i]->setNumeraire(
model_->numeraire(0, t, ir_state[0], Handle<YieldTermStructure>(), ir_state_aux));
359 for (Size j = 0; j <
n_ccy_; j++) {
360 curves_[j]->move(t, ir_state[j]);
361 for (Size k = 0; k <
ten_dsc_[j].size(); k++) {
363 Time T = dc.yearFraction(
dates_[i], d);
364 Real discount = std::max(
curves_[j]->discount(T), 0.00001);
372 for (Size k = 0; k <
ten_idx_[j].size(); ++k) {
374 Time T = dc.yearFraction(
dates_[i], d);
375 Real discount = std::max(
fwdCurves_[j]->discount(T), 0.00001);
383 for (Size k = 0; k <
ten_yc_[j].size(); ++k) {
385 Time T = dc.yearFraction(
dates_[i], d);
386 Real discount = std::max(
yieldCurves_[j]->discount(T), 0.00001);
392 for (Size k = 0; k <
n_ccy_ - 1; k++) {
393 Real fx = std::exp(sample.value[
model_->pIdx(CrossAssetModel::AssetType::FX, k)][i + 1]);
394 scenarios[i]->add(
fxKeys_[k], fx);
403 Size fxIndex =
fxVols_[k]->fxIndex();
404 Real zFor = sample.value[fxIndex + 1][i + 1];
405 Real logFx = sample.value[
n_ccy_ + fxIndex][i + 1];
408 for (Size j = 0; j < expires.size(); j++) {
409 Real vol =
fxVols_[k]->blackVol(
dates_[i] + expires[j], Null<Real>(),
true);
416 for (Size k = 0; k <
n_eq_; k++) {
417 Real eqSpot = std::exp(sample.value[
model_->pIdx(CrossAssetModel::AssetType::EQ, k)][i + 1]);
418 scenarios[i]->add(
eqKeys_[k], eqSpot);
426 const vector<Period>& expiries =
simMarketConfig_->equityVolExpiries(equityName);
428 Size eqIndex =
eqVols_[k]->equityIndex();
429 Size eqCcyIdx =
eqVols_[k]->eqCcyIndex();
430 Real z_eqIr = sample.value[eqCcyIdx][i + 1];
431 Real logEq = sample.value[eqIndex][i + 1];
434 for (Size j = 0; j < expiries.size(); j++) {
435 Real vol =
eqVols_[k]->blackVol(
dates_[i] + expiries[j], Null<Real>(),
true);
442 for (Size j = 0; j <
n_inf_; j++) {
445 Real z = sample.value[
model_->pIdx(CrossAssetModel::AssetType::INF, j, 0)][i + 1];
446 Real y = sample.value[
model_->pIdx(CrossAssetModel::AssetType::INF, j, 1)][i + 1];
450 if (
model_->modelType(CrossAssetModel::AssetType::INF, j) == CrossAssetModel::ModelType::JY) {
451 cpi = std::exp(sample.value[
model_->pIdx(CrossAssetModel::AssetType::INF, j, 1)][i + 1]);
452 }
else if (
model_->modelType(CrossAssetModel::AssetType::INF, j) == CrossAssetModel::ModelType::DK) {
454 Date baseDate = index->zeroInflationTermStructure()->baseDate();
455 auto zts = index->zeroInflationTermStructure();
456 Time relativeTime = inflationYearFraction(zts->frequency(),
false, zts->dayCounter(),
457 baseDate,
dates_[i] - zts->observationLag());
458 std::tie(cpi, std::ignore) =
model_->infdkI(j, relativeTime, relativeTime, z, y);
459 cpi *= index->fixing(baseDate);
461 QL_FAIL(
"CrossAssetModelScenarioGenerator: expected inflation model to be JY or DK.");
464 scenarios[i]->add(
cpiKeys_[j], cpi);
473 auto idx = std::get<0>(tup);
475 state[0] = sample.value[
model_->pIdx(CrossAssetModel::AssetType::INF, idx, 0)][i + 1];
476 state[1] = sample.value[
model_->pIdx(CrossAssetModel::AssetType::INF, idx, 1)][i + 1];
477 if (std::get<2>(tup) == CrossAssetModel::ModelType::DK) {
480 state[2] = ir_state[std::get<1>(tup)][0];
484 auto ts = std::get<3>(tup);
485 ts->move(
dates_[i], state);
488 for (Size k = 0; k <
ten_zinf_[j].size(); k++) {
500 auto idx = std::get<0>(tup);
502 state[0] = sample.value[
model_->pIdx(CrossAssetModel::AssetType::INF, idx, 0)][i + 1];
503 state[1] = sample.value[
model_->pIdx(CrossAssetModel::AssetType::INF, idx, 1)][i + 1];
504 state[2] = ir_state[std::get<1>(tup)][0];
507 auto ts = std::get<3>(tup);
508 ts->move(
dates_[i], state);
512 for (Size k = 0; k < pillarDates.size(); ++k)
516 auto yoyRates = ts->yoyRates(pillarDates);
517 for (Size k = 0; k < pillarDates.size(); ++k) {
523 for (Size j = 0; j <
n_cr_; ++j) {
524 if (
model_->modelType(CrossAssetModel::AssetType::CR, j) == CrossAssetModel::ModelType::LGM1F) {
525 Real z = sample.value[
model_->pIdx(CrossAssetModel::AssetType::CR, j, 0)][i + 1];
526 Real y = sample.value[
model_->pIdx(CrossAssetModel::AssetType::CR, j, 1)][i + 1];
528 for (Size k = 0; k <
ten_dfc_[j].size(); k++) {
530 Time T = dc.yearFraction(
dates_[i], d);
534 }
else if (
model_->modelType(CrossAssetModel::AssetType::CR, j) == CrossAssetModel::ModelType::CIRPP) {
535 Real y = sample.value[
model_->pIdx(CrossAssetModel::AssetType::CR, j, 0)][i + 1];
537 for (Size k = 0; k <
ten_dfc_[j].size(); k++) {
539 Time T = dc.yearFraction(
dates_[i], d);
547 Array comState(1, 0.0);
548 for (Size j = 0; j <
n_com_; j++) {
549 comState[0] = sample.value[
model_->pIdx(CrossAssetModel::AssetType::COM, j)][i + 1];
551 for (Size k = 0; k <
ten_com_[j].size(); k++) {
553 Time T = dc.yearFraction(
dates_[i], d);
554 Real price = std::max(
comCurves_[j]->price(T), 0.00001);
561 Real z = sample.value[
model_->pIdx(CrossAssetModel::AssetType::CrState, k)][i + 1];
QuantLib::ext::shared_ptr< QuantExt::CrossAssetModel > model_
std::vector< std::vector< Period > > ten_yc_
std::vector< QuantLib::ext::shared_ptr< Scenario > > nextPath() override
const std::string configuration_
QuantLib::ext::shared_ptr< ScenarioSimMarketParameters > simMarketConfig_
std::vector< RiskFactorKey > yieldCurveKeys_
std::vector< RiskFactorKey > eqKeys_
vector< Currency > yieldCurveCurrency_
std::vector< RiskFactorKey > commodityCurveKeys_
vector< QuantLib::ext::shared_ptr< QuantExt::ModelImpliedYieldTermStructure > > yieldCurves_
vector< QuantLib::ext::shared_ptr< QuantExt::ModelImpliedYieldTermStructure > > fwdCurves_
std::vector< RiskFactorKey > crStateKeys_
vector< tuple< Size, Size, CrossAssetModel::ModelType, QuantLib::ext::shared_ptr< ZeroInflationModelTermStructure > > > zeroInfCurves_
std::vector< RiskFactorKey > cpiKeys_
std::vector< RiskFactorKey > survivalWeightKeys_
vector< QuantLib::ext::shared_ptr< QuantExt::ModelImpliedPriceTermStructure > > comCurves_
vector< QuantLib::ext::shared_ptr< QuantExt::LgmImpliedDefaultTermStructure > > lgmDefaultCurves_
std::vector< RiskFactorKey > zeroInflationKeys_
std::vector< std::vector< Period > > ten_idx_
std::vector< RiskFactorKey > discountCurveKeys_
std::vector< std::vector< Period > > ten_dfc_
CrossAssetModelScenarioGenerator(QuantLib::ext::shared_ptr< QuantExt::CrossAssetModel > model, QuantLib::ext::shared_ptr< QuantExt::MultiPathGeneratorBase > multiPathGenerator, QuantLib::ext::shared_ptr< ScenarioFactory > scenarioFactory, QuantLib::ext::shared_ptr< ScenarioSimMarketParameters > simMarketConfig, QuantLib::Date today, QuantLib::ext::shared_ptr< DateGrid > grid, QuantLib::ext::shared_ptr< ore::data::Market > initMarket, const std::string &configuration=Market::defaultConfiguration)
Constructor.
std::vector< std::vector< Period > > ten_com_
std::vector< RiskFactorKey > recoveryRateKeys_
std::vector< QuantLib::ext::shared_ptr< QuantExt::CrossAssetModelImpliedEqVolTermStructure > > eqVols_
vector< tuple< Size, Size, CrossAssetModel::ModelType, QuantLib::ext::shared_ptr< YoYInflationModelTermStructure > > > yoyInfCurves_
QuantLib::ext::shared_ptr< QuantExt::MultiPathGeneratorBase > pathGenerator_
vector< QuantLib::ext::shared_ptr< QuantExt::ModelImpliedYieldTermStructure > > curves_
vector< QuantLib::ext::shared_ptr< QuantExt::CirppImpliedDefaultTermStructure > > cirppDefaultCurves_
std::vector< RiskFactorKey > defaultCurveKeys_
std::vector< std::vector< Period > > ten_zinf_
vector< QuantLib::ext::shared_ptr< QuantExt::CreditCurve > > survivalWeightsDefaultCurves_
std::vector< QuantLib::ext::shared_ptr< QuantExt::CrossAssetModelImpliedFxVolTermStructure > > fxVols_
std::vector< std::vector< Period > > ten_dsc_
QuantLib::ext::shared_ptr< ore::data::Market > initMarket_
std::vector< std::vector< Period > > ten_yinf_
std::vector< RiskFactorKey > fxKeys_
QuantLib::ext::shared_ptr< ScenarioFactory > scenarioFactory_
vector< QuantLib::ext::shared_ptr< IborIndex > > indices_
std::vector< RiskFactorKey > yoyInflationKeys_
std::vector< RiskFactorKey > indexCurveKeys_
Data types stored in the scenario class.
Scenario generator that generates an entire path.
const QuantLib::ext::shared_ptr< ModelCG > model_
Scenario generation using cross asset model paths.
Currency parseCurrency(const string &s)
Size size(const ValueType &v)