Skip to content

Commit f02364a

Browse files
pcaspersjenkins
authored andcommitted
Resolve QPR-12108 optional fixings
1 parent 8be3ce7 commit f02364a

18 files changed

Lines changed: 513 additions & 300 deletions

OREAnalytics/orea/app/marketdatacsvloader.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ void MarketDataCsvLoaderImpl::retrieveMarketData(
7272
}
7373

7474
void MarketDataCsvLoaderImpl::retrieveFixings(const boost::shared_ptr<ore::data::InMemoryLoader>& loader,
75-
map<string, set<Date>> fixings,
75+
ore::analytics::FixingMap fixings,
7676
map<pair<string, Date>, set<Date>> lastAvailableFixingLookupMap) {
7777

7878
LOG("MarketDataCsvLoader::retrieveFixings called: all fixings ? " << (inputs_->allFixings() ? "Y" : "N"));
@@ -86,11 +86,10 @@ void MarketDataCsvLoaderImpl::retrieveFixings(const boost::shared_ptr<ore::data:
8686
// Filter by required fixing data
8787

8888
// Loop over the relevant fixings and add only them to the InMemoryLoader
89-
for (auto kv : fixings) {
89+
for (const auto& [name, fixingDates] : fixings) {
9090
// LOG("fixings are required for index " << kv.first << " and " << kv.second.size() << " dates");
9191
// map<string, set<Date>>
92-
const string& name = kv.first;
93-
for (const auto& date : kv.second) {
92+
for (const auto& [date, mandatory] : fixingDates) {
9493
// lazy loop over all of them...
9594
for (const auto& fix : csvLoader_->loadFixings()) {
9695
if (fix.name == name && fix.date == date) {

OREAnalytics/orea/app/marketdatainmemoryloader.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ void MarketDataInMemoryLoaderImpl::retrieveMarketData(
4343
}
4444

4545
void MarketDataInMemoryLoaderImpl::retrieveFixings(const boost::shared_ptr<ore::data::InMemoryLoader>& loader,
46-
map<string, set<Date>> fixings,
46+
map<string, RequiredFixings::FixingDates> fixings,
4747
map<pair<string, Date>, set<Date>> lastAvailableFixingLookupMap) {
4848

4949
if (inputs_->allFixings()) {

OREAnalytics/orea/app/marketdataloader.cpp

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,15 @@ namespace analytics {
3131

3232
// Additional quotes for fx fixings, add fixing quotes with USD and EUR to the list of fixings
3333
// requested in order to triangulate missing fixings
34-
void additional_fx_fixings(const string& fixingId, const set<Date>& fixingDates, FixingMap& relevantFixings) {
34+
void additional_fx_fixings(const string& fixingId, const RequiredFixings::FixingDates& fixingDates,
35+
FixingMap& relevantFixings) {
3536
std::vector<std::string> tokens;
3637
boost::split(tokens, fixingId, boost::is_any_of("-"));
3738
QL_REQUIRE(tokens.size() == 4, "MarketDataLoader::additional_fx_fixings: Invalid fixing id, "
3839
<< "must be of form FX-TYPE-CCY1-CCY, e.g FX-ECB-EUR-GBP");
3940

4041
// add fixings on inverted ccy pair
41-
relevantFixings[tokens[0] + "-" + tokens[1] + "-" + tokens[3] + "-" + tokens[2]].insert(fixingDates.begin(),
42-
fixingDates.end());
42+
relevantFixings[tokens[0] + "-" + tokens[1] + "-" + tokens[3] + "-" + tokens[2]].addDates(fixingDates, false);
4343

4444
vector<string> baseCcys = {"USD", "EUR"};
4545

@@ -48,28 +48,28 @@ void additional_fx_fixings(const string& fixingId, const set<Date>& fixingDates,
4848
string fixingType = tokens[0] + "-" + tokens[1] + "-";
4949
if (tokens[2] != ccy) {
5050
string fix = fixingType + ccy + "-" + tokens[2];
51-
relevantFixings[fix].insert(fixingDates.begin(), fixingDates.end());
51+
relevantFixings[fix].addDates(fixingDates, false);
5252

5353
if (tokens[3] != ccy) {
5454
fix = fixingType + tokens[2] + "-" + ccy;
55-
relevantFixings[fix].insert(fixingDates.begin(), fixingDates.end());
55+
relevantFixings[fix].addDates(fixingDates, false);
5656
}
5757
}
5858

5959
if (tokens[3] != ccy) {
6060
string fix = fixingType + ccy + "-" + tokens[3];
61-
relevantFixings[fix].insert(fixingDates.begin(), fixingDates.end());
61+
relevantFixings[fix].addDates(fixingDates, false);
6262

6363
if (tokens[2] != ccy) {
6464
fix = fixingType + tokens[3] + "-" + ccy;
65-
relevantFixings[fix].insert(fixingDates.begin(), fixingDates.end());
65+
relevantFixings[fix].addDates(fixingDates, false);
6666
}
6767
}
6868
}
6969
}
7070

7171
// Additional quotes for commodity fixings
72-
void additional_commodity_fixings(const string& fixingId, const set<Date>& fixingDates, FixingMap& fixings,
72+
void additional_commodity_fixings(const string& fixingId, const RequiredFixings::FixingDates& fixingDates, FixingMap& fixings,
7373
map<pair<string, Date>, set<Date>>& commodityMap) {
7474

7575
boost::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
@@ -86,7 +86,7 @@ void additional_commodity_fixings(const string& fixingId, const set<Date>& fixin
8686
// Add historical fixings for daily and monthly expiring contracts
8787
// TODO: potentially need to add for OffPeakPowerIndex commodities too.
8888
if (cfc->contractFrequency() == Daily) {
89-
for (const auto& fd : fixingDates) {
89+
for (const auto& [fd, _]: fixingDates) {
9090
// Add 1 week lookback for each date for daily expiry
9191
set<Date> dates;
9292
Date wLookback = fd - Period(1, Weeks);
@@ -97,12 +97,12 @@ void additional_commodity_fixings(const string& fixingId, const set<Date>& fixin
9797
TLOG("Adding (date, id) = (" << io::iso_date(fd) << "," << fixingId << ")");
9898
// Add to the fixings so a fixing is requested for all dates, and also to the commodityMap
9999
// so we can map a fixing to the correct date required
100-
fixings[fixingId].insert(dates.begin(), dates.end());
100+
fixings[fixingId].addDates(dates, false);
101101
commodityMap[pair(fixingId, fd)].insert(dates.begin(), dates.end());
102102
}
103103
} else {
104104
// for monthly expiries add fixings for the last 45 days
105-
for (const auto& fd : fixingDates) {
105+
for (const auto& [fd,_] : fixingDates) {
106106
set<Date> dates;
107107
Date wLookback = fd - Period(45, Days);
108108
do {
@@ -112,15 +112,15 @@ void additional_commodity_fixings(const string& fixingId, const set<Date>& fixin
112112
TLOG("Adding (date, id) = (" << io::iso_date(fd) << "," << fixingId << ")");
113113
// Add to the fixings so a fixing is requested for all dates, and also to the commodityMap
114114
// so we can map a fixing to the correct date required
115-
fixings[fixingId].insert(dates.begin(), dates.end());
115+
fixings[fixingId].addDates(dates, false);
116116
commodityMap[pair(fixingId, fd)].insert(dates.begin(), dates.end());
117117
}
118118
}
119119
}
120120
}
121121

122122
// Additional fixings for equity index decomposition
123-
void additional_equity_fixings(map<string, set<Date>>& fixings, const TodaysMarketParameters& mktParams,
123+
void additional_equity_fixings(map<string, RequiredFixings::FixingDates>& fixings, const TodaysMarketParameters& mktParams,
124124
const boost::shared_ptr<ReferenceDataManager> refData,
125125
const boost::shared_ptr<CurveConfigurations>& curveConfigs) {
126126
std::string configuration = Market::defaultConfiguration;
@@ -146,7 +146,7 @@ const boost::shared_ptr<MarketDataLoaderImpl>& MarketDataLoader::impl() const {
146146
}
147147

148148
void MarketDataLoader::addRelevantFixings(
149-
const std::pair<std::string, std::set<QuantLib::Date>>& fixing,
149+
const std::pair<std::string, RequiredFixings::FixingDates>& fixing,
150150
std::map<std::pair<std::string, QuantLib::Date>, std::set<QuantLib::Date>>& lastAvailableFixingLookupMap) {
151151
if (isFxIndex(fixing.first)) {
152152
// for FX fixings we want to add additional fixings to allow triangulation in case of missing
@@ -156,9 +156,7 @@ void MarketDataLoader::addRelevantFixings(
156156
if (isCommodityIndex(fixing.first)) {
157157
additional_commodity_fixings(fixing.first, fixing.second, fixings_, lastAvailableFixingLookupMap);
158158
}
159-
fixings_[fixing.first].insert(fixing.second.begin(), fixing.second.end());
160-
// also add to portfolioFixings_, used for alerting missing required fixings
161-
portfolioFixings_[fixing.first].insert(fixing.second.begin(), fixing.second.end());
159+
fixings_[fixing.first].addDates(fixing.second);
162160
}
163161

164162
void MarketDataLoader::populateFixings(
@@ -191,7 +189,6 @@ void MarketDataLoader::populateFixings(
191189
if (inputs_->eomInflationFixings()) {
192190
LOG("Adjust inflation fixing dates to the end of the month before the request");
193191
amendInflationFixingDates(fixings_);
194-
amendInflationFixingDates(portfolioFixings_);
195192
}
196193

197194
if (fixings_.size() > 0)
@@ -200,13 +197,13 @@ void MarketDataLoader::populateFixings(
200197
// apply all fixings now
201198
applyFixings(loader_->loadFixings());
202199

203-
// check and warn any missing fixings - only warn for portfolio fixings
204-
for (const auto& f : portfolioFixings_) {
205-
for (const auto& d : f.second) {
206-
if (!loader_->hasFixing(f.first, d)) {
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)) {
207204
string fixingErr = "";
208-
if (isFxIndex(f.first)) {
209-
auto fxInd = parseFxIndex(f.first);
205+
if (isFxIndex(indexName)) {
206+
auto fxInd = parseFxIndex(indexName);
210207
try {
211208
if(fxInd->fixingCalendar().isBusinessDay(d))
212209
fxInd->fixing(d);
@@ -215,7 +212,7 @@ void MarketDataLoader::populateFixings(
215212
fixingErr = ", error: " + ore::data::to_string(e.what());
216213
}
217214
}
218-
StructuredFixingWarningMessage(f.first, d, "Missing fixing", "Could not find required fixing ID.")
215+
StructuredFixingWarningMessage(indexName, d, "Missing fixing", "Could not find required fixing ID.")
219216
.log();
220217
}
221218
}

OREAnalytics/orea/app/marketdataloader.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ namespace ore {
3030
namespace analytics {
3131

3232
typedef std::map<QuantLib::Date, std::set<std::string>> QuoteMap;
33-
typedef std::map<std::string, std::set<QuantLib::Date>> FixingMap;
33+
typedef std::map<std::string, RequiredFixings::FixingDates> FixingMap;
3434

3535
//! Utility class for Structured Fixing warnings
3636
class StructuredFixingWarningMessage : public StructuredMessage {
@@ -80,7 +80,7 @@ class MarketDataLoader {
8080
populateFixings(const std::vector<boost::shared_ptr<ore::data::TodaysMarketParameters>>& todaysMarketParameters,
8181
const std::set<QuantLib::Date>& loaderDates = {});
8282

83-
virtual void addRelevantFixings(const std::pair<std::string, std::set<QuantLib::Date>>& fixing,
83+
virtual void addRelevantFixings(const std::pair<std::string, RequiredFixings::FixingDates>& fixing,
8484
std::map<std::pair<std::string, QuantLib::Date>, std::set<QuantLib::Date>>& lastAvailableFixingLookupMap);
8585

8686
//! clear the loader
@@ -94,7 +94,7 @@ class MarketDataLoader {
9494
boost::shared_ptr<InputParameters> inputs_;
9595
boost::shared_ptr<ore::data::InMemoryLoader> loader_;
9696
QuoteMap quotes_;
97-
FixingMap portfolioFixings_, fixings_;
97+
FixingMap fixings_;
9898

9999
const boost::shared_ptr<MarketDataLoaderImpl>& impl() const;
100100

OREAnalytics/orea/simulation/fixingmanager.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,15 @@ void FixingManager::initialise(const boost::shared_ptr<Portfolio>& portfolio, co
6969
for (auto const& [tradeId,t] : portfolio->trades()) {
7070
auto r = t->requiredFixings();
7171
r.unsetPayDates();
72-
for (auto const& [name, dates] : r.fixingDatesIndices(QuantLib::Date::maxDate())) {
72+
for (auto const& [name, fixingDates] : r.fixingDatesIndices(QuantLib::Date::maxDate())) {
73+
std::set<Date> dates;
74+
for (const auto& [d, _] : fixingDates) {
75+
dates.insert(d);
76+
}
7377
try {
7478
auto rawIndex = parseIndex(name);
7579
if (auto index = boost::dynamic_pointer_cast<EquityIndex2>(rawIndex)) {
80+
7681
fixingMap_[*market->equityCurve(index->familyName(), configuration)].insert(dates.begin(),
7782
dates.end());
7883
} else if (auto index = boost::dynamic_pointer_cast<BondIndex>(rawIndex)) {

OREData/ored/portfolio/compositetrade.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -198,13 +198,13 @@ Real CompositeTrade::calculateNotional(const vector<Real>& notionals) const {
198198
QL_FAIL("Unsupported notional calculation type.");
199199
}
200200

201-
map<string, set<Date>> CompositeTrade::fixings(const Date& settlementDate) const {
201+
map<string, RequiredFixings::FixingDates> CompositeTrade::fixings(const Date& settlementDate) const {
202202

203-
map<string, set<Date>> result;
203+
map<string, RequiredFixings::FixingDates> result;
204204
for (const auto& t : trades_) {
205205
auto fixings = t->fixings(settlementDate);
206-
for (const auto& kv : fixings) {
207-
result[kv.first].insert(kv.second.begin(), kv.second.end());
206+
for (const auto& [indexName, fixingDates] : fixings) {
207+
result[indexName].addDates(fixingDates);
208208
}
209209
}
210210
return result;

OREData/ored/portfolio/compositetrade.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ class CompositeTrade : public Trade {
9191

9292
//! \name trade overrides
9393
//@{
94-
std::map<std::string, std::set<QuantLib::Date>> fixings(const QuantLib::Date& settlementDate) const override;
94+
std::map<std::string, RequiredFixings::FixingDates> fixings(const QuantLib::Date& settlementDate) const override;
9595
std::map<AssetClass, std::set<std::string>> underlyingIndices(const boost::shared_ptr<ReferenceDataManager>& referenceDataManager) const override;;
9696
const std::map<std::string,boost::any>& additionalData() const override;
9797
//@}

0 commit comments

Comments
 (0)