26#include <ql/math/comparison.hpp>
27#include <ql/time/calendars/target.hpp>
28#include <ql/time/daycounters/actualactual.hpp>
44 const QuantLib::ext::shared_ptr<SensitivityScenarioData>& sensitivityData,
const QuantLib::ext::shared_ptr<Scenario>& baseScenario,
45 const QuantLib::ext::shared_ptr<ScenarioSimMarketParameters>& simMarketData,
46 const QuantLib::ext::shared_ptr<ScenarioSimMarket>& simMarket,
47 const QuantLib::ext::shared_ptr<ScenarioFactory>& sensiScenarioFactory,
const bool overrideTenors,
48 const std::string& sensitivityTemplate,
const bool continueOnError,
49 const QuantLib::ext::shared_ptr<Scenario>& baseScenarioAbsolute)
51 sensiScenarioFactory_(sensiScenarioFactory), sensitivityTemplate_(sensitivityTemplate),
52 overrideTenors_(overrideTenors), continueOnError_(continueOnError),
53 baseScenarioAbsolute_(baseScenarioAbsolute == nullptr ? baseScenario : baseScenarioAbsolute) {
55 QL_REQUIRE(
sensitivityData_,
"SensitivityScenarioGenerator: sensitivityData is null");
61 findFactor(
const string& factor) : factor_(factor) {}
64 const bool operator()(
const std::pair<string, string>& p)
const {
65 return (p.first == factor_) || (p.second == factor_);
70 findPair(
const string& first,
const string& second) : first_(first), second_(second) {}
74 const bool operator()(
const std::pair<string, string>& p)
const {
75 return (p.first == first_ && p.second == second_) || (p.second == first_ && p.first == second_);
79bool close(
const Real& t_1,
const Real& t_2) {
return QuantLib::close(t_1, t_2); }
81bool vectorEqual(
const vector<Real>& v_1,
const vector<Real>& v_2) {
82 return (v_1.size() == v_2.size() && std::equal(v_1.begin(), v_1.end(), v_2.begin(),
close));
89 "SensitivityScenarioGenerator::generateScenarios(): if gamma computation is disabled, the cross gamma "
90 "filter must be empty");
192 DLOG(
"Fill maps linking factors with RiskFactorKeys");
200 DLOG(
"KeyToFactor map: " << key <<
" to " << factor);
205 for (Size i = 0; i <
scenarios_.size(); ++i) {
207 if (iDesc.
type() != ScenarioDescription::Type::Up)
216 for (Size j = i + 1; j <
scenarios_.size(); ++j) {
218 if (jDesc.
type() != ScenarioDescription::Type::Up)
224 findPair(iKeyName, jKeyName)) ==
sensitivityData_->crossGammaFilter().end())
228 QuantLib::ext::shared_ptr<Scenario> crossScenario =
237 crossScenario->add(k, v1 + v2 - b);
243 DLOG(
"Sensitivity scenario # " <<
scenarios_.size() <<
", label " << crossScenario->label() <<
" created");
247 LOG(
"sensitivity scenario generator finished generating scenarios.");
251bool tryGetBaseScenarioValue(
const QuantLib::ext::shared_ptr<Scenario> baseScenario,
const RiskFactorKey& key, Real& value,
252 const bool continueOnError) {
254 value = baseScenario->get(key);
256 }
catch (
const std::exception& e) {
257 if (continueOnError) {
258 ALOG(
"skip scenario generation for key " << key <<
": " << e.what());
270 return data.shiftType;
276 return data.shiftSize;
282 return data.shiftScheme;
313 string foreign = sensi_fx.first.substr(0, 3);
314 string domestic = sensi_fx.first.substr(3);
315 QL_REQUIRE((domestic == baseCcy) || (foreign == baseCcy),
316 "SensitivityScenarioGenerator does not support cross FX pairs("
317 << sensi_fx.first <<
", but base currency is " << baseCcy <<
")");
322 WLOG(
"FX pair " << sim_fx <<
" in simmarket is not included in sensitivities analysis");
326 string ccypair = sensi_fx.first;
339 QuantLib::ext::shared_ptr<Scenario> scenario =
342 Real newRate = relShift ? rate * (1.0 +
size) : (rate +
size);
343 scenario->add(key,
sensitivityData_->useSpreadedTermStructures() ? newRate / rate : newRate);
351 DLOG(
"Sensitivity scenario # " <<
scenarios_.size() <<
", label " << scenario->label()
352 <<
" created: " << newRate);
354 DLOG(
"FX scenarios done");
363 WLOG(
"Equity " << sim_equity <<
" in simmarket is not included in sensitivities analysis");
367 string equity = e.first;
380 QuantLib::ext::shared_ptr<Scenario> scenario =
383 Real newRate = relShift ? rate * (1.0 +
size) : (rate +
size);
385 scenario->add(key,
sensitivityData_->useSpreadedTermStructures() ? newRate / rate : newRate);
392 DLOG(
"Sensitivity scenario # " <<
scenarios_.size() <<
", label " << scenario->label()
393 <<
" created: " << newRate);
395 DLOG(
"Equity scenarios done");
399void checkShiftTenors(
const std::vector<Period>& effective,
const std::vector<Period>& config,
400 const std::string& curveLabel,
bool continueOnError =
false) {
401 if (effective.size() != config.size()) {
402 string message =
"mismatch between effective shift tenors (" + std::to_string(effective.size()) +
403 ") and configured shift tenors (" + std::to_string(config.size()) +
") for " + curveLabel;
405 for (
auto const& p : effective)
406 ALOG(
"effective tenor: " << p);
407 for (
auto const& p : config)
408 ALOG(
"config tenor: " << p);
409 if (!continueOnError)
421 WLOG(
"Currency " << sim_ccy <<
" in simmarket is not included in sensitivities analysis");
426 string ccy = c.first;
430 }
catch (
const std::exception& e) {
431 ALOG(
"skip scenario generation for discount curve " << ccy <<
": " << e.what());
435 std::vector<Real> zeros(n_ten);
436 std::vector<Real> times(n_ten);
438 std::vector<Real> shiftedZeros(n_ten);
443 DayCounter dc = Actual365Fixed();
446 dc = s->discountCurve(ccy)->dayCounter();
448 QL_FAIL(
"Internal error: could not lock simMarket. Contact dev.");
450 }
catch (
const std::exception&) {
451 WLOG(
"Day counter lookup in simulation market failed for discount curve " << ccy <<
", using default A365");
456 for (Size j = 0; j < n_ten; ++j) {
458 times[j] = dc.yearFraction(
asof, d);
462 zeros[j] = -std::log(quote) / times[j];
471 std::vector<Time> shiftTimes(shiftTenors.size());
472 for (Size j = 0; j < shiftTenors.size(); ++j)
473 shiftTimes[j] = dc.yearFraction(
asof,
asof + shiftTenors[j]);
475 QL_REQUIRE(shiftTenors.size() > 0,
"Discount shift tenors not specified");
478 bool validShiftSize =
vectorEqual(times, shiftTimes);
480 for (Size j = 0; j < shiftTenors.size(); ++j) {
482 QuantLib::ext::shared_ptr<Scenario> scenario =
485 applyShift(j, shiftSize, up, shiftType, shiftTimes, zeros, times, shiftedZeros,
true);
488 for (Size k = 0; k < n_ten; ++k) {
492 Real shiftedDiscount =
exp(-shiftedZeros[k] * times[k]);
494 Real discount =
exp(-zeros[k] * times[k]);
495 scenario->add(key, shiftedDiscount / discount);
497 scenario->add(key, shiftedDiscount);
502 if (validShiftSize && j == k) {
511 DLOG(
"Sensitivity scenario # " <<
scenarios_.size() <<
", label " << scenario->label() <<
" created");
515 DLOG(
"Discount curve scenarios done");
523 WLOG(
"Index " << sim_idx <<
" in simmarket is not included in sensitivities analysis");
528 string indexName = idx.first;
532 }
catch (
const std::exception& e) {
533 ALOG(
"skip scenario generation for index curve " << indexName <<
": " << e.what());
537 std::vector<Real> zeros(n_ten);
538 std::vector<Real> times(n_ten);
540 std::vector<Real> shiftedZeros(n_ten);
547 DayCounter dc = Actual365Fixed();
550 dc = s->iborIndex(indexName)->forwardingTermStructure()->dayCounter();
552 QL_FAIL(
"Internal error: could not lock simMarket. Contact dev.");
554 }
catch (
const std::exception&) {
555 WLOG(
"Day counter lookup in simulation market failed for index " << indexName <<
", using default A365");
560 for (Size j = 0; j < n_ten; ++j) {
562 times[j] = dc.yearFraction(
asof, d);
565 zeros[j] = -std::log(quote) / times[j];
574 std::vector<Time> shiftTimes(shiftTenors.size());
575 for (Size j = 0; j < shiftTenors.size(); ++j)
576 shiftTimes[j] = dc.yearFraction(
asof,
asof + shiftTenors[j]);
578 QL_REQUIRE(shiftTenors.size() > 0,
"Index shift tenors not specified");
581 bool validShiftSize =
vectorEqual(times, shiftTimes);
583 for (Size j = 0; j < shiftTenors.size(); ++j) {
585 QuantLib::ext::shared_ptr<Scenario> scenario =
589 applyShift(j, shiftSize, up, shiftType, shiftTimes, zeros, times, shiftedZeros,
true);
592 for (Size k = 0; k < n_ten; ++k) {
595 Real shiftedDiscount =
exp(-shiftedZeros[k] * times[k]);
597 Real discount =
exp(-zeros[k] * times[k]);
598 scenario->add(key, shiftedDiscount / discount);
600 scenario->add(key, shiftedDiscount);
604 if (validShiftSize && j == k) {
613 DLOG(
"Sensitivity scenario # " <<
scenarios_.size() <<
", label " << scenario->label()
614 <<
" created for indexName " << indexName);
618 DLOG(
"Index curve scenarios done");
627 WLOG(
"Yield Curve " << sim_yc <<
" in simmarket is not included in sensitivities analysis");
632 string name = y.first;
636 }
catch (
const std::exception& e) {
637 ALOG(
"skip scenario generation for yield curve " <<
name <<
": " << e.what());
641 std::vector<Real> zeros(n_ten);
642 std::vector<Real> times(n_ten);
644 std::vector<Real> shiftedZeros(n_ten);
649 DayCounter dc = Actual365Fixed();
652 dc = s->yieldCurve(
name)->dayCounter();
654 QL_FAIL(
"Internal error: could not lock simMarket. Contact dev.");
656 }
catch (
const std::exception&) {
657 WLOG(
"Day counter lookup in simulation market failed for yield curve " <<
name <<
", using default A365");
662 for (Size j = 0; j < n_ten; ++j) {
664 times[j] = dc.yearFraction(
asof, d);
667 zeros[j] = -std::log(quote) / times[j];
676 std::vector<Time> shiftTimes(shiftTenors.size());
677 for (Size j = 0; j < shiftTenors.size(); ++j)
678 shiftTimes[j] = dc.yearFraction(
asof,
asof + shiftTenors[j]);
680 QL_REQUIRE(shiftTenors.size() > 0,
"Discount shift tenors not specified");
683 bool validShiftSize =
vectorEqual(times, shiftTimes);
685 for (Size j = 0; j < shiftTenors.size(); ++j) {
687 QuantLib::ext::shared_ptr<Scenario> scenario =
691 applyShift(j, shiftSize, up, shiftType, shiftTimes, zeros, times, shiftedZeros,
true);
694 for (Size k = 0; k < n_ten; ++k) {
695 Real shiftedDiscount =
exp(-shiftedZeros[k] * times[k]);
698 Real discount =
exp(-zeros[k] * times[k]);
699 scenario->add(key, shiftedDiscount / discount);
701 scenario->add(key, shiftedDiscount);
705 if (validShiftSize && j == k) {
714 DLOG(
"Sensitivity scenario # " <<
scenarios_.size() <<
", label " << scenario->label() <<
" created");
718 DLOG(
"Yield curve scenarios done");
728 WLOG(
"Equity " << sim <<
" in simmarket is not included in dividend yield sensitivity analysis");
733 string name = d.first;
737 }
catch (
const std::exception& e) {
738 ALOG(
"skip scenario generation for div yield " <<
name <<
": " << e.what());
742 std::vector<Real> zeros(n_ten);
743 std::vector<Real> times(n_ten);
745 std::vector<Real> shiftedZeros(n_ten);
750 DayCounter dc = Actual365Fixed();
753 dc = s->equityDividendCurve(
name)->dayCounter();
755 QL_FAIL(
"Internal error: could not lock simMarket. Contact dev.");
757 }
catch (
const std::exception&) {
758 WLOG(
"Day counter lookup in simulation market failed for dividend yield curve " <<
name
759 <<
", using default A365");
764 for (Size j = 0; j < n_ten; ++j) {
766 times[j] = dc.yearFraction(
asof, d);
769 zeros[j] = -std::log(quote) / times[j];
778 std::vector<Time> shiftTimes(shiftTenors.size());
779 for (Size j = 0; j < shiftTenors.size(); ++j)
780 shiftTimes[j] = dc.yearFraction(
asof,
asof + shiftTenors[j]);
782 QL_REQUIRE(shiftTenors.size() > 0,
"Discount shift tenors not specified");
785 bool validShiftSize =
vectorEqual(times, shiftTimes);
787 for (Size j = 0; j < shiftTenors.size(); ++j) {
789 QuantLib::ext::shared_ptr<Scenario> scenario =
793 applyShift(j, shiftSize, up, shiftType, shiftTimes, zeros, times, shiftedZeros,
true);
796 for (Size k = 0; k < n_ten; ++k) {
797 Real shiftedDiscount =
exp(-shiftedZeros[k] * times[k]);
800 Real discount =
exp(-zeros[k] * times[k]);
801 scenario->add(key, shiftedDiscount / discount);
803 scenario->add(key, shiftedDiscount);
807 if (validShiftSize && j == k) {
816 DLOG(
"Sensitivity scenario # " <<
scenarios_.size() <<
", label " << scenario->label() <<
" created");
820 DLOG(
"Dividend yield curve scenarios done");
829 WLOG(
"FX pair " << sim_fx <<
" in simmarket is not included in sensitivities analysis");
834 string ccyPair = f.first;
835 QL_REQUIRE(ccyPair.length() == 6,
"invalid ccy pair length");
840 }
catch (
const std::exception& e) {
841 ALOG(
"skip scenario generation for fx vol " << ccyPair <<
": " << e.what());
844 std::vector<Real> times(n_fxvol_exp);
845 Size n_fxvol_strikes;
846 vector<Real> vol_strikes;
857 vector<vector<Real>> values(n_fxvol_exp, vector<Real>(n_fxvol_strikes, 0.0));
860 vector<vector<Real>> shiftedValues(n_fxvol_exp, vector<Real>(n_fxvol_strikes, 0.0));
866 std::vector<Period> shiftTenors =
data.shiftExpiries;
867 std::vector<Real> shiftStrikes =
data.shiftStrikes;
868 std::vector<Time> shiftTimes(shiftTenors.size());
870 QL_REQUIRE(shiftTenors.size() > 0,
"FX vol shift tenors not specified");
872 DayCounter dc = Actual365Fixed();
875 dc = s->fxVol(ccyPair)->dayCounter();
877 QL_FAIL(
"Internal error: could not lock simMarket. Contact dev.");
879 }
catch (
const std::exception&) {
880 WLOG(
"Day counter lookup in simulation market failed for fx vol surface " << ccyPair
881 <<
", using default A365");
884 for (Size j = 0; j < n_fxvol_exp; ++j) {
886 times[j] = dc.yearFraction(
asof, d);
887 for (Size k = 0; k < n_fxvol_strikes; k++) {
888 Size idx = k * n_fxvol_exp + j;
896 for (Size j = 0; j < shiftTenors.size(); ++j)
897 shiftTimes[j] = dc.yearFraction(
asof,
asof + shiftTenors[j]);
901 (vol_strikes.size() == 1 && shiftStrikes.size() == 1));
903 for (Size j = 0; j < shiftTenors.size(); ++j) {
904 for (Size strikeBucket = 0; strikeBucket < shiftStrikes.size(); ++strikeBucket) {
905 QuantLib::ext::shared_ptr<Scenario> scenario =
908 applyShift(j, strikeBucket, shiftSize, up, shiftType, shiftTimes, shiftStrikes, times, vol_strikes,
909 values, shiftedValues,
true);
911 for (Size k = 0; k < n_fxvol_strikes; ++k) {
912 for (Size l = 0; l < n_fxvol_exp; ++l) {
913 Size idx = k * n_fxvol_exp + l;
917 scenario->add(key, shiftedValues[l][k] - values[l][k]);
919 scenario->add(key, shiftedValues[l][k]);
923 if (validShiftSize && j == l && strikeBucket == k) {
934 DLOG(
"Sensitivity scenario # " <<
scenarios_.size() <<
", label " << scenario->label() <<
" created");
938 DLOG(
"FX vol scenarios done");
947 WLOG(
"Equity " << sim_equity <<
" in simmarket is not included in sensitivities analysis");
952 string equity = e.first;
960 }
catch (
const std::exception& e) {
961 ALOG(
"skip scenario generation for eq vol " << equity <<
": " << e.what());
964 Size n_eqvol_strikes;
965 vector<Real> vol_strikes;
971 n_eqvol_strikes =
simMarketData_->equityVolMoneyness(equity).size();
974 n_eqvol_strikes =
simMarketData_->equityVolStandardDevs(equity).size();
978 vector<vector<Real>> values(n_eqvol_strikes, vector<Real>(n_eqvol_exp, 0.0));
979 vector<Real> times(n_eqvol_exp);
982 vector<vector<Real>> shiftedValues(n_eqvol_strikes, vector<Real>(n_eqvol_exp, 0.0));
985 vector<Period> shiftTenors =
data.shiftExpiries;
986 std::vector<Real> shiftStrikes =
data.shiftStrikes;
987 vector<Time> shiftTimes(shiftTenors.size());
989 QL_REQUIRE(shiftTenors.size() > 0,
"Equity vol shift tenors not specified");
990 DayCounter dc = Actual365Fixed();
993 dc = s->equityVol(equity)->dayCounter();
995 QL_FAIL(
"Internal error: could not lock simMarket. Contact dev.");
997 }
catch (
const std::exception&) {
998 WLOG(
"Day counter lookup in simulation market failed for equity vol surface " << equity
999 <<
", using default A365");
1002 for (Size j = 0; j < n_eqvol_exp; ++j) {
1004 times[j] = dc.yearFraction(
asof, d);
1005 for (Size k = 0; k < n_eqvol_strikes; k++) {
1006 Size idx = k * n_eqvol_exp + j;
1014 for (Size j = 0; j < shiftTenors.size(); ++j) {
1015 shiftTimes[j] = dc.yearFraction(
asof,
asof + shiftTenors[j]);
1020 bool validShiftSize =
vectorEqual(times, shiftTimes);
1021 validShiftSize = validShiftSize &&
vectorEqual(vol_strikes, shiftStrikes);
1023 for (Size j = 0; j < shiftTenors.size(); ++j) {
1024 for (Size strikeBucket = 0; strikeBucket < shiftStrikes.size(); ++strikeBucket) {
1025 QuantLib::ext::shared_ptr<Scenario> scenario =
1028 applyShift(strikeBucket, j, shiftSize, up, shiftType, shiftStrikes, shiftTimes, vol_strikes, times,
1029 values, shiftedValues,
true);
1032 for (Size k = 0; k < n_eqvol_strikes; ++k) {
1033 for (Size l = 0; l < n_eqvol_exp; l++) {
1034 Size idx = k * n_eqvol_exp + l;
1038 scenario->add(key, shiftedValues[k][l] - values[k][l]);
1040 scenario->add(key, shiftedValues[k][l]);
1044 if (validShiftSize && j == l && k == strikeBucket) {
1055 DLOG(
"Sensitivity scenario # " <<
scenarios_.size() <<
", label " << scenario->label() <<
" created");
1059 DLOG(
"Equity vol scenarios done");
1069 map<string, SensitivityScenarioData::GenericYieldVolShiftData> shiftData;
1070 function<Size(
string)> get_n_term;
1071 function<Size(
string)> get_n_expiry;
1072 function<vector<Real>(
string)> getVolStrikes;
1073 function<vector<Period>(
string)> getVolExpiries;
1074 function<vector<Period>(
string)> getVolTerms;
1075 function<string(
string)> getDayCounter;
1077 getScenarioDescription;
1079 if (rfType == RFType::SwaptionVolatility) {
1082 get_n_term = [
this](
const string& k) {
return simMarketData_->swapVolTerms(k).size(); };
1083 get_n_expiry = [
this](
const string& k) {
return simMarketData_->swapVolExpiries(k).size(); };
1084 getVolStrikes = [
this](
const string& k) {
return simMarketData_->swapVolStrikeSpreads(k); };
1085 getVolExpiries = [
this](
const string& k) {
return simMarketData_->swapVolExpiries(k); };
1086 getVolTerms = [
this](
const string& k) {
return simMarketData_->swapVolTerms(k); };
1087 getDayCounter = [
this](
const string& k) {
1090 return to_string(s->swaptionVol(k)->dayCounter());
1092 QL_FAIL(
"Internal error: could not lock simMarket. Contact dev.");
1094 }
catch (
const std::exception&) {
1095 WLOG(
"Day counter lookup in simulation market failed for swaption vol '" << k
1096 <<
"', using default A365");
1097 return std::string(
"A365F");
1100 getScenarioDescription = [
this](
string q, Size n, Size m, Size k,
bool up,
1104 }
else if (rfType == RFType::YieldVolatility) {
1107 get_n_term = [
this](
const string& k) {
return simMarketData_->yieldVolTerms().size(); };
1108 get_n_expiry = [
this](
const string& k) {
return simMarketData_->yieldVolExpiries().size(); };
1109 getVolStrikes = [](
const string& k) {
return vector<Real>({0.0}); };
1110 getVolExpiries = [
this](
const string& k) {
return simMarketData_->yieldVolExpiries(); };
1111 getVolTerms = [
this](
const string& k) {
return simMarketData_->yieldVolTerms(); };
1112 getDayCounter = [
this](
const string& k) {
1115 return to_string(s->yieldVol(k)->dayCounter());
1117 QL_FAIL(
"Internal error: could not lock simMarket. Contact dev.");
1119 }
catch (
const std::exception&) {
1120 WLOG(
"Day counter lookup in simulation market failed for swaption vol '" << k
1121 <<
"', using default A365");
1122 return std::string(
"A365F");
1125 getScenarioDescription = [
this](
string q, Size n, Size m, Size k,
bool up,
1130 QL_FAIL(
"SensitivityScenarioGenerator::generateGenericYieldVolScenarios: risk factor type " << rfType
1131 <<
" not handled.");
1135 for (
auto s : shiftData) {
1136 std::string qualifier = s.first;
1140 n_term = get_n_term(qualifier);
1141 }
catch (
const std::exception& e) {
1142 ALOG(
"skip scenario generation for general yield vol " << qualifier <<
": " << e.what());
1145 Size n_expiry = get_n_expiry(qualifier);
1147 vector<Real> volExpiryTimes(n_expiry, 0.0);
1148 vector<Real> volTermTimes(n_term, 0.0);
1149 Size n_strike = getVolStrikes(qualifier).size();
1151 vector<vector<vector<Real>>> volData(n_strike, vector<vector<Real>>(n_expiry, vector<Real>(n_term, 0.0)));
1152 vector<vector<vector<Real>>> shiftedVolData = volData;
1160 vector<Real> shiftExpiryTimes(
data.shiftExpiries.size(), 0.0);
1161 vector<Real> shiftTermTimes(
data.shiftTerms.size(), 0.0);
1163 vector<Real> shiftStrikes;
1165 shiftStrikes =
data.shiftStrikes;
1166 QL_REQUIRE(
data.shiftStrikes.size() == n_strike,
1167 "number of simulated strikes must equal number of sensitivity strikes");
1169 shiftStrikes = {0.0};
1175 for (Size j = 0; j < n_expiry; ++j) {
1176 Date expiry =
asof + getVolExpiries(qualifier)[j];
1177 volExpiryTimes[j] = dc.yearFraction(
asof, expiry);
1179 for (Size j = 0; j < n_term; ++j) {
1180 Date term =
asof + getVolTerms(qualifier)[j];
1181 volTermTimes[j] = dc.yearFraction(
asof, term);
1185 for (Size j = 0; j < n_expiry; ++j) {
1186 for (Size k = 0; k < n_term; ++k) {
1187 for (Size l = 0; l < n_strike; ++l) {
1188 Size idx = j * n_term * n_strike + k * n_strike + l;
1199 for (Size j = 0; j < shiftExpiryTimes.size(); ++j)
1200 shiftExpiryTimes[j] = dc.yearFraction(
asof,
asof +
data.shiftExpiries[j]);
1201 for (Size j = 0; j < shiftTermTimes.size(); ++j)
1202 shiftTermTimes[j] = dc.yearFraction(
asof,
asof +
data.shiftTerms[j]);
1205 bool validShiftSize =
vectorEqual(volExpiryTimes, shiftExpiryTimes);
1206 validShiftSize = validShiftSize &&
vectorEqual(volTermTimes, shiftTermTimes);
1207 validShiftSize = validShiftSize &&
vectorEqual(getVolStrikes(qualifier), shiftStrikes);
1210 for (Size j = 0; j < shiftExpiryTimes.size(); ++j) {
1211 for (Size k = 0; k < shiftTermTimes.size(); ++k) {
1212 for (Size l = 0; l < shiftStrikes.size(); ++l) {
1213 Size strikeBucket = l;
1214 QuantLib::ext::shared_ptr<Scenario> scenario =
1218 Size loopStart = atmOnly ? 0 : l;
1219 Size loopEnd = atmOnly ? n_strike : loopStart + 1;
1221 for (Size ll = loopStart; ll < loopEnd; ++ll) {
1222 applyShift(j, k, shiftSize, up, shiftType, shiftExpiryTimes, shiftTermTimes, volExpiryTimes,
1223 volTermTimes, volData[ll], shiftedVolData[ll],
true);
1226 for (Size jj = 0; jj < n_expiry; ++jj) {
1227 for (Size kk = 0; kk < n_term; ++kk) {
1228 for (Size ll = 0; ll < n_strike; ++ll) {
1230 Size idx = jj * n_term * n_strike + kk * n_strike + ll;
1233 if (ll >= loopStart && ll < loopEnd) {
1235 scenario->add(key, shiftedVolData[ll][jj][kk] - volData[ll][jj][kk]);
1237 scenario->add(key, shiftedVolData[ll][jj][kk]);
1242 if (validShiftSize && j == jj && k == kk && l == ll) {
1243 storeShiftData(key, volData[ll][jj][kk], shiftedVolData[ll][jj][kk]);
1253 DLOG(
"Sensitivity scenario # " <<
scenarios_.size() <<
", label " << scenario->label()
1254 <<
" created for generic yield vol " << qualifier);
1262 DLOG(
"starting swapVol sgen");
1267 WLOG(
"Swaption key " << sim_key <<
" in simmarket is not included in sensitivities analysis");
1271 DLOG(
"Swaption vol scenarios done");
1275 DLOG(
"starting yieldVol sgen");
1280 WLOG(
"Bond securityId " << sim_securityId <<
" in simmarket is not included in sensitivities analysis");
1284 DLOG(
"Yield vol scenarios done");
1293 WLOG(
"CapFloor key " << sim_cap <<
" in simmarket is not included in sensitivities analysis");
1298 std::string key = c.first;
1300 vector<Real> volStrikes;
1303 }
catch (
const std::exception& e) {
1304 ALOG(
"skip scenario generation for cf vol " << key <<
": " << e.what());
1308 if (volStrikes.empty()) {
1311 Size n_cfvol_strikes = volStrikes.size();
1313 Size n_cfvol_exp =
simMarketData_->capFloorVolExpiries(key).size();
1319 vector<vector<Real>> volData(n_cfvol_exp, vector<Real>(n_cfvol_strikes, 0.0));
1320 vector<Real> volExpiryTimes(n_cfvol_exp, 0.0);
1321 vector<vector<Real>> shiftedVolData(n_cfvol_exp, vector<Real>(n_cfvol_strikes, 0.0));
1325 :
data.shiftExpiries;
1326 QL_REQUIRE(expiries.size() ==
data.shiftExpiries.size(),
"mismatch between effective shift expiries ("
1327 << expiries.size() <<
") and shift tenors ("
1328 <<
data.shiftExpiries.size());
1329 vector<Real> shiftExpiryTimes(expiries.size(), 0.0);
1330 vector<Real> shiftStrikes =
data.shiftStrikes;
1332 bool sensiIsAtm =
false;
1333 if (shiftStrikes.size() == 1 && shiftStrikes[0] == 0.0 &&
data.isRelative) {
1337 DayCounter dc = Actual365Fixed();
1340 dc = s->capFloorVol(key)->dayCounter();
1342 QL_FAIL(
"Internal error: could not lock simMarket. Contact dev.");
1344 }
catch (
const std::exception&) {
1345 WLOG(
"Day counter lookup in simulation market failed for cap/floor vol surface " << key
1346 <<
", using default A365");
1350 for (Size j = 0; j < n_cfvol_exp; ++j) {
1352 volExpiryTimes[j] = dc.yearFraction(
asof, expiry);
1355 for (Size j = 0; j < n_cfvol_exp; ++j) {
1356 for (Size k = 0; k < n_cfvol_strikes; ++k) {
1357 Size idx = j * n_cfvol_strikes + k;
1368 for (Size j = 0; j < shiftExpiryTimes.size(); ++j)
1369 shiftExpiryTimes[j] = dc.yearFraction(
asof,
asof + expiries[j]);
1372 bool validShiftSize =
vectorEqual(volExpiryTimes, shiftExpiryTimes);
1373 validShiftSize = validShiftSize &&
vectorEqual(volStrikes, shiftStrikes);
1376 for (Size j = 0; j < shiftExpiryTimes.size(); ++j) {
1377 for (Size k = 0; k < shiftStrikes.size(); ++k) {
1378 QuantLib::ext::shared_ptr<Scenario> scenario =
1381 applyShift(j, k, shiftSize, up, shiftType, shiftExpiryTimes, shiftStrikes, volExpiryTimes, volStrikes,
1382 volData, shiftedVolData,
true);
1385 for (Size jj = 0; jj < n_cfvol_exp; ++jj) {
1386 for (Size kk = 0; kk < n_cfvol_strikes; ++kk) {
1387 Size idx = jj * n_cfvol_strikes + kk;
1391 scenario->add(rfkey, shiftedVolData[jj][kk] - volData[jj][kk]);
1393 scenario->add(rfkey, shiftedVolData[jj][kk]);
1397 if (validShiftSize && j == jj && k == kk) {
1409 DLOG(
"Sensitivity scenario # " <<
scenarios_.size() <<
", label " << scenario->label() <<
" created");
1413 DLOG(
"Optionlet vol scenarios done");
1422 WLOG(
"Credit Name " << sim_name <<
" in simmarket is not included in sensitivities analysis");
1428 std::vector<Real> times;
1431 string name = c.first;
1434 }
catch (
const std::exception& e) {
1435 ALOG(
"skip scenario generation for survival curve " <<
name <<
": " << e.what());
1438 std::vector<Real> hazardRates(n_ten);
1440 times.resize(n_ten);
1442 std::vector<Real> shiftedHazardRates(n_ten);
1447 DayCounter dc = Actual365Fixed();
1450 dc = s->defaultCurve(
name)->curve()->dayCounter();
1452 QL_FAIL(
"Internal error: could not lock simMarket. Contact dev.");
1454 }
catch (
const std::exception&) {
1455 WLOG(
"Day counter lookup in simulation market failed for default curve " <<
name <<
", using default A365");
1461 for (Size j = 0; j < n_ten; ++j) {
1463 times[j] = dc.yearFraction(
asof, d);
1467 hazardRates[j] = -std::log(std::max(prob, 1E-8)) / times[j];
1478 std::vector<Time> shiftTimes(shiftTenors.size());
1479 for (Size j = 0; j < shiftTenors.size(); ++j)
1480 shiftTimes[j] = dc.yearFraction(
asof,
asof + shiftTenors[j]);
1482 QL_REQUIRE(shiftTenors.size() > 0,
"Discount shift tenors not specified");
1485 bool validShiftSize =
vectorEqual(times, shiftTimes);
1487 for (Size j = 0; j < shiftTenors.size(); ++j) {
1489 QuantLib::ext::shared_ptr<Scenario> scenario =
1493 applyShift(j, shiftSize, up, shiftType, shiftTimes, hazardRates, times, shiftedHazardRates,
true);
1496 for (Size k = 0; k < n_ten; ++k) {
1498 Real shiftedProb =
exp(-shiftedHazardRates[k] * times[k]);
1500 Real prob =
exp(-hazardRates[k] * times[k]);
1501 scenario->add(key, shiftedProb / prob);
1503 scenario->add(key, shiftedProb);
1507 if (validShiftSize && k == j) {
1516 DLOG(
"Sensitivity scenario # " <<
scenarios_.size() <<
", label " << scenario->label() <<
" created");
1520 DLOG(
"Discount curve scenarios done");
1529 WLOG(
"CDS name " << sim_name <<
" in simmarket is not included in sensitivities analysis");
1535 vector<Real> volData(n_cdsvol_exp, 0.0);
1536 vector<Real> volExpiryTimes(n_cdsvol_exp, 0.0);
1537 vector<Real> shiftedVolData(n_cdsvol_exp, 0.0);
1540 std::string
name = c.first;
1547 vector<Time> shiftExpiryTimes(
data.shiftExpiries.size(), 0.0);
1549 DayCounter dc = Actual365Fixed();
1552 dc = s->cdsVol(
name)->dayCounter();
1554 QL_FAIL(
"Internal error: could not lock simMarket. Contact dev.");
1556 }
catch (
const std::exception&) {
1557 WLOG(
"Day counter lookup in simulation market failed for cds vol surface " <<
name
1558 <<
", using default A365");
1562 for (Size j = 0; j < n_cdsvol_exp; ++j) {
1564 volExpiryTimes[j] = dc.yearFraction(
asof, expiry);
1567 for (Size j = 0; j < n_cdsvol_exp; ++j) {
1575 for (Size j = 0; j < shiftExpiryTimes.size(); ++j)
1576 shiftExpiryTimes[j] = dc.yearFraction(
asof,
asof +
data.shiftExpiries[j]);
1579 bool validShiftSize =
vectorEqual(volExpiryTimes, shiftExpiryTimes);
1582 for (Size j = 0; j < shiftExpiryTimes.size(); ++j) {
1583 Size strikeBucket = 0;
1584 QuantLib::ext::shared_ptr<Scenario> scenario =
1587 applyShift(j, shiftSize, up, shiftType, shiftExpiryTimes, volData, volExpiryTimes, shiftedVolData,
true);
1589 for (Size jj = 0; jj < n_cdsvol_exp; ++jj) {
1592 scenario->add(key, shiftedVolData[jj] - volData[jj]);
1594 scenario->add(key, shiftedVolData[jj]);
1598 if (validShiftSize && j == jj) {
1607 DLOG(
"Sensitivity scenario # " <<
scenarios_.size() <<
", label " << scenario->label() <<
" created");
1610 DLOG(
"CDS vol scenarios done");
1620 WLOG(
"Zero Inflation Index " << sim_idx <<
" in simmarket is not included in sensitivities analysis");
1625 string indexName = z.first;
1629 }
catch (
const std::exception& e) {
1630 ALOG(
"skip scenario generation for zero inflation curve " << indexName <<
": " << e.what());
1634 std::vector<Real> zeros(n_ten);
1635 std::vector<Real> times(n_ten);
1637 std::vector<Real> shiftedZeros(n_ten);
1642 DayCounter dc = Actual365Fixed();
1645 dc = s->zeroInflationIndex(indexName)->zeroInflationTermStructure()->dayCounter();
1647 QL_FAIL(
"Internal error: could not lock simMarket. Contact dev.");
1649 }
catch (
const std::exception&) {
1650 WLOG(
"Day counter lookup in simulation market failed for zero inflation index " << indexName
1651 <<
", using default A365");
1654 for (Size j = 0; j < n_ten; ++j) {
1658 times[j] = dc.yearFraction(
asof, d);
1666 checkShiftTenors(shiftTenors,
data.shiftTenors,
"Zero Inflation " + indexName,
continueOnError_);
1667 std::vector<Time> shiftTimes(shiftTenors.size());
1668 for (Size j = 0; j < shiftTenors.size(); ++j)
1669 shiftTimes[j] = dc.yearFraction(
asof,
asof + shiftTenors[j]);
1671 QL_REQUIRE(shiftTenors.size() > 0,
"Zero Inflation Index shift tenors not specified");
1674 bool validShiftSize =
vectorEqual(times, shiftTimes);
1676 for (Size j = 0; j < shiftTenors.size(); ++j) {
1678 QuantLib::ext::shared_ptr<Scenario> scenario =
1682 applyShift(j, shiftSize, up, shiftType, shiftTimes, zeros, times, shiftedZeros,
true);
1685 for (Size k = 0; k < n_ten; ++k) {
1686 RiskFactorKey key(RFType::ZeroInflationCurve, indexName, k);
1688 scenario->add(key, shiftedZeros[k] - zeros[k]);
1690 scenario->add(key, shiftedZeros[k]);
1694 if (validShiftSize && j == k) {
1703 DLOG(
"Sensitivity scenario # " <<
scenarios_.size() <<
", label " << scenario->label()
1704 <<
" created for indexName " << indexName);
1708 DLOG(
"Zero Inflation Index curve scenarios done");
1715 std::vector<string> yoyInfIndexNames;
1720 WLOG(
"YoY Inflation Index " << sim_idx <<
" in simmarket is not included in sensitivities analysis");
1725 string indexName = y.first;
1729 }
catch (
const std::exception& e) {
1730 ALOG(
"skip scenario generation for yoy inflation curve " << indexName <<
": " << e.what());
1734 std::vector<Real> yoys(n_ten);
1735 std::vector<Real> times(n_ten);
1737 std::vector<Real> shiftedYoys(n_ten);
1740 "yoyinflation CurveShiftData not found for " << indexName);
1745 DayCounter dc = Actual365Fixed();
1748 dc = s->yoyInflationIndex(indexName)->yoyInflationTermStructure()->dayCounter();
1750 QL_FAIL(
"Internal error: could not lock simMarket. Contact dev.");
1752 }
catch (
const std::exception&) {
1753 WLOG(
"Day counter lookup in simulation market failed for yoy inflation index " << indexName
1754 <<
", using default A365");
1757 for (Size j = 0; j < n_ten; ++j) {
1761 times[j] = dc.yearFraction(
asof, d);
1769 checkShiftTenors(shiftTenors,
data.shiftTenors,
"YoY Inflation " + indexName,
continueOnError_);
1770 std::vector<Time> shiftTimes(shiftTenors.size());
1771 for (Size j = 0; j < shiftTenors.size(); ++j) {
1772 shiftTimes[j] = dc.yearFraction(
asof,
asof + shiftTenors[j]);
1775 QL_REQUIRE(shiftTenors.size() > 0,
"YoY Inflation Index shift tenors not specified");
1778 bool validShiftSize =
vectorEqual(times, shiftTimes);
1780 for (Size j = 0; j < shiftTenors.size(); ++j) {
1782 QuantLib::ext::shared_ptr<Scenario> scenario =
1786 applyShift(j, shiftSize, up, shiftType, shiftTimes, yoys, times, shiftedYoys,
true);
1789 for (Size k = 0; k < n_ten; ++k) {
1792 scenario->add(key, shiftedYoys[k] - yoys[k]);
1794 scenario->add(key, shiftedYoys[k]);
1798 if (validShiftSize && j == k) {
1807 DLOG(
"Sensitivity scenario # " <<
scenarios_.size() <<
", label " << scenario->label()
1808 <<
" created for indexName " << indexName);
1812 DLOG(
"YoY Inflation Index curve scenarios done");
1817 for (
auto sim_yoy :
simMarketData_->yoyInflationCapFloorVolNames()) {
1820 WLOG(
"Inflation index " << sim_yoy <<
" in simmarket is not included in sensitivities analysis");
1825 std::string
name = c.first;
1826 Size n_yoyvol_strikes;
1829 }
catch (
const std::exception& e) {
1830 ALOG(
"skip scenario generation for yoy inflation cf vol " <<
name <<
": " << e.what());
1840 vector<vector<Real>> volData(n_yoyvol_exp, vector<Real>(n_yoyvol_strikes, 0.0));
1841 vector<Real> volExpiryTimes(n_yoyvol_exp, 0.0);
1842 vector<vector<Real>> shiftedVolData(n_yoyvol_exp, vector<Real>(n_yoyvol_strikes, 0.0));
1846 :
data.shiftExpiries;
1847 QL_REQUIRE(expiries.size() ==
data.shiftExpiries.size(),
"mismatch between effective shift expiries ("
1848 << expiries.size() <<
") and shift tenors ("
1849 <<
data.shiftExpiries.size());
1850 vector<Real> shiftExpiryTimes(expiries.size(), 0.0);
1851 vector<Real> shiftStrikes =
data.shiftStrikes;
1853 DayCounter dc = Actual365Fixed();
1856 dc = s->yoyCapFloorVol(
name)->dayCounter();
1858 QL_FAIL(
"Internal error: could not lock simMarket. Contact dev.");
1860 }
catch (
const std::exception&) {
1861 WLOG(
"Day counter lookup in simulation market failed for yoy cap/floor vol surface "
1862 <<
name <<
", using default A365");
1866 for (Size j = 0; j < n_yoyvol_exp; ++j) {
1868 volExpiryTimes[j] = dc.yearFraction(
asof, expiry);
1871 for (Size j = 0; j < n_yoyvol_exp; ++j) {
1872 for (Size k = 0; k < n_yoyvol_strikes; ++k) {
1873 Size idx = j * n_yoyvol_strikes + k;
1882 for (Size j = 0; j < shiftExpiryTimes.size(); ++j)
1883 shiftExpiryTimes[j] = dc.yearFraction(
asof,
asof + expiries[j]);
1885 bool validShiftSize =
vectorEqual(volExpiryTimes, shiftExpiryTimes);
1886 validShiftSize = validShiftSize &&
vectorEqual(volStrikes, shiftStrikes);
1889 for (Size j = 0; j < shiftExpiryTimes.size(); ++j) {
1890 for (Size k = 0; k < shiftStrikes.size(); ++k) {
1891 QuantLib::ext::shared_ptr<Scenario> scenario =
1894 applyShift(j, k, shiftSize, up, shiftType, shiftExpiryTimes, shiftStrikes, volExpiryTimes, volStrikes,
1895 volData, shiftedVolData,
true);
1898 for (Size jj = 0; jj < n_yoyvol_exp; ++jj) {
1899 for (Size kk = 0; kk < n_yoyvol_strikes; ++kk) {
1900 Size idx = jj * n_yoyvol_strikes + kk;
1903 scenario->add(key, shiftedVolData[jj][kk] - volData[jj][kk]);
1905 scenario->add(key, shiftedVolData[jj][kk]);
1909 if (validShiftSize && j == jj && k == kk) {
1920 DLOG(
"Sensitivity scenario # " <<
scenarios_.size() <<
", label " << scenario->label() <<
" created");
1924 DLOG(
"YoY inflation optionlet vol scenarios done");
1929 for (
auto sim_zci :
simMarketData_->zeroInflationCapFloorVolNames()) {
1932 WLOG(
"Inflation index " << sim_zci <<
" in simmarket is not included in sensitivities analysis");
1937 std::string
name = c.first;
1941 }
catch (
const std::exception& e) {
1942 ALOG(
"skip scenario generation for zero inflation cf vol " <<
name <<
": " << e.what());
1952 vector<vector<Real>> volData(n_exp, vector<Real>(n_strikes, 0.0));
1953 vector<Real> volExpiryTimes(n_exp, 0.0);
1954 vector<vector<Real>> shiftedVolData(n_exp, vector<Real>(n_strikes, 0.0));
1958 :
data.shiftExpiries;
1959 QL_REQUIRE(expiries.size() ==
data.shiftExpiries.size(),
"mismatch between effective shift expiries ("
1960 << expiries.size() <<
") and shift tenors ("
1961 <<
data.shiftExpiries.size());
1962 vector<Real> shiftExpiryTimes(expiries.size(), 0.0);
1963 vector<Real> shiftStrikes =
data.shiftStrikes;
1965 DayCounter dc = Actual365Fixed();
1968 dc = s->cpiInflationCapFloorVolatilitySurface(
name)->dayCounter();
1970 QL_FAIL(
"Internal error: could not lock simMarket. Contact dev.");
1972 }
catch (
const std::exception&) {
1973 WLOG(
"Day counter lookup in simulation market failed for cpi cap/floor vol surface "
1974 <<
name <<
", using default A365");
1978 for (Size j = 0; j < n_exp; ++j) {
1980 volExpiryTimes[j] = dc.yearFraction(
asof, expiry);
1983 for (Size j = 0; j < n_exp; ++j) {
1984 for (Size k = 0; k < n_strikes; ++k) {
1985 Size idx = j * n_strikes + k;
1994 for (Size j = 0; j < shiftExpiryTimes.size(); ++j)
1995 shiftExpiryTimes[j] = dc.yearFraction(
asof,
asof + expiries[j]);
1997 bool validShiftSize =
vectorEqual(volExpiryTimes, shiftExpiryTimes);
1998 validShiftSize = validShiftSize &&
vectorEqual(volStrikes, shiftStrikes);
2001 for (Size j = 0; j < shiftExpiryTimes.size(); ++j) {
2002 for (Size k = 0; k < shiftStrikes.size(); ++k) {
2003 QuantLib::ext::shared_ptr<Scenario> scenario =
2006 applyShift(j, k, shiftSize, up, shiftType, shiftExpiryTimes, shiftStrikes, volExpiryTimes, volStrikes,
2007 volData, shiftedVolData,
true);
2010 for (Size jj = 0; jj < n_exp; ++jj) {
2011 for (Size kk = 0; kk < n_strikes; ++kk) {
2012 Size idx = jj * n_strikes + kk;
2015 scenario->add(key, shiftedVolData[jj][kk] - volData[jj][kk]);
2017 scenario->add(key, shiftedVolData[jj][kk]);
2021 if (validShiftSize && j == jj && k == kk) {
2032 DLOG(
"Sensitivity scenario # " <<
scenarios_.size() <<
", label " << scenario->label() <<
" created");
2036 DLOG(
"Zero inflation cap/floor vol scenarios done");
2046 WLOG(
"Base Correlation " <<
name <<
" in simmarket is not included in sensitivities analysis");
2051 Size n_bc_levels =
simMarketData_->baseCorrelationDetachmentPoints().size();
2053 vector<vector<Real>> bcData(n_bc_levels, vector<Real>(n_bc_terms, 0.0));
2054 vector<vector<Real>> shiftedBcData(n_bc_levels, vector<Real>(n_bc_levels, 0.0));
2055 vector<Real> termTimes(n_bc_terms, 0.0);
2056 vector<Real> levels =
simMarketData_->baseCorrelationDetachmentPoints();
2059 std::string
name = b.first;
2066 vector<Real> shiftLevels =
data.shiftLossLevels;
2067 vector<Real> shiftTermTimes(
data.shiftTerms.size(), 0.0);
2069 DayCounter dc = Actual365Fixed();
2072 dc = s->baseCorrelation(
name)->dayCounter();
2074 QL_FAIL(
"Internal error: could not lock simMarket. Contact dev.");
2076 }
catch (
const std::exception&) {
2077 WLOG(
"Day counter lookup in simulation market failed for base correlation structure "
2078 <<
name <<
", using default A365");
2082 for (Size j = 0; j < n_bc_terms; ++j) {
2084 termTimes[j] = dc.yearFraction(
asof, term);
2087 for (Size j = 0; j < n_bc_levels; ++j) {
2088 for (Size k = 0; k < n_bc_terms; ++k) {
2097 for (Size j = 0; j < shiftTermTimes.size(); ++j)
2098 shiftTermTimes[j] = dc.yearFraction(
asof,
asof +
data.shiftTerms[j]);
2101 bool validShiftSize =
vectorEqual(termTimes, shiftTermTimes);
2102 validShiftSize = validShiftSize &&
vectorEqual(levels, shiftLevels);
2105 for (Size j = 0; j < shiftLevels.size(); ++j) {
2106 for (Size k = 0; k < shiftTermTimes.size(); ++k) {
2107 QuantLib::ext::shared_ptr<Scenario> scenario =
2110 applyShift(j, k, shiftSize, up, shiftType, shiftLevels, shiftTermTimes, levels, termTimes, bcData,
2111 shiftedBcData,
true);
2114 for (Size jj = 0; jj < n_bc_levels; ++jj) {
2115 for (Size kk = 0; kk < n_bc_terms; ++kk) {
2116 Size idx = jj * n_bc_terms + kk;
2117 if (shiftedBcData[jj][kk] < 0.0) {
2118 ALOG(
"invalid shifted base correlation " << shiftedBcData[jj][kk] <<
" at lossLevelIndex "
2119 << jj <<
" and termIndex " << kk
2121 shiftedBcData[jj][kk] = 0.0;
2122 }
else if (shiftedBcData[jj][kk] > 1.0) {
2123 ALOG(
"invalid shifted base correlation " << shiftedBcData[jj][kk] <<
" at lossLevelIndex "
2124 << jj <<
" and termIndex " << kk
2125 <<
" set to 1 - epsilon");
2126 shiftedBcData[jj][kk] = 1.0 - QL_EPSILON;
2131 scenario->add(key, shiftedBcData[jj][kk] - bcData[jj][kk]);
2133 scenario->add(key, shiftedBcData[jj][kk]);
2136 if (validShiftSize && j == jj && k == kk) {
2147 DLOG(
"Sensitivity scenario # " <<
scenarios_.size() <<
", label " << scenario->label() <<
" created");
2151 DLOG(
"Base correlation scenarios done");
2163 <<
" in simulation market is not "
2164 "included in commodity sensitivity analysis");
2169 string name = c.first;
2171 vector<Period> simMarketTenors;
2174 }
catch (
const std::exception& e) {
2175 ALOG(
"skip scenario generation for comm curve " <<
name <<
": " << e.what());
2178 DayCounter dc = Actual365Fixed();
2181 dc = s->commodityPriceCurve(
name)->dayCounter();
2183 QL_FAIL(
"Internal error: could not lock simMarket. Contact dev.");
2185 }
catch (
const std::exception&) {
2186 WLOG(
"Day counter lookup in simulation market failed for commodity price curve " <<
name
2187 <<
", using default A365");
2190 vector<Real> times(simMarketTenors.size());
2191 vector<Real> basePrices(times.size());
2192 vector<Real> shiftedPrices(times.size());
2196 for (Size j = 0; j < times.size(); ++j) {
2197 times[j] = dc.yearFraction(
asof,
asof + simMarketTenors[j]);
2212 QL_REQUIRE(!
data.shiftTenors.empty(),
"Commodity curve shift tenors have not been given");
2213 vector<Time> shiftTimes(
data.shiftTenors.size());
2214 for (Size j = 0; j <
data.shiftTenors.size(); ++j) {
2215 shiftTimes[j] = dc.yearFraction(
asof,
asof +
data.shiftTenors[j]);
2219 bool validShiftSize =
vectorEqual(times, shiftTimes);
2222 for (Size j = 0; j <
data.shiftTenors.size(); ++j) {
2224 QuantLib::ext::shared_ptr<Scenario> scenario =
2228 applyShift(j, shiftSize, up, shiftType, shiftTimes, basePrices, times, shiftedPrices,
true);
2231 for (Size k = 0; k < times.size(); ++k) {
2234 scenario->add(key, shiftedPrices[k] - basePrices[k]);
2236 scenario->add(key, shiftedPrices[k]);
2240 if (validShiftSize && j == k) {
2249 DLOG(
"Sensitivity scenario # " <<
scenarios_.size() <<
", label " << scenario->label() <<
" created");
2252 DLOG(
"Commodity curve scenarios done");
2260 ALOG(
"Commodity volatility " <<
name
2261 <<
" in simulation market is not "
2262 "included in commodity sensitivity analysis");
2269 string name = c.first;
2271 vector<Period> expiries;
2274 }
catch (
const std::exception& e) {
2275 ALOG(
"skip scenario generation for comm vol " <<
name <<
": " << e.what());
2279 QL_REQUIRE(!expiries.empty(),
"Sim market commodity volatility expiries have not been specified for " <<
name);
2280 QL_REQUIRE(!moneyness.empty(),
"Sim market commodity volatility moneyness has not been specified for " <<
name);
2282 vector<vector<Real>>
baseValues(moneyness.size(), vector<Real>(expiries.size()));
2284 vector<Time> times(expiries.size());
2286 vector<vector<Real>> shiftedValues =
baseValues;
2291 QL_REQUIRE(!sd.
shiftExpiries.empty(),
"commodity volatility shift tenors must be specified");
2295 DayCounter dc = Actual365Fixed();
2298 dc = s->commodityVolatility(
name)->dayCounter();
2300 QL_FAIL(
"Internal error: could not lock simMarket. Contact dev.");
2302 }
catch (
const std::exception&) {
2303 WLOG(
"Day counter lookup in simulation market failed for commodity vol surface " <<
name
2304 <<
", using default A365");
2309 for (Size j = 0; j < expiries.size(); j++) {
2310 times[j] = dc.yearFraction(
asof,
asof + expiries[j]);
2311 for (Size i = 0; i < moneyness.size(); i++) {
2326 bool validShiftSize =
vectorEqual(times, shiftTimes);
2333 QuantLib::ext::shared_ptr<Scenario> scenario =
2340 for (Size i = 0; i < moneyness.size(); i++) {
2341 for (Size j = 0; j < expiries.size(); ++j) {
2344 scenario->add(key, shiftedValues[i][j] -
baseValues[i][j]);
2346 scenario->add(key, shiftedValues[i][j]);
2349 if (validShiftSize && si == i && sj == j) {
2361 DLOG(
"Sensitivity scenario # " <<
scenarios_.size() <<
", label " << scenario->label() <<
" created");
2365 DLOG(
"Commodity volatility scenarios done");
2372 WLOG(
"Correlation " << sim_cap <<
" in simmarket is not included in sensitivities analysis");
2380 std::string label = c.first;
2382 std::pair<string, string> pair(tokens[0], tokens[1]);
2389 vector<vector<Real>> corrData(n_c_exp, vector<Real>(n_c_strikes, 0.0));
2390 vector<Real> corrExpiryTimes(n_c_exp, 0.0);
2391 vector<vector<Real>> shiftedCorrData(n_c_exp, vector<Real>(n_c_strikes, 0.0));
2394 QL_REQUIRE(expiries.size() ==
data.shiftExpiries.size(),
"mismatch between effective shift expiries ("
2395 << expiries.size() <<
") and shift tenors ("
2396 <<
data.shiftExpiries.size());
2397 vector<Real> shiftExpiryTimes(expiries.size(), 0.0);
2398 vector<Real> shiftStrikes =
data.shiftStrikes;
2400 DayCounter dc = Actual365Fixed();
2403 dc = s->correlationCurve(pair.first, pair.second)->dayCounter();
2405 QL_FAIL(
"Internal error: could not lock simMarket. Contact dev.");
2407 }
catch (
const std::exception&) {
2408 WLOG(
"Day counter lookup in simulation market failed for correlation curve "
2409 << pair.first <<
" - " << pair.second <<
", using default A365");
2413 for (Size j = 0; j < n_c_exp; ++j) {
2415 corrExpiryTimes[j] = dc.yearFraction(
asof, expiry);
2418 for (Size j = 0; j < n_c_exp; ++j) {
2419 for (Size k = 0; k < n_c_strikes; ++k) {
2420 Size idx = j * n_c_strikes + k;
2429 for (Size j = 0; j < shiftExpiryTimes.size(); ++j)
2430 shiftExpiryTimes[j] = dc.yearFraction(
asof,
asof + expiries[j]);
2433 bool validShiftSize =
vectorEqual(corrExpiryTimes, shiftExpiryTimes);
2434 validShiftSize = validShiftSize &&
vectorEqual(corrStrikes, shiftStrikes);
2437 for (Size j = 0; j < shiftExpiryTimes.size(); ++j) {
2438 for (Size k = 0; k < shiftStrikes.size(); ++k) {
2439 QuantLib::ext::shared_ptr<Scenario> scenario =
2442 applyShift(j, k, shiftSize, up, shiftType, shiftExpiryTimes, shiftStrikes, corrExpiryTimes, corrStrikes,
2443 corrData, shiftedCorrData,
true);
2446 for (Size jj = 0; jj < n_c_exp; ++jj) {
2447 for (Size kk = 0; kk < n_c_strikes; ++kk) {
2448 Size idx = jj * n_c_strikes + kk;
2451 if (shiftedCorrData[jj][kk] > 1) {
2452 shiftedCorrData[jj][kk] = 1;
2453 }
else if (shiftedCorrData[jj][kk] < -1) {
2454 shiftedCorrData[jj][kk] = -1;
2458 scenario->add(key, shiftedCorrData[jj][kk] - corrData[jj][kk]);
2460 scenario->add(key, shiftedCorrData[jj][kk]);
2463 if (validShiftSize && j == jj && k == kk) {
2473 DLOG(
"Sensitivity scenario # " <<
scenarios_.size() <<
", label " << scenario->label() <<
" created");
2477 DLOG(
"Correlation scenarios done");
2486 WLOG(
"Security " << sim_security <<
" in simmarket is not included in sensitivities analysis");
2490 string bond = s.first;
2498 QuantLib::ext::shared_ptr<Scenario> scenario =
2505 Real newSpread = relShift ? base_spread * (1.0 +
size) : (base_spread +
size);
2507 scenario->add(key,
sensitivityData_->useSpreadedTermStructures() ? newSpread - base_spread : newSpread);
2514 DLOG(
"Sensitivity scenario # " <<
scenarios_.size() <<
", label " << scenario->label()
2515 <<
" created: " << newSpread);
2517 DLOG(
"Security scenarios done");
2523 ScenarioDescription::Type type = up ? ScenarioDescription::Type::Up : ScenarioDescription::Type::Down;
2533 ScenarioDescription::Type type = up ? ScenarioDescription::Type::Up : ScenarioDescription::Type::Down;
2544 "equity " <<
name <<
" not found in dividend yield shift data");
2545 QL_REQUIRE(bucket < sensitivityData_->dividendYieldShiftData()[
name]->shiftTenors.size(),
2546 "bucket " << bucket <<
" out of range");
2548 std::ostringstream o;
2550 string text = o.str();
2551 ScenarioDescription::Type type = up ? ScenarioDescription::Type::Up : ScenarioDescription::Type::Down;
2561 "currency " << ccy <<
" not found in discount shift data");
2562 QL_REQUIRE(bucket < sensitivityData_->discountCurveShiftData()[ccy]->shiftTenors.size(),
2563 "bucket " << bucket <<
" out of range");
2565 std::ostringstream o;
2567 string text = o.str();
2568 ScenarioDescription::Type type = up ? ScenarioDescription::Type::Up : ScenarioDescription::Type::Down;
2578 "currency " << index <<
" not found in index shift data");
2579 QL_REQUIRE(bucket < sensitivityData_->indexCurveShiftData()[index]->shiftTenors.size(),
2580 "bucket " << bucket <<
" out of range");
2582 std::ostringstream o;
2584 string text = o.str();
2585 ScenarioDescription::Type type = up ? ScenarioDescription::Type::Up : ScenarioDescription::Type::Down;
2595 "currency " <<
name <<
" not found in index shift data");
2596 QL_REQUIRE(bucket < sensitivityData_->yieldCurveShiftData()[
name]->shiftTenors.size(),
2597 "bucket " << bucket <<
" out of range");
2599 std::ostringstream o;
2601 string text = o.str();
2602 ScenarioDescription::Type type = up ? ScenarioDescription::Type::Up : ScenarioDescription::Type::Down;
2613 "currency pair " << ccypair <<
" not found in fx vol shift data");
2615 QL_REQUIRE(expiryBucket <
data.shiftExpiries.size(),
"expiry bucket " << expiryBucket <<
" out of range");
2616 Size index = strikeBucket *
data.shiftExpiries.size() + expiryBucket;
2618 std::ostringstream o;
2619 if (
data.shiftStrikes.size() == 0 ||
2621 o <<
data.shiftExpiries[expiryBucket] <<
"/ATM";
2623 QL_REQUIRE(strikeBucket <
data.shiftStrikes.size(),
"strike bucket " << strikeBucket <<
" out of range");
2624 o <<
data.shiftExpiries[expiryBucket] <<
"/" <<
data.shiftStrikes[strikeBucket];
2626 string text = o.str();
2627 ScenarioDescription::Type type = up ? ScenarioDescription::Type::Up : ScenarioDescription::Type::Down;
2638 "currency pair " << equity <<
" not found in fx vol shift data");
2640 QL_REQUIRE(expiryBucket <
data.shiftExpiries.size(),
"expiry bucket " << expiryBucket <<
" out of range");
2641 Size index = strikeBucket *
data.shiftExpiries.size() + expiryBucket;
2643 std::ostringstream o;
2645 o <<
data.shiftExpiries[expiryBucket] <<
"/ATM";
2647 QL_REQUIRE(strikeBucket <
data.shiftStrikes.size(),
"strike bucket " << strikeBucket <<
" out of range");
2648 o <<
data.shiftExpiries[expiryBucket] <<
"/" <<
data.shiftStrikes[strikeBucket];
2650 string text = o.str();
2651 ScenarioDescription::Type type = up ? ScenarioDescription::Type::Up : ScenarioDescription::Type::Down;
2660 Size strikeBucket,
bool up,
ShiftScheme shiftScheme) {
2662 "currency " << ccy <<
" not found in swaption vol shift data");
2664 QL_REQUIRE(expiryBucket <
data.shiftExpiries.size(),
"expiry bucket " << expiryBucket <<
" out of range");
2665 QL_REQUIRE(termBucket <
data.shiftTerms.size(),
"term bucket " << termBucket <<
" out of range");
2666 QL_REQUIRE(strikeBucket <
data.shiftStrikes.size(),
"strike bucket " << strikeBucket <<
" out of range");
2667 Size index = expiryBucket *
data.shiftStrikes.size() *
data.shiftTerms.size() +
2668 termBucket *
data.shiftStrikes.size() + strikeBucket;
2670 std::ostringstream o;
2672 o <<
data.shiftExpiries[expiryBucket] <<
"/" <<
data.shiftTerms[termBucket] <<
"/ATM";
2674 o <<
data.shiftExpiries[expiryBucket] <<
"/" <<
data.shiftTerms[termBucket] <<
"/" << std::setprecision(4)
2675 <<
data.shiftStrikes[strikeBucket];
2677 string text = o.str();
2678 ScenarioDescription::Type type = up ? ScenarioDescription::Type::Up : ScenarioDescription::Type::Down;
2689 "currency " << securityId <<
" not found in yield vol shift data");
2691 QL_REQUIRE(expiryBucket <
data.shiftExpiries.size(),
"expiry bucket " << expiryBucket <<
" out of range");
2692 QL_REQUIRE(termBucket <
data.shiftTerms.size(),
"term bucket " << termBucket <<
" out of range");
2694 expiryBucket *
data.shiftStrikes.size() *
data.shiftTerms.size() + termBucket *
data.shiftStrikes.size();
2696 std::ostringstream o;
2697 o <<
data.shiftExpiries[expiryBucket] <<
"/" <<
data.shiftTerms[termBucket] <<
"/ATM";
2698 string text = o.str();
2699 ScenarioDescription::Type type = up ? ScenarioDescription::Type::Up : ScenarioDescription::Type::Down;
2710 "currency " << ccy <<
" not found in cap/floor vol shift data");
2712 QL_REQUIRE(expiryBucket <
data.shiftExpiries.size(),
"expiry bucket " << expiryBucket <<
" out of range");
2713 QL_REQUIRE(strikeBucket <
data.shiftStrikes.size(),
"strike bucket " << strikeBucket <<
" out of range");
2714 Size index = expiryBucket *
data.shiftStrikes.size() + strikeBucket;
2716 std::ostringstream o;
2717 o <<
data.shiftExpiries[expiryBucket] <<
"/";
2721 o << std::setprecision(4) <<
data.shiftStrikes[strikeBucket];
2723 ScenarioDescription::Type type = up ? ScenarioDescription::Type::Up : ScenarioDescription::Type::Down;
2734 "Name " <<
name <<
" not found in credit shift data");
2735 QL_REQUIRE(bucket < sensitivityData_->creditCurveShiftData()[
name]->shiftTenors.size(),
2736 "bucket " << bucket <<
" out of range");
2738 std::ostringstream o;
2740 string text = o.str();
2741 ScenarioDescription::Type type = up ? ScenarioDescription::Type::Up : ScenarioDescription::Type::Down;
2752 "name " <<
name <<
" not found in swaption name shift data");
2754 QL_REQUIRE(expiryBucket <
data.shiftExpiries.size(),
"expiry bucket " << expiryBucket <<
" out of range");
2755 Size index = strikeBucket *
data.shiftExpiries.size() + expiryBucket;
2757 std::ostringstream o;
2758 o <<
data.shiftExpiries[expiryBucket] <<
"/"
2760 string text = o.str();
2761 ScenarioDescription::Type type = up ? ScenarioDescription::Type::Up : ScenarioDescription::Type::Down;
2772 "inflation index " << index <<
" not found in zero inflation index shift data");
2773 QL_REQUIRE(bucket < sensitivityData_->zeroInflationCurveShiftData()[index]->shiftTenors.size(),
2774 "bucket " << bucket <<
" out of range");
2776 std::ostringstream o;
2777 o <<
sensitivityData_->zeroInflationCurveShiftData()[index]->shiftTenors[bucket];
2778 string text = o.str();
2779 ScenarioDescription::Type type = up ? ScenarioDescription::Type::Up : ScenarioDescription::Type::Down;
2790 "yoy inflation index " << index <<
" not found in zero inflation index shift data");
2791 QL_REQUIRE(bucket < sensitivityData_->yoyInflationCurveShiftData()[index]->shiftTenors.size(),
2792 "bucket " << bucket <<
" out of range");
2794 std::ostringstream o;
2795 o <<
sensitivityData_->yoyInflationCurveShiftData()[index]->shiftTenors[bucket];
2796 string text = o.str();
2797 ScenarioDescription::Type type = up ? ScenarioDescription::Type::Up : ScenarioDescription::Type::Down;
2806 Size strikeBucket,
bool up,
2810 "index " <<
name <<
" not found in yoy cap/floor vol shift data");
2812 QL_REQUIRE(expiryBucket <
data.shiftExpiries.size(),
"expiry bucket " << expiryBucket <<
" out of range");
2813 QL_REQUIRE(strikeBucket <
data.shiftStrikes.size(),
"strike bucket " << strikeBucket <<
" out of range");
2814 Size index = expiryBucket *
data.shiftStrikes.size() + strikeBucket;
2816 std::ostringstream o;
2818 o <<
data.shiftExpiries[expiryBucket] <<
"/" << std::setprecision(4) <<
data.shiftStrikes[strikeBucket];
2819 string text = o.str();
2820 ScenarioDescription::Type type = up ? ScenarioDescription::Type::Up : ScenarioDescription::Type::Down;
2829 Size strikeBucket,
bool up,
2833 "currency " <<
name <<
" not found in zero inflation cap/floor vol shift data");
2835 QL_REQUIRE(expiryBucket <
data.shiftExpiries.size(),
"expiry bucket " << expiryBucket <<
" out of range");
2836 QL_REQUIRE(strikeBucket <
data.shiftStrikes.size(),
"strike bucket " << strikeBucket <<
" out of range");
2837 Size index = expiryBucket *
data.shiftStrikes.size() + strikeBucket;
2839 std::ostringstream o;
2841 o <<
data.shiftExpiries[expiryBucket] <<
"/ATM";
2843 o <<
data.shiftExpiries[expiryBucket] <<
"/" << std::setprecision(4) <<
data.shiftStrikes[strikeBucket];
2845 string text = o.str();
2846 ScenarioDescription::Type type = up ? ScenarioDescription::Type::Up : ScenarioDescription::Type::Down;
2855 Size termBucket,
bool up,
ShiftScheme shiftScheme) {
2858 "name " << indexName <<
" not found in base correlation shift data");
2860 QL_REQUIRE(termBucket <
data.shiftTerms.size(),
"term bucket " << termBucket <<
" out of range");
2861 QL_REQUIRE(lossLevelBucket <
data.shiftLossLevels.size(),
2862 "loss level bucket " << lossLevelBucket <<
" out of range");
2863 Size index = lossLevelBucket *
data.shiftTerms.size() + termBucket;
2865 std::ostringstream o;
2866 o <<
data.shiftLossLevels[lossLevelBucket] <<
"/" <<
data.shiftTerms[termBucket];
2867 string text = o.str();
2868 ScenarioDescription::Type type = up ? ScenarioDescription::Type::Up : ScenarioDescription::Type::Down;
2879 QL_REQUIRE(
sensitivityData_->commodityCurveShiftData().count(commodityName) > 0,
2880 "Name " << commodityName <<
" not found in commodity curve shift data");
2881 vector<Period>& shiftTenors =
sensitivityData_->commodityCurveShiftData()[commodityName]->shiftTenors;
2882 QL_REQUIRE(bucket < shiftTenors.size(),
"bucket " << bucket <<
" out of commodity curve bucket range");
2886 oss << shiftTenors[bucket];
2887 ScenarioDescription::Type type = up ? ScenarioDescription::Type::Up : ScenarioDescription::Type::Down;
2895 Size strikeBucket,
bool up,
ShiftScheme shiftScheme) {
2897 QL_REQUIRE(
sensitivityData_->commodityVolShiftData().count(commodityName) > 0,
2898 "commodity " << commodityName <<
" not found in commodity vol shift data");
2901 QL_REQUIRE(expiryBucket <
data.shiftExpiries.size(),
"expiry bucket " << expiryBucket <<
" out of range");
2902 Size index = strikeBucket *
data.shiftExpiries.size() + expiryBucket;
2906 o <<
data.shiftExpiries[expiryBucket] <<
"/ATM";
2908 QL_REQUIRE(strikeBucket <
data.shiftStrikes.size(),
"strike bucket " << strikeBucket <<
" out of range");
2909 o <<
data.shiftExpiries[expiryBucket] <<
"/" <<
data.shiftStrikes[strikeBucket];
2911 ScenarioDescription::Type type = up ? ScenarioDescription::Type::Up : ScenarioDescription::Type::Down;
2921 "pair " << pair <<
" not found in correlation shift data");
2923 QL_REQUIRE(expiryBucket <
data.shiftExpiries.size(),
"expiry bucket " << expiryBucket <<
" out of range");
2924 QL_REQUIRE(strikeBucket <
data.shiftStrikes.size(),
"strike bucket " << strikeBucket <<
" out of range");
2926 Size index = expiryBucket *
data.shiftStrikes.size() + strikeBucket;
2928 std::ostringstream o;
2930 o <<
data.shiftExpiries[expiryBucket] <<
"/ATM";
2932 o <<
data.shiftExpiries[expiryBucket] <<
"/" << std::setprecision(4) <<
data.shiftStrikes[strikeBucket];
2934 string text = o.str();
2935 ScenarioDescription::Type type = up ? ScenarioDescription::Type::Up : ScenarioDescription::Type::Down;
2945 ScenarioDescription::Type type = up ? ScenarioDescription::Type::Up : ScenarioDescription::Type::Down;
Data types stored in the scenario class.
KeyType
Risk Factor types.
@ YoYInflationCapFloorVolatility
@ ZeroInflationCapFloorVolatility
const std::map< RiskFactorKey, QuantLib::Real > & baseValues() const
ScenarioDescription fxVolScenarioDescription(string ccypair, Size expiryBucket, Size strikeBucket, bool up, ShiftScheme shiftScheme)
ScenarioDescription indexScenarioDescription(string index, Size bucket, bool up, ShiftScheme shiftScheme)
std::map< RiskFactorKey, ShiftScheme > shiftSchemes_
Holds the delta shift schemes for each risk factor key.
QuantLib::ext::shared_ptr< ScenarioFactory > sensiScenarioFactory_
ScenarioDescription correlationScenarioDescription(string pair, Size expiryBucket, Size strikeBucket, bool up, ShiftScheme shiftScheme)
QuantLib::ext::shared_ptr< SensitivityScenarioData > sensitivityData_
void generateYoYInflationCapFloorVolScenarios(bool up)
SensitivityScenarioGenerator(const QuantLib::ext::shared_ptr< SensitivityScenarioData > &sensitivityData, const QuantLib::ext::shared_ptr< Scenario > &baseScenario, const QuantLib::ext::shared_ptr< ScenarioSimMarketParameters > &simMarketData, const QuantLib::ext::shared_ptr< ScenarioSimMarket > &simMarket, const QuantLib::ext::shared_ptr< ScenarioFactory > &sensiScenarioFactory, const bool overrideTenors, const std::string &sensitivityTemplate=std::string(), const bool continueOnError=false, const QuantLib::ext::shared_ptr< Scenario > &baseScenarioAbsolute=nullptr)
Constructor.
ScenarioDescription yieldScenarioDescription(string name, Size bucket, bool up, ShiftScheme shiftScheme)
void generateYoYInflationScenarios(bool up)
ScenarioDescription commodityVolScenarioDescription(const std::string &commodityName, QuantLib::Size expiryBucket, QuantLib::Size strikeBucket, bool up, ShiftScheme shiftScheme)
ScenarioDescription fxScenarioDescription(string ccypair, bool up, ShiftScheme shiftScheme)
ScenarioDescription dividendYieldScenarioDescription(string equity, Size bucket, bool up, ShiftScheme shiftScheme)
void generateSwaptionVolScenarios(bool up)
void generateZeroInflationCapFloorVolScenarios(bool up)
ScenarioDescription zeroInflationCapFloorVolScenarioDescription(string name, Size expiryBucket, Size strikeBucket, bool up, ShiftScheme shiftScheme)
void generateZeroInflationScenarios(bool up)
void generateIndexCurveScenarios(bool up)
const bool continueOnError_
ScenarioDescription securitySpreadScenarioDescription(string bond, bool up, ShiftScheme shiftScheme)
ScenarioDescription yoyInflationScenarioDescription(string index, Size bucket, bool up, ShiftScheme shiftScheme)
void generateCapFloorVolScenarios(bool up)
ScenarioDescription zeroInflationScenarioDescription(string index, Size bucket, bool up, ShiftScheme shiftScheme)
void generateCommodityCurveScenarios(bool up)
std::map< RiskFactorKey, QuantLib::Real > baseValues_
Holds the base valuesfor each risk factor key.
void storeShiftData(const RiskFactorKey &key, const Real rate, const Real newRate)
std::map< RiskFactorKey, QuantLib::Real > shiftSizes_
Holds the shift sizes for each risk factor key.
ScenarioDescription baseCorrelationScenarioDescription(string indexName, Size lossLevelBucket, Size termBucket, bool up, ShiftScheme shiftScheme)
ScenarioDescription survivalProbabilityScenarioDescription(string name, Size bucket, bool up, ShiftScheme shiftScheme)
void generateYieldCurveScenarios(bool up)
QuantLib::ext::shared_ptr< Scenario > baseScenarioAbsolute_
void generateEquityVolScenarios(bool up)
ScenarioDescription equityVolScenarioDescription(string equity, Size expiryBucket, Size strikeBucket, bool up, ShiftScheme shiftScheme)
void generateBaseCorrelationScenarios(bool up)
ScenarioDescription CdsVolScenarioDescription(string name, Size expiryBucket, Size strikeBucket, bool up, ShiftScheme shiftScheme)
void generateYieldVolScenarios(bool up)
ScenarioDescription yoyInflationCapFloorVolScenarioDescription(string name, Size expiryBucket, Size strikeBucket, bool up, ShiftScheme shiftScheme)
void generateDiscountCurveScenarios(bool up)
bool isScenarioRelevant(bool up, SensitivityScenarioData::ShiftData &data) const
void generateGenericYieldVolScenarios(bool up, RiskFactorKey::KeyType rfType)
ScenarioDescription yieldVolScenarioDescription(string securityId, Size expiryBucket, Size termBucket, bool up, ShiftScheme shiftScheme)
void generateCdsVolScenarios(bool up)
ShiftScheme getShiftScheme(SensitivityScenarioData::ShiftData &data) const
void generateSecuritySpreadScenarios(bool up)
std::string sensitivityTemplate_
const bool overrideTenors_
void generateFxScenarios(bool up)
ScenarioDescription discountScenarioDescription(string ccy, Size bucket, bool up, ShiftScheme shiftScheme)
ScenarioDescription swaptionVolScenarioDescription(string ccy, Size expiryBucket, Size termBucket, Size strikeBucket, bool up, ShiftScheme shiftScheme)
ShiftType getShiftType(SensitivityScenarioData::ShiftData &data) const
void generateSurvivalProbabilityScenarios(bool up)
ScenarioDescription commodityCurveScenarioDescription(const std::string &commodityName, QuantLib::Size bucket, bool up, ShiftScheme shiftScheme)
void generateFxVolScenarios(bool up)
Real getShiftSize(SensitivityScenarioData::ShiftData &data) const
ScenarioDescription capFloorVolScenarioDescription(string ccy, Size expiryBucket, Size strikeBucket, bool up, bool isAtm, ShiftScheme shiftScheme)
void generateCommodityVolScenarios(bool up)
void generateDividendYieldScenarios(bool up)
ScenarioDescription equityScenarioDescription(string equity, bool up, ShiftScheme shiftScheme)
void generateCorrelationScenarios(bool up)
void generateEquityScenarios(bool up)
const Type & type() const
Inspectors.
Shift Scenario Generator.
std::vector< ScenarioDescription > scenarioDescriptions_
std::map< RiskFactorKey, std::string > keyToFactor_
std::vector< QuantLib::ext::shared_ptr< Scenario > > scenarios_
const QuantLib::ext::shared_ptr< Scenario > baseScenario_
void applyShift(Size j, Real shiftSize, bool up, ShiftType type, const vector< Time > &shiftTimes, const vector< Real > &values, const vector< Time > ×, vector< Real > &shiftedValues, bool initialise)
Apply 1d triangular shift to 1d data such as yield curves, public to allow test suite access.
std::map< std::string, RiskFactorKey > factorToKey_
const QuantLib::ext::weak_ptr< ScenarioSimMarket > simMarket_
const QuantLib::ext::shared_ptr< ScenarioSimMarketParameters > simMarketData_
SafeStack< ValueType > value
Calendar parseCalendar(const string &s)
DayCounter parseDayCounter(const string &s)
RandomVariable exp(RandomVariable x)
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
bool close(const Real &t_1, const Real &t_2)
bool vectorEqual(const vector< Real > &v_1, const vector< Real > &v_2)
std::vector< std::string > getCorrelationTokens(const std::string &name)
Size size(const ValueType &v)
std::string to_string(const LocationInfo &l)
Sensitivity scenario generation.
vector< Real > shiftStrikes
vector< Period > shiftExpiries
Structured analytics error.