Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
csvloader.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2016 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
19/*! \file ored/marketdata/csvloader.cpp
20 \brief Market Datum Loader impl
21 \ingroup
22*/
23
24#include <algorithm>
25#include <boost/algorithm/string.hpp>
26#include <fstream>
27#include <map>
32
33using namespace std;
34
35namespace ore {
36namespace data {
37
38CSVLoader::CSVLoader(const string& marketFilename, const string& fixingFilename, bool implyTodaysFixings,
39 Date fixingCutOffDate)
40 : CSVLoader(marketFilename, fixingFilename, "", implyTodaysFixings, fixingCutOffDate) {}
41
42CSVLoader::CSVLoader(const vector<string>& marketFiles, const vector<string>& fixingFiles, bool implyTodaysFixings, Date fixingCutOffDate)
43 : CSVLoader(marketFiles, fixingFiles, {}, implyTodaysFixings, fixingCutOffDate) {}
44
45CSVLoader::CSVLoader(const string& marketFilename, const string& fixingFilename, const string& dividendFilename,
46 bool implyTodaysFixings, Date fixingCutOffDate)
47 : implyTodaysFixings_(implyTodaysFixings), fixingCutOffDate_(fixingCutOffDate) {
48
49 // load market data
50 loadFile(marketFilename, DataType::Market);
51 // log
52 for (auto it : data_) {
53 LOG("CSVLoader loaded " << it.second.size() << " market data points for " << it.first);
54 }
55
56 // load fixings
57 loadFile(fixingFilename, DataType::Fixing);
58 LOG("CSVLoader loaded " << fixings_.size() << " fixings");
59
60 // load dividends
61 if (dividendFilename != "") {
62 loadFile(dividendFilename, DataType::Dividend);
63 LOG("CSVLoader loaded " << dividends_.size() << " dividends");
64 }
65
66 LOG("CSVLoader complete.");
67}
68
69CSVLoader::CSVLoader(const vector<string>& marketFiles, const vector<string>& fixingFiles,
70 const vector<string>& dividendFiles, bool implyTodaysFixings,
71 Date fixingCutOffDate)
72 : implyTodaysFixings_(implyTodaysFixings), fixingCutOffDate_(fixingCutOffDate) {
73
74 for (auto marketFile : marketFiles)
75 // load market data
76 loadFile(marketFile, DataType::Market);
77
78 // log
79 for (auto it : data_)
80 LOG("CSVLoader loaded " << it.second.size() << " market data points for " << it.first);
81
82 for (auto fixingFile : fixingFiles)
83 // load fixings
84 loadFile(fixingFile, DataType::Fixing);
85 LOG("CSVLoader loaded " << fixings_.size() << " fixings");
86
87 for (auto dividendFile : dividendFiles)
88 // load dividends
89 loadFile(dividendFile, DataType::Dividend);
90 LOG("CSVLoader loaded " << dividends_.size() << " dividends");
91
92 LOG("CSVLoader complete.");
93}
94
95QuantLib::ext::shared_ptr<MarketDatum> makeDummyMarketDatum(const Date& d, const std::string& name) {
96 return QuantLib::ext::make_shared<MarketDatum>(0.0, d, name, MarketDatum::QuoteType::NONE,
98}
99
100void CSVLoader::loadFile(const string& filename, DataType dataType) {
101 LOG("CSVLoader loading from " << filename);
102
103 Date today = QuantLib::Settings::instance().evaluationDate();
104
105 ifstream file;
106 file.open(filename.c_str());
107 QL_REQUIRE(file.is_open(), "error opening file " << filename);
108
109 while (!file.eof()) {
110 string line;
111 getline(file, line);
112 boost::trim(line);
113 // skip blank and comment lines
114 if (line.size() > 0 && line[0] != '#') {
115
116 vector<string> tokens;
117 boost::trim(line);
118 boost::split(tokens, line, boost::is_any_of(",;\t "), boost::token_compress_on);
119
120 // TODO: should we try, catch and log any invalid lines?
121 QL_REQUIRE(tokens.size() == 3 || tokens.size() == 4, "Invalid CSVLoader line, 3 tokens expected " << line);
122 if (tokens.size() == 4)
123 QL_REQUIRE(dataType == DataType::Dividend, "CSVLoader, dataType must be of type Dividend");
124 Date date = parseDate(tokens[0]);
125 const string& key = tokens[1];
126 Real value = parseReal(tokens[2]);
127
128 if (dataType == DataType::Market) {
129 // process market
130 // build market datum and add to map
131 try {
132 QuantLib::ext::shared_ptr<MarketDatum> md;
133 try {
134 md = parseMarketDatum(date, key, value);
135 } catch (std::exception& e) {
136 WLOG("Failed to parse MarketDatum " << key << ": " << e.what());
137 }
138 if (md != nullptr) {
139 std::pair<bool, string> addFX = {true, ""};
140 if (md->instrumentType() == MarketDatum::InstrumentType::FX_SPOT &&
141 md->quoteType() == MarketDatum::QuoteType::RATE) {
142 addFX = checkFxDuplicate(md, date);
143 if (!addFX.second.empty()) {
144 auto it2 = data_[date].find(makeDummyMarketDatum(date, addFX.second));
145 TLOG("Replacing MarketDatum " << addFX.second << " with " << key
146 << " due to FX Dominance.");
147 if (it2 != data_[date].end())
148 data_[date].erase(it2);
149 }
150 }
151 if (addFX.first && data_[date].insert(md).second) {
152 LOG("Added MarketDatum " << key);
153 } else if (!addFX.first) {
154 LOG("Skipped MarketDatum " << key << " - dominant FX already present.")
155 }
156 else {
157 LOG("Skipped MarketDatum " << key << " - this is already present.");
158 }
159 }
160 } catch (std::exception& e) {
161 WLOG("Failed to parse MarketDatum " << key << ": " << e.what());
162 }
163 } else if (dataType == DataType::Fixing) {
164 // process fixings
165 if (date < today || (date == today && !implyTodaysFixings_)
166 || (fixingCutOffDate_ != Date() && date <= fixingCutOffDate_)) {
167 if(!fixings_.insert(Fixing(date, key, value)).second) {
168 WLOG("Skipped Fixing " << key << "@" << QuantLib::io::iso_date(date)
169 << " - this is already present.");
170 }
171 }
172 } else if (dataType == DataType::Dividend) {
173 Date payDate = date;
174 if (tokens.size() == 4)
175 payDate = parseDate(tokens[3]);
176 // process dividends
177 if (date <= today) {
178 if (!dividends_.insert(QuantExt::Dividend(date, key, value, payDate)).second) {
179 WLOG("Skipped Dividend " << key << "@" << QuantLib::io::iso_date(date)
180 << " - this is already present.");
181 }
182 }
183 } else {
184 QL_FAIL("unknown data type");
185 }
186 }
187 }
188 file.close();
189 LOG("CSVLoader completed processing " << filename);
190}
191
192vector<QuantLib::ext::shared_ptr<MarketDatum>> CSVLoader::loadQuotes(const QuantLib::Date& d) const {
193 auto it = data_.find(d);
194 if (it == data_.end())
195 return {};
196 return std::vector<QuantLib::ext::shared_ptr<MarketDatum>>(it->second.begin(), it->second.end());
197}
198
199QuantLib::ext::shared_ptr<MarketDatum> CSVLoader::get(const string& name, const QuantLib::Date& d) const {
200 auto it = data_.find(d);
201 QL_REQUIRE(it != data_.end(), "No datum for " << name << " on date " << d);
202 auto it2 = it->second.find(makeDummyMarketDatum(d, name));
203 QL_REQUIRE(it2 != it->second.end(), "No datum for " << name << " on date " << d);
204 return *it2;
205}
206
207std::set<QuantLib::ext::shared_ptr<MarketDatum>> CSVLoader::get(const std::set<std::string>& names,
208 const QuantLib::Date& asof) const {
209 auto it = data_.find(asof);
210 if(it == data_.end())
211 return {};
212 std::set<QuantLib::ext::shared_ptr<MarketDatum>> result;
213 for (auto const& n : names) {
214 auto it2 = it->second.find(makeDummyMarketDatum(asof, n));
215 if (it2 != it->second.end())
216 result.insert(*it2);
217 }
218 return result;
219}
220
221std::set<QuantLib::ext::shared_ptr<MarketDatum>> CSVLoader::get(const Wildcard& wildcard,
222 const QuantLib::Date& asof) const {
223 if (!wildcard.hasWildcard()) {
224 // no wildcard => use get by name function
225 try {
226 return {get(wildcard.pattern(), asof)};
227 } catch (...) {
228 }
229 return {};
230 }
231 auto it = data_.find(asof);
232 if (it == data_.end())
233 return {};
234 std::set<QuantLib::ext::shared_ptr<MarketDatum>> result;
235 std::set<QuantLib::ext::shared_ptr<MarketDatum>>::iterator it1, it2;
236 if (wildcard.wildcardPos() == 0) {
237 // wildcard at first position => we have to search all of the data
238 it1 = it->second.begin();
239 it2 = it->second.end();
240 } else {
241 // search the range matching the substring of the pattern until the wildcard
242 std::string prefix = wildcard.pattern().substr(0, wildcard.wildcardPos());
243 it1 = it->second.lower_bound(makeDummyMarketDatum(asof, prefix));
244 it2 = it->second.upper_bound(makeDummyMarketDatum(asof, prefix + "\xFF"));
245 }
246 for (auto it = it1; it != it2; ++it) {
247 if (wildcard.isPrefix() || wildcard.matches((*it)->name()))
248 result.insert(*it);
249 }
250 return result;
251}
252} // namespace data
253} // namespace ore
Utility class for loading market quotes and fixings from a file.
Definition: csvloader.hpp:41
std::set< QuantExt::Dividend > dividends_
Definition: csvloader.hpp:107
std::set< Fixing > fixings_
Definition: csvloader.hpp:106
QuantLib::ext::shared_ptr< MarketDatum > get(const string &name, const QuantLib::Date &d) const override
get quote by its unique name, throws if not existent, override in derived classes for performance
Definition: csvloader.cpp:199
CSVLoader()
Constructor.
Definition: csvloader.hpp:44
std::vector< QuantLib::ext::shared_ptr< MarketDatum > > loadQuotes(const QuantLib::Date &) const override
get all quotes, TODO change the return value to std::set
Definition: csvloader.cpp:192
std::map< QuantLib::Date, std::set< QuantLib::ext::shared_ptr< MarketDatum >, SharedPtrMarketDatumComparator > > data_
Definition: csvloader.hpp:105
void loadFile(const string &, DataType)
Definition: csvloader.cpp:100
std::pair< bool, string > checkFxDuplicate(const ext::shared_ptr< MarketDatum >, const QuantLib::Date &)
Definition: loader.cpp:85
bool isPrefix() const
Definition: wildcard.cpp:66
bool hasWildcard() const
Definition: wildcard.cpp:62
const std::string & pattern() const
Definition: wildcard.cpp:80
bool matches(const std::string &s) const
Definition: wildcard.cpp:68
std::size_t wildcardPos() const
Definition: wildcard.cpp:64
SafeStack< ValueType > value
Market Datum Loader Implementation.
QuantLib::ext::shared_ptr< MarketDatum > parseMarketDatum(const Date &asof, const string &datumName, const Real &value)
Function to parse a market datum.
Date parseDate(const string &s)
Convert std::string to QuantLib::Date.
Definition: parsers.cpp:51
Real parseReal(const string &s)
Convert text to Real.
Definition: parsers.cpp:112
Classes and functions for log message handling.
@ data
Definition: log.hpp:77
#define LOG(text)
Logging Macro (Level = Notice)
Definition: log.hpp:552
#define WLOG(text)
Logging Macro (Level = Warning)
Definition: log.hpp:550
#define TLOG(text)
Logging Macro (Level = Data)
Definition: log.hpp:556
Market Datum parser.
QuantLib::ext::shared_ptr< MarketDatum > makeDummyMarketDatum(const Date &d, const std::string &name)
Definition: csvloader.cpp:95
Serializable Credit Default Swap.
Definition: namespaces.docs:23
Map text representations to QuantLib/QuantExt types.
Fixing data structure.
Definition: fixings.hpp:44
string name