28#include <boost/algorithm/string.hpp>
29#include <boost/range/adaptor/map.hpp>
30#include <boost/range/adaptor/indexed.hpp>
31#include <boost/range/algorithm/max_element.hpp>
48using std::max_element;
59 {0, {
"tradeid",
"trade_id"}},
60 {1, {
"portfolioid",
"portfolio_id"}},
61 {2, {
"productclass",
"product_class",
"asset_class"}},
62 {3, {
"risktype",
"risk_type"}},
67 {8, {
"amountcurrency",
"currency",
"amount_currency"}},
69 {10, {
"amountusd",
"amount_usd"}}};
74 {11, {
"agreementtype",
"agreement_type"}},
75 {12, {
"calltype",
"call_type"}},
76 {13, {
"initialmargintype",
"initial_margin_type"}},
77 {14, {
"legalentityid",
"legal_entity_id"}},
78 {15, {
"tradetype",
"trade_type"}},
79 {16, {
"immodel",
"im_model"}},
80 {17, {
"post_regulations"}},
81 {18, {
"collect_regulations"}},
84 {21, {
"creditquality"}},
85 {22, {
"longshortind"}},
86 {23, {
"coveredbonind"}},
87 {24, {
"tranchethickness"}},
103 recordToAdd.tradeId =
"";
108 QL_FAIL(
"Risk type string " << recordToAdd.riskType <<
" does not correspond to a valid SimmConfiguration::RiskType");
114 case RiskType::AddOnFixedAmount:
115 case RiskType::AddOnNotionalFactor:
117 "Expected product class " << ProductClass::Empty <<
" for risk type " << cr.
riskType);
119 case RiskType::ProductClassMultiplier: {
122 "Expected product class " << ProductClass::Empty <<
" for risk type " << cr.
riskType);
125 QL_REQUIRE(pc != ProductClass::Empty,
126 "The qualifier " << cr.
qualifier <<
" should parse to a valid product class for risk type "
129 QL_REQUIRE(cr.
amount >= 0.0,
"Expected an amount greater than or equal to 0 "
131 <<
" but got " << cr.
amount);
134 case RiskType::Notional:
137 QL_REQUIRE(!cr.
endDate.empty(),
138 "Expected end date for risk type " << cr.
riskType <<
" and im_model=\'Schedule\'");
147 case RiskType::IRCurve:
148 case RiskType::IRVol:
149 case RiskType::Inflation:
150 case RiskType::InflationVol:
151 case RiskType::XCcyBasis:
158 "currency code '" << cr.
qualifier <<
"' is not a supported currency code");
160 case RiskType::FXVol: {
164 "Expected a string of length 6 for FXVol qualifier but got " << cr.
qualifier);
172 <<
") is not a supported currency code");
174 <<
") is not a supported currency code");
198 const std::vector<std::set<std::string>>& additionalHeaders,
bool updateMapper,
199 bool aggregateTrades,
char eol,
char delim,
char quoteChar,
char escapeChar,
const std::string& nullString)
200 :
CrifLoader(configuration, additionalHeaders, updateMapper, aggregateTrades), eol_(eol), delim_(delim),
201 quoteChar_(quoteChar), escapeChar_(escapeChar), nullString_(nullString) {
203 size_t maxIndexRequired = *boost::max_element(
requiredHeaders | boost::adaptors::map_keys);
204 size_t maxIndexOptional = *boost::max_element(
optionalHeaders | boost::adaptors::map_keys);
205 size_t maxIndex = std::max(maxIndexRequired, maxIndexOptional);
219 std::stringstream result;
221 QL_REQUIRE(file.is_open(),
"error opening file " <<
filename_);
222 result << file.rdbuf();
228 std::stringstream csvStream;
235 vector<string> entries;
236 bool headerProcessed =
false;
239 Size invalidLines = 0;
241 Size currentLine = 0;
260 if (headerProcessed) {
262 if (
process(entries, maxIndex, currentLine, result)) {
270 headerProcessed =
true;
271 auto maxPair = max_element(
273 [](
const pair<Size, Size>& p1,
const pair<Size, Size>& p2) { return p1.second < p2.second; });
274 maxIndex = maxPair->second;
278 LOG(
"Out of " << currentLine <<
" lines, there were " << validLines <<
" valid lines, " << invalidLines
279 <<
" invalid lines and " << emptyLines <<
" empty lines.");
290 for (Size i = 0; i < headers.size(); ++i) {
291 header = boost::to_lower_copy(headers[i]);
292 if (kv.second.count(header) > 0) {
298 if (kv.first == 0 || kv.first == 1 || kv.first == 2) {
301 WLOG(
"Did not find a header for portfolioid in the CRIF file so using a default value");
303 }
else if (kv.first == 10) {
309 "Must provide either amount and amount_currency, or amount_usd");
313 "Could not find a header in the CRIF file for " << *kv.second.begin());
318 for (Size i = 0; i < headers.size(); ++i) {
319 header = boost::to_lower_copy(headers[i]);
320 if (kv.second.count(header) > 0) {
327 for (Size columnPos = 0; columnPos < headers.size(); ++columnPos) {
328 header = boost::to_lower_copy(headers[columnPos]);
329 if (kv.second.count(header) > 0) {
339 if (entries.size() <= maxIndex) {
340 WLOG(
"Line number: " << currentLine <<
". Expected at least " << maxIndex + 1 <<
" entries but got only "
347 auto loadOptionalString = [&entries,
this](
int column) {
350 auto loadOptionalReal = [&entries,
this](
int column) -> QuantLib::Real{
352 return QuantLib::Null<QuantLib::Real>();
361 string tradeId, tradeType, imModel;
363 tradeId = loadOptionalString(0);
364 tradeType = loadOptionalString(15);
365 imModel = loadOptionalString(16);
379 string ccyUpper = boost::to_upper_copy(cr.
qualifier);
389 const string ccyPairDelimiters =
"/.,-_|;: ";
393 string ccy1Upper = ccyPair.first.code();
394 string ccy2Upper = ccyPair.second.code();
401 if (boost::to_lower_copy(cr.
bucket) ==
"residual")
408 if (boost::to_lower_copy(cr.
label1) == boost::to_lower_copy(l))
416 if (boost::to_lower_copy(cr.
label2) == boost::to_lower_copy(l))
429 cr.
amount = loadOptionalReal(9);
434 cr.
callType = loadOptionalString(12);
441 cr.
endDate = loadOptionalString(19);
442 cr.
label3 = loadOptionalString(20);
447 cr.
bb_rw = loadOptionalString(25);
459 std::string
value = loadOptionalString(additionalField.first);
466 }
catch (
const exception& e) {
468 "Line number: " +
to_string(currentLine) +
469 ". Error processing CRIF line, so skipping it. Error: " +
to_string(e.what()))
void addRecord(const CrifRecord &record, bool aggregateDifferentAmountCurrencies=false, bool sortFxVolQualifer=true)
void currencyOverrides(CrifRecord &crifRecord) const
Override currency codes.
static std::map< QuantLib::Size, std::set< std::string > > requiredHeaders
Map giving required CRIF file headers and their allowable alternatives.
QuantLib::ext::shared_ptr< SimmConfiguration > configuration_
Simm configuration that is used during loading of CRIF records.
void updateMapping(const CrifRecord &cr) const
update bucket mappings
static std::map< QuantLib::Size, std::set< std::string > > optionalHeaders
Map giving optional CRIF file headers and their allowable alternatives.
void validateSimmRecord(const CrifRecord &cr) const
Check if the record is a valid Simm Crif Record.
std::vector< std::set< std::string > > additionalHeaders_
Defines accepted column headers, beyond required and optional headers, see crifloader....
void addRecordToCrif(Crif &crif, CrifRecord &&recordToAdd) const
std::stringstream stream() const override
std::stringstream stream() const override
std::map< QuantLib::Size, QuantLib::Size > columnIndex_
bool process(const std::vector< std::string > &entries, QuantLib::Size maxIndex, QuantLib::Size currentLine, Crif &result)
virtual std::stringstream stream() const =0
StringStreamCrifLoader(const QuantLib::ext::shared_ptr< SimmConfiguration > &configuration, const std::vector< std::set< std::string > > &additionalHeaders={}, bool updateMapper=false, bool aggregateTrades=true, char eol='\n', char delim='\t', char quoteChar='\0', char escapeChar='\\', const std::string &nullString="#N/A")
std::map< QuantLib::Size, std::set< std::string > > additionalHeadersIndexMap_
Crif loadFromStream(std::stringstream &&stream)
Core CRIF loader from generic istream.
void processHeader(const std::vector< std::string > &headers)
Process the elements of a header line of a CRIF file.
SafeStack< ValueType > value
Class for loading CRIF records.
bool parseBool(const string &s)
pair< Currency, Currency > parseCurrencyPair(const string &s, const string &delimiters)
Real parseReal(const string &s)
bool checkCurrency(const string &code)
SimmConfiguration::IMModel parseIMModel(const string &model)
boost::bimap< T, boost::bimaps::set_of< string, string_cmp > > bm
CrifRecord::RiskType parseRiskType(const string &rt)
CrifRecord::ProductClass parseProductClass(const string &pc)
std::vector< string > parseListOfValues(string s, const char escape, const char delim, const char quote)
std::string to_string(const LocationInfo &l)
Abstract base class for classes that map SIMM qualifiers to buckets.
SIMM configuration interface.
std::string amountCurrency
std::map< std::string, std::variant< std::string, double, bool > > additionalFields
std::string creditQuality
std::string legalEntityId
std::string collectRegulations
ProductClass productClass
std::string agreementType
std::string trancheThickness
std::string coveredBondInd
NettingSetDetails nettingSetDetails
bool isSimmParameter() const
std::string initialMarginType
std::string postRegulations
Class for structured analytics warnings.