31 const QuantLib::ext::shared_ptr<SensitivityStream>& ss,
const std::string& baseCurrency,
32 std::map<std::string, std::map<std::string, double>> defaultRiskDecompositionWeights,
33 const std::set<std::string>& eqComDecompositionTradeIds,
34 const std::map<std::string, std::map<std::string, double>>& currencyHedgedIndexQuantities,
35 const QuantLib::ext::shared_ptr<ore::data::ReferenceDataManager>& refDataManager,
36 const QuantLib::ext::shared_ptr<ore::data::CurveConfigurations>& curveConfigs,
37 const QuantLib::ext::shared_ptr<SensitivityScenarioData>& scenarioData,
38 const QuantLib::ext::shared_ptr<ore::data::Market>& todaysMarket)
39 : ss_(ss), baseCurrency_(baseCurrency), defaultRiskDecompositionWeights_(defaultRiskDecompositionWeights),
40 eqComDecompositionTradeIds_(eqComDecompositionTradeIds),
41 currencyHedgedIndexQuantities_(currencyHedgedIndexQuantities), refDataManager_(refDataManager),
42 curveConfigs_(
curveConfigs), ssd_(scenarioData), todaysMarket_(todaysMarket) {
60 std::vector<SensitivityRecord> results;
62 bool tradeMarkedForDecompositionDefaultRisk =
64 bool tradeMarkedForDecomposition =
71 bool decomposeEquitySpot = tradeMarkedForDecomposition && isEquitySpotSensi &&
refDataManager_ !=
nullptr &&
73 bool decomposeCurrencyHedgedSpot = tradeMarkedForDecomposition && isEquitySpotSensi &&
refDataManager_ !=
nullptr &&
75 bool decomposeCommoditySpot = tradeMarkedForDecomposition && (isCommoditySpotSensi || isEquitySpotSensi) &&
80 if (tradeMarkedForDecompositionDefaultRisk && isSurvivalProbSensi && isNotCrossGamma) {
82 }
else if (decomposeEquitySpot && isNotCrossGamma) {
85 return sensitivityRecords(decompResults.spotRisk, decompResults.fxRisk, decompResults.indexCurrency,
87 }
else if (decomposeCurrencyHedgedSpot && isNotCrossGamma) {
89 }
else if (decomposeCommoditySpot && isNotCrossGamma) {
92 return sensitivityRecords(decompResults.spotRisk, decompResults.fxRisk, decompResults.indexCurrency,
94 }
else if (tradeMarkedForDecomposition && (isCommoditySpotSensi || isEquitySpotSensi) && isNotCrossGamma) {
95 auto subFields = std::map<std::string, std::string>({{
"tradeId", record.
tradeId}});
97 "Sensitivity Decomposition",
"Index decomposition failed",
98 "Cannot decompose equity index delta (" + record.
key_1.
name +
99 ") for trade: no reference data found. Continuing without decomposition.",
103 }
catch (
const std::exception& e) {
104 auto subFields = std::map<std::string, std::string>({{
"tradeId", record.
tradeId}});
106 "Sensitivity Decomposition",
"Index decomposition failed",
107 "Cannot decompose equity index delta (" + record.
key_1.
name +
") for trade:" + e.what(), subFields)
110 auto subFields = std::map<std::string, std::string>({{
"tradeId", record.
tradeId}});
112 "Sensitivity Decomposition",
"Index decomposition failed",
113 "Cannot decompose equity index delta (" + record.
key_1.
name +
") for trade: unkown error", subFields)
119std::vector<SensitivityRecord>
121 std::vector<SensitivityRecord> results;
122 auto decompRecord = record;
125 decompRecord.delta = record.
delta * weight;
126 decompRecord.gamma = record.
gamma * weight;
127 results.push_back(decompRecord);
134 const double spotDelta,
const std::map<std::string, double>& indexWeights)
const {
135 std::map<std::string, double> results;
136 for (
const auto& [constituent, weight] : indexWeights) {
137 results[constituent] = weight * spotDelta;
143 const std::map<std::string, double>& spotRisk,
144 const std::map<std::string, std::vector<std::string>>& constituentCurrencies,
145 const std::map<std::string, double>& fxSpotShiftSize,
const double eqShiftSize)
const {
146 std::map<std::string, double> results;
147 for (
const auto& [currency, constituents] : constituentCurrencies) {
149 QL_REQUIRE(fxSpotShiftSize.count(currency) == 1,
"Can not find fxSpotShiftSize for currency " << currency);
150 for (
const auto& constituent : constituents) {
151 QL_REQUIRE(spotRisk.count(constituent) == 1,
"Can not find spotDelta for " << constituent);
152 results[currency] += spotRisk.at(constituent) * fxSpotShiftSize.at(currency) / eqShiftSize;
161 auto fxShiftSizeIt =
ssd_->fxShiftData().find(fxpair);
162 QL_REQUIRE(fxShiftSizeIt !=
ssd_->fxShiftData().end(),
"Couldn't find shiftsize for " << fxpair);
164 "Requires a relative fxSpot shift for index decomposition");
165 return fxShiftSizeIt->second.shiftSize;
168std::map<std::string, double>
170 std::map<std::string, double> results;
171 for (
const auto& [ccy,_] : currencies) {
174 results[ccy] = shiftSize;
181 auto eqShiftSizeIt =
ssd_->equityShiftData().find(
name);
182 QL_REQUIRE(eqShiftSizeIt !=
ssd_->equityShiftData().end(),
"Couldn't find a equity shift size for " <<
name);
184 "Requires a relative eqSpot shift for index decomposition");
185 return eqShiftSizeIt->second.shiftSize;
190 if (curveType == ore::data::CurveSpec::CurveType::Equity) {
192 }
else if (curveType == ore::data::CurveSpec::CurveType::Commodity) {
195 QL_FAIL(
"unsupported curveType, got "
196 << curveType <<
". Only Equity and Commodity curves are supported for decomposition.");
201 auto commShiftSizeIt =
ssd_->commodityCurveShiftData().find(
name);
202 if (commShiftSizeIt !=
ssd_->commodityCurveShiftData().end()) {
204 "Requires a relative eqSpot shift for index decomposition");
205 return commShiftSizeIt->second->shiftSize;
207 LOG(
"Could not find a commodity shift size for commodity index "
208 <<
name <<
". Try to find a equity spot shift size as fallback")
213std::map<std::string, std::vector<std::string>>
215 const std::string& indexCurrency,
217 std::map<std::string, std::vector<std::string>> results;
218 for (
const auto& [constituent, _] : constituents) {
223 "Cannot find currency for equity " + constituent +
224 " from curve configs, fallback to use index currency (" +
229 results[ccy].push_back(constituent);
240 std::string refDataType = curveType == ore::data::CurveSpec::CurveType::Equity ?
"EquityIndex" :
"CommodityIndex";
243 "Cannot decompose equity index delta ("
244 << indexName <<
") for trade: no reference data found. Continuing without decomposition.");
247 auto indexRefDatum = QuantLib::ext::dynamic_pointer_cast<ore::data::IndexReferenceDatum>(refDatum);
248 std::string indexCurrency =
curveCurrency(indexName, curveType);
249 std::map<string, double> indexWeights = indexRefDatum->underlyings();
261std::vector<SensitivityRecord>
265 auto indexCurrency =
curveCurrency(indexName, ore::data::CurveSpec::CurveType::Equity);
267 QuantLib::ext::shared_ptr<ore::data::CurrencyHedgedEquityIndexDecomposition> decomposeCurrencyHedgedIndexHelper;
268 decomposeCurrencyHedgedIndexHelper =
270 if (decomposeCurrencyHedgedIndexHelper !=
nullptr) {
272 "CurrencyHedgedIndexDecomposition failed, there is no index quantity for trade "
273 << sr.
tradeId <<
" and equity index EQ-" << indexName);
275 "CurrencyHedgedIndexDecomposition failed, there is no index quantity for trade "
276 << sr.
tradeId <<
" and equity index EQ-" << indexName);
278 "CurrencyHedgedIndexDecomposition failed, there is no market given quantity for trade "
281 Date today = QuantLib::Settings::instance().evaluationDate();
285 QL_REQUIRE(quantity != QuantLib::Null<double>(),
286 "CurrencyHedgedIndexDecomposition failed, index quantity cannot be NULL.");
288 double assetSensiShift =
assetSpotShiftSize(indexName, ore::data::CurveSpec::CurveType::Equity);
290 double hedgedExposure = sr.
delta / assetSensiShift;
292 double unhedgedExposure =
293 decomposeCurrencyHedgedIndexHelper->unhedgedSpotExposure(hedgedExposure, quantity, today,
todaysMarket_);
295 double unhedgedDelta = unhedgedExposure * assetSensiShift;
298 indexDecomposition(unhedgedDelta, decomposeCurrencyHedgedIndexHelper->underlyingIndexName(),
299 ore::data::CurveSpec::CurveType::Equity);
302 for (
const auto& [ccy, fxRisk] :
303 decomposeCurrencyHedgedIndexHelper->fxSpotRiskFromForwards(quantity, today,
todaysMarket_, 1.0)) {
304 decompResults.fxRisk[ccy] = decompResults.fxRisk[ccy] - fxRisk *
fxRiskShiftSize(ccy);
307 return sensitivityRecords(decompResults.spotRisk, decompResults.fxRisk, indexCurrency, sr);
309 auto subFields = std::map<std::string, std::string>({{
"tradeId", sr.
tradeId}});
311 "Cannot decompose equity index delta (" + indexName +
312 ") for trade: no reference data found. Continuing without decomposition.",
325std::vector<SensitivityRecord>
327 const std::map<std::string, double>& fxDeltas,
329 std::vector<SensitivityRecord> records;
330 for (
auto [underlying, delta] : eqDeltas) {
336 for (
auto [ccy, delta] : fxDeltas) {
350 curveCurrency = curveType == ore::data::CurveSpec::CurveType::Equity
QuantLib::ext::shared_ptr< ore::data::CurveConfigurations > curveConfigs_
std::map< std::string, std::vector< std::string > > getConstituentCurrencies(const std::map< std::string, double > &constituents, const std::string &indexCurrency, const ore::data::CurveSpec::CurveType curveType) const
QuantLib::ext::shared_ptr< ore::data::Market > todaysMarket_
std::string baseCurrency_
IndexDecompositionResult indexDecomposition(double delta, const std::string &indexName, const ore::data::CurveSpec::CurveType curveType) const
double commoditySpotShiftSize(const std::string name) const
double assetSpotShiftSize(const std::string name, const ore::data::CurveSpec::CurveType curveType) const
Return the asset spot shift size.
DecomposedSensitivityStream(const QuantLib::ext::shared_ptr< SensitivityStream > &ss, const std::string &baseCurrency, std::map< std::string, std::map< std::string, double > > defaultRiskDecompositionWeights={}, const std::set< std::string > &eqComDecompositionTradeIds={}, const std::map< std::string, std::map< std::string, double > > ¤cyHedgedIndexQuantities={}, const QuantLib::ext::shared_ptr< ore::data::ReferenceDataManager > &refDataManager=nullptr, const QuantLib::ext::shared_ptr< ore::data::CurveConfigurations > &curveConfigs=nullptr, const QuantLib::ext::shared_ptr< SensitivityScenarioData > &scenarioData=nullptr, const QuantLib::ext::shared_ptr< ore::data::Market > &todaysMarket=nullptr)
std::string curveCurrency(const std::string &name, ore::data::CurveSpec::CurveType curveType) const
double equitySpotShiftSize(const std::string name) const
QuantLib::ext::shared_ptr< SensitivityScenarioData > ssd_
std::vector< SensitivityRecord > decomposeSurvivalProbability(const SensitivityRecord &record) const
QuantLib::ext::shared_ptr< SensitivityStream > ss_
The underlying sensitivity stream that has been wrapped.
std::vector< SensitivityRecord > decompose(const SensitivityRecord &record) const
Decompose the record and add it to the internal storage;.
std::map< std::string, double > fxRiskFromDecomposition(const std::map< std::string, double > &spotRisk, const std::map< std::string, std::vector< std::string > > &constituentCurrencies, const std::map< std::string, double > &fxSpotShiftSize, const double eqShiftSize) const
Compute the resulting fx risks from a given equity/commodity decomposition.
QuantLib::ext::shared_ptr< ore::data::ReferenceDataManager > refDataManager_
refDataManager holding the equity and commodity index decomposition weights
double fxRiskShiftSize(const std::string ccy) const
Return the sensi shift size for the shifting the ccy-baseCurrency spot quote.
std::vector< SensitivityRecord >::iterator itCurrent_
std::vector< SensitivityRecord > decomposedRecords_
std::map< std::string, std::map< std::string, double > > currencyHedgedIndexQuantities_
list of trade id, for which a commodity index decomposition should be applied
std::vector< SensitivityRecord > decomposeCurrencyHedgedIndexRisk(const SensitivityRecord &record) const
std::map< std::string, double > constituentSpotRiskFromDecomposition(const double spotDelta, const std::map< std::string, double > &indexWeights) const
Decompose a equity/commodity spot sensitivity into the constituent spot sensistivities.
std::map< std::string, double > fxRiskShiftSizes(const std::map< std::string, std::vector< std::string > > &constituentCurrencies) const
Returns the shift sizes for all currencies in the map.
std::vector< SensitivityRecord > sensitivityRecords(const std::map< std::string, double > &eqDeltas, const std::map< std::string, double > &fxDeltas, const std::string indexCurrency, const SensitivityRecord &orginialRecord) const
void reset() override
Resets the stream so that SensitivityRecord objects can be streamed again.
SensitivityRecord next() override
Returns the next SensitivityRecord in the stream after filtering.
std::set< std::string > eqComDecompositionTradeIds_
list of trade id, for which a equity index decomposition should be applied
std::map< std::string, std::map< std::string, double > > defaultRiskDecompositionWeights_
map of trade ids to the basket consituents with their resp. weights
Data types stored in the scenario class.
std::string name
Key name.
Class that wraps a sensitivity stream and decomposes equity/commodity and default risk records.
QuantLib::ext::shared_ptr< CurrencyHedgedEquityIndexDecomposition > loadCurrencyHedgedIndexDecomposition(const std::string &name, const QuantLib::ext::shared_ptr< ReferenceDataManager > &refDataMgr, const QuantLib::ext::shared_ptr< CurveConfigurations > &curveConfigs)
std::map< std::string, double > spotRisk
std::map< std::string, double > fxRisk
std::string indexCurrency
bool isCrossGamma() const
True if a SensitivityRecord is a cross gamma, otherwise false.
Structured analytics error.
Class for structured analytics warnings.
vector< string > curveConfigs