Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
crifrecord.hpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2018 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 orea/simm/crifrecord.hpp
20 \brief Struct for holding a CRIF record
21*/
22
23#pragma once
24
28#include <string>
29#include <variant>
30
31namespace ore {
32namespace analytics {
33
35/*! A container for holding single CRIF records or aggregated CRIF records.
36 A CRIF record is a row of the CRIF file outlined in the document:
37 <em>ISDA SIMM Methodology, Risk Data Standards. Version 1.36: 1 February 2017.</em>
38 or an updated version thereof.
39*/
40struct CrifRecord {
41
42 enum class RecordType {
43 SIMM,
44 FRTB,
46 };
47
48 /*! Risk types plus an All type for convenience
49 Internal methods rely on the last element being 'All'
50 Note that the risk type inflation has to be treated as an additional, single
51 tenor bucket in IRCurve
52 */
53 enum class RiskType {
54 // Empty for null, misisng field
55 Empty,
56 // SIMM Risk Types
60 CreditQ,
63 Equity,
65 FX,
66 FXVol,
68 IRCurve,
69 IRVol,
77 PV, // IM Schedule
78 // FRTB Risk Types
92 EQ_VEGA,
93 EQ_CURV,
98 FX_VEGA,
99 FX_CURV,
100 DRC_NS,
101 DRC_SNC,
102 DRC_SC,
105 // All type for aggreggation purposes
106 All
107 };
108
109 //! Product class types in SIMM plus an All type for convenience
110 //! Internal methods rely on the last element being 'All'
111 enum class ProductClass {
112 RatesFX,
113 Rates, // extension for IM Schedule
114 FX, // extension for IM Schedule
115 Credit,
116 Equity,
117 Commodity,
118 Empty,
119 Other, // extension for IM Schedule
120 AddOnNotionalFactor, // extension for additional IM
121 AddOnFixedAmount, // extension for additional IM
122 All
123 };
124
125 //! There are two entries for curvature risk in frtb, a up and down shift
126 enum class CurvatureScenario { Empty, Up, Down };
127
128 // clang-format off
129 // trade ID qualifier bucket label1 label2 collect regs post regs
130 typedef std::tuple<std::string, NettingSetDetails, ProductClass, RiskType, std::string, std::string, std::string, std::string, std::string, std::string> SimmAmountCcyKey;
131 // clang-format on
132
133 // required data
134 std::string tradeId;
135 std::string portfolioId;
136 ProductClass productClass = ProductClass::Empty;
137 RiskType riskType = RiskType::Notional;
138 std::string qualifier;
139 std::string bucket;
140 std::string label1;
141 std::string label2;
142 std::string amountCurrency;
143 mutable QuantLib::Real amount = QuantLib::Null<QuantLib::Real>();
144 mutable QuantLib::Real amountUsd = QuantLib::Null<QuantLib::Real>();
145
146 // additional fields used exclusively by the SIMM calculator for handling amounts converted in a given result ccy
147 std::string resultCurrency;
148 mutable QuantLib::Real amountResultCcy = QuantLib::Null<QuantLib::Real>();
149
150 // optional data
151 std::string tradeType;
152 std::string agreementType;
153 std::string callType;
154 std::string initialMarginType;
155 std::string legalEntityId;
156 NettingSetDetails nettingSetDetails; // consists of the above: agreementType ... legalEntityId
157 mutable std::string imModel;
158 mutable std::string collectRegulations;
159 mutable std::string postRegulations;
160 std::string endDate;
161
162 // frtb fields
163 std::string label3;
164 std::string creditQuality;
165 std::string longShortInd;
166 std::string coveredBondInd;
167 std::string trancheThickness;
168 std::string bb_rw;
169
170 // additional data
171 std::map<std::string, std::variant<std::string, double, bool>> additionalFields;
172
173 // Default Constructor
175
178 std::string qualifier, std::string bucket, std::string label1, std::string label2,
179 std::string amountCurrency, QuantLib::Real amount, QuantLib::Real amountUsd, std::string imModel = "",
180 std::string collectRegulations = "", std::string postRegulations = "", std::string endDate = "",
181 std::map<std::string, std::string> extraFields = {})
187 for (const auto& [key, value] : extraFields) {
188 additionalFields[key] = value;
189 }
190 }
191
192 CrifRecord(std::string tradeId, std::string tradeType, std::string portfolioId,
194 std::string qualifier, std::string bucket, std::string label1, std::string label2,
195 std::string amountCurrency, QuantLib::Real amount, QuantLib::Real amountUsd, std::string imModel = "",
196 std::string collectRegulations = "", std::string postRegulations = "", std::string endDate = "",
197 std::map<std::string, std::string> additionalFields = {})
201
202 RecordType type() const;
203
204 bool hasAmountCcy() const { return !amountCurrency.empty(); }
205 bool hasAmount() const { return amount != QuantLib::Null<QuantLib::Real>(); }
206 bool hasAmountUsd() const { return amountUsd != QuantLib::Null<QuantLib::Real>(); }
207 bool hasResultCcy() const { return !resultCurrency.empty(); }
208 bool hasAmountResultCcy() const { return amountResultCcy != QuantLib::Null<QuantLib::Real>(); }
209
210 // We use (and require) amountUsd for all risk types except for SIMM parameters AddOnNotionalFactor and
211 // ProductClassMultiplier as these are multipliers and not amounts denominated in the amountCurrency
212 bool requiresAmountUsd() const {
213 return riskType != RiskType::AddOnNotionalFactor &&
214 riskType != RiskType::ProductClassMultiplier;
215 }
216
217 bool isSimmParameter() const {
218 return riskType == RiskType::AddOnFixedAmount ||
219 riskType == RiskType::AddOnNotionalFactor ||
220 riskType == RiskType::ProductClassMultiplier;
221 }
222
223 bool isEmpty() const { return riskType == RiskType::Empty; }
224
225
226 bool isFrtbCurvatureRisk() const {
227 switch (riskType) {
228 case RiskType::GIRR_CURV:
229 case RiskType::CSR_NS_CURV:
230 case RiskType::CSR_SNC_CURV:
231 case RiskType::CSR_SC_CURV:
232 case RiskType::EQ_CURV:
233 case RiskType::COMM_CURV:
234 case RiskType::FX_CURV:
235 return true;
236 default:
237 return false;
238 }
239 }
240
242 double shift = 0.0;
243 if (isFrtbCurvatureRisk() && ore::data::tryParseReal(label1, shift) && shift < 0.0) {
245 } else if (isFrtbCurvatureRisk()) {
247 } else {
249 }
250 }
251
252 std::string getAdditionalFieldAsStr(const std::string& fieldName) const {
253 auto it = additionalFields.find(fieldName);
254 std::string value;
255 if (it != additionalFields.end()) {
256 if (const std::string* vstr = std::get_if<std::string>(&it->second)) {
257 value = *vstr;
258 } else if (const double* vdouble = std::get_if<double>(&it->second)) {
259 value = ore::data::to_string(*vdouble);
260 } else {
261 const bool* vbool = std::get_if<bool>(&it->second);
262 value = ore::data::to_string(*vbool);
263 }
264 }
265 return value;
266 }
267
268 double getAdditionalFieldAsDouble(const std::string& fieldName) const {
269 auto it = additionalFields.find(fieldName);
270 double value = QuantLib::Null<double>();
271 if (it != additionalFields.end()) {
272 if (const double* vdouble = std::get_if<double>(&it->second)) {
273 value = *vdouble;
274 } else if (const std::string* vstr = std::get_if<std::string>(&it->second)) {
276 }
277 }
278 return value;
279 }
280
281 bool getAdditionalFieldAsBool(const std::string& fieldName) const {
282 auto it = additionalFields.find(fieldName);
283 bool value = false;
284 if (it != additionalFields.end()) {
285 if (const bool* vbool = std::get_if<bool>(&it->second)) {
286 value = *vbool;
287 } else if (const std::string* vstr = std::get_if<std::string>(&it->second)) {
289 }
290 }
291 return value;
292 }
293
297 }
298
299 //! Define how CRIF records are compared
300 bool operator<(const CrifRecord& cr) const {
301 if (type() == RecordType::FRTB || cr.type() == RecordType::FRTB) {
305 std::tie(cr.tradeId, cr.nettingSetDetails, cr.productClass, cr.riskType, cr.qualifier, cr.bucket,
306 cr.label1, cr.label2, cr.label3, cr.endDate, cr.creditQuality, cr.longShortInd,
308 cr.postRegulations);
309 } else {
312 std::tie(cr.tradeId, cr.nettingSetDetails, cr.productClass, cr.riskType, cr.qualifier, cr.bucket,
314 }
315 }
316
317 static bool amountCcyLTCompare(const CrifRecord& cr1, const CrifRecord& cr2) {
318 if (cr1.type() == RecordType::FRTB || cr2.type() == RecordType::FRTB) {
319 return std::tie(cr1.tradeId, cr1.nettingSetDetails, cr1.productClass, cr1.riskType, cr1.qualifier,
320 cr1.bucket, cr1.label1, cr1.label2, cr1.label3, cr1.endDate, cr1.creditQuality,
323 std::tie(cr2.tradeId, cr2.nettingSetDetails, cr2.productClass, cr2.riskType, cr2.qualifier,
324 cr2.bucket, cr2.label1, cr2.label2, cr2.label3, cr2.endDate, cr2.creditQuality,
327 } else {
328 return std::tie(cr1.tradeId, cr1.nettingSetDetails, cr1.productClass, cr1.riskType, cr1.qualifier,
329 cr1.bucket, cr1.label1, cr1.label2, cr1.collectRegulations, cr1.postRegulations) <
330 std::tie(cr2.tradeId, cr2.nettingSetDetails, cr2.productClass, cr2.riskType, cr2.qualifier,
331 cr2.bucket, cr2.label1, cr2.label2, cr2.collectRegulations, cr2.postRegulations);
332 }
333 }
334
335 bool operator==(const CrifRecord& cr) const {
336 if (type() == RecordType::FRTB || cr.type() == RecordType::FRTB) {
340 std::tie(cr.tradeId, cr.nettingSetDetails, cr.productClass, cr.riskType, cr.qualifier, cr.bucket,
341 cr.label1, cr.label2, cr.label3, cr.endDate, cr.creditQuality, cr.longShortInd,
343 cr.postRegulations);
344 } else {
347 std::tie(cr.tradeId, cr.nettingSetDetails, cr.productClass, cr.riskType, cr.qualifier, cr.bucket,
349 }
350 }
351 static bool amountCcyEQCompare(const CrifRecord& cr1, const CrifRecord& cr2) {
352 if (cr1.type() == RecordType::FRTB || cr2.type() == RecordType::FRTB) {
353 return std::tie(cr1.tradeId, cr1.nettingSetDetails, cr1.productClass, cr1.riskType, cr1.qualifier,
354 cr1.bucket, cr1.label1, cr1.label2, cr1.label3, cr1.endDate, cr1.creditQuality,
357 std::tie(cr2.tradeId, cr2.nettingSetDetails, cr2.productClass, cr2.riskType, cr2.qualifier,
358 cr2.bucket, cr2.label1, cr2.label2, cr2.label3, cr2.endDate, cr2.creditQuality,
361 } else {
362 return std::tie(cr1.tradeId, cr1.nettingSetDetails, cr1.productClass, cr1.riskType, cr1.qualifier,
363 cr1.bucket, cr1.label1, cr1.label2, cr1.collectRegulations, cr1.postRegulations) ==
364 std::tie(cr2.tradeId, cr2.nettingSetDetails, cr2.productClass, cr2.riskType, cr2.qualifier,
365 cr2.bucket, cr2.label1, cr2.label2, cr2.collectRegulations, cr2.postRegulations);
366 }
367 }
368
369 static std::vector<std::set<std::string>> additionalHeaders;
370};
371
372//! Enable writing of a CrifRecord
373std::ostream& operator<<(std::ostream& out, const CrifRecord& cr);
374
375std::ostream& operator<<(std::ostream& out, const CrifRecord::RiskType& rt);
376
377std::ostream& operator<<(std::ostream& out, const CrifRecord::ProductClass& pc);
378
379std::ostream& operator<<(std::ostream& out, const CrifRecord::CurvatureScenario& scenario);
380
381CrifRecord::RiskType parseRiskType(const std::string& rt);
382
383CrifRecord::ProductClass parseProductClass(const std::string& pc);
384
386
387} // namespace analytics
388} // namespace ore
const string & nettingSetId() const
SafeStack< ValueType > value
bool tryParseReal(const string &s, QuantLib::Real &result)
bool parseBool(const string &s)
Real parseReal(const string &s)
std::ostream & operator<<(std::ostream &out, EquityReturnType t)
CrifRecord::CurvatureScenario parseFrtbCurvatureScenario(const std::string &scenario)
Definition: crifrecord.cpp:152
CrifRecord::RiskType parseRiskType(const string &rt)
Definition: crifrecord.cpp:117
CrifRecord::ProductClass parseProductClass(const string &pc)
Definition: crifrecord.cpp:127
std::string to_string(const LocationInfo &l)
std::map< std::string, std::variant< std::string, double, bool > > additionalFields
Definition: crifrecord.hpp:171
bool requiresAmountUsd() const
Definition: crifrecord.hpp:212
std::string getAdditionalFieldAsStr(const std::string &fieldName) const
Definition: crifrecord.hpp:252
RecordType type() const
Definition: crifrecord.cpp:186
bool operator<(const CrifRecord &cr) const
Define how CRIF records are compared.
Definition: crifrecord.hpp:300
static std::vector< std::set< std::string > > additionalHeaders
Definition: crifrecord.hpp:369
static bool amountCcyEQCompare(const CrifRecord &cr1, const CrifRecord &cr2)
Definition: crifrecord.hpp:351
bool isFrtbCurvatureRisk() const
Definition: crifrecord.hpp:226
const SimmAmountCcyKey getSimmAmountCcyKey() const
Definition: crifrecord.hpp:294
QuantLib::Real amountResultCcy
Definition: crifrecord.hpp:148
static bool amountCcyLTCompare(const CrifRecord &cr1, const CrifRecord &cr2)
Definition: crifrecord.hpp:317
bool getAdditionalFieldAsBool(const std::string &fieldName) const
Definition: crifrecord.hpp:281
CurvatureScenario frtbCurveatureScenario() const
Definition: crifrecord.hpp:241
std::tuple< std::string, NettingSetDetails, ProductClass, RiskType, std::string, std::string, std::string, std::string, std::string, std::string > SimmAmountCcyKey
Definition: crifrecord.hpp:130
CrifRecord(std::string tradeId, std::string tradeType, NettingSetDetails nettingSetDetails, ProductClass productClass, RiskType riskType, std::string qualifier, std::string bucket, std::string label1, std::string label2, std::string amountCurrency, QuantLib::Real amount, QuantLib::Real amountUsd, std::string imModel="", std::string collectRegulations="", std::string postRegulations="", std::string endDate="", std::map< std::string, std::string > extraFields={})
Definition: crifrecord.hpp:176
CrifRecord(std::string tradeId, std::string tradeType, std::string portfolioId, ProductClass productClass, RiskType riskType, std::string qualifier, std::string bucket, std::string label1, std::string label2, std::string amountCurrency, QuantLib::Real amount, QuantLib::Real amountUsd, std::string imModel="", std::string collectRegulations="", std::string postRegulations="", std::string endDate="", std::map< std::string, std::string > additionalFields={})
Definition: crifrecord.hpp:192
NettingSetDetails nettingSetDetails
Definition: crifrecord.hpp:156
double getAdditionalFieldAsDouble(const std::string &fieldName) const
Definition: crifrecord.hpp:268
CurvatureScenario
There are two entries for curvature risk in frtb, a up and down shift.
Definition: crifrecord.hpp:126
bool operator==(const CrifRecord &cr) const
Definition: crifrecord.hpp:335
bool hasAmountResultCcy() const
Definition: crifrecord.hpp:208