Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
currencyhedgedequityindexdecomposition.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2023 Quaternion Risk Management Ltd.
3 All rights reserved.
4*/
5
6/*! \file orepsimm/ored/portfolio/equityindexdecomposition.hpp
7 \brief Helper function used for the index decompositon
8 */
11
12namespace ore {
13namespace data {
14
15QuantLib::ext::shared_ptr<CurrencyHedgedEquityIndexDecomposition>
16loadCurrencyHedgedIndexDecomposition(const std::string& name, const QuantLib::ext::shared_ptr<ReferenceDataManager>& refDataMgr,
17 const QuantLib::ext::shared_ptr<CurveConfigurations>& curveConfigs) {
18 QuantLib::ext::shared_ptr<CurrencyHedgedEquityIndexReferenceDatum> indexRefData;
19 QuantLib::ext::shared_ptr<EquityIndexReferenceDatum> underlyingRefData;
20 std::map<std::string, std::pair<double, std::string>> currencyWeightsAndFxIndexNames;
21
22 if (refDataMgr) {
23 if (refDataMgr->hasData("CurrencyHedgedEquityIndex", name))
24 indexRefData = QuantLib::ext::dynamic_pointer_cast<CurrencyHedgedEquityIndexReferenceDatum>(
25 refDataMgr->getData("CurrencyHedgedEquityIndex", name));
26
27 if (indexRefData != nullptr && refDataMgr->hasData("EquityIndex", indexRefData->underlyingIndexName()))
28 underlyingRefData = QuantLib::ext::dynamic_pointer_cast<EquityIndexReferenceDatum>(
29 refDataMgr->getData("EquityIndex", indexRefData->underlyingIndexName()));
30 }
31
32 if (indexRefData == nullptr || underlyingRefData == nullptr) {
33 return nullptr;
34 }
35
36 // Load currency Weights
37 std::map<std::string, double> currencyWeights;
38 std::string indexCurrency;
39 std::string underlyingIndexCurrency;
40 std::string fxIndexName;
41
42 // Get currency hedged index currency
43 if (curveConfigs && curveConfigs->hasEquityCurveConfig(indexRefData->id())) {
44 indexCurrency = curveConfigs->equityCurveConfig(indexRefData->id())->currency();
45 } else {
46 WLOG("Can not find curveConfig for " << indexRefData->id() << " and can not determine the index currecy");
47 return nullptr;
48 }
49
50
51 if (curveConfigs && curveConfigs->hasEquityCurveConfig(indexRefData->underlyingIndexName())) {
52
53 // Get Fx Index to convert UnderlyingIndexCCY into HedgedIndexCurrency
54 std::string underlyingIndexName = indexRefData->underlyingIndexName();
55 underlyingIndexCurrency =
56 curveConfigs->equityCurveConfig(indexRefData->underlyingIndexName())->currency();
57
58 auto fxIndexIt = indexRefData->fxIndexes().find(underlyingIndexCurrency);
59 if (fxIndexIt != indexRefData->fxIndexes().end()) {
60 fxIndexName = fxIndexIt->second;
61 } else {
62 fxIndexName = "FX-GENERIC-" + indexCurrency + "-" + underlyingIndexCurrency;
63 }
64
65 // Load the currency weights at referenceDate for hedge notionals
66 QuantLib::Date refDate =
67 CurrencyHedgedEquityIndexDecomposition::referenceDate(indexRefData, Settings::instance().evaluationDate());
68
69 std::map<std::string, double> underlyingIndexWeightsAtRebalancing;
70
71 if (indexRefData->currencyWeights().empty()) {
72 QuantLib::ext::shared_ptr<ReferenceDatum> undIndexRefDataAtRefDate;
73 try {
74 undIndexRefDataAtRefDate = refDataMgr->getData("EquityIndex", underlyingIndexName, refDate);
75 } catch (...) {
76 // Try to load ref data, but don't throw on error
77 }
78 if (undIndexRefDataAtRefDate) {
79 underlyingIndexWeightsAtRebalancing =
80 QuantLib::ext::dynamic_pointer_cast<EquityIndexReferenceDatum>(undIndexRefDataAtRefDate)->underlyings();
81 }
82 } else {
83 underlyingIndexWeightsAtRebalancing = indexRefData->currencyWeights();
84 }
85
86 if (underlyingIndexWeightsAtRebalancing.empty()) {
87 currencyWeights[underlyingIndexCurrency] = 1.0;
88 } else {
89 for (const auto& [name, weight] : underlyingIndexWeightsAtRebalancing) {
90 // try look up currency in reference data and add if FX delta risk if necessary
91 if (curveConfigs->hasEquityCurveConfig(name)) {
92 auto ecc = curveConfigs->equityCurveConfig(name);
93 auto eqCcy = ecc->currency();
94 currencyWeights[eqCcy] += weight;
95 } else {
96 // Assume Index currency
97 currencyWeights[underlyingIndexCurrency] += weight;
98 }
99 }
100 }
101 }
102
103 for (const auto& [currency, weight] : currencyWeights) {
104 if (currency != indexCurrency) {
105 auto defaultIndexIt = indexRefData->fxIndexes().find(currency);
106 if (defaultIndexIt != indexRefData->fxIndexes().end()) {
107 currencyWeightsAndFxIndexNames[currency] = std::make_pair(weight, defaultIndexIt->second);
108 } else {
109 currencyWeightsAndFxIndexNames[currency] =
110 std::make_pair(weight, "FX-GENERIC-" + indexCurrency + "-" + currency);
111 }
112 }
113 }
114 return QuantLib::ext::make_shared<CurrencyHedgedEquityIndexDecomposition>(name, indexRefData, underlyingRefData,
115 indexCurrency, underlyingIndexCurrency,
116 fxIndexName, currencyWeightsAndFxIndexNames);
117}
118
120 const QuantLib::ext::shared_ptr<CurrencyHedgedEquityIndexReferenceDatum>& refData,
121 const QuantLib::Date& asof) {
122 QuantLib::Date hedgingDate = CurrencyHedgedEquityIndexDecomposition::rebalancingDate(refData, asof);
123 if (hedgingDate == QuantLib::Date()) {
124 return QuantLib::Date();
125 } else {
126 return refData->hedgeCalendar().advance(hedgingDate, -refData->referenceDateOffset() * QuantLib::Days,
127 QuantLib::Preceding);
128 }
129}
130
132 const QuantLib::ext::shared_ptr<CurrencyHedgedEquityIndexReferenceDatum>& refData,
133 const QuantLib::Date& asof) {
134 if (refData->rebalancingStrategy() ==
136 QuantLib::Date lastBusinessDayOfCurrentMonth = QuantLib::Date::endOfMonth(asof);
137 lastBusinessDayOfCurrentMonth =
138 refData->hedgeCalendar().adjust(lastBusinessDayOfCurrentMonth, QuantLib::Preceding);
139 if (asof == lastBusinessDayOfCurrentMonth) {
140 return asof;
141 } else {
142 return refData->hedgeCalendar().advance(QuantLib::Date(1, asof.month(), asof.year()), -1 * QuantLib::Days,
143 QuantLib::Preceding);
144 }
145 }
146 return QuantLib::Date();
147}
148
149QuantLib::Date CurrencyHedgedEquityIndexDecomposition::referenceDate(const QuantLib::Date& asof) const {
151}
152
153QuantLib::Date CurrencyHedgedEquityIndexDecomposition::rebalancingDate(const QuantLib::Date& asof) const {
155}
156
158 const double quantity, const QuantLib::Date& asof, const QuantLib::ext::shared_ptr<ore::data::Market>& todaysMarket, const double shiftsize) const {
159
160 std::map<std::string, double> fxRisks;
161 auto indexCurve = todaysMarket->equityCurve(indexName());
162 auto underlyingCurve = todaysMarket->equityCurve(underlyingIndexName());
163 QuantLib::Date refDate = referenceDate(asof);
164 double adjustmentFactor = 1.0;
165 // If adjustement is daily, the fxForward notional will be adjusted by the relative return of the underlying index
167 adjustmentFactor = underlyingCurve->fixing(asof) / underlyingCurve->fixing(rebalancingDate(asof));
168 }
169 // Compute notionals and fxSpotRisks
170 for (const auto& [ccy, weightAndIndex] : currencyWeightsAndFxIndexNames()) {
171 double weight = weightAndIndex.first;
172 auto fxIndexFamily = parseFxIndex(fxIndexName())->familyName();
173 auto fxIndex = todaysMarket->fxIndex("FX-" + fxIndexFamily + "-" + underlyingIndexCurrency_ + "-" + indexCurrency_);
174 double forwardNotional =
175 quantity * adjustmentFactor * weight * indexCurve->fixing(refDate) / fxIndex->fixing(refDate);
176 fxRisks[ccy] = shiftsize * forwardNotional * fxIndex->fixing(asof);
177 }
178 return fxRisks;
179}
180
181double
182CurrencyHedgedEquityIndexDecomposition::unhedgedSpotExposure(double hedgedExposure, const double quantity,
183 const QuantLib::Date& asof,
184 const QuantLib::ext::shared_ptr<ore::data::Market>& todaysMarket) const {
185 auto indexCurve = todaysMarket->equityCurve(indexName());
186 auto underlyingCurve = todaysMarket->equityCurve(underlyingIndexName());
187 QuantLib::Date rebalanceDt = rebalancingDate(asof);
188 auto fxIndexFamily = parseFxIndex(fxIndexName())->familyName();
189 auto fxIndex = todaysMarket->fxIndex("FX-" + fxIndexFamily + "-" + underlyingIndexCurrency_ + "-" + indexCurrency_);
190 double hedgedUnitPrice = (hedgedExposure / quantity);
191 // In case we have a option and the unit delta isnt one
192 double scaling = hedgedUnitPrice / indexCurve->fixing(asof);
193 // Change in the fx since the last rebalacing
194 double fxReturn = fxIndex->fixing(asof) / fxIndex->fixing(rebalanceDt);
195 // Return of the underlying since last rebalacning
196 double underlyingIndexReturn = underlyingCurve->equitySpot()->value() / underlyingCurve->fixing(rebalanceDt);
197 // Unhedged price of the index
198 double unhedgedUnitPrice= indexCurve->fixing(rebalanceDt) * underlyingIndexReturn * fxReturn;
199 // Unhedged exposure
200 return scaling * quantity * unhedgedUnitPrice;
201}
202
204 const QuantLib::Date& asof, std::map<std::string, RequiredFixings::FixingDates>& fixings) const {
205 if (isValid()) {
206 QuantLib::Date rebalancingDt = rebalancingDate(asof);
207 QuantLib::Date referenceDt = referenceDate(asof);
208 fixings[IndexNameTranslator::instance().oreName(indexName())].addDate(rebalancingDt, false);
209 fixings[IndexNameTranslator::instance().oreName(indexName())].addDate(referenceDt, false);
210
211 IndexNameTranslator::instance().add(underlyingIndexName(), "EQ-" + underlyingIndexName());
212 fixings[IndexNameTranslator::instance().oreName(underlyingIndexName())].addDate(rebalancingDt, false);
213 fixings[IndexNameTranslator::instance().oreName(underlyingIndexName())].addDate(referenceDt, false);
214
215 fixings[fxIndexName()].addDate(referenceDt, false);
216 fixings[fxIndexName()].addDate(rebalancingDt, false);
217
218 for (const auto& [currency, name] : currencyWeightsAndFxIndexNames()) {
219 fixings[name.second].addDate(referenceDt, false);
220 fixings[name.second].addDate(rebalancingDt, false);
221 }
222 }
223}
224
225} // namespace data
226} // namespace ore
QuantLib::Date referenceDate(const QuantLib::Date &asof) const
double unhedgedSpotExposure(double hedgedExposure, const double quantity, const QuantLib::Date &asof, const QuantLib::ext::shared_ptr< ore::data::Market > &todaysMarket) const
QuantLib::ext::shared_ptr< ore::data::CurrencyHedgedEquityIndexReferenceDatum > indexRefData() const
const std::map< std::string, std::pair< double, std::string > > & currencyWeightsAndFxIndexNames() const
std::map< std::string, double > fxSpotRiskFromForwards(const double quantity, const QuantLib::Date &asof, const QuantLib::ext::shared_ptr< ore::data::Market > &todaysMarket, const double shiftsize) const
QuantLib::Date rebalancingDate(const QuantLib::Date &asof) const
QuantLib::ext::shared_ptr< ore::data::CurrencyHedgedEquityIndexReferenceDatum > indexRefData_
void addAdditionalFixingsForEquityIndexDecomposition(const QuantLib::Date &asof, std::map< std::string, RequiredFixings::FixingDates > &fixings) const
Helper function used for the index decompositon.
QuantLib::ext::shared_ptr< FxIndex > parseFxIndex(const string &s, const Handle< Quote > &fxSpot, const Handle< YieldTermStructure > &sourceYts, const Handle< YieldTermStructure > &targetYts, const bool useConventions)
Convert std::string to QuantExt::FxIndex.
translates between QuantLib::Index::name() and ORE names
@ data
Definition: log.hpp:77
#define WLOG(text)
Logging Macro (Level = Warning)
Definition: log.hpp:550
Date referenceDate
Definition: utilities.cpp:442
QuantLib::ext::shared_ptr< CurrencyHedgedEquityIndexDecomposition > loadCurrencyHedgedIndexDecomposition(const std::string &name, const QuantLib::ext::shared_ptr< ReferenceDataManager > &refDataMgr, const QuantLib::ext::shared_ptr< CurveConfigurations > &curveConfigs)
Serializable Credit Default Swap.
Definition: namespaces.docs:23
vector< string > curveConfigs
string name