Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
marketdataloader.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2022 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
25
26using namespace ore::data;
28
29namespace ore {
30namespace analytics {
31
32// Additional quotes for fx fixings, add fixing quotes with USD and EUR to the list of fixings
33// requested in order to triangulate missing fixings
34void additional_fx_fixings(const string& fixingId, const RequiredFixings::FixingDates& fixingDates,
35 FixingMap& relevantFixings) {
36 std::vector<std::string> tokens;
37 boost::split(tokens, fixingId, boost::is_any_of("-"));
38 QL_REQUIRE(tokens.size() == 4, "MarketDataLoader::additional_fx_fixings: Invalid fixing id, "
39 << "must be of form FX-TYPE-CCY1-CCY, e.g FX-ECB-EUR-GBP");
40
41 // add fixings on inverted ccy pair
42 relevantFixings[tokens[0] + "-" + tokens[1] + "-" + tokens[3] + "-" + tokens[2]].addDates(fixingDates, false);
43
44 vector<string> baseCcys = {"USD", "EUR"};
45
46 for (auto ccy : baseCcys) {
47
48 string fixingType = tokens[0] + "-" + tokens[1] + "-";
49 if (tokens[2] != ccy) {
50 string fix = fixingType + ccy + "-" + tokens[2];
51 relevantFixings[fix].addDates(fixingDates, false);
52
53 if (tokens[3] != ccy) {
54 fix = fixingType + tokens[2] + "-" + ccy;
55 relevantFixings[fix].addDates(fixingDates, false);
56 }
57 }
58
59 if (tokens[3] != ccy) {
60 string fix = fixingType + ccy + "-" + tokens[3];
61 relevantFixings[fix].addDates(fixingDates, false);
62
63 if (tokens[2] != ccy) {
64 fix = fixingType + tokens[3] + "-" + ccy;
65 relevantFixings[fix].addDates(fixingDates, false);
66 }
67 }
68 }
69}
70
71// Additional quotes for commodity fixings
72void additional_commodity_fixings(const string& fixingId, const RequiredFixings::FixingDates& fixingDates, FixingMap& fixings,
73 map<pair<string, Date>, set<Date>>& commodityMap) {
74
75 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
76
77 auto ind = parseCommodityIndex(fixingId);
78 string commName = ind->underlyingName();
79
80 QuantLib::ext::shared_ptr<CommodityFutureConvention> cfc;
81 if (conventions->has(commName)) {
82 cfc = QuantLib::ext::dynamic_pointer_cast<CommodityFutureConvention>(conventions->get(commName));
83 }
84
85 if (cfc) {
86 // Add historical fixings for daily and monthly expiring contracts
87 // TODO: potentially need to add for OffPeakPowerIndex commodities too.
88 if (cfc->contractFrequency() == Daily) {
89 for (const auto& [fd, _]: fixingDates) {
90 // Add 1 week lookback for each date for daily expiry
91 set<Date> dates;
92 Date wLookback = fd - Period(1, Weeks);
93 do {
94 dates.insert(wLookback++);
95 } while (wLookback <= fd);
96
97 TLOG("Adding (date, id) = (" << io::iso_date(fd) << "," << fixingId << ")");
98 // Add to the fixings so a fixing is requested for all dates, and also to the commodityMap
99 // so we can map a fixing to the correct date required
100 fixings[fixingId].addDates(dates, false);
101 commodityMap[pair(fixingId, fd)].insert(dates.begin(), dates.end());
102 }
103 } else {
104 // for monthly expiries add fixings for the last 45 days
105 for (const auto& [fd,_] : fixingDates) {
106 set<Date> dates;
107 Date wLookback = fd - Period(45, Days);
108 do {
109 dates.insert(wLookback++);
110 } while (wLookback <= fd);
111
112 TLOG("Adding (date, id) = (" << io::iso_date(fd) << "," << fixingId << ")");
113 // Add to the fixings so a fixing is requested for all dates, and also to the commodityMap
114 // so we can map a fixing to the correct date required
115 fixings[fixingId].addDates(dates, false);
116 commodityMap[pair(fixingId, fd)].insert(dates.begin(), dates.end());
117 }
118 }
119 }
120}
121
122// Additional fixings for equity index decomposition
123void additional_equity_fixings(map<string, RequiredFixings::FixingDates>& fixings, const TodaysMarketParameters& mktParams,
124 const QuantLib::ext::shared_ptr<ReferenceDataManager> refData,
125 const QuantLib::ext::shared_ptr<CurveConfigurations>& curveConfigs) {
126 std::string configuration = Market::defaultConfiguration;
127 Date asof = Settings::instance().evaluationDate();
128 QuantLib::ext::shared_ptr<CurrencyHedgedEquityIndexReferenceDatum> currencyHedgedIndexData;
129 if (mktParams.hasMarketObject(MarketObject::EquityCurve)) {
130 for (const auto& [equityName, _] : mktParams.mapping(MarketObject::EquityCurve, configuration)) {
131 try {
132 auto indexDecomposition = loadCurrencyHedgedIndexDecomposition(equityName, refData, curveConfigs);
133 if (indexDecomposition) {
134 indexDecomposition->addAdditionalFixingsForEquityIndexDecomposition(asof, fixings);
135 }
136 } catch (const std::exception& e) {
137 ALOG("adding additional equity fixing failed, " << e.what());
138 }
139 }
140 }
141}
142
143const QuantLib::ext::shared_ptr<MarketDataLoaderImpl>& MarketDataLoader::impl() const {
144 QL_REQUIRE(impl_, "No MarketDataLoader implementation of type MarketDataLoaderImpl set");
145 return impl_;
146}
147
149 const std::pair<std::string, RequiredFixings::FixingDates>& fixing,
150 std::map<std::pair<std::string, QuantLib::Date>, std::set<QuantLib::Date>>& lastAvailableFixingLookupMap) {
151 if (isFxIndex(fixing.first)) {
152 // for FX fixings we want to add additional fixings to allow triangulation in case of missing
153 // fixings if we need EUR/GBP fixing but it is not available, we can imply from EUR/USD and GBP/USD
154 additional_fx_fixings(fixing.first, fixing.second, fixings_);
155 }
156 if (isCommodityIndex(fixing.first)) {
157 additional_commodity_fixings(fixing.first, fixing.second, fixings_, lastAvailableFixingLookupMap);
158 }
159 fixings_[fixing.first].addDates(fixing.second);
160}
161
163 const std::vector<QuantLib::ext::shared_ptr<ore::data::TodaysMarketParameters>>& todaysMarketParameters,
164 const std::set<QuantLib::Date>& loaderDates) {
165 if (inputs_->allFixings()) {
166 impl()->retrieveFixings(loader_);
167 } else {
168 LOG("Asking portfolio for its required fixings");
169 FixingMap portfolioFixings;
170 std::map<std::pair<std::string, QuantLib::Date>, std::set<QuantLib::Date>> lastAvailableFixingLookupMap;
171
172 // portfolio fixings will warn if missing
173 if (inputs_->portfolio()) {
174 portfolioFixings = inputs_->portfolio()->fixings();
175 LOG("The portfolio depends on fixings from " << portfolioFixings.size() << " indices");
176 for (const auto& it : portfolioFixings)
177 addRelevantFixings(it, lastAvailableFixingLookupMap);
178 }
179
180 LOG("Add fixings possibly required for bootstrapping TodaysMarket");
181 for (const auto& tmp : todaysMarketParameters) {
182 for (const auto d : loaderDates)
184 LOG("Add fixing possibly required for equity index delta risk decomposition")
185 additional_equity_fixings(fixings_, *tmp, inputs_->refDataManager(),
186 inputs_->curveConfigs().get());
187 }
188
189 if (inputs_->eomInflationFixings()) {
190 LOG("Adjust inflation fixing dates to the end of the month before the request");
192 }
193
194 if (fixings_.size() > 0)
195 impl()->retrieveFixings(loader_, fixings_, lastAvailableFixingLookupMap);
196
197 // apply all fixings now
198 applyFixings(loader_->loadFixings());
199
200 // check and warn any missing fixings - only warn for mandatory fixings
201 for (const auto& [indexName, fixingDates] : fixings_) {
202 for (const auto& [d, mandatory] :fixingDates) {
203 if (mandatory && !loader_->hasFixing(indexName, d)) {
204 string fixingErr = "";
205 if (isFxIndex(indexName)) {
206 auto fxInd = parseFxIndex(indexName);
207 try {
208 if(fxInd->fixingCalendar().isBusinessDay(d))
209 fxInd->fixing(d);
210 break;
211 } catch (const std::exception& e) {
212 fixingErr = ", error: " + ore::data::to_string(e.what());
213 }
214 }
215 StructuredFixingWarningMessage(indexName, d, "Missing fixing", "Could not find required fixing ID.")
216 .log();
217 }
218 }
219 }
220 }
221}
222
224 const std::vector<QuantLib::ext::shared_ptr<ore::data::TodaysMarketParameters>>& todaysMarketParameters,
225 const std::set<QuantLib::Date>& loaderDates) {
226
227 // create a loader if doesn't already exist
228 if (!loader_)
229 loader_ = QuantLib::ext::make_shared<InMemoryLoader>();
230 else
231 loader_->reset(); // can only populate once to avoid duplicates
232
233 // check input data
234 QL_REQUIRE(!inputs_->curveConfigs().empty(), "Need at least one curve configuration to populate loader.");
235 QL_REQUIRE(todaysMarketParameters.size() > 0, "No todaysMarketParams provided to populate market data loader.");
236
237 // for equities check if we have corporate action data
238 std::map<std::string, std::string> equities;
239 for (const auto& tmp : todaysMarketParameters) {
240 if (tmp->hasMarketObject(MarketObject::EquityCurve)) {
241 auto eqMap = tmp->mapping(MarketObject::EquityCurve, Market::defaultConfiguration);
242 for (auto eq : eqMap) {
243 if (inputs_->refDataManager() && inputs_->refDataManager()->hasData("Equity", eq.first)) {
244 auto refData = QuantLib::ext::dynamic_pointer_cast<EquityReferenceDatum>(
245 inputs_->refDataManager()->getData("Equity", eq.first));
246 auto erData = refData->equityData();
247 equities[eq.first] = erData.equityId;
248 } else
249 equities[eq.first] = eq.first;
250 }
251 }
252 }
253 if (equities.size() > 0)
254 impl()->loadCorporateActionData(loader_, equities);
255
256 // apply dividends now
257 applyDividends(loader_->loadDividends());
258
259 populateFixings(todaysMarketParameters, loaderDates);
260
261 LOG("Adding the loaded fixings to the IndexManager");
262 applyFixings(loader_->loadFixings());
263
264 // Get set of quotes we need
265 LOG("Generating market datum set");
266 set<string> quotes;
267 for (const auto& tmp : todaysMarketParameters) {
268 // Find all configurations in this todaysMarket
269 std::set<std::string> configurations;
270 for (auto c : tmp->configurations())
271 configurations.insert(c.first);
272
273 for (const auto& [_,curveConfig] : inputs_->curveConfigs().curveConfigurations()) {
274 auto qs = curveConfig->quotes(tmp, configurations);
275 quotes.insert(qs.begin(), qs.end());
276 }
277 }
278
279 for (const auto& d : loaderDates) {
280 QuoteMap quoteMap;
281 quoteMap[d] = quotes;
282
283 LOG("CurveConfigs require " << quotes.size() << " quotes");
284
285 // Get the relevant market data loader for the pricing call
286 impl()->retrieveMarketData(loader_, quoteMap, d);
287
288 quotes_[d] = quotes;
289 }
290 LOG("Got market data");
291}
292
293}
294} // namespace oreplus
virtual void populateFixings(const std::vector< QuantLib::ext::shared_ptr< ore::data::TodaysMarketParameters > > &todaysMarketParameters, const std::set< QuantLib::Date > &loaderDates={})
QuantLib::ext::shared_ptr< MarketDataLoaderImpl > impl_
void populateLoader(const std::vector< QuantLib::ext::shared_ptr< ore::data::TodaysMarketParameters > > &todaysMarketParameters, const std::set< QuantLib::Date > &loaderDates)
virtual void addRelevantFixings(const std::pair< std::string, RequiredFixings::FixingDates > &fixing, std::map< std::pair< std::string, QuantLib::Date >, std::set< QuantLib::Date > > &lastAvailableFixingLookupMap)
QuantLib::ext::shared_ptr< ore::data::InMemoryLoader > loader_
QuantLib::ext::shared_ptr< InputParameters > inputs_
const QuantLib::ext::shared_ptr< MarketDataLoaderImpl > & impl() const
Utility class for Structured Fixing warnings.
static const string defaultConfiguration
const map< string, string > & mapping(const MarketObject o, const string &configuration) const
bool hasMarketObject(const MarketObject &o) const
QuantLib::ext::shared_ptr< FxIndex > parseFxIndex(const string &s, const Handle< Quote > &fxSpot=Handle< Quote >(), const Handle< YieldTermStructure > &sourceYts=Handle< YieldTermStructure >(), const Handle< YieldTermStructure > &targetYts=Handle< YieldTermStructure >(), const bool useConventions=false)
bool isCommodityIndex(const std::string &indexName)
#define LOG(text)
#define ALOG(text)
#define TLOG(text)
Market Data Loader.
void applyDividends(const std::set< Dividend > &dividends)
std::map< std::string, RequiredFixings::FixingDates > FixingMap
void additional_fx_fixings(const string &fixingId, const RequiredFixings::FixingDates &fixingDates, FixingMap &relevantFixings)
std::map< QuantLib::Date, std::set< std::string > > QuoteMap
void additional_equity_fixings(map< string, RequiredFixings::FixingDates > &fixings, const TodaysMarketParameters &mktParams, const QuantLib::ext::shared_ptr< ReferenceDataManager > refData, const QuantLib::ext::shared_ptr< CurveConfigurations > &curveConfigs)
void additional_commodity_fixings(const string &fixingId, const RequiredFixings::FixingDates &fixingDates, FixingMap &fixings, map< pair< string, Date >, set< Date > > &commodityMap)
bool isFxIndex(const std::string &indexName)
void amendInflationFixingDates(std::map< std::string, RequiredFixings::FixingDates > &fixings)
QuantLib::ext::shared_ptr< CurrencyHedgedEquityIndexDecomposition > loadCurrencyHedgedIndexDecomposition(const std::string &name, const QuantLib::ext::shared_ptr< ReferenceDataManager > &refDataMgr, const QuantLib::ext::shared_ptr< CurveConfigurations > &curveConfigs)
void addMarketFixingDates(const Date &asof, map< string, RequiredFixings::FixingDates > &fixings, const TodaysMarketParameters &mktParams, const Period &iborLookback, const Period &oisLookback, const Period &bmaLookback, const Period &inflationLookback)
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)
void applyFixings(const std::set< Fixing > &fixings)
vector< string > curveConfigs
Date asof(14, Jun, 2018)