Skip to content

Commit b5cb806

Browse files
pcaspersjenkins
authored andcommitted
Merge remote-tracking branch 'origin/QPR-11529'
1 parent 4e0677c commit b5cb806

5 files changed

Lines changed: 291 additions & 103 deletions

File tree

OREData/ored/portfolio/referencedata.cpp

Lines changed: 85 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,22 @@ void ReferenceDatum::fromXML(XMLNode* node) {
3030
XMLUtils::checkNode(node, "ReferenceDatum");
3131
type_ = XMLUtils::getChildValue(node, "Type", true);
3232
id_ = XMLUtils::getAttribute(node, "id");
33+
std::string dateStr = XMLUtils::getAttribute(node, "validFrom");
34+
if (!dateStr.empty()) {
35+
validFrom_ = parseDate(dateStr);
36+
} else {
37+
validFrom_ = QuantLib::Date::minDate();
38+
}
3339
}
3440

3541
XMLNode* ReferenceDatum::toXML(XMLDocument& doc) {
3642
XMLNode* node = doc.allocNode("ReferenceDatum");
3743
QL_REQUIRE(node, "Failed to create ReferenceDatum node");
3844
XMLUtils::addAttribute(doc, node, "id", id_);
3945
XMLUtils::addChild(doc, node, "Type", type_);
46+
if (validFrom_ > QuantLib::Date::minDate()) {
47+
XMLUtils::addAttribute(doc, node, "validFrom", to_string(validFrom_));
48+
}
4049
return node;
4150
}
4251

@@ -189,6 +198,9 @@ CreditIndexReferenceDatum::CreditIndexReferenceDatum() {}
189198

190199
CreditIndexReferenceDatum::CreditIndexReferenceDatum(const string& name) : ReferenceDatum(TYPE, name) {}
191200

201+
CreditIndexReferenceDatum::CreditIndexReferenceDatum(const string& name, const QuantLib::Date& validFrom)
202+
: ReferenceDatum(TYPE, name, validFrom) {}
203+
192204
void CreditIndexReferenceDatum::fromXML(XMLNode* node) {
193205

194206
ReferenceDatum::fromXML(node);
@@ -292,8 +304,6 @@ void CurrencyHedgedEquityIndexReferenceDatum::fromXML(XMLNode* node) {
292304

293305
underlyingIndexName_ = XMLUtils::getChildValue(innerNode, "UnderlyingIndex", true);
294306

295-
hedgeCurrency_ = XMLUtils::getChildValue(innerNode, "HedgeCurrency", true);
296-
297307
auto rebalancingStr = XMLUtils::getChildValue(innerNode, "RebalancingStrategy", false, "EndOfMonth");
298308
if (rebalancingStr == "EndOfMonth") {
299309
rebalancingStrategy_ = CurrencyHedgedEquityIndexReferenceDatum::RebalancingDate::EndOfMonth;
@@ -313,7 +323,6 @@ void CurrencyHedgedEquityIndexReferenceDatum::fromXML(XMLNode* node) {
313323
fxIndexes_[currency] = indexFamily;
314324
}
315325
}
316-
317326
// Optional Fields
318327
referenceDateOffset_ = XMLUtils::getChildValueAsInt(innerNode, "ReferenceDateOffset", false, 0);
319328
auto hedgeAdjStr = XMLUtils::getChildValue(innerNode, "HedgeAdjustment", false, "None");
@@ -351,7 +360,6 @@ XMLNode* CurrencyHedgedEquityIndexReferenceDatum::toXML(XMLDocument& doc) {
351360
XMLNode* rdNode = XMLUtils::addChild(doc, node, type() + "ReferenceData");
352361

353362
XMLUtils::addChild(doc, rdNode, "UnderlyingIndex", underlyingIndexName_);
354-
XMLUtils::addChild(doc, rdNode, "HedgeCurrency", hedgeCurrency_);
355363
XMLUtils::addChild(doc, rdNode, "RebalancingStrategy", "EndOfMonth");
356364
XMLUtils::addChild(doc, rdNode, "HedgeCalendar", to_string(hedgeCalendar_));
357365
if (referenceDateOffset_ != 0)
@@ -485,10 +493,11 @@ void BasicReferenceDataManager::fromXML(XMLNode* node) {
485493

486494
void BasicReferenceDataManager::add(const boost::shared_ptr<ReferenceDatum>& rd) {
487495
// Add reference datum, it is overwritten if it is already present.
488-
data_[make_pair(rd->type(), rd->id())] = rd;
496+
data_[make_pair(rd->type(), rd->id())][rd->validFrom()] = rd;
489497
}
490498

491-
boost::shared_ptr<ReferenceDatum> BasicReferenceDataManager::addFromXMLNode(XMLNode* node, const std::string& inputId) {
499+
boost::shared_ptr<ReferenceDatum> BasicReferenceDataManager::addFromXMLNode(XMLNode* node, const std::string& inputId,
500+
const QuantLib::Date& inputValidFrom) {
492501
string refDataType = XMLUtils::getChildValue(node, "Type", false);
493502
boost::shared_ptr<ReferenceDatum> refData;
494503

@@ -498,16 +507,29 @@ boost::shared_ptr<ReferenceDatum> BasicReferenceDataManager::addFromXMLNode(XMLN
498507
}
499508

500509
string id = inputId.empty() ? XMLUtils::getAttribute(node, "id") : inputId;
510+
511+
string validFromStr = XMLUtils::getAttribute(node, "validFrom");
512+
QuantLib::Date validFrom;
513+
if (validFromStr.empty()) {
514+
validFrom = QuantLib::Date::minDate();
515+
} else {
516+
validFrom = ore::data::parseDate(validFromStr);
517+
}
518+
519+
validFrom = inputValidFrom == QuantLib::Null<QuantLib::Date>() ? validFrom : inputValidFrom;
501520

502521
if (id.empty()) {
503522
ALOG("Found referenceDatum without id - skipping");
504523
return refData;
505524
}
506525

507-
if (data_.find(make_pair(refDataType, id)) != data_.end()) {
508-
duplicates_.insert(make_pair(refDataType, id));
509-
ALOG("Found duplicate referenceDatum for type='" << refDataType << "', id='" << id << "'");
510-
return refData;
526+
if (auto it = data_.find(make_pair(refDataType, id)); it != data_.end()) {
527+
if (it->second.count(validFrom) > 0) {
528+
duplicates_.insert(make_tuple(refDataType, id, validFrom));
529+
ALOG("Found duplicate referenceDatum for type='" << refDataType << "', id='" << id << "', validFrom='"
530+
<< validFrom << "'");
531+
return refData;
532+
}
511533
}
512534

513535
try {
@@ -516,11 +538,14 @@ boost::shared_ptr<ReferenceDatum> BasicReferenceDataManager::addFromXMLNode(XMLN
516538
// set the type and id at top level (is this needed?)
517539
refData->setType(refDataType);
518540
refData->setId(id);
519-
data_[make_pair(refDataType, id)] = refData;
520-
TLOG("added referenceDatum for type='" << refDataType << "', id='" << id << "'");
541+
refData->setValidFrom(validFrom);
542+
data_[make_pair(refDataType, id)][validFrom] = refData;
543+
TLOG("added referenceDatum for type='" << refDataType << "', id='" << id << "', validFrom='" << validFrom
544+
<< "'");
521545
} catch (const std::exception& e) {
522-
buildErrors_[make_pair(refDataType, id)] = e.what();
523-
ALOG("Error building referenceDatum for type='" << refDataType << "', id='" << id << "': " << e.what());
546+
buildErrors_[make_pair(refDataType, id)][validFrom] = e.what();
547+
ALOG("Error building referenceDatum for type='" << refDataType << "', id='" << id << "', validFrom='" << validFrom
548+
<< "': " << e.what());
524549
}
525550

526551
return refData;
@@ -536,31 +561,61 @@ boost::shared_ptr<ReferenceDatum> BasicReferenceDataManager::buildReferenceDatum
536561
XMLNode* BasicReferenceDataManager::toXML(XMLDocument& doc) {
537562
XMLNode* node = doc.allocNode("ReferenceData");
538563
for (const auto& kv : data_) {
539-
XMLUtils::appendNode(node, kv.second->toXML(doc));
564+
for (const auto& [_, refData] : kv.second) {
565+
XMLUtils::appendNode(node, refData->toXML(doc));
566+
}
540567
}
541568
return node;
542569
}
543570

544-
void BasicReferenceDataManager::check(const string& type, const string& id) const {
545-
auto key = make_pair(type, id);
571+
std::tuple<QuantLib::Date, boost::shared_ptr<ReferenceDatum>> BasicReferenceDataManager::latestValidFrom(const string& type, const string& id,
572+
const QuantLib::Date& asof) const {
573+
auto it = data_.find(make_pair(type, id));
574+
if (it != data_.end() && !it->second.empty()){
575+
auto uB = it->second.upper_bound(asof);
576+
if (uB != it->second.begin()) {
577+
return *(--uB);
578+
}
579+
}
580+
return {QuantLib::Date(), nullptr};
581+
}
582+
583+
void BasicReferenceDataManager::check(const string& type, const string& id, const QuantLib::Date& validFrom) const {
584+
auto key = make_tuple(type, id, validFrom);
546585
if (duplicates_.find(key) != duplicates_.end())
547-
ALOG("BasicReferenceDataManager: duplicate entries for type='" << type << "', id='" << id << "'");
548-
auto err = buildErrors_.find(key);
549-
if (err != buildErrors_.end())
550-
ALOG("BasicReferenceDataManager: Build error for type='" << type << "', id='" << id << "': " << err->second);
586+
ALOG("BasicReferenceDataManager: duplicate entries for type='" << type << "', id='" << id << "', validFrom='"
587+
<< validFrom << "'");
588+
auto err = buildErrors_.find(make_pair(type, id));
589+
if (err != buildErrors_.end()) {
590+
for (const auto& [validFrom, error] : err->second) {
591+
ALOG("BasicReferenceDataManager: Build error for type='" << type << "', id='" << id << "', validFrom='"
592+
<< validFrom << "': " << error);
593+
}
594+
}
595+
551596
}
552597

553-
bool BasicReferenceDataManager::hasData(const string& type, const string& id) const {
554-
check(type, id);
555-
return data_.find(make_pair(type, id)) != data_.end();
598+
bool BasicReferenceDataManager::hasData(const string& type, const string& id, const QuantLib::Date& asof) const {
599+
Date asofDate = asof;
600+
if (asofDate == QuantLib::Null<QuantLib::Date>()) {
601+
asofDate = Settings::instance().evaluationDate();
602+
}
603+
auto [validFrom, refData] = latestValidFrom(type, id, asofDate);
604+
check(type, id, validFrom);
605+
return refData != nullptr;
556606
}
557607

558-
boost::shared_ptr<ReferenceDatum> BasicReferenceDataManager::getData(const string& type, const string& id) {
559-
check(type, id);
560-
auto it = data_.find(make_pair(type, id));
561-
QL_REQUIRE(it != data_.end(),
562-
"BasicReferenceDataManager::getData(): No Reference data for type='" << type << "', id='" << id << "'");
563-
return it->second;
608+
boost::shared_ptr<ReferenceDatum> BasicReferenceDataManager::getData(const string& type, const string& id,
609+
const QuantLib::Date& asof) {
610+
Date asofDate = asof;
611+
if (asofDate == QuantLib::Null<QuantLib::Date>()) {
612+
asofDate = Settings::instance().evaluationDate();
613+
}
614+
auto [validFrom, refData] = latestValidFrom(type, id, asofDate);
615+
check(type, id, validFrom);
616+
QL_REQUIRE(refData != nullptr, "BasicReferenceDataManager::getData(): No Reference data for type='"
617+
<< type << "', id='" << id << "', asof='" << asof << "'");
618+
return refData;
564619
}
565620

566621
} // namespace data

0 commit comments

Comments
 (0)