Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Speed up adding fixings #2085

Merged
merged 10 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
pcaspers marked this conversation as resolved.
Show resolved Hide resolved
}

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
Loading