329
330 LOG(
"building ScenarioSimMarket...");
331 asof_ = initMarket->asofDate();
332 DLOG(
"AsOf " << QuantLib::io::iso_date(
asof_));
333
334
336 "ScenarioSimMarket: Interpolation (" <<
parameters_->interpolation()
337 << ") must be set to 'LogLinear' or 'LinearZero'");
339 "ScenarioSimMarket: YieldCurves / Extrapolation ('" <<
parameters_->extrapolation()
340 << "') must be set to 'FlatZero' or 'FlatFwd'");
341 QL_REQUIRE(
parameters_->defaultCurveExtrapolation() ==
"FlatZero" ||
342 parameters_->defaultCurveExtrapolation() ==
"FlatFwd",
343 "ScenarioSimMarket: DefaultCurves / Extrapolation ('" <<
parameters_->extrapolation()
344 << "') must be set to 'FlatZero' or 'FlatFwd'");
345
346 for (const auto& param : parameters->parameters()) {
347 try {
348
349
350 std::map<RiskFactorKey, QuantLib::ext::shared_ptr<SimpleQuote>> simDataTmp;
351 std::map<RiskFactorKey, Real> absoluteSimDataTmp;
352
353 boost::timer::cpu_timer timer;
354
355 switch (param.first) {
357 std::map<std::string, Handle<Quote>> fxQuotes;
358 for (const auto& name : param.second.second) {
359 bool simDataWritten = false;
360 try {
361
362 DLOG(
"adding " << name <<
" FX rates");
363 Real v = initMarket->fxSpot(name, configuration)->value();
366 auto m = [v](Real x) { return x * v; };
367 fxQuotes[
name] = Handle<Quote>(
368 QuantLib::ext::make_shared<DerivedQuote<decltype(m)>>(Handle<Quote>(q), m));
369 } else {
370 fxQuotes[
name] = Handle<Quote>(q);
371 }
372
373 if (param.second.first) {
374 simDataTmp.emplace(std::piecewise_construct, std::forward_as_tuple(param.first, name),
375 std::forward_as_tuple(q));
377 absoluteSimDataTmp.emplace(std::piecewise_construct,
378 std::forward_as_tuple(param.first, name),
379 std::forward_as_tuple(v));
380 }
381 }
382 writeSimData(simDataTmp, absoluteSimDataTmp, param.first, name, {});
383 simDataWritten = true;
384 } catch (const std::exception& e) {
385 processException(continueOnError, e, name, param.first, simDataWritten);
386 }
387 }
388 fx_ = QuantLib::ext::make_shared<FXTriangulation>(fxQuotes);
389 break;
390 }
391
394 for (const auto& name : param.second.second) {
395 bool simDataWritten = false;
396 try {
397 DLOG(
"building " << name <<
" yield curve..");
398 vector<Period> tenors = parameters->yieldCurveTenors(name);
399 addYieldCurve(initMarket, configuration, param.first, name, tenors, simDataWritten,
401 DLOG(
"building " << name <<
" yield curve done");
402 } catch (const std::exception& e) {
403 processException(continueOnError, e, name, param.first, simDataWritten);
404 }
405 }
406 break;
407
409
410
411 std::vector<std::string> indices;
412 for (auto const& i : param.second.second) {
413 bool isOn = false;
414 try {
415 isOn = QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(*initMarket->iborIndex(i, configuration)) !=
416 nullptr;
417 } catch (...) {
418 }
419 if (isOn)
420 indices.insert(indices.begin(), i);
421 else
422 indices.push_back(i);
423 }
424
425 for (const auto& name : indices) {
426 bool simDataWritten = false;
427 try {
428 DLOG(
"building " << name <<
" index curve");
429 std::vector<string> indexTokens;
430 split(indexTokens, name, boost::is_any_of("-"));
431 Handle<IborIndex> index;
432 if (indexTokens[1] == "GENERIC") {
433
434
435 index = Handle<IborIndex>(
436 parseIborIndex(name, initMarket->discountCurve(indexTokens[0], configuration)));
437 } else {
438 index = initMarket->iborIndex(name, configuration);
439 }
440 QL_REQUIRE(!index.empty(), "index object for " << name << " not provided");
441 Handle<YieldTermStructure> wrapperIndex = index->forwardingTermStructure();
442 QL_REQUIRE(!wrapperIndex.empty(), "no termstructure for index " << name);
443 vector<string> keys(parameters->yieldCurveTenors(name).size());
444
445 DayCounter dc = wrapperIndex->dayCounter();
446 vector<Time> yieldCurveTimes(1, 0.0);
447 vector<Date> yieldCurveDates(1,
asof_);
448 QL_REQUIRE(parameters->yieldCurveTenors(name).front() > 0 * Days,
449 "yield curve tenors must not include t=0");
450 for (auto& tenor : parameters->yieldCurveTenors(name)) {
451 yieldCurveTimes.push_back(dc.yearFraction(
asof_,
asof_ + tenor));
452 yieldCurveDates.push_back(
asof_ + tenor);
453 }
454
455
456 vector<Handle<Quote>> quotes;
457 QuantLib::ext::shared_ptr<SimpleQuote> q(new SimpleQuote(1.0));
458 quotes.push_back(Handle<Quote>(q));
459
460 for (Size i = 0; i < yieldCurveTimes.size() - 1; i++) {
461 Real val = wrapperIndex->discount(yieldCurveDates[i + 1]);
463 Handle<Quote> qh(q);
464 quotes.push_back(qh);
465
466 simDataTmp.emplace(std::piecewise_construct, std::forward_as_tuple(param.first, name, i),
467 std::forward_as_tuple(q));
469 absoluteSimDataTmp.emplace(std::piecewise_construct,
470 std::forward_as_tuple(param.first, name, i),
471 std::forward_as_tuple(val));
472 }
473
474 DLOG(
"ScenarioSimMarket index curve " << name <<
" discount[" << i <<
"]=" << val);
475 }
476
477 writeSimData(simDataTmp, absoluteSimDataTmp, param.first, name,
478 {std::vector<Real>(std::next(yieldCurveTimes.begin(), 1), yieldCurveTimes.end())});
479 simDataWritten = true;
480
481 QuantLib::ext::shared_ptr<YieldTermStructure> indexCurve = makeYieldCurve(
484
485 Handle<YieldTermStructure> ich(indexCurve);
486 if (wrapperIndex->allowsExtrapolation())
487 ich->enableExtrapolation();
488
489 QuantLib::ext::shared_ptr<IborIndex> i = index->clone(ich);
491
495 "Could not build ibor fallback index '"
496 << name << "', because rfr index '" << fallbackData.rfrIndex
497 << "' is not present in scenario sim market, is the rfr index in the "
498 "scenario sim market parameters?");
499 auto rfrInd = QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(*f->second);
500 QL_REQUIRE(rfrInd != nullptr,
501 "Could not cast '"
502 << fallbackData.rfrIndex
503 << "' to overnight index when building the ibor fallback index '" << name
504 << "'");
505 if (auto original = QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(i))
506 i = QuantLib::ext::make_shared<QuantExt::FallbackOvernightIndex>(
507 original, rfrInd, fallbackData.spread, fallbackData.switchDate,
509 else
510 i = QuantLib::ext::make_shared<QuantExt::FallbackIborIndex>(
511 i, rfrInd, fallbackData.spread, fallbackData.switchDate,
513 DLOG(
"built ibor fall back index '"
514 << name << "' with rfr index '" << fallbackData.rfrIndex << "', spread "
515 << fallbackData.spread << ", use rfr curve in scen sim market: " << std::boolalpha
517 }
520 DLOG(
"building " << name <<
" index curve done");
521 } catch (const std::exception& e) {
522 processException(continueOnError, e, name, param.first, simDataWritten);
523 }
524 }
525 break;
526 }
527
529 for (const auto& name : param.second.second) {
530 bool simDataWritten = false;
531 try {
532
533 DLOG(
"adding " << name <<
" equity spot...");
534 Real spotVal = initMarket->equitySpot(name, configuration)->value();
537 auto m = [spotVal](Real x) { return x * spotVal; };
540 Handle<Quote>(QuantLib::ext::make_shared<DerivedQuote<decltype(m)>>(
541 Handle<Quote>(q), m))));
542 } else {
545 }
546 simDataTmp.emplace(std::piecewise_construct, std::forward_as_tuple(param.first, name),
547 std::forward_as_tuple(q));
549 absoluteSimDataTmp.emplace(std::piecewise_construct,
550 std::forward_as_tuple(param.first, name),
551 std::forward_as_tuple(spotVal));
552 }
553 writeSimData(simDataTmp, absoluteSimDataTmp, param.first, name, {});
554 simDataWritten = true;
555 DLOG(
"adding " << name <<
" equity spot done");
556 } catch (const std::exception& e) {
557 processException(continueOnError, e, name, param.first, simDataWritten);
558 }
559 }
560 break;
561
563 for (const auto& name : param.second.second) {
564 bool simDataWritten = false;
565 try {
566 DLOG(
"building " << name <<
" equity dividend yield curve..");
567 vector<Period> tenors = parameters->equityDividendTenors(name);
568 addYieldCurve(initMarket, configuration, param.first, name, tenors, simDataWritten,
570 DLOG(
"building " << name <<
" equity dividend yield curve done");
571
572
573
574 string forecastCurve;
576
577 auto eqVolConfig =
curveConfigs.equityCurveConfig(name);
578 string forecastName = eqVolConfig->forecastingCurve();
579 string eqCcy = eqVolConfig->currency();
580
582 forecastCurve = ycspec.name();
583 TLOG(
"Got forecast curve '" << forecastCurve <<
"' from equity curve config for " << name);
584 }
585
586
587 Handle<YieldTermStructure> forecastTs =
589 Handle<EquityIndex2> curve = initMarket->equityCurve(name, configuration);
590
591
592
593 if (forecastTs.empty()) {
594 string ccy = curve->currency().code();
595 TLOG(
"Falling back on the discount curve for currency '"
596 << ccy << "' for equity forecast curve '" << name << "'");
598 }
599 QuantLib::ext::shared_ptr<EquityIndex2> ei(
600 curve->clone(
equitySpot(name, configuration), forecastTs,
601 yieldCurve(YieldCurveType::EquityDividend, name, configuration)));
602 Handle<EquityIndex2> eh(ei);
604 } catch (const std::exception& e) {
605 processException(continueOnError, e, name, param.first, simDataWritten);
606 }
607 }
608 break;
609
611 for (const auto& name : param.second.second) {
612
613 try {
614 DLOG(
"Adding security spread " << name <<
" from configuration " << configuration);
615 Real v = initMarket->securitySpread(name, configuration)->value();
618 auto m = [v](Real x) { return x + v; };
621 Handle<Quote>(QuantLib::ext::make_shared<DerivedQuote<decltype(m)>>(
622 Handle<Quote>(q), m))));
623 } else {
626 }
627 if (param.second.first) {
628 simDataTmp.emplace(std::piecewise_construct, std::forward_as_tuple(param.first, name),
629 std::forward_as_tuple(q));
631 absoluteSimDataTmp.emplace(std::piecewise_construct,
632 std::forward_as_tuple(param.first, name),
633 std::forward_as_tuple(v));
634 }
635 }
636 writeSimData(simDataTmp, absoluteSimDataTmp, param.first, name, {});
637
638 } catch (const std::exception& e) {
639 DLOG(
"skipping this object: " << e.what());
640 }
641
642 try {
643 DLOG(
"Adding security recovery rate " << name <<
" from configuration " << configuration);
644 Real v = initMarket->recoveryRate(name, configuration)->value();
647 auto m = [v](Real x) { return x * v; };
650 Handle<Quote>(QuantLib::ext::make_shared<DerivedQuote<decltype(m)>>(
651 Handle<Quote>(q), m))));
652 } else {
655 }
656
657
658
659 if (parameters->simulateRecoveryRates()) {
660 simDataTmp.emplace(std::piecewise_construct,
662 std::forward_as_tuple(q));
664 absoluteSimDataTmp.emplace(std::piecewise_construct,
665 std::forward_as_tuple(param.first, name),
666 std::forward_as_tuple(v));
667 }
668 }
670 } catch (const std::exception& e) {
671 DLOG(
"skipping this object: " << e.what());
672 }
673 }
674 break;
675
678 for (const auto& name : param.second.second) {
679 bool simDataWritten = false;
680 try {
681
682 RelinkableHandle<SwaptionVolatilityStructure> wrapper;
683 vector<Period> optionTenors, underlyingTenors;
684 vector<Real> strikeSpreads;
686 bool isCube, isAtm, simulateAtmOnly;
688 DLOG(
"building " << name <<
" swaption volatility curve...");
689 wrapper.linkTo(*initMarket->swaptionVol(name, configuration));
691 swapIndexBase = initMarket->swapIndexBase(name, configuration);
692 isCube = parameters->swapVolIsCube(name);
693 optionTenors = parameters->swapVolExpiries(name);
694 underlyingTenors = parameters->swapVolTerms(name);
695 strikeSpreads = parameters->swapVolStrikeSpreads(name);
696 simulateAtmOnly = parameters->simulateSwapVolATMOnly();
697 } else {
698 DLOG(
"building " << name <<
" yield volatility curve...");
699 wrapper.linkTo(*initMarket->yieldVol(name, configuration));
700 isCube = false;
701 optionTenors = parameters->yieldVolExpiries();
702 underlyingTenors = parameters->yieldVolTerms();
703 strikeSpreads = {0.0};
704 simulateAtmOnly = true;
705 }
706 DLOG(
"Initial market " << name <<
" yield volatility type = " << wrapper->volatilityType());
707
708
709 isAtm = QuantLib::ext::dynamic_pointer_cast<SwaptionVolatilityMatrix>(*wrapper) != nullptr ||
710 QuantLib::ext::dynamic_pointer_cast<ConstantSwaptionVolatility>(*wrapper) != nullptr;
711
712 Handle<SwaptionVolatilityStructure> svp;
713 if (param.second.first) {
714 LOG(
"Simulating yield vols for ccy " << name);
715 DLOG(
"YieldVol T0 source is atm : " << (isAtm ?
"True" :
"False"));
716 DLOG(
"YieldVol ssm target is cube : " << (isCube ?
"True" :
"False"));
717 DLOG(
"YieldVol simulate atm only : " << (simulateAtmOnly ?
"True" :
"False"));
718 if (simulateAtmOnly) {
719 QL_REQUIRE(strikeSpreads.size() == 1 &&
close_enough(strikeSpreads[0], 0),
720 "for atmOnly strikeSpreads must be {0.0}");
721 }
722 QuantLib::ext::shared_ptr<QuantLib::SwaptionVolatilityCube> cube;
723 if (isCube && !isAtm) {
724 QuantLib::ext::shared_ptr<SwaptionVolCubeWithATM> tmp =
725 QuantLib::ext::dynamic_pointer_cast<SwaptionVolCubeWithATM>(*wrapper);
726 QL_REQUIRE(tmp, "swaption cube missing");
727 cube = tmp->cube();
728 }
729 vector<vector<Handle<Quote>>> quotes, atmQuotes;
730 quotes.resize(optionTenors.size() * underlyingTenors.size(),
731 vector<Handle<Quote>>(strikeSpreads.size(), Handle<Quote>()));
732 atmQuotes.resize(optionTenors.size(),
733 std::vector<Handle<Quote>>(underlyingTenors.size(), Handle<Quote>()));
734 vector<vector<Real>> shift(optionTenors.size(), vector<Real>(underlyingTenors.size(), 0.0));
735 Size atmSlice = std::find_if(strikeSpreads.begin(), strikeSpreads.end(),
736 [](const Real s) { return close_enough(s, 0.0); }) -
737 strikeSpreads.begin();
738 QL_REQUIRE(atmSlice < strikeSpreads.size(),
739 "could not find atm slice (strikeSpreads do not contain 0.0)");
740
741
742
743
744
745
746
747
748
749 bool convertToNormal = wrapper->volatilityType() != Normal &&
752 DLOG(
"T0 ts is normal : " << (wrapper->volatilityType() == Normal ?
"True"
753 : "False"));
754 DLOG(
"Have swaption vol : "
756 DLOG(
"Will convert to normal vol : " << (convertToNormal ?
"True" :
"False"));
757
758
760 if (convertToNormal) {
762 Handle<SwapIndex> shortSwapIndex =
765 *shortSwapIndex, Normal);
766 }
767
768 for (Size k = 0; k < strikeSpreads.size(); ++k) {
769 for (Size i = 0; i < optionTenors.size(); ++i) {
770 for (Size j = 0; j < underlyingTenors.size(); ++j) {
771 Real strike = Null<Real>();
772 if (!simulateAtmOnly && cube)
773 strike = cube->atmStrike(optionTenors[i], underlyingTenors[j]) +
774 strikeSpreads[k];
775 Real vol;
776 if (convertToNormal) {
777
778
779 vol = converter->
convert(wrapper->optionDateFromTenor(optionTenors[i]),
780 underlyingTenors[j], strikeSpreads[k],
781 wrapper->dayCounter(), Normal);
782 } else {
783 vol =
784 wrapper->volatility(optionTenors[i], underlyingTenors[j], strike, true);
785 }
786 QuantLib::ext::shared_ptr<SimpleQuote> q(
788
789 Size index = i * underlyingTenors.size() * strikeSpreads.size() +
790 j * strikeSpreads.size() + k;
791
792 simDataTmp.emplace(std::piecewise_construct,
793 std::forward_as_tuple(param.first, name, index),
794 std::forward_as_tuple(q));
796 absoluteSimDataTmp.emplace(std::piecewise_construct,
797 std::forward_as_tuple(param.first, name, index),
798 std::forward_as_tuple(vol));
799 }
800 auto tmp = Handle<Quote>(q);
801 quotes[i * underlyingTenors.size() + j][k] = tmp;
802 if (k == atmSlice) {
803 atmQuotes[i][j] = tmp;
804 shift[i][j] =
805 !convertToNormal && wrapper->volatilityType() == ShiftedLognormal
806 ? wrapper->shift(optionTenors[i], underlyingTenors[j])
807 : 0.0;
808 DLOG(
"AtmVol at " << optionTenors.at(i) <<
"/" << underlyingTenors.at(j)
809 << " is " << vol << ", shift is " << shift[i][j]
810 << ", (name,index) = (" << name << "," << index << ")");
811 } else {
812 DLOG(
"SmileVol at " << optionTenors.at(i) <<
"/" << underlyingTenors.at(j)
813 << "/" << strikeSpreads.at(k) << " is " << vol
814 << ", (name,index) = (" << name << "," << index << ")");
815 }
816 }
817 }
818 }
819
820 std::vector<std::vector<Real>> coordinates(3);
821 for (Size i = 0; i < optionTenors.size(); ++i) {
822 coordinates[0].push_back(
823 wrapper->timeFromReference(wrapper->optionDateFromTenor(optionTenors[i])));
824 }
825 for (Size j = 0; j < underlyingTenors.size(); ++j) {
826 coordinates[1].push_back(wrapper->swapLength(underlyingTenors[j]));
827 }
828 for (Size k = 0; k < strikeSpreads.size(); ++k) {
829 coordinates[2].push_back(strikeSpreads[k]);
830 }
831
832 writeSimData(simDataTmp, absoluteSimDataTmp, param.first, name, coordinates);
833 simDataWritten = true;
834 bool flatExtrapolation = true;
835 VolatilityType volType = convertToNormal ? Normal : wrapper->volatilityType();
836 DayCounter dc = wrapper->dayCounter();
837
839 bool stickyStrike =
parameters_->swapVolSmileDynamics(name) ==
"StickyStrike";
840 QuantLib::ext::shared_ptr<SwapIndex>
swapIndex, shortSwapIndex;
841 QuantLib::ext::shared_ptr<SwapIndex> simSwapIndex, simShortSwapIndex;
842 if (!stickyStrike) {
845 }
847 simShortSwapIndex = *this->
swapIndex(shortSwapIndexBase, configuration);
848 }
849 if (simSwapIndex == nullptr || simShortSwapIndex == nullptr)
850 stickyStrike = true;
851 }
856 svp =
857 Handle<SwaptionVolatilityStructure>(QuantLib::ext::make_shared<SpreadedSwaptionVolatility>(
858 wrapper, optionTenors, underlyingTenors, strikeSpreads, quotes,
swapIndex,
859 shortSwapIndex, simSwapIndex, simShortSwapIndex, !stickyStrike));
860 } else {
861 Handle<SwaptionVolatilityStructure> atm;
862 atm = Handle<SwaptionVolatilityStructure>(QuantLib::ext::make_shared<SwaptionVolatilityMatrix>(
863 wrapper->calendar(), wrapper->businessDayConvention(), optionTenors,
864 underlyingTenors, atmQuotes, dc, flatExtrapolation, volType, shift));
865 atm->enableExtrapolation();
866 if (simulateAtmOnly) {
867 if (isAtm) {
868 svp = atm;
869 } else {
870
871
872
873
874
875
876 svp = Handle<SwaptionVolatilityStructure>(
877 QuantLib::ext::make_shared<SwaptionVolatilityConstantSpread>(atm, wrapper));
878 }
879 } else {
880 if (isCube) {
882 atm, optionTenors, underlyingTenors, strikeSpreads, quotes,
885 flatExtrapolation, false));
886 tmp->setAdjustReferenceDate(false);
887 svp = Handle<SwaptionVolatilityStructure>(
888 QuantLib::ext::make_shared<SwaptionVolCubeWithATM>(tmp));
889 } else {
890 svp = atm;
891 }
892 }
893 }
894 } else {
895 string decayModeString = parameters->swapVolDecayMode();
897 DLOG(
"Dynamic (" << wrapper->volatilityType() <<
") yield vols (" << decayModeString
898 << ") for qualifier " << name);
899
900 QL_REQUIRE(!QuantLib::ext::dynamic_pointer_cast<ProxySwaptionVolatility>(*wrapper),
901 "DynamicSwaptionVolatilityMatrix does not support ProxySwaptionVolatility surface");
902
903 QuantLib::ext::shared_ptr<SwaptionVolatilityStructure> atmSlice;
904 if (isAtm)
905 atmSlice = *wrapper;
906 else {
907 auto c = QuantLib::ext::dynamic_pointer_cast<SwaptionVolCubeWithATM>(*wrapper);
908 QL_REQUIRE(c, "internal error - expected swaption cube to be SwaptionVolCubeWithATM.");
909 atmSlice = *c->cube()->atmVol();
910 }
911
912 if (isCube)
913 WLOG(
"Only ATM slice is considered from init market's cube");
914 QuantLib::ext::shared_ptr<QuantLib::SwaptionVolatilityStructure> svolp =
915 QuantLib::ext::make_shared<QuantExt::DynamicSwaptionVolatilityMatrix>(
916 atmSlice, 0, NullCalendar(), decayMode);
917 svp = Handle<SwaptionVolatilityStructure>(svolp);
918 }
919 svp->setAdjustReferenceDate(false);
920 svp->enableExtrapolation();
921
922 DLOG(
"Simulation market " << name <<
" yield volatility type = " << svp->volatilityType());
923
930 } else {
932 }
933 } catch (const std::exception& e) {
934 processException(continueOnError, e, name, param.first, simDataWritten);
935 }
936 }
937 break;
938
940 for (const auto& name : param.second.second) {
941 bool simDataWritten = false;
942 try {
943 LOG(
"building " << name <<
" cap/floor volatility curve...");
944 Handle<OptionletVolatilityStructure> wrapper = initMarket->capFloorVol(name, configuration);
945 auto [iborIndexName, rateComputationPeriod] =
946 initMarket->capFloorVolIndexBase(name, configuration);
947 QuantLib::ext::shared_ptr<IborIndex>
iborIndex =
949
950 LOG(
"Initial market cap/floor volatility type = " << wrapper->volatilityType());
951
952 Handle<OptionletVolatilityStructure> hCapletVol;
953
954
955 if (param.second.first) {
956 LOG(
"Simulating Cap/Floor Optionlet vols for key " << name);
957
958
959
960 Natural settleDays = 0;
961 bool isOis = false;
962 Calendar iborCalendar;
963 Size onSettlementDays = 0;
964
965
966 QuantLib::ext::shared_ptr<CapFloorVolatilityCurveConfig> config;
969 } else {
972 }
973 }
974
975
976 if (config) {
977 settleDays = config->settleDays();
978 onSettlementDays = config->onCapSettlementDays();
979 }
980
981
983 iborCalendar =
iborIndex->fixingCalendar();
984 isOis = QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(
iborIndex) !=
nullptr;
985 }
986
987 vector<Period> optionTenors = parameters->capFloorVolExpiries(name);
988 vector<Date> optionDates(optionTenors.size());
989
990 vector<Real>
strikes = parameters->capFloorVolStrikes(name);
991 bool isAtm = false;
992
994 QL_REQUIRE(
995 parameters->capFloorVolIsAtm(name),
996 "Strikes for "
997 << name
998 << " is empty in simulation parameters so expected its ATM flag to be true");
1000 isAtm = true;
1001 }
1002
1003 vector<vector<Handle<Quote>>> quotes(
1004 optionTenors.size(), vector<Handle<Quote>>(
strikes.size(), Handle<Quote>()));
1005
1006 DLOG(
"cap floor use adjusted option pillars = " << std::boolalpha <<
parameters_->capFloorVolAdjustOptionletPillars());
1007 DLOG(
"have ibor index = " << std::boolalpha << (
iborIndex !=
nullptr));
1008
1009 Rate atmStrike = Null<Rate>();
1010 for (Size i = 0; i < optionTenors.size(); ++i) {
1011
1013
1014
1015
1016 if(isOis) {
1017 Leg capFloor =
1019 CapFloor::Cap, optionTenors[i],
1020 QuantLib::ext::dynamic_pointer_cast<QuantLib::OvernightIndex>(
iborIndex),
1021 rateComputationPeriod, 0.0)
1024 if (capFloor.empty()) {
1025 optionDates[i] =
asof_ + 1;
1026 } else {
1027 auto lastCoupon = QuantLib::ext::dynamic_pointer_cast<
1029 QL_REQUIRE(lastCoupon, "SSM internal error, could not cast to "
1030 "CappedFlooredOvernightIndexedCoupon "
1031 "when building optionlet vol for '"
1032 << name <<
"' (index=" <<
iborIndex->name()
1033 << ")");
1034 optionDates[i] =
1035 std::max(
asof_ + 1, lastCoupon->underlying()->fixingDates().front());
1036 }
1037 } else {
1038 QuantLib::ext::shared_ptr<CapFloor> capFloor =
1039 MakeCapFloor(CapFloor::Cap, optionTenors[i],
iborIndex, 0.0, 0 * Days);
1040 if (capFloor->floatingLeg().empty()) {
1041 optionDates[i] =
asof_ + 1;
1042 } else {
1043 optionDates[i] =
1044 std::max(
asof_ + 1, capFloor->lastFloatingRateCoupon()->fixingDate());
1045 }
1046 }
1047 QL_REQUIRE(i == 0 || optionDates[i] > optionDates[i - 1],
1048 "SSM: got non-increasing option dates "
1049 << optionDates[i - 1] << ", " << optionDates[i] << " for tenors "
1050 << optionTenors[i - 1] << ", " << optionTenors[i] << " for index "
1052 } else {
1053
1054 optionDates[i] = wrapper->optionDateFromTenor(optionTenors[i]);
1055 if (iborCalendar != Calendar()) {
1056
1057 optionDates[i] = iborCalendar.adjust(optionDates[i]);
1058 }
1059 }
1060
1061 DLOG(
"Option [tenor, date] pair is [" << optionTenors[i] <<
", "
1062 << io::iso_date(optionDates[i]) << "]");
1063
1064
1065 if (isAtm) {
1067 "SSM: Expected ibor index for key "
1068 << name << " from the key or a curve config for a ccy");
1069 auto t0_iborIndex = *initMarket->iborIndex(
1070 IndexNameTranslator::instance().oreName(
iborIndex->name()), configuration);
1072 QL_REQUIRE(!isOis, "SSM: capFloorVolUseCapATM not supported for OIS indices ("
1073 << t0_iborIndex->name() << ")");
1074 QuantLib::ext::shared_ptr<CapFloor> cap =
1075 MakeCapFloor(CapFloor::Cap, optionTenors[i], t0_iborIndex, 0.0, 0 * Days);
1076 atmStrike = cap->atmRate(**initMarket->discountCurve(name, configuration));
1077 } else {
1078 if (isOis) {
1079 Leg capFloor =
1081 QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(t0_iborIndex),
1082 rateComputationPeriod, 0.0)
1085 if (capFloor.empty()) {
1086 atmStrike = t0_iborIndex->fixing(optionDates[i]);
1087 } else {
1088 auto lastCoupon =
1089 QuantLib::ext::dynamic_pointer_cast<CappedFlooredOvernightIndexedCoupon>(
1090 capFloor.back());
1091 QL_REQUIRE(lastCoupon, "SSM internal error, could not cast to "
1092 "CappedFlooredOvernightIndexedCoupon "
1093 "when building optionlet vol for '"
1094 << name << "', index=" << t0_iborIndex->name());
1095 atmStrike = lastCoupon->underlying()->rate();
1096 }
1097 } else {
1098 atmStrike = t0_iborIndex->fixing(optionDates[i]);
1099 }
1100 }
1101 }
1102
1103 for (Size j = 0; j <
strikes.size(); ++j) {
1104 Real strike = isAtm ? atmStrike :
strikes[j];
1105 Real vol =
1106 wrapper->volatility(optionDates[i], strike, true);
1107 DLOG(
"Vol at [date, strike] pair [" << optionDates[i] <<
", " << std::fixed
1108 << std::setprecision(4) << strike << "] is "
1109 << std::setprecision(12) << vol);
1110 QuantLib::ext::shared_ptr<SimpleQuote> q =
1112 Size index = i *
strikes.size() + j;
1113 simDataTmp.emplace(std::piecewise_construct,
1114 std::forward_as_tuple(param.first, name, index),
1115 std::forward_as_tuple(q));
1117 absoluteSimDataTmp.emplace(std::piecewise_construct,
1118 std::forward_as_tuple(param.first, name, index),
1119 std::forward_as_tuple(vol));
1120 }
1121 quotes[i][j] = Handle<Quote>(q);
1122 }
1123 }
1124
1125 std::vector<std::vector<Real>> coordinates(2);
1126 for(Size i=0;i<optionTenors.size();++i) {
1127 coordinates[0].push_back(
1128 wrapper->timeFromReference(wrapper->optionDateFromTenor(optionTenors[i])));
1129 }
1130 for(Size j=0;j<
strikes.size();++j) {
1131 coordinates[1].push_back(isAtm ? atmStrike : strikes[j]);
1132 }
1133
1134 writeSimData(simDataTmp, absoluteSimDataTmp, param.first, name, coordinates);
1135 simDataWritten = true;
1136
1137 DayCounter dc = wrapper->dayCounter();
1138
1140 hCapletVol = Handle<OptionletVolatilityStructure>(
1141 QuantLib::ext::make_shared<QuantExt::SpreadedOptionletVolatility2>(wrapper, optionDates,
1142 strikes, quotes));
1143 } else {
1144
1145
1146 QuantLib::ext::shared_ptr<StrippedOptionlet> optionlet = QuantLib::ext::make_shared<StrippedOptionlet>(
1147 settleDays, wrapper->calendar(), wrapper->businessDayConvention(),
iborIndex,
1148 optionDates, strikes, quotes, dc, wrapper->volatilityType(),
1149 wrapper->displacement());
1150
1151 hCapletVol = Handle<OptionletVolatilityStructure>(
1153 optionlet));
1154 }
1155 } else {
1156 string decayModeString = parameters->capFloorVolDecayMode();
1158
1159 QL_REQUIRE(!QuantLib::ext::dynamic_pointer_cast<ProxyOptionletVolatility>(*wrapper),
1160 "DynamicOptionletVolatilityStructure does not support ProxyOptionletVolatility surface.");
1161
1162 QuantLib::ext::shared_ptr<OptionletVolatilityStructure> capletVol =
1163 QuantLib::ext::make_shared<DynamicOptionletVolatilityStructure>(*wrapper, 0, NullCalendar(),
1164 decayMode);
1165 hCapletVol = Handle<OptionletVolatilityStructure>(capletVol);
1166 }
1167 hCapletVol->setAdjustReferenceDate(false);
1168 hCapletVol->enableExtrapolation();
1171 std::forward_as_tuple(hCapletVol));
1174 std::forward_as_tuple(std::make_pair(iborIndexName, rateComputationPeriod)));
1175
1176 LOG(
"Simulation market cap/floor volatility type = " << hCapletVol->volatilityType());
1177 } catch (const std::exception& e) {
1178 processException(continueOnError, e, name, param.first, simDataWritten);
1179 }
1180 }
1181 break;
1182
1184 for (const auto& name : param.second.second) {
1185 bool simDataWritten = false;
1186 try {
1187 LOG(
"building " << name <<
" default curve..");
1188 auto wrapper = initMarket->defaultCurve(name, configuration);
1189 vector<Handle<Quote>> quotes;
1190
1191 QL_REQUIRE(parameters->defaultTenors(name).front() > 0 * Days,
1192 "default curve tenors must not include t=0");
1193
1194 vector<Date> dates(1,
asof_);
1195 vector<Real> times(1, 0.0);
1196
1197 DayCounter dc = wrapper->curve()->dayCounter();
1198
1199 for (Size i = 0; i < parameters->defaultTenors(name).
size(); i++) {
1200 dates.push_back(
asof_ + parameters->defaultTenors(name)[i]);
1201 times.push_back(dc.yearFraction(
asof_, dates.back()));
1202 }
1203
1204 QuantLib::ext::shared_ptr<SimpleQuote> q(new SimpleQuote(1.0));
1205 quotes.push_back(Handle<Quote>(q));
1206 for (Size i = 0; i < dates.size() - 1; i++) {
1207 Probability prob = wrapper->curve()->survivalProbability(dates[i + 1], true);
1208 QuantLib::ext::shared_ptr<SimpleQuote> q =
1210
1211 if (param.second.first) {
1212 simDataTmp.emplace(std::piecewise_construct,
1213 std::forward_as_tuple(param.first, name, i),
1214 std::forward_as_tuple(q));
1215 DLOG(
"ScenarioSimMarket default curve " << name <<
" survival[" << i <<
"]=" << prob);
1217 absoluteSimDataTmp.emplace(std::piecewise_construct,
1218 std::forward_as_tuple(param.first, name, i),
1219 std::forward_as_tuple(prob));
1220 }
1221 }
1222 Handle<Quote> qh(q);
1223 quotes.push_back(qh);
1224 }
1225 writeSimData(simDataTmp, absoluteSimDataTmp, param.first, name,
1226 {std::vector<Real>(std::next(times.begin(), 1), times.end())});
1227 simDataWritten = true;
1231 defaultCurve = Handle<DefaultProbabilityTermStructure>(
1232 QuantLib::ext::make_shared<QuantExt::SpreadedSurvivalProbabilityTermStructure>(
1233 wrapper->curve(), times, quotes,
1234 parameters->defaultCurveExtrapolation() == "FlatZero"
1235 ? QuantExt::SpreadedSurvivalProbabilityTermStructure::Extrapolation::flatZero
1236 : QuantExt::SpreadedSurvivalProbabilityTermStructure::Extrapolation::flatFwd));
1237 } else {
1238 defaultCurve = Handle<DefaultProbabilityTermStructure>(
1240 dates, quotes, dc, cal, std::vector<Handle<Quote>>(), std::vector<Date>(),
1241 LogLinear(),
1242 parameters->defaultCurveExtrapolation() == "FlatZero"
1245 }
1250 Handle<CreditCurve>(QuantLib::ext::make_shared<CreditCurve>(
1251 defaultCurve, wrapper->rateCurve(), wrapper->recovery(), wrapper->refData()))));
1252 } catch (const std::exception& e) {
1253 processException(continueOnError, e, name, param.first, simDataWritten);
1254 }
1255 }
1256 break;
1257
1259 for (const auto& name : param.second.second) {
1260 bool simDataWritten = false;
1261 try {
1262 DLOG(
"Adding security recovery rate " << name <<
" from configuration " << configuration);
1263 Real v = initMarket->recoveryRate(name, configuration)->value();
1266 auto m = [v](Real x) { return x * v; };
1269 Handle<Quote>(QuantLib::ext::make_shared<DerivedQuote<decltype(m)>>(
1270 Handle<Quote>(q), m))));
1271 } else {
1274 }
1275
1276 if (param.second.first) {
1277 simDataTmp.emplace(std::piecewise_construct,
1279 std::forward_as_tuple(q));
1281 absoluteSimDataTmp.emplace(
1282 std::piecewise_construct,
1284 std::forward_as_tuple(v));
1285 }
1286 }
1287 writeSimData(simDataTmp, absoluteSimDataTmp, param.first, name, {});
1288 simDataWritten = true;
1291 } catch (const std::exception& e) {
1292 processException(continueOnError, e, name, param.first, simDataWritten);
1293 }
1294 }
1295 break;
1296
1298 for (const auto& name : param.second.second) {
1299 bool simDataWritten = false;
1300 try {
1301 LOG(
"building " << name <<
" cds vols..");
1302 Handle<QuantExt::CreditVolCurve> wrapper = initMarket->cdsVol(name, configuration);
1303 Handle<QuantExt::CreditVolCurve> cvh;
1304 bool stickyStrike =
parameters_->cdsVolSmileDynamics(name) ==
"StickyStrike";
1305 if (param.second.first) {
1306 LOG(
"Simulating CDS Vols for " << name);
1307 vector<Handle<Quote>> quotes;
1308 vector<Volatility> vols;
1309 vector<Time> times;
1310 vector<Date> expiryDates;
1311 DayCounter dc = wrapper->dayCounter();
1312 for (Size i = 0; i < parameters->cdsVolExpiries().
size(); i++) {
1313 Date date =
asof_ + parameters->cdsVolExpiries()[i];
1314 expiryDates.push_back(date);
1315
1316 Volatility vol = wrapper->volatility(date, 5.0, Null<Real>(), wrapper->type());
1317 vols.push_back(vol);
1318 times.push_back(dc.yearFraction(
asof_, date));
1319 QuantLib::ext::shared_ptr<SimpleQuote> q =
1321 if (parameters->simulateCdsVols()) {
1322 simDataTmp.emplace(std::piecewise_construct,
1323 std::forward_as_tuple(param.first, name, i),
1324 std::forward_as_tuple(q));
1326 absoluteSimDataTmp.emplace(std::piecewise_construct,
1327 std::forward_as_tuple(param.first, name, i),
1328 std::forward_as_tuple(vol));
1329 }
1330 }
1331 quotes.emplace_back(q);
1332 }
1333 writeSimData(simDataTmp, absoluteSimDataTmp, param.first, name, {times});
1334 simDataWritten = true;
1337 std::vector<Handle<Quote>> spreads;
1339 for (size_t i = 0; i < quotes.size(); i++) {
1340 Handle<Quote> atmVol(QuantLib::ext::make_shared<SimpleQuote>(quotes[i]->
value()));
1341 Handle<Quote> quote(QuantLib::ext::make_shared <
1342 CompositeQuote<std::minus<double>>>(quotes[i], atmVol,
1343 std::minus<double>()));
1344 spreads.push_back(quote);
1345 }
1346 } else {
1347 spreads = quotes;
1348 }
1349 std::vector<QuantLib::Period> simTerms;
1350 std::vector<Handle<CreditCurve>> simTermCurves;
1352
1354 simTerms = cc->terms();
1355 for (auto const& c : cc->termCurves())
1357 } else {
1358
1359 simTerms = wrapper->terms();
1360 for (auto const& t : simTerms) {
1362 }
1363 }
1364 cvh = Handle<CreditVolCurve>(QuantLib::ext::make_shared<SpreadedCreditVolCurve>(
1365 wrapper, expiryDates, spreads, !stickyStrike, simTerms, simTermCurves));
1366 } else {
1367
1368 cvh = Handle<CreditVolCurve>(QuantLib::ext::make_shared<CreditVolCurveWrapper>(
1369 Handle<BlackVolTermStructure>(QuantLib::ext::make_shared<BlackVarianceCurve3>(
1370 0, NullCalendar(), wrapper->businessDayConvention(), dc, times, quotes,
1371 false))));
1372 }
1373 } else {
1374 string decayModeString = parameters->cdsVolDecayMode();
1375 LOG(
"Deterministic CDS Vols with decay mode " << decayModeString <<
" for " << name);
1377
1378
1379 cvh = Handle<CreditVolCurve>(
1380 QuantLib::ext::make_shared<CreditVolCurveWrapper>(Handle<BlackVolTermStructure>(
1382 Handle<BlackVolTermStructure>(
1383 QuantLib::ext::make_shared<BlackVolFromCreditVolWrapper>(wrapper, 5.0)),
1384 0, NullCalendar(), decayMode,
1386 }
1387 cvh->setAdjustReferenceDate(false);
1388 if (wrapper->allowsExtrapolation())
1389 cvh->enableExtrapolation();
1391 } catch (const std::exception& e) {
1392 processException(continueOnError, e, name, param.first, simDataWritten);
1393 }
1394 }
1395 break;
1396
1398 for (const auto& name : param.second.second) {
1399 bool simDataWritten = false;
1400 try {
1401 Handle<BlackVolTermStructure> wrapper = initMarket->fxVol(name, configuration);
1402 Handle<Quote> spot =
fxSpot(name);
1403 QL_REQUIRE(
name.length() == 6,
"invalid ccy pair length");
1404 string forCcy =
name.substr(0, 3);
1405 string domCcy =
name.substr(3, 3);
1406
1407
1408
1409 string foreignTsId;
1410 string domesticTsId;
1412 auto fxVolConfig =
curveConfigs.fxVolCurveConfig(name);
1413 foreignTsId = fxVolConfig->fxForeignYieldCurveID();
1414 TLOG(
"Got foreign term structure '" << foreignTsId
1415 << "' from FX volatility curve config for " << name);
1416 domesticTsId = fxVolConfig->fxDomesticYieldCurveID();
1417 TLOG(
"Got domestic term structure '" << domesticTsId
1418 << "' from FX volatility curve config for " << name);
1419 }
1420 Handle<BlackVolTermStructure> fvh;
1421
1422 bool stickyStrike =
parameters_->fxVolSmileDynamics(name) ==
"StickyStrike";
1423
1424 if (param.second.first) {
1425 LOG(
"Simulating FX Vols for " << name);
1426 auto& expiries = parameters->fxVolExpiries(name);
1427 Size m = expiries.size();
1428 Calendar cal = wrapper->calendar();
1429 if (cal.empty()) {
1430 cal = NullCalendar();
1431 }
1432 DayCounter dc = wrapper->dayCounter();
1433 vector<vector<Handle<Quote>>> quotes;
1434 vector<Time> times(m);
1435 vector<Date> dates(m);
1436
1437
1438 Handle<YieldTermStructure> initForTS =
1439 getYieldCurve(foreignTsId, todaysMarketParams, configuration, initMarket);
1440 TLOG(
"Foreign term structure '" << foreignTsId <<
"' from t_0 market is "
1441 << (initForTS.empty() ? "empty" : "not empty"));
1442 Handle<YieldTermStructure> initDomTS =
1443 getYieldCurve(domesticTsId, todaysMarketParams, configuration, initMarket);
1444 TLOG(
"Domestic term structure '" << domesticTsId <<
"' from t_0 market is "
1445 << (initDomTS.empty() ? "empty" : "not empty"));
1446
1447
1448 if (initForTS.empty() || initDomTS.empty()) {
1449 TLOG(
"Falling back on the discount curves for " << forCcy <<
" and " << domCcy
1450 << " from t_0 market");
1451 initForTS = initMarket->discountCurve(forCcy, configuration);
1452 initDomTS = initMarket->discountCurve(domCcy, configuration);
1453 }
1454
1455
1456 Handle<YieldTermStructure> forTS =
1458 TLOG(
"Foreign term structure '" << foreignTsId <<
"' from sim market is "
1459 << (forTS.empty() ? "empty" : "not empty"));
1460 Handle<YieldTermStructure> domTS =
1462 TLOG(
"Domestic term structure '" << domesticTsId <<
"' from sim market is "
1463 << (domTS.empty() ? "empty" : "not empty"));
1464
1465
1466 if (forTS.empty() || domTS.empty()) {
1467 TLOG(
"Falling back on the discount curves for " << forCcy <<
" and " << domCcy
1468 << " from sim market");
1471 }
1472
1473 for (Size k = 0; k < m; k++) {
1474 dates[k] =
asof_ + expiries[k];
1475 times[k] = wrapper->timeFromReference(dates[k]);
1476 }
1477
1478 QuantLib::ext::shared_ptr<BlackVolTermStructure> fxVolCurve;
1479 if (parameters->fxVolIsSurface(name)) {
1481 strikes = parameters->fxUseMoneyness(name) ? parameters->fxVolMoneyness(name)
1482 : parameters->fxVolStdDevs(name);
1484 quotes.resize(n, vector<Handle<Quote>>(m, Handle<Quote>()));
1485
1486
1487 bool flatExtrapolation = true;
1488
1489
1490 if (parameters->fxUseMoneyness(name)) {
1491 for (Size j = 0; j < m; j++) {
1492 for (Size i = 0; i < n; i++) {
1494
1495 Real k = spot->value() * mon * initForTS->discount(dates[j]) /
1496 initDomTS->discount(dates[j]);
1497 Size idx = i * m + j;
1498
1499 Volatility vol = wrapper->blackVol(dates[j], k,
true);
1500 QuantLib::ext::shared_ptr<SimpleQuote> q(
1502 simDataTmp.emplace(std::piecewise_construct,
1503 std::forward_as_tuple(param.first, name, idx),
1504 std::forward_as_tuple(q));
1506 absoluteSimDataTmp.emplace(
1507 std::piecewise_construct,
1508 std::forward_as_tuple(param.first, name, idx),
1509 std::forward_as_tuple(q->value()));
1510 }
1511 quotes[i][j] = Handle<Quote>(q);
1512 }
1513 }
1514 writeSimData(simDataTmp, absoluteSimDataTmp, param.first, name, {strikes, times});
1515 simDataWritten = true;
1516
1518 fxVolCurve = QuantLib::ext::make_shared<SpreadedBlackVolatilitySurfaceMoneynessForward>(
1519 Handle<BlackVolTermStructure>(wrapper), spot, times,
1520 parameters->fxVolMoneyness(name), quotes,
1521 Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(spot->value())), initForTS,
1522 initDomTS, forTS, domTS, stickyStrike);
1523 } else {
1524 fxVolCurve = QuantLib::ext::make_shared<BlackVarianceSurfaceMoneynessForward>(
1525 cal, spot, times, parameters->fxVolMoneyness(name), quotes, dc, forTS,
1526 domTS, stickyStrike, flatExtrapolation);
1527 }
1528 } else {
1529
1530 vector<Real> fwds;
1531 vector<Real> atmVols;
1532 for (Size i = 0; i < m; i++) {
1533 Real k = spot->value() * initForTS->discount(dates[i]) / initDomTS->discount(dates[i]);
1534 fwds.push_back(k);
1535 atmVols.push_back(wrapper->blackVol(dates[i], k));
1536 DLOG(
"on date " << dates[i] <<
": fwd = " << fwds.back()
1537 << ", atmVol = " << atmVols.back());
1538 }
1539
1540
1541 Interpolation forwardCurve =
1542 Linear().interpolate(times.begin(), times.end(), fwds.begin());
1543 Interpolation atmVolCurve =
1544 Linear().interpolate(times.begin(), times.end(), atmVols.begin());
1545
1546
1547 vector<vector<Handle<Quote>>> absQuotes(n,
1548 vector<Handle<Quote>>(m, Handle<Quote>()));
1550 parameters->fxVolStdDevs(name),
1551 forwardCurve, atmVolCurve);
1553 for (Size i = 0; i < n; ++i)
1554 for (Size j = 0; j < m; ++j)
1555 quotes[i][j] = Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(0.0));
1556 } else {
1557 quotes = absQuotes;
1558 }
1559
1560
1561 for (Size i = 0; i < m; i++) {
1562 for (Size j = 0; j < n; j++) {
1563 Size idx = j * m + i;
1564 QuantLib::ext::shared_ptr<Quote> q = quotes[j][i].currentLink();
1565 QuantLib::ext::shared_ptr<SimpleQuote> sq =
1566 QuantLib::ext::dynamic_pointer_cast<SimpleQuote>(q);
1567 simDataTmp.emplace(std::piecewise_construct,
1568 std::forward_as_tuple(param.first, name, idx),
1569 std::forward_as_tuple(sq));
1571 absoluteSimDataTmp.emplace(
1572 std::piecewise_construct,
1573 std::forward_as_tuple(param.first, name, idx),
1574 std::forward_as_tuple(absQuotes[j][i]->value()));
1575 }
1576 }
1577 }
1578 writeSimData(simDataTmp, absoluteSimDataTmp, param.first, name, {strikes, times});
1579 simDataWritten = true;
1580
1581
1582 Handle<FxIndex> fxInd =
fxIndex(name);
1583
1584 if (parameters->fxUseMoneyness(name)) {
1585 } else {
1587 fxVolCurve = QuantLib::ext::make_shared<SpreadedBlackVolatilitySurfaceStdDevs>(
1588 Handle<BlackVolTermStructure>(wrapper), spot, times,
1589 parameters->fxVolStdDevs(name), quotes,
1590 Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(spot->value())),
1591 initForTS, initDomTS, forTS, domTS, stickyStrike);
1592 } else {
1593 fxVolCurve = QuantLib::ext::make_shared<BlackVarianceSurfaceStdDevs>(
1594 cal, spot, times, parameters->fxVolStdDevs(name), quotes, dc,
1595 fxInd.currentLink(), stickyStrike, flatExtrapolation);
1596 }
1597 }
1598 }
1599 } else {
1600 quotes.resize(1, vector<Handle<Quote>>(m, Handle<Quote>()));
1601
1602 for (Size j = 0; j < m; j++) {
1603
1604 Size idx = j;
1605 Real f =
1606 spot->value() * initForTS->discount(dates[j]) / initDomTS->discount(dates[j]);
1607 Volatility vol = wrapper->blackVol(dates[j], f);
1608 QuantLib::ext::shared_ptr<SimpleQuote> q(
1610 simDataTmp.emplace(std::piecewise_construct,
1611 std::forward_as_tuple(param.first, name, idx),
1612 std::forward_as_tuple(q));
1614 absoluteSimDataTmp.emplace(std::piecewise_construct,
1615 std::forward_as_tuple(param.first, name, idx),
1616 std::forward_as_tuple(vol));
1617 }
1618 quotes[0][j] = Handle<Quote>(q);
1619 }
1620
1621 writeSimData(simDataTmp, absoluteSimDataTmp, param.first, name, {times});
1622 simDataWritten = true;
1623
1625
1626
1627 fxVolCurve = QuantLib::ext::make_shared<SpreadedBlackVolatilityCurve>(
1628 Handle<BlackVolTermStructure>(wrapper), times, quotes[0],
1629 !parameters->simulateFxVolATMOnly());
1630 } else {
1631 LOG(
"ATM FX Vols (BlackVarianceCurve3) for " << name);
1632 QuantLib::ext::shared_ptr<BlackVolTermStructure> atmCurve;
1633 atmCurve = QuantLib::ext::make_shared<BlackVarianceCurve3>(
1634 0, NullCalendar(), wrapper->businessDayConvention(), dc, times, quotes[0], false);
1635
1636
1637 if (parameters->simulateFxVolATMOnly()) {
1638 LOG(
"Simulating FX Vols (FXVolatilityConstantSpread) for " << name);
1639 fxVolCurve = QuantLib::ext::make_shared<BlackVolatilityConstantSpread>(
1640 Handle<BlackVolTermStructure>(atmCurve), wrapper);
1641 } else {
1642 fxVolCurve = atmCurve;
1643 }
1644 }
1645 }
1646 fvh = Handle<BlackVolTermStructure>(fxVolCurve);
1647
1648 } else {
1649 string decayModeString = parameters->fxVolDecayMode();
1650 LOG(
"Deterministic FX Vols with decay mode " << decayModeString <<
" for " << name);
1652
1653
1654
1655
1656
1657 fvh = Handle<BlackVolTermStructure>(
1659 wrapper, 0, NullCalendar(), decayMode,
1661 }
1662
1663 fvh->setAdjustReferenceDate(false);
1664 fvh->enableExtrapolation();
1666
1667
1668 QL_REQUIRE(
name.size() == 6,
"Invalid Ccy pair " << name);
1669 string reverse =
name.substr(3) +
name.substr(0, 3);
1670 Handle<QuantLib::BlackVolTermStructure> ifvh(
1671 QuantLib::ext::make_shared<BlackInvertedVolTermStructure>(fvh));
1672 ifvh->enableExtrapolation();
1674 } catch (const std::exception& e) {
1675 processException(continueOnError, e, name, param.first, simDataWritten);
1676 }
1677 }
1678 break;
1679
1681 for (const auto& name : param.second.second) {
1682 bool simDataWritten = false;
1683 try {
1684 Handle<BlackVolTermStructure> wrapper = initMarket->equityVol(name, configuration);
1685 Handle<BlackVolTermStructure> evh;
1686
1687 bool stickyStrike =
parameters_->equityVolSmileDynamics(name) ==
"StickyStrike";
1688 if (param.second.first) {
1690 Handle<Quote> spot = eqCurve->equitySpot();
1691 auto expiries = parameters->equityVolExpiries(name);
1692
1693 Size m = expiries.size();
1694 vector<vector<Handle<Quote>>> quotes;
1695 vector<Time> times(m);
1696 vector<Date> dates(m);
1697 Calendar cal;
1700 if (cfg->calendar().empty())
1702 else
1704 }
1705 if (cal.empty() || cal == NullCalendar()) {
1706
1707 cal = eqCurve->fixingCalendar();
1708 }
1709 DayCounter dc = wrapper->dayCounter();
1710
1711 for (Size k = 0; k < m; k++) {
1712 dates[k] = cal.advance(
asof_, expiries[k]);
1713 times[k] = dc.yearFraction(
asof_, dates[k]);
1714 }
1715
1716 QuantLib::ext::shared_ptr<BlackVolTermStructure> eqVolCurve;
1717
1718 if (parameters->equityVolIsSurface(name)) {
1720 strikes = parameters->equityUseMoneyness(name)
1721 ? parameters->equityVolMoneyness(name)
1722 : parameters->equityVolStandardDevs(name);
1724 quotes.resize(n, vector<Handle<Quote>>(m, Handle<Quote>()));
1725
1726 if (parameters->equityUseMoneyness(name)) {
1727 for (Size j = 0; j < m; j++) {
1728 for (Size i = 0; i < n; i++) {
1730
1731 Real k = eqCurve->forecastFixing(dates[j]) * mon;
1732 Size idx = i * m + j;
1733 Volatility vol = wrapper->blackVol(dates[j], k);
1734 QuantLib::ext::shared_ptr<SimpleQuote> q(
1736 simDataTmp.emplace(std::piecewise_construct,
1737 std::forward_as_tuple(param.first, name, idx),
1738 std::forward_as_tuple(q));
1740 absoluteSimDataTmp.emplace(
1741 std::piecewise_construct,
1742 std::forward_as_tuple(param.first, name, idx),
1743 std::forward_as_tuple(vol));
1744 }
1745 quotes[i][j] = Handle<Quote>(q);
1746 }
1747 }
1748 writeSimData(simDataTmp, absoluteSimDataTmp, param.first, name, {strikes, times});
1749 simDataWritten = true;
1750 LOG(
"Simulating EQ Vols (BlackVarianceSurfaceMoneyness) for " << name);
1751
1753 eqVolCurve = QuantLib::ext::make_shared<SpreadedBlackVolatilitySurfaceMoneynessForward>(
1754 Handle<BlackVolTermStructure>(wrapper), spot, times,
1755 parameters->equityVolMoneyness(name), quotes,
1756 Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(spot->value())),
1757 initMarket->equityCurve(name, configuration)->equityDividendCurve(),
1758 initMarket->equityCurve(name, configuration)->equityForecastCurve(),
1759 eqCurve->equityDividendCurve(), eqCurve->equityForecastCurve(),
1760 stickyStrike);
1761 } else {
1762
1763 eqVolCurve = QuantLib::ext::make_shared<BlackVarianceSurfaceMoneynessSpot>(
1764 cal, spot, times, parameters->equityVolMoneyness(name), quotes, dc,
1765 stickyStrike);
1766 }
1767 eqVolCurve->enableExtrapolation();
1768
1769 } else {
1770
1771 vector<Real> fwds;
1772 vector<Real> atmVols;
1773 for (Size i = 0; i < expiries.size(); i++) {
1774 auto eqForward = eqCurve->forecastFixing(dates[i]);
1775 fwds.push_back(eqForward);
1776 atmVols.push_back(wrapper->blackVol(dates[i], eqForward));
1777 DLOG(
"on date " << dates[i] <<
": fwd = " << fwds.back()
1778 << ", atmVol = " << atmVols.back());
1779 }
1780
1781
1782 Interpolation forwardCurve =
1783 Linear().interpolate(times.begin(), times.end(), fwds.begin());
1784 Interpolation atmVolCurve =
1785 Linear().interpolate(times.begin(), times.end(), atmVols.begin());
1786
1787
1788 vector<vector<Handle<Quote>>> absQuotes(n,
1789 vector<Handle<Quote>>(m, Handle<Quote>()));
1791 forwardCurve, atmVolCurve);
1793 for (Size i = 0; i < n; ++i)
1794 for (Size j = 0; j < m; ++j)
1795 quotes[i][j] = Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(0.0));
1796 } else {
1797 quotes = absQuotes;
1798 }
1799
1800
1801 for (Size i = 0; i < m; i++) {
1802 for (Size j = 0; j < n; j++) {
1803 Size idx = j * m + i;
1804 QuantLib::ext::shared_ptr<Quote> q = quotes[j][i].currentLink();
1805 QuantLib::ext::shared_ptr<SimpleQuote> sq =
1806 QuantLib::ext::dynamic_pointer_cast<SimpleQuote>(q);
1807 QL_REQUIRE(sq, "Quote is not a SimpleQuote");
1808 simDataTmp.emplace(std::piecewise_construct,
1809 std::forward_as_tuple(param.first, name, idx),
1810 std::forward_as_tuple(sq));
1812 absoluteSimDataTmp.emplace(
1813 std::piecewise_construct,
1814 std::forward_as_tuple(param.first, name, idx),
1815 std::forward_as_tuple(absQuotes[j][i]->value()));
1816 }
1817 }
1818 }
1819 writeSimData(simDataTmp, absoluteSimDataTmp, param.first, name, {strikes, times});
1820 simDataWritten = true;
1821 bool flatExtrapolation = true;
1823 eqVolCurve = QuantLib::ext::make_shared<SpreadedBlackVolatilitySurfaceStdDevs>(
1824 Handle<BlackVolTermStructure>(wrapper), spot, times,
1825 parameters->equityVolStandardDevs(name), quotes,
1826 Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(spot->value())),
1827 initMarket->equityCurve(name, configuration)->equityDividendCurve(),
1828 initMarket->equityCurve(name, configuration)->equityForecastCurve(),
1829 eqCurve->equityDividendCurve(), eqCurve->equityForecastCurve(),
1830 stickyStrike);
1831 } else {
1832 eqVolCurve = QuantLib::ext::make_shared<BlackVarianceSurfaceStdDevs>(
1833 cal, spot, times, parameters->equityVolStandardDevs(name), quotes, dc,
1834 eqCurve.currentLink(), stickyStrike, flatExtrapolation);
1835 }
1836 }
1837 } else {
1838 quotes.resize(1, vector<Handle<Quote>>(m, Handle<Quote>()));
1839
1840 for (Size j = 0; j < m; j++) {
1841
1842 Size idx = j;
1843 auto eqForward = eqCurve->fixing(dates[j]);
1844 Volatility vol = wrapper->blackVol(dates[j], eqForward);
1845 QuantLib::ext::shared_ptr<SimpleQuote> q(
1847 simDataTmp.emplace(std::piecewise_construct,
1848 std::forward_as_tuple(param.first, name, idx),
1849 std::forward_as_tuple(q));
1851 absoluteSimDataTmp.emplace(std::piecewise_construct,
1852 std::forward_as_tuple(param.first, name, idx),
1853 std::forward_as_tuple(vol));
1854 }
1855 quotes[0][j] = Handle<Quote>(q);
1856 }
1857
1858 writeSimData(simDataTmp, absoluteSimDataTmp, param.first, name, {times});
1859 simDataWritten = true;
1860
1862
1863
1864 eqVolCurve = QuantLib::ext::make_shared<SpreadedBlackVolatilityCurve>(
1865 Handle<BlackVolTermStructure>(wrapper), times, quotes[0],
1866 !parameters->simulateEquityVolATMOnly());
1867 } else {
1868 LOG(
"ATM EQ Vols (BlackVarianceCurve3) for " << name);
1869 QuantLib::ext::shared_ptr<BlackVolTermStructure> atmCurve;
1870 atmCurve = QuantLib::ext::make_shared<BlackVarianceCurve3>(0, NullCalendar(),
1871 wrapper->businessDayConvention(),
1872 dc, times, quotes[0], false);
1873
1874
1875 if (parameters->simulateEquityVolATMOnly()) {
1876 LOG(
"Simulating EQ Vols (EquityVolatilityConstantSpread) for " << name);
1877 eqVolCurve = QuantLib::ext::make_shared<BlackVolatilityConstantSpread>(
1878 Handle<BlackVolTermStructure>(atmCurve), wrapper);
1879 } else {
1880 eqVolCurve = atmCurve;
1881 }
1882 }
1883 }
1884 evh = Handle<BlackVolTermStructure>(eqVolCurve);
1885
1886 } else {
1887 string decayModeString = parameters->equityVolDecayMode();
1888 DLOG(
"Deterministic EQ Vols with decay mode " << decayModeString <<
" for " << name);
1890
1891
1892
1893
1894
1895 evh = Handle<BlackVolTermStructure>(
1897 wrapper, 0, NullCalendar(), decayMode,
1899 }
1900
1901 evh->setAdjustReferenceDate(false);
1902 if (wrapper->allowsExtrapolation())
1903 evh->enableExtrapolation();
1905 DLOG(
"EQ volatility curve built for " << name);
1906 } catch (const std::exception& e) {
1907 processException(continueOnError, e, name, param.first, simDataWritten);
1908 }
1909 }
1910 break;
1911
1913 for (const auto& name : param.second.second) {
1914 bool simDataWritten = false;
1915 try {
1916 Handle<QuantExt::BaseCorrelationTermStructure> wrapper =
1917 initMarket->baseCorrelation(name, configuration);
1918 if (!param.second.first)
1920 else {
1921 std::vector<Real> times;
1922 Size nd = parameters->baseCorrelationDetachmentPoints().size();
1923 Size nt = parameters->baseCorrelationTerms().size();
1924 vector<vector<Handle<Quote>>> quotes(nd, vector<Handle<Quote>>(nt));
1925 vector<Period> terms(nt);
1926 vector<double> detachmentPoints(nd);
1927 for (Size i = 0; i < nd; ++i) {
1928 Real lossLevel = parameters->baseCorrelationDetachmentPoints()[i];
1929 detachmentPoints[i] = lossLevel;
1930 for (Size j = 0; j < nt; ++j) {
1931 Period term = parameters->baseCorrelationTerms()[j];
1932 if (i == 0)
1933 terms[j] = term;
1934 times.push_back(wrapper->timeFromReference(
asof_ + term));
1935 Real bc = wrapper->correlation(
asof_ + term, lossLevel,
true);
1936 QuantLib::ext::shared_ptr<SimpleQuote> q =
1938 simDataTmp.emplace(std::piecewise_construct,
1939 std::forward_as_tuple(param.first, name, i * nt + j),
1940 std::forward_as_tuple(q));
1942 absoluteSimDataTmp.emplace(std::piecewise_construct,
1943 std::forward_as_tuple(param.first, name, i * nt + j),
1944 std::forward_as_tuple(bc));
1945 }
1946 quotes[i][j] = Handle<Quote>(q);
1947 }
1948 }
1949
1951 simDataTmp, absoluteSimDataTmp, param.first, name,
1952 {parameters->baseCorrelationDetachmentPoints(), times});
1953 simDataWritten = true;
1954
1955
1956 if (nt == 1) {
1957 terms.push_back(terms[0] + 1 * terms[0].units());
1958 for (Size i = 0; i < nd; ++i)
1959 quotes[i].push_back(quotes[i][0]);
1960 }
1961
1962 if (nd == 1) {
1963 quotes.push_back(vector<Handle<Quote>>(terms.size()));
1964 for (Size j = 0; j < terms.size(); ++j)
1965 quotes[1][j] = quotes[0][j];
1966
1967 if (detachmentPoints[0] < 1.0 && !QuantLib::close_enough(detachmentPoints[0], 1.0)) {
1968 detachmentPoints.push_back(1.0);
1969 } else {
1970 detachmentPoints.insert(detachmentPoints.begin(), 0.01);
1971 }
1972 }
1973
1974 QuantLib::ext::shared_ptr<QuantExt::BaseCorrelationTermStructure> bcp;
1976 bcp = QuantLib::ext::make_shared<QuantExt::SpreadedBaseCorrelationCurve>(
1977 wrapper, terms, detachmentPoints, quotes);
1978 bcp->enableExtrapolation(wrapper->allowsExtrapolation());
1979 } else {
1980 DayCounter dc = wrapper->dayCounter();
1981 bcp = QuantLib::ext::make_shared<InterpolatedBaseCorrelationTermStructure<Bilinear>>(
1982 wrapper->settlementDays(), wrapper->calendar(), wrapper->businessDayConvention(),
1983 terms, detachmentPoints, quotes, dc);
1984
1985 bcp->enableExtrapolation(wrapper->allowsExtrapolation());
1986 }
1987 bcp->setAdjustReferenceDate(false);
1988 Handle<QuantExt::BaseCorrelationTermStructure> bch(bcp);
1990 }
1991 DLOG(
"Base correlations built for " << name);
1992 } catch (const std::exception& e) {
1993 processException(continueOnError, e, name, param.first, simDataWritten);
1994 }
1995 }
1996 break;
1997
1999 for (const auto& name : param.second.second) {
2000 bool simDataWritten = false;
2001 try {
2002 DLOG(
"adding " << name <<
" base CPI price");
2004 initMarket->zeroInflationIndex(name, configuration);
2008
2009 QuantLib::ext::shared_ptr<InflationIndex> inflationIndex =
2011
2012 auto q = QuantLib::ext::make_shared<SimpleQuote>(baseCPI);
2014 auto m = [baseCPI](Real x) { return x * baseCPI; };
2015 Handle<InflationIndexObserver> inflObserver(
2016 QuantLib::ext::make_shared<InflationIndexObserver>(
2017 inflationIndex,
2018 Handle<Quote>(
2019 QuantLib::ext::make_shared<DerivedQuote<decltype(m)>>(Handle<Quote>(q), m)),
2020 obsLag));
2022 } else {
2023 Handle<InflationIndexObserver> inflObserver(
2024 QuantLib::ext::make_shared<InflationIndexObserver>(inflationIndex, Handle<Quote>(q),
2025 obsLag));
2027 }
2028 simDataTmp.emplace(std::piecewise_construct, std::forward_as_tuple(param.first, name),
2029 std::forward_as_tuple(q));
2031 absoluteSimDataTmp.emplace(std::piecewise_construct,
2032 std::forward_as_tuple(param.first, name),
2033 std::forward_as_tuple(baseCPI));
2034 }
2035 writeSimData(simDataTmp, absoluteSimDataTmp, param.first, name, {});
2036 simDataWritten = true;
2037 } catch (const std::exception& e) {
2038 processException(continueOnError, e, name, param.first, simDataWritten);
2039 }
2040 }
2041 break;
2042
2044 for (const auto& name : param.second.second) {
2045 bool simDataWritten = false;
2046 try {
2047 LOG(
"building " << name <<
" zero inflation curve");
2048
2049 Handle<ZeroInflationIndex> inflationIndex = initMarket->zeroInflationIndex(name, configuration);
2050 Handle<ZeroInflationTermStructure> inflationTs = inflationIndex->zeroInflationTermStructure();
2051 vector<string> keys(parameters->zeroInflationTenors(name).size());
2052
2053 Date date0 =
asof_ - inflationTs->observationLag();
2054 DayCounter dc = inflationTs->dayCounter();
2055 vector<Date> quoteDates;
2056 vector<Time> zeroCurveTimes(
2057 1, -dc.yearFraction(inflationPeriod(date0, inflationTs->frequency()).first,
asof_));
2058 vector<Handle<Quote>> quotes;
2059 QL_REQUIRE(parameters->zeroInflationTenors(name).front() > 0 * Days,
2060 "zero inflation tenors must not include t=0");
2061
2062 for (auto& tenor : parameters->zeroInflationTenors(name)) {
2063 Date inflDate = inflationPeriod(date0 + tenor, inflationTs->frequency()).first;
2064 zeroCurveTimes.push_back(dc.yearFraction(
asof_, inflDate));
2065 quoteDates.push_back(
asof_ + tenor);
2066 }
2067
2068 for (Size i = 1; i < zeroCurveTimes.size(); i++) {
2069 Real rate = inflationTs->zeroRate(quoteDates[i - 1]);
2070 if (inflationTs->hasSeasonality()) {
2071 Date
fixingDate = quoteDates[i - 1] - inflationTs->observationLag();
2072 rate = inflationTs->seasonality()->deseasonalisedZeroRate(fixingDate,
2073 rate, *inflationTs.currentLink());
2074 }
2076 if (i == 1) {
2077
2078
2079 quotes.push_back(Handle<Quote>(q));
2080 }
2081 quotes.push_back(Handle<Quote>(q));
2082 simDataTmp.emplace(std::piecewise_construct,
2083 std::forward_as_tuple(param.first, name, i - 1),
2084 std::forward_as_tuple(q));
2086 absoluteSimDataTmp.emplace(std::piecewise_construct,
2087 std::forward_as_tuple(param.first, name, i - 1),
2088 std::forward_as_tuple(rate));
2089 DLOG(
"ScenarioSimMarket zero inflation curve " << name <<
" zeroRate[" << i
2090 << "]=" << rate);
2091 }
2092
2093 writeSimData(simDataTmp, absoluteSimDataTmp, param.first, name,
2094 {std::vector<Real>(std::next(zeroCurveTimes.begin(), 1), zeroCurveTimes.end())});
2095 simDataWritten = true;
2096
2097
2098 QuantLib::ext::shared_ptr<ZeroInflationTermStructure> zeroCurve;
2100 zeroCurve =
2101 QuantLib::ext::make_shared<SpreadedZeroInflationCurve>(inflationTs, zeroCurveTimes, quotes);
2102 } else {
2103 zeroCurve = QuantLib::ext::make_shared<ZeroInflationCurveObserverMoving<Linear>>(
2104 0, inflationIndex->fixingCalendar(), dc, inflationTs->observationLag(),
2105 inflationTs->frequency(), false, zeroCurveTimes, quotes,
2106 inflationTs->seasonality());
2107 }
2108
2109 Handle<ZeroInflationTermStructure> its(zeroCurve);
2110 its->setAdjustReferenceDate(false);
2111 its->enableExtrapolation();
2112 QuantLib::ext::shared_ptr<ZeroInflationIndex> i =
2114 Handle<ZeroInflationIndex> zh(i);
2116
2117 LOG(
"building " << name <<
" zero inflation curve done");
2118 } catch (const std::exception& e) {
2119 processException(continueOnError, e, name, param.first, simDataWritten);
2120 }
2121 }
2122 break;
2123
2125 for (const auto& name : param.second.second) {
2126 bool simDataWritten = false;
2127 try {
2128 LOG(
"building " << name <<
" zero inflation cap/floor volatility curve...");
2129 Handle<QuantLib::CPIVolatilitySurface> wrapper =
2130 initMarket->cpiInflationCapFloorVolatilitySurface(name, configuration);
2132 initMarket->zeroInflationIndex(name, configuration);
2133
2134
2135
2136 Handle<QuantLib::CPIVolatilitySurface> hCpiVol;
2137
2138
2139 if (param.second.first) {
2140 LOG(
"Simulating zero inflation cap/floor vols for index name " << name);
2141
2142 DayCounter dc = wrapper->dayCounter();
2143 vector<Period> optionTenors = parameters->zeroInflationCapFloorVolExpiries(name);
2144 vector<Date> optionDates(optionTenors.size());
2145 vector<Real>
strikes = parameters->zeroInflationCapFloorVolStrikes(name);
2146 vector<vector<Handle<Quote>>> quotes(
2147 optionTenors.size(), vector<Handle<Quote>>(
strikes.size(), Handle<Quote>()));
2148 for (Size i = 0; i < optionTenors.size(); ++i) {
2149 optionDates[i] = wrapper->optionDateFromTenor(optionTenors[i]);
2150 for (Size j = 0; j <
strikes.size(); ++j) {
2151 Real vol =
2152 wrapper->volatility(optionTenors[i], strikes[j], wrapper->observationLag(),
2153 wrapper->allowsExtrapolation());
2155 Size index = i *
strikes.size() + j;
2156 simDataTmp.emplace(std::piecewise_construct,
2157 std::forward_as_tuple(param.first, name, index),
2158 std::forward_as_tuple(q));
2160 absoluteSimDataTmp.emplace(std::piecewise_construct,
2161 std::forward_as_tuple(param.first, name, index),
2162 std::forward_as_tuple(vol));
2163 }
2164 quotes[i][j] = Handle<Quote>(q);
2165 }
2166 }
2167
2168 std::vector<std::vector<Real>> coordinates(2);
2169 for (Size i = 0; i < optionTenors.size(); ++i) {
2170 coordinates[0].push_back(
2171 wrapper->timeFromReference(wrapper->optionDateFromTenor(optionTenors[i])));
2172 }
2173 for (Size j = 0; j <
strikes.size(); ++j) {
2174 coordinates[1].push_back(strikes[j]);
2175 }
2176
2177 writeSimData(simDataTmp, absoluteSimDataTmp, param.first, name, coordinates);
2178 simDataWritten = true;
2179
2180
2181
2183 auto surface = QuantLib::ext::dynamic_pointer_cast<QuantExt::CPIVolatilitySurface>(wrapper.currentLink());
2184 QL_REQUIRE(surface,
2185 "Internal error, todays market should build QuantExt::CPIVolatiltiySurface "
2186 "instead of QuantLib::CPIVolatilitySurface");
2187 hCpiVol = Handle<QuantLib::CPIVolatilitySurface>(
2188 QuantLib::ext::make_shared<SpreadedCPIVolatilitySurface>(
2189 Handle<QuantExt::CPIVolatilitySurface>(surface), optionDates, strikes, quotes));
2190 } else {
2191 auto surface =
2192 QuantLib::ext::dynamic_pointer_cast<QuantExt::CPIVolatilitySurface>(wrapper.currentLink());
2193 QL_REQUIRE(surface,
2194 "Internal error, todays market should build QuantExt::CPIVolatiltiySurface "
2195 "instead of QuantLib::CPIVolatilitySurface");
2196 hCpiVol = Handle<QuantLib::CPIVolatilitySurface>(
2199 wrapper->settlementDays(), wrapper->calendar(),
2200 wrapper->businessDayConvention(), wrapper->dayCounter(),
2201 wrapper->observationLag(), surface->capFloorStartDate(), Bilinear(),
2202 surface->volatilityType(), surface->displacement()));
2203 }
2204 } else {
2205
2206
2207
2208
2209
2210
2211 hCpiVol = wrapper;
2212 }
2213
2214 hCpiVol->setAdjustReferenceDate(false);
2215 if (wrapper->allowsExtrapolation())
2216 hCpiVol->enableExtrapolation();
2219 std::forward_as_tuple(hCpiVol));
2220
2221 } catch (const std::exception& e) {
2222 processException(continueOnError, e, name, param.first, simDataWritten);
2223 }
2224 }
2225 break;
2226
2228 for (const auto& name : param.second.second) {
2229 bool simDataWritten = false;
2230 try {
2232 initMarket->yoyInflationIndex(name, configuration);
2233 Handle<YoYInflationTermStructure> yoyInflationTs =
2235 vector<string> keys(parameters->yoyInflationTenors(name).size());
2236
2237 Date date0 =
asof_ - yoyInflationTs->observationLag();
2238 DayCounter dc = yoyInflationTs->dayCounter();
2239 vector<Date> quoteDates;
2240 vector<Time> yoyCurveTimes(
2241 1, -dc.yearFraction(inflationPeriod(date0, yoyInflationTs->frequency()).first,
asof_));
2242 vector<Handle<Quote>> quotes;
2243 QL_REQUIRE(parameters->yoyInflationTenors(name).front() > 0 * Days,
2244 "zero inflation tenors must not include t=0");
2245
2246 for (auto& tenor : parameters->yoyInflationTenors(name)) {
2247 Date inflDate = inflationPeriod(date0 + tenor, yoyInflationTs->frequency()).first;
2248 yoyCurveTimes.push_back(dc.yearFraction(
asof_, inflDate));
2249 quoteDates.push_back(
asof_ + tenor);
2250 }
2251
2252 for (Size i = 1; i < yoyCurveTimes.size(); i++) {
2253 Real rate = yoyInflationTs->yoyRate(quoteDates[i - 1]);
2255 if (i == 1) {
2256
2257
2258 quotes.push_back(Handle<Quote>(q));
2259 }
2260 quotes.push_back(Handle<Quote>(q));
2261 simDataTmp.emplace(std::piecewise_construct,
2262 std::forward_as_tuple(param.first, name, i - 1),
2263 std::forward_as_tuple(q));
2265 absoluteSimDataTmp.emplace(std::piecewise_construct,
2266 std::forward_as_tuple(param.first, name, i - 1),
2267 std::forward_as_tuple(rate));
2268 DLOG(
"ScenarioSimMarket yoy inflation curve " << name <<
" yoyRate[" << i <<
"]=" << rate);
2269 }
2270
2271 writeSimData(simDataTmp, absoluteSimDataTmp, param.first, name,
2272 {std::vector<Real>(std::next(yoyCurveTimes.begin(), 1), yoyCurveTimes.end())});
2273 simDataWritten = true;
2274
2275 QuantLib::ext::shared_ptr<YoYInflationTermStructure> yoyCurve;
2276
2277
2279 yoyCurve =
2280 QuantLib::ext::make_shared<SpreadedYoYInflationCurve>(yoyInflationTs, yoyCurveTimes, quotes);
2281 } else {
2282 yoyCurve = QuantLib::ext::make_shared<YoYInflationCurveObserverMoving<Linear>>(
2285 quotes, yoyInflationTs->seasonality());
2286 }
2287 yoyCurve->setAdjustReferenceDate(false);
2288 Handle<YoYInflationTermStructure> its(yoyCurve);
2289 its->enableExtrapolation();
2291 Handle<YoYInflationIndex> zh(i);
2293 } catch (const std::exception& e) {
2294 processException(continueOnError, e, name, param.first, simDataWritten);
2295 }
2296 }
2297 break;
2298
2300 for (const auto& name : param.second.second) {
2301 bool simDataWritten = false;
2302 try {
2303 LOG(
"building " << name <<
" yoy inflation cap/floor volatility curve...");
2304 Handle<QuantExt::YoYOptionletVolatilitySurface> wrapper =
2305 initMarket->yoyCapFloorVol(name, configuration);
2306 LOG(
"Initial market "
2307 << name << " yoy inflation cap/floor volatility type = " << wrapper->volatilityType());
2308 Handle<QuantExt::YoYOptionletVolatilitySurface> hYoYCapletVol;
2309
2310
2311 if (param.second.first) {
2312 LOG(
"Simulating yoy inflation optionlet vols for index name " << name);
2313 vector<Period> optionTenors = parameters->yoyInflationCapFloorVolExpiries(name);
2314 vector<Date> optionDates(optionTenors.size());
2315 vector<Real>
strikes = parameters->yoyInflationCapFloorVolStrikes(name);
2316 vector<vector<Handle<Quote>>> quotes(
2317 optionTenors.size(), vector<Handle<Quote>>(
strikes.size(), Handle<Quote>()));
2318 for (Size i = 0; i < optionTenors.size(); ++i) {
2319 optionDates[i] = wrapper->optionDateFromTenor(optionTenors[i]);
2320 for (Size j = 0; j <
strikes.size(); ++j) {
2321 Real vol =
2322 wrapper->volatility(optionTenors[i], strikes[j], wrapper->observationLag(),
2323 wrapper->allowsExtrapolation());
2324 QuantLib::ext::shared_ptr<SimpleQuote> q(
2326 Size index = i *
strikes.size() + j;
2327 simDataTmp.emplace(std::piecewise_construct,
2328 std::forward_as_tuple(param.first, name, index),
2329 std::forward_as_tuple(q));
2331 absoluteSimDataTmp.emplace(std::piecewise_construct,
2332 std::forward_as_tuple(param.first, name, index),
2333 std::forward_as_tuple(vol));
2334 }
2335 quotes[i][j] = Handle<Quote>(q);
2336 TLOG(
"ScenarioSimMarket yoy cf vol " << name <<
" tenor #" << i <<
" strike #" << j
2337 << " " << vol);
2338 }
2339 }
2340
2341 std::vector<std::vector<Real>> coordinates(2);
2342 for (Size i = 0; i < optionTenors.size(); ++i) {
2343 coordinates[0].push_back(
2344 wrapper->timeFromReference(wrapper->optionDateFromTenor(optionTenors[i])));
2345 }
2346 for (Size j = 0; j <
strikes.size(); ++j) {
2347 coordinates[1].push_back(strikes[j]);
2348 }
2349
2350 writeSimData(simDataTmp, absoluteSimDataTmp, param.first, name, coordinates);
2351 simDataWritten = true;
2352
2353 DayCounter dc = wrapper->dayCounter();
2354
2355 QuantLib::ext::shared_ptr<QuantExt::YoYOptionletVolatilitySurface> yoyoptionletvolsurface;
2357 yoyoptionletvolsurface = QuantLib::ext::make_shared<QuantExt::SpreadedYoYVolatilitySurface>(
2358 wrapper, optionDates, strikes, quotes);
2359 } else {
2360 yoyoptionletvolsurface = QuantLib::ext::make_shared<StrippedYoYInflationOptionletVol>(
2361 0, wrapper->calendar(), wrapper->businessDayConvention(), dc,
2362 wrapper->observationLag(), wrapper->frequency(), wrapper->indexIsInterpolated(),
2363 optionDates, strikes, quotes, wrapper->volatilityType(), wrapper->displacement());
2364 }
2365 hYoYCapletVol = Handle<QuantExt::YoYOptionletVolatilitySurface>(yoyoptionletvolsurface);
2366 } else {
2367 string decayModeString = parameters->yoyInflationCapFloorVolDecayMode();
2369 QuantLib::ext::shared_ptr<QuantExt::DynamicYoYOptionletVolatilitySurface> yoyCapletVol =
2370 QuantLib::ext::make_shared<QuantExt::DynamicYoYOptionletVolatilitySurface>(*wrapper, decayMode);
2371 hYoYCapletVol = Handle<QuantExt::YoYOptionletVolatilitySurface>(yoyCapletVol);
2372 }
2373 hYoYCapletVol->setAdjustReferenceDate(false);
2374 if (wrapper->allowsExtrapolation())
2375 hYoYCapletVol->enableExtrapolation();
2378 std::forward_as_tuple(hYoYCapletVol));
2379 LOG(
"Simulation market yoy inflation cap/floor volatility type = "
2380 << hYoYCapletVol->volatilityType());
2381 } catch (const std::exception& e) {
2382 processException(continueOnError, e, name, param.first, simDataWritten);
2383 }
2384 }
2385 break;
2386
2388
2389 std::vector<std::string> curveNames;
2390 std::vector<std::string> basisCurves;
2391 for (const auto& name : param.second.second) {
2392 try {
2393 Handle<PriceTermStructure> initialCommodityCurve =
2394 initMarket->commodityPriceCurve(name, configuration);
2395 QuantLib::ext::shared_ptr<CommodityBasisPriceTermStructure> basisCurve =
2396 QuantLib::ext::dynamic_pointer_cast<QuantExt::CommodityBasisPriceTermStructure>(
2397 initialCommodityCurve.currentLink());
2398 if (basisCurve != nullptr) {
2399 basisCurves.push_back(name);
2400 } else {
2401 curveNames.push_back(name);
2402 }
2403 } catch (...) {
2404 curveNames.push_back(name);
2405 }
2406 }
2407 curveNames.insert(curveNames.end(), basisCurves.begin(), basisCurves.end());
2408
2409 for (const auto& name : curveNames) {
2410
2411 bool simDataWritten = false;
2412 try {
2413 LOG(
"building commodity curve for " << name);
2414
2415
2416 Handle<PriceTermStructure> initialCommodityCurve =
2417 initMarket->commodityPriceCurve(name, configuration);
2418
2419 bool allowsExtrapolation = initialCommodityCurve->allowsExtrapolation();
2420
2421
2422
2423 vector<Period> simulationTenors = parameters->commodityCurveTenors(name);
2424 DayCounter commodityCurveDayCounter = initialCommodityCurve->dayCounter();
2425 if (simulationTenors.empty()) {
2426 DLOG(
"simulation tenors are empty, use "
2427 << initialCommodityCurve->pillarDates().size()
2428 << " pillar dates from T0 curve to build ssm curve.");
2429 simulationTenors.reserve(initialCommodityCurve->pillarDates().size());
2430 for (const Date& d : initialCommodityCurve->pillarDates()) {
2431 QL_REQUIRE(d >=
asof_,
"Commodity curve pillar date (" << io::iso_date(d)
2432 << ") must be after as of ("
2433 << io::iso_date(
asof_) <<
").");
2434 simulationTenors.push_back(Period(d -
asof_, Days));
2435 }
2436
2437
2438
2439 parameters->setCommodityCurveTenors(name, simulationTenors);
2440 } else {
2441 DLOG(
"using " << simulationTenors.size() <<
" simulation tenors.");
2442 }
2443
2444
2445 vector<Handle<Quote>> quotes(simulationTenors.size());
2446 vector<Real> times;
2447 for (Size i = 0; i < simulationTenors.size(); i++) {
2448 Date d =
asof_ + simulationTenors[i];
2449 Real price = initialCommodityCurve->price(d, allowsExtrapolation);
2450 times.push_back(initialCommodityCurve->timeFromReference(d));
2451 TLOG(
"Commodity curve: price at " << io::iso_date(d) <<
" is " << price);
2452
2453 QuantLib::ext::shared_ptr<SimpleQuote> quote = QuantLib::ext::make_shared<SimpleQuote>(
2455 quotes[i] = Handle<Quote>(quote);
2456
2457
2458 if (param.second.first) {
2459 simDataTmp.emplace(piecewise_construct, forward_as_tuple(param.first, name, i),
2460 forward_as_tuple(quote));
2462 absoluteSimDataTmp.emplace(piecewise_construct,
2463 forward_as_tuple(param.first, name, i),
2464 forward_as_tuple(price));
2465 }
2466 }
2467
2468 writeSimData(simDataTmp, absoluteSimDataTmp, param.first, name, {times});
2469 simDataWritten = true;
2470 QuantLib::ext::shared_ptr<PriceTermStructure> priceCurve;
2471
2473 vector<Real> simulationTimes;
2474 for (auto const& t : simulationTenors) {
2475 simulationTimes.push_back(commodityCurveDayCounter.yearFraction(
asof_,
asof_ + t));
2476 }
2477 if (simulationTimes.front() != 0.0) {
2478 simulationTimes.insert(simulationTimes.begin(), 0.0);
2479 quotes.insert(quotes.begin(), quotes.front());
2480 }
2481
2482
2483 priceCurve = QuantLib::ext::make_shared<SpreadedPriceTermStructure>(initialCommodityCurve,
2484 simulationTimes, quotes);
2485 } else {
2486 priceCurve= QuantLib::ext::make_shared<InterpolatedPriceCurve<LinearFlat>>(
2487 simulationTenors, quotes, commodityCurveDayCounter, initialCommodityCurve->currency());
2488 }
2489
2490 auto orgBasisCurve =
2491 QuantLib::ext::dynamic_pointer_cast<QuantExt::CommodityBasisPriceTermStructure>(
2492 initialCommodityCurve.currentLink());
2493
2494 Handle<PriceTermStructure> pts;
2495 if (orgBasisCurve == nullptr) {
2496 pts = Handle<PriceTermStructure>(priceCurve);
2497 } else {
2501 "Internal error in scenariosimmarket: couldn't find underlying base curve '"
2502 << orgBasisCurve->baseIndex()->underlyingName()
2503 << "' while building commodity basis curve '" << name << "'");
2504 pts = Handle<PriceTermStructure>(QuantLib::ext::make_shared<CommodityBasisPriceCurveWrapper>(
2505 orgBasisCurve, baseIndex->second.currentLink(), priceCurve));
2506 }
2507
2508 pts->setAdjustReferenceDate(false);
2509 pts->enableExtrapolation(allowsExtrapolation);
2510
2514 forward_as_tuple(commIdx));
2515 } catch (const std::exception& e) {
2516 processException(continueOnError, e, name, param.first, simDataWritten);
2517 }
2518 }
2519 break;
2520 }
2522 for (const auto& name : param.second.second) {
2523 bool simDataWritten = false;
2524 try {
2525 LOG(
"building commodity volatility for " << name);
2526
2527
2528 Handle<BlackVolTermStructure> baseVol = initMarket->commodityVolatility(name, configuration);
2529
2530 Handle<BlackVolTermStructure> newVol;
2531 bool stickyStrike =
parameters_->commodityVolSmileDynamics(name) ==
"StickyStrike";
2532 if (param.second.first) {
2533
2534
2535 vector<Real> moneyness = parameters->commodityVolMoneyness(name);
2536 QL_REQUIRE(!moneyness.empty(), "Commodity volatility moneyness for "
2537 << name << " should have at least one element.");
2538 sort(moneyness.begin(), moneyness.end());
2539 auto mIt = unique(moneyness.begin(), moneyness.end(),
2540 [](const Real& x, const Real& y) { return close(x, y); });
2541 QL_REQUIRE(mIt == moneyness.end(),
2542 "Commodity volatility moneyness values for " << name << " should be unique.");
2543
2544 vector<Period> expiries = parameters->commodityVolExpiries(name);
2545 QL_REQUIRE(!expiries.empty(), "Commodity volatility expiries for "
2546 << name << " should have at least one element.");
2547 sort(expiries.begin(), expiries.end());
2548 auto eIt = unique(expiries.begin(), expiries.end());
2549 QL_REQUIRE(eIt == expiries.end(),
2550 "Commodity volatility expiries for " << name << " should be unique.");
2551
2552
2553
2555
2556
2557
2558
2559
2560
2561 bool isSurface = moneyness.size() > 1;
2562 Handle<YieldTermStructure> yts;
2563 Handle<YieldTermStructure> priceYts;
2564
2565 if (isSurface) {
2566
2567 vector<Date> dates{
asof_};
2568 vector<Real> dfs{1.0};
2569
2570 auto discCurve =
discountCurve(priceCurve->currency().code(), configuration);
2571 for (const auto& expiry : expiries) {
2572 auto d =
asof_ + expiry;
2574 continue;
2575 dates.push_back(d);
2576 dfs.push_back(discCurve->discount(d, true));
2577 }
2578
2579 auto ytsPtr = QuantLib::ext::make_shared<DiscountCurve>(dates, dfs, discCurve->dayCounter());
2580 ytsPtr->enableExtrapolation();
2581 yts = Handle<YieldTermStructure>(ytsPtr);
2582 priceYts = Handle<YieldTermStructure>(
2583 QuantLib::ext::make_shared<PriceTermStructureAdapter>(priceCurve, ytsPtr));
2584 priceYts->enableExtrapolation();
2585 }
2586
2587
2588 using QuoteRow = vector<Handle<Quote>>;
2589 using QuoteMatrix = vector<QuoteRow>;
2590 QuoteMatrix quotes(moneyness.size(), QuoteRow(expiries.size()));
2591
2592
2593 vector<Date> expiryDates(expiries.size());
2594 vector<Time> expiryTimes(expiries.size());
2595 vector<Real> forwards(expiries.size());
2596
2597
2598 DayCounter dayCounter = baseVol->dayCounter();
2599 for (Size j = 0; j < expiries.size(); ++j) {
2600 Date d =
asof_ + expiries[j];
2601 expiryDates[j] = d;
2602 expiryTimes[j] = dayCounter.yearFraction(
asof_, d);
2603 forwards[j] = priceCurve->price(d);
2604 }
2605
2606
2607 Size index = 0;
2608 for (Size i = 0; i < moneyness.size(); ++i) {
2609 for (Size j = 0; j < expiries.size(); ++j) {
2610 Real strike = moneyness[i] * forwards[j];
2611 auto vol = baseVol->blackVol(expiryDates[j], strike);
2612 auto quote =
2614 simDataTmp.emplace(piecewise_construct, forward_as_tuple(param.first, name, index),
2615 forward_as_tuple(quote));
2617 absoluteSimDataTmp.emplace(piecewise_construct,
2618 forward_as_tuple(param.first, name, index),
2619 forward_as_tuple(vol));
2620 }
2621 quotes[i][j] = Handle<Quote>(quote);
2622 ++index;
2623 }
2624 }
2625
2626 writeSimData(simDataTmp, absoluteSimDataTmp, param.first, name, {moneyness, expiryTimes});
2627 simDataWritten = true;
2628
2629
2630 if (!isSurface) {
2631 DLOG(
"Ssm comm vol for " << name <<
" uses BlackVarianceCurve3.");
2633 newVol =
2634 Handle<BlackVolTermStructure>(QuantLib::ext::make_shared<SpreadedBlackVolatilityCurve>(
2635 Handle<BlackVolTermStructure>(baseVol), expiryTimes, quotes[0], true));
2636 } else {
2637 newVol = Handle<BlackVolTermStructure>(QuantLib::ext::make_shared<BlackVarianceCurve3>(
2638 0, NullCalendar(), baseVol->businessDayConvention(), dayCounter, expiryTimes,
2639 quotes[0], false));
2640 }
2641 } else {
2642 DLOG(
"Ssm comm vol for " << name <<
" uses BlackVarianceSurfaceMoneynessSpot.");
2643
2644 bool flatExtrapMoneyness = true;
2645 Handle<Quote> spot(QuantLib::ext::make_shared<SimpleQuote>(priceCurve->price(0)));
2647
2648 Handle<YieldTermStructure> initMarketYts =
2649 initMarket->discountCurve(priceCurve->currency().code(), configuration);
2650 Handle<QuantExt::PriceTermStructure> priceCurve =
2651 initMarket->commodityPriceCurve(name, configuration);
2652 Handle<YieldTermStructure> initMarketPriceYts(
2653 QuantLib::ext::make_shared<PriceTermStructureAdapter>(*priceCurve, *initMarketYts));
2654
2655 newVol = Handle<BlackVolTermStructure>(
2656 QuantLib::ext::make_shared<SpreadedBlackVolatilitySurfaceMoneynessForward>(
2657 Handle<BlackVolTermStructure>(baseVol), spot, expiryTimes, moneyness,
2658 quotes, Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(spot->value())),
2659 initMarketPriceYts, initMarketYts, priceYts, yts, stickyStrike));
2660 } else {
2661 newVol = Handle<BlackVolTermStructure>(
2662 QuantLib::ext::make_shared<BlackVarianceSurfaceMoneynessForward>(
2663 baseVol->calendar(), spot, expiryTimes, moneyness, quotes, dayCounter,
2664 priceYts, yts, stickyStrike, flatExtrapMoneyness));
2665 }
2666 }
2667
2668 } else {
2669 string decayModeString = parameters->commodityVolDecayMode();
2670 DLOG(
"Deterministic commodity volatilities with decay mode " << decayModeString <<
" for "
2671 << name);
2673
2674
2675 newVol = Handle<BlackVolTermStructure>(
2677 baseVol, 0, NullCalendar(), decayMode,
2679 }
2680
2681 newVol->setAdjustReferenceDate(false);
2682 newVol->enableExtrapolation(baseVol->allowsExtrapolation());
2685 forward_as_tuple(newVol));
2686
2687 DLOG(
"Commodity volatility curve built for " << name);
2688 } catch (const std::exception& e) {
2689 processException(continueOnError, e, name, param.first, simDataWritten);
2690 }
2691 }
2692 break;
2693
2695 for (const auto& name : param.second.second) {
2696 bool simDataWritten = false;
2697 try {
2698 LOG(
"Adding correlations for " << name <<
" from configuration " << configuration);
2699
2701 QL_REQUIRE(tokens.size() == 2, "not a valid correlation pair: " << name);
2702 pair<string, string> pair = std::make_pair(tokens[0], tokens[1]);
2703
2704 QuantLib::ext::shared_ptr<QuantExt::CorrelationTermStructure> corr;
2705 Handle<QuantExt::CorrelationTermStructure> baseCorr =
2706 initMarket->correlationCurve(pair.first, pair.second, configuration);
2707
2708 Handle<QuantExt::CorrelationTermStructure> ch;
2709 if (param.second.first) {
2710 Size n = parameters->correlationStrikes().size();
2711 Size m = parameters->correlationExpiries().size();
2712 vector<vector<Handle<Quote>>> quotes(n, vector<Handle<Quote>>(m, Handle<Quote>()));
2713 vector<Time> times(m);
2714 Calendar cal = baseCorr->calendar();
2715 DayCounter dc = baseCorr->dayCounter();
2716
2717 for (Size i = 0; i < n; i++) {
2718 Real strike = parameters->correlationStrikes()[i];
2719
2720 for (Size j = 0; j < m; j++) {
2721
2722 Size idx = i * m + j;
2723 times[j] = dc.yearFraction(
asof_,
asof_ + parameters->correlationExpiries()[j]);
2724 Real correlation =
2725 baseCorr->correlation(
asof_ + parameters->correlationExpiries()[j], strike);
2726 QuantLib::ext::shared_ptr<SimpleQuote> q(
2728 simDataTmp.emplace(
2729 std::piecewise_construct,
2731 std::forward_as_tuple(q));
2733 absoluteSimDataTmp.emplace(
2734 std::piecewise_construct,
2736 std::forward_as_tuple(correlation));
2737 }
2738 quotes[i][j] = Handle<Quote>(q);
2739 }
2740 }
2741
2742 writeSimData(simDataTmp, absoluteSimDataTmp, param.first, name,
2743 {parameters->correlationStrikes(), times});
2744 simDataWritten = true;
2745
2746 if (n == 1 && m == 1) {
2748 ch = Handle<QuantExt::CorrelationTermStructure>(
2749 QuantLib::ext::make_shared<QuantExt::SpreadedCorrelationCurve>(baseCorr, times,
2750 quotes[0]));
2751 } else {
2752 ch = Handle<QuantExt::CorrelationTermStructure>(QuantLib::ext::make_shared<FlatCorrelation>(
2753 baseCorr->settlementDays(), cal, quotes[0][0], dc));
2754 }
2755 } else if (n == 1) {
2757 ch = Handle<QuantExt::CorrelationTermStructure>(
2758 QuantLib::ext::make_shared<QuantExt::SpreadedCorrelationCurve>(baseCorr, times,
2759 quotes[0]));
2760 } else {
2761 ch = Handle<QuantExt::CorrelationTermStructure>(
2763 cal));
2764 }
2765 } else {
2766 QL_FAIL("only atm or flat correlation termstructures currently supported");
2767 }
2768
2769 ch->enableExtrapolation(baseCorr->allowsExtrapolation());
2770 } else {
2771 ch = Handle<QuantExt::CorrelationTermStructure>(*baseCorr);
2772 }
2773
2774 ch->setAdjustReferenceDate(false);
2776 } catch (const std::exception& e) {
2777 processException(continueOnError, e, name, param.first, simDataWritten);
2778 }
2779 }
2780 break;
2781
2783 for (const auto& name : param.second.second) {
2784 bool simDataWritten = false;
2785 try {
2786 DLOG(
"Adding cpr " << name <<
" from configuration " << configuration);
2787 Real v = initMarket->cpr(name, configuration)->value();
2790 auto m = [v](Real x) { return x + v; };
2792 Handle<Quote>(QuantLib::ext::make_shared<DerivedQuote<decltype(m)>>(
2793 Handle<Quote>(q), m))));
2794 } else {
2796 }
2797
2798 if (param.second.first) {
2799 simDataTmp.emplace(std::piecewise_construct, std::forward_as_tuple(param.first, name),
2800 std::forward_as_tuple(q));
2802 absoluteSimDataTmp.emplace(std::piecewise_construct,
2803 std::forward_as_tuple(param.first, name),
2804 std::forward_as_tuple(v));
2805 }
2806 }
2807 writeSimData(simDataTmp, absoluteSimDataTmp, param.first, name, {});
2808 simDataWritten = true;
2809 } catch (const std::exception& e) {
2810 processException(continueOnError, e, name, param.first, simDataWritten);
2811 }
2812 }
2813 break;
2814
2816
2817 break;
2818
2820
2821 break;
2822
2824 WLOG(
"RiskFactorKey None not yet implemented");
2825 break;
2826 }
2827
2828 if (!param.second.second.empty()) {
2829 LOG(
"built " << std::left << std::setw(25) << param.first << std::right << std::setw(10)
2830 << param.second.second.size() << std::setprecision(3) << std::setw(15)
2831 << static_cast<double>(timer.elapsed().wall) / 1E6 << " ms");
2832 }
2833
2834 } catch (const std::exception& e) {
2836 ore::data::StructuredMessage::Group::Curve, e.what(),
2837 {{"exceptionType", "ScenarioSimMarket top level catch - this should never happen, "
2838 "contact dev. Results are likely wrong or incomplete."}})
2840 processException(continueOnError, e);
2841 }
2842 }
2843
2844
2845 DLOG(
"building swap indices...");
2846 for (const auto& it : parameters->swapIndices()) {
2848 }
2849
2852 QL_REQUIRE(recastedScenario != nullptr, "ScenarioSimMarke: Offset Scenario couldn't applied");
2853 for (
auto& [key, quote] :
simData_) {
2854 if (recastedScenario->has(key)) {
2855 quote->setValue(recastedScenario->get(key));
2856 } else {
2857 QL_FAIL("ScenarioSimMarket: Offset Scenario doesnt contain key "
2858 << key
2859 << ". Internal error, possibly an internal error in the recastScenario method, contact dev.");
2860 }
2861 }
2864 QL_REQUIRE(recastedScenario != nullptr, "ScenarioSimMarke: Offset Scenario couldn't applied");
2865 for (
auto& [key, data] :
simData_) {
2866 if (recastedScenario->has(key)) {
2868 data->setValue(shift);
2870 } else {
2871 QL_FAIL("ScenarioSimMarket: Offset Scenario doesnt contain key "
2872 << key
2873 << ". Internal error, possibly an internal error in the recastScenario method, contact dev.");
2874 }
2875 }
2878 QL_REQUIRE(recastedScenario != nullptr, "ScenarioSimMarke: Offset Scenario couldn't applied");
2879 for (
auto& [key, quote] :
simData_) {
2880 if (recastedScenario->has(key)) {
2882 } else {
2883 QL_FAIL("ScenarioSimMarket: Offset Scenario doesnt contain key "
2884 << key
2885 << ". Internal error, possibly an internal error in the recastScenario method, contact dev.");
2886 }
2887 }
2890 QL_REQUIRE(recastedScenario != nullptr, "ScenarioSimMarke: Offset Scenario couldn't applied");
2891 for (
auto& [key, quote] :
simData_) {
2892 if (recastedScenario->has(key)) {
2893 quote->setValue(recastedScenario->get(key));
2896 } else {
2897 QL_FAIL("ScenarioSimMarket: Offset Scenario doesnt contain key "
2898 << key
2899 << ". Internal error, possibly an internal error in the recastScenario method, contact dev.");
2900 }
2901 }
2902 }
2903
2904 LOG(
"building base scenario");
2905 auto tmp = QuantLib::ext::make_shared<SimpleScenario>(initMarket->asofDate(), "BASE", 1.0);
2907 for (
auto const& data :
simData_) {
2908 tmp->add(
data.first,
data.second->value());
2909 }
2910 tmp->setAbsolute(true);
2912 tmp->setCoordinates(type, name, coordinates);
2913 }
2915 } else {
2916 auto tmpAbs = QuantLib::ext::make_shared<SimpleScenario>(initMarket->asofDate(), "BASE", 1.0);
2917 for (
auto const& data :
simData_) {
2918 tmp->add(
data.first,
data.second->value());
2919 }
2921 tmpAbs->add(
data.first,
data.second);
2922 }
2923 tmp->setAbsolute(false);
2924 tmpAbs->setAbsolute(true);
2926 tmp->setCoordinates(type, name, coordinates);
2927 tmpAbs->setCoordinates(type, name, coordinates);
2928 }
2931 }
2932 LOG(
"building base scenario done");
2933}
static void populateVolMatrix(const QuantLib::Handle< QuantLib::BlackVolTermStructure > &termStructre, std::vector< std::vector< Handle< QuantLib::Quote > > > "esToPopulate, const std::vector< Real > ×, const std::vector< Real > &stdDevPoints, const QuantLib::Interpolation &forwardCurve, const QuantLib::Interpolation atmVolCurve)
MakeOISCapFloor & withSettlementDays(Natural settlementDays)
MakeOISCapFloor & withTelescopicValueDates(bool telescopicValueDates)
boost::shared_ptr< SwaptionVolatilityStructure > convert() const
@ YoYInflationCapFloorVolatility
@ ZeroInflationCapFloorVolatility
std::map< RiskFactorKey, QuantLib::ext::shared_ptr< SimpleQuote > > simData_
QuantLib::ext::shared_ptr< ScenarioFilter > filter_
bool addSwapIndexToSsm(const std::string &indexName, const bool continueOnError)
QuantLib::ext::shared_ptr< FixingManager > fixingManager_
QuantLib::Handle< QuantLib::YieldTermStructure > getYieldCurve(const std::string &yieldSpecId, const ore::data::TodaysMarketParameters &todaysMarketParams, const std::string &configuration, const QuantLib::ext::shared_ptr< ore::data::Market > &market=nullptr) const
bool useSpreadedTermStructures_
QuantLib::ext::shared_ptr< Scenario > baseScenario_
const QuantLib::ext::shared_ptr< ScenarioSimMarketParameters > parameters_
QuantLib::ext::shared_ptr< Scenario > baseScenarioAbsolute_
void addYieldCurve(const QuantLib::ext::shared_ptr< Market > &initMarket, const std::string &configuration, const RiskFactorKey::KeyType rf, const string &key, const vector< Period > &tenors, bool &simDataWritten, bool simulate=true, bool spreaded=false)
bool allowPartialScenarios_
QuantLib::ext::shared_ptr< Scenario > offsetScenario_
const QuantLib::ext::shared_ptr< FixingManager > & fixingManager() const override
Return the fixing manager.
std::set< std::tuple< RiskFactorKey::KeyType, std::string, std::vector< std::vector< Real > > > > coordinatesData_
IborFallbackConfig iborFallbackConfig_
std::map< RiskFactorKey, Real > absoluteSimData_
void writeSimData(std::map< RiskFactorKey, QuantLib::ext::shared_ptr< SimpleQuote > > &simDataTmp, std::map< RiskFactorKey, Real > &absoluteSimDataTmp, const RiskFactorKey::KeyType keyType, const std::string &name, const std::vector< std::vector< Real > > &coordinates)
const FallbackData & fallbackData(const string &iborIndex) const
bool useRfrCurveInSimulationMarket() const
bool isIndexReplaced(const string &iborIndex, const QuantLib::Date &asof=QuantLib::Date::maxDate()) const
Handle< Quote > fxSpot(const string &ccypair, const string &configuration=Market::defaultConfiguration) const
QuantLib::Handle< QuantExt::FxIndex > fxIndex(const string &fxIndex, const string &configuration=Market::defaultConfiguration) const
static const string defaultConfiguration
Handle< YieldTermStructure > discountCurve(const string &ccy, const string &configuration=Market::defaultConfiguration) const
map< pair< string, string >, Handle< OptionletVolatilityStructure > > capFloorCurves_
string shortSwapIndexBase(const string &key, const string &configuration=Market::defaultConfiguration) const override
string swapIndexBase(const string &key, const string &configuration=Market::defaultConfiguration) const override
virtual Handle< ZeroInflationIndex > zeroInflationIndex(const string &indexName, const string &configuration=Market::defaultConfiguration) const override
Handle< QuantExt::EquityIndex2 > equityCurve(const string &eqName, const string &configuration=Market::defaultConfiguration) const override
map< tuple< string, string, string >, Handle< QuantExt::CorrelationTermStructure > > correlationCurves_
map< pair< string, string >, QuantLib::Handle< QuantExt::EquityIndex2 > > equityCurves_
map< pair< string, string >, Handle< CPIVolatilitySurface > > cpiInflationCapFloorVolatilitySurfaces_
map< pair< string, string >, Handle< QuantExt::InflationIndexObserver > > baseCpis_
map< pair< string, string >, Handle< BlackVolTermStructure > > fxVols_
QuantLib::ext::shared_ptr< FXTriangulation > fx_
map< pair< string, string >, QuantLib::Handle< QuantExt::CommodityIndex > > commodityIndices_
map< pair< string, string >, Handle< QuantExt::CreditCurve > > defaultCurves_
map< pair< string, string >, Handle< IborIndex > > iborIndices_
map< pair< string, string >, Handle< YoYOptionletVolatilitySurface > > yoyCapFloorVolSurfaces_
Handle< QuantExt::CreditCurve > defaultCurve(const string &, const string &configuration=Market::defaultConfiguration) const override
map< pair< string, string >, Handle< YoYInflationIndex > > yoyInflationIndices_
map< pair< string, string >, Handle< QuantExt::CreditVolCurve > > cdsVols_
map< pair< string, string >, Handle< Quote > > equitySpots_
map< pair< string, string >, Handle< QuantLib::SwaptionVolatilityStructure > > swaptionCurves_
map< pair< string, string >, Handle< QuantExt::BaseCorrelationTermStructure > > baseCorrelations_
map< pair< string, string >, Handle< Quote > > cprs_
map< pair< string, string >, Handle< Quote > > recoveryRates_
QuantLib::Handle< QuantExt::PriceTermStructure > commodityPriceCurve(const string &commodityName, const string &configuration=Market::defaultConfiguration) const override
Handle< Quote > equitySpot(const string &eqName, const string &configuration=Market::defaultConfiguration) const override
map< pair< string, string >, Handle< ZeroInflationIndex > > zeroInflationIndices_
Handle< SwapIndex > swapIndex(const string &indexName, const string &configuration=Market::defaultConfiguration) const override
map< pair< string, string >, pair< string, string > > swaptionIndexBases_
map< pair< string, string >, Handle< BlackVolTermStructure > > equityVols_
virtual Handle< YoYInflationIndex > yoyInflationIndex(const string &indexName, const string &configuration=Market::defaultConfiguration) const override
map< pair< string, string >, Handle< QuantLib::SwaptionVolatilityStructure > > yieldVolCurves_
map< pair< string, string >, Handle< Quote > > securitySpreads_
Handle< YieldTermStructure > yieldCurve(const YieldCurveType &type, const string &ccy, const string &configuration=Market::defaultConfiguration) const override
Handle< IborIndex > iborIndex(const string &indexName, const string &configuration=Market::defaultConfiguration) const override
map< pair< string, string >, QuantLib::Handle< QuantLib::BlackVolTermStructure > > commodityVols_
map< pair< string, string >, std::pair< string, QuantLib::Period > > capFloorIndexBase_
SafeStack< ValueType > value
QuantLib::ext::shared_ptr< CurveSpec > parseCurveSpec(const string &s)
QuantLib::ext::shared_ptr< ZeroInflationIndex > parseZeroInflationIndex(const string &s, const Handle< ZeroInflationTermStructure > &h=Handle< ZeroInflationTermStructure >())
Calendar parseCalendar(const string &s)
QuantLib::ext::shared_ptr< IborIndex > parseIborIndex(const string &s, const Handle< YieldTermStructure > &h=Handle< YieldTermStructure >())
QuantLib::Date fixingDate(const QuantLib::Date &d, const QuantLib::Period obsLag, const QuantLib::Frequency freq, bool interpolated)
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
RandomVariable log(RandomVariable x)
Real getDifferenceScenario(const RiskFactorKey::KeyType keyType, const Real v1, const Real v2)
QuantLib::ext::shared_ptr< Scenario > recastScenario(const QuantLib::ext::shared_ptr< Scenario > &scenario, const std::map< std::pair< RiskFactorKey::KeyType, std::string >, std::vector< std::vector< Real > > > &oldCoordinates, const std::map< std::pair< RiskFactorKey::KeyType, std::string >, std::vector< std::vector< Real > > > &newCoordinates)
Real addDifferenceToScenario(const RiskFactorKey::KeyType keyType, const Real v, const Real d)
std::vector< std::string > getCorrelationTokens(const std::string &name)
Size size(const ValueType &v)
std::string to_string(const LocationInfo &l)
QuantLib::ext::shared_ptr< QuantExt::CommodityIndex > parseCommodityIndex(const string &name, bool hasPrefix, const Handle< PriceTermStructure > &ts, const Calendar &cal, const bool enforceFutureIndex)
vector< string > curveConfigs