Skip to content

Commit

Permalink
Speed up adding fixings (#2085)
Browse files Browse the repository at this point in the history
  • Loading branch information
lballabio authored Oct 15, 2024
2 parents e1701c3 + 0e52676 commit 8d297ba
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 46 deletions.
4 changes: 1 addition & 3 deletions ql/index.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@ namespace QuantLib {
Real fixing,
bool forceOverwrite) {
checkNativeFixingsAllowed();
addFixings(&fixingDate, (&fixingDate)+1,
&fixing,
forceOverwrite);
addFixings(&fixingDate, (&fixingDate) + 1, &fixing, forceOverwrite);
}

void Index::addFixings(const TimeSeries<Real>& t,
Expand Down
39 changes: 3 additions & 36 deletions ql/index.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,42 +100,9 @@ namespace QuantLib {
ValueIterator vBegin,
bool forceOverwrite = false) {
checkNativeFixingsAllowed();
std::string tag = name();
TimeSeries<Real> h = IndexManager::instance().getHistory(tag);
bool noInvalidFixing = true, noDuplicatedFixing = true;
Date invalidDate, duplicatedDate;
Real nullValue = Null<Real>();
Real invalidValue = Null<Real>();
Real duplicatedValue = Null<Real>();
while (dBegin != dEnd) {
bool validFixing = isValidFixingDate(*dBegin);
Real currentValue = h[*dBegin];
bool missingFixing = forceOverwrite || currentValue == nullValue;
if (validFixing) {
if (missingFixing)
h[*(dBegin++)] = *(vBegin++);
else if (close(currentValue, *(vBegin))) {
++dBegin;
++vBegin;
} else {
noDuplicatedFixing = false;
duplicatedDate = *(dBegin++);
duplicatedValue = *(vBegin++);
}
} else {
noInvalidFixing = false;
invalidDate = *(dBegin++);
invalidValue = *(vBegin++);
}
}
IndexManager::instance().setHistory(tag, h);
QL_REQUIRE(noInvalidFixing, "At least one invalid fixing provided: "
<< invalidDate.weekday() << " " << invalidDate << ", "
<< invalidValue);
QL_REQUIRE(noDuplicatedFixing, "At least one duplicated fixing provided: "
<< duplicatedDate << ", " << duplicatedValue
<< " while " << h[duplicatedDate]
<< " value is already present");
IndexManager::instance().addFixings(
name(), dBegin, dEnd, vBegin, forceOverwrite,
[this](const Date& d) { return isValidFixingDate(d); });
}
//! clears all stored historical fixings
void clearFixings();
Expand Down
30 changes: 25 additions & 5 deletions ql/indexes/indexmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,28 @@ namespace QuantLib {
}

const TimeSeries<Real>& IndexManager::getHistory(const std::string& name) const {
return data_[name].value();
return data_[name];
}

void IndexManager::setHistory(const std::string& name, TimeSeries<Real> history) {
notifier(name)->notifyObservers();
data_[name] = std::move(history);
}

void IndexManager::addFixing(const std::string& name,
const Date& fixingDate,
Real fixing,
bool forceOverwrite) {
addFixings(name, &fixingDate, (&fixingDate) + 1, &fixing, forceOverwrite);
}

ext::shared_ptr<Observable> IndexManager::notifier(const std::string& name) const {
return data_[name];
auto n = notifiers_.find(name);
if(n != notifiers_.end())
return n->second;
auto o = ext::make_shared<Observable>();
notifiers_[name] = o;
return o;
}

std::vector<std::string> IndexManager::histories() const {
Expand All @@ -45,14 +58,21 @@ namespace QuantLib {
return temp;
}

void IndexManager::clearHistory(const std::string& name) { data_.erase(name); }
void IndexManager::clearHistory(const std::string& name) {
notifier(name)->notifyObservers();
data_.erase(name);
}

void IndexManager::clearHistories() { data_.clear(); }
void IndexManager::clearHistories() {
for (auto const& d : data_)
notifier(d.first)->notifyObservers();
data_.clear();
}

bool IndexManager::hasHistoricalFixing(const std::string& name, const Date& fixingDate) const {
auto const& indexIter = data_.find(name);
return (indexIter != data_.end()) &&
((*indexIter).second.value()[fixingDate] != Null<Real>());
((*indexIter).second[fixingDate] != Null<Real>());
}

}
56 changes: 54 additions & 2 deletions ql/indexes/indexmanager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#include <ql/patterns/singleton.hpp>
#include <ql/timeseries.hpp>
#include <ql/math/comparison.hpp>
#include <ql/utilities/observablevalue.hpp>
#include <algorithm>
#include <cctype>
Expand All @@ -39,6 +40,56 @@ namespace QuantLib {

private:
IndexManager() = default;
friend class Index;
//! add a fixing
void addFixing(const std::string& name,
const Date& fixingDate,
Real fixing,
bool forceOverwrite = false);
//! add fixings
template <class DateIterator, class ValueIterator>
void addFixings(const std::string& name,
DateIterator dBegin,
DateIterator dEnd,
ValueIterator vBegin,
bool forceOverwrite = false,
const std::function<bool(const Date& d)>& isValidFixingDate = {}) {
auto& h = data_[name];
bool noInvalidFixing = true, noDuplicatedFixing = true;
Date invalidDate, duplicatedDate;
Real nullValue = Null<Real>();
Real invalidValue = Null<Real>();
Real duplicatedValue = Null<Real>();
while (dBegin != dEnd) {
bool validFixing = isValidFixingDate ? isValidFixingDate(*dBegin) : true;
Real currentValue = h[*dBegin];
bool missingFixing = forceOverwrite || currentValue == nullValue;
if (validFixing) {
if (missingFixing)
h[*(dBegin++)] = *(vBegin++);
else if (close(currentValue, *(vBegin))) {
++dBegin;
++vBegin;
} else {
noDuplicatedFixing = false;
duplicatedDate = *(dBegin++);
duplicatedValue = *(vBegin++);
}
} else {
noInvalidFixing = false;
invalidDate = *(dBegin++);
invalidValue = *(vBegin++);
}
}
notifier(name)->notifyObservers();
QL_REQUIRE(noInvalidFixing, "At least one invalid fixing provided: "
<< invalidDate.weekday() << " " << invalidDate << ", "
<< invalidValue);
QL_REQUIRE(noDuplicatedFixing, "At least one duplicated fixing provided: "
<< duplicatedDate << ", " << duplicatedValue
<< " while " << h[duplicatedDate]
<< " value is already present");
}

public:
//! returns whether historical fixings were stored for the index
Expand All @@ -47,7 +98,7 @@ namespace QuantLib {
const TimeSeries<Real>& getHistory(const std::string& name) const;
//! stores the historical fixings of the index
void setHistory(const std::string& name, TimeSeries<Real> history);
//! observer notifying of changes in the index fixings
//! observer notifying of changes in the index fixings_
ext::shared_ptr<Observable> notifier(const std::string& name) const;
//! returns all names of the indexes for which fixings were stored
std::vector<std::string> histories() const;
Expand All @@ -67,7 +118,8 @@ namespace QuantLib {
}
};

mutable std::map<std::string, ObservableValue<TimeSeries<Real>>, CaseInsensitiveCompare> data_;
mutable std::map<std::string, TimeSeries<Real>, CaseInsensitiveCompare> data_;
mutable std::map<std::string, ext::shared_ptr<Observable>> notifiers_;
};

}
Expand Down

0 comments on commit 8d297ba

Please sign in to comment.