Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
Classes | Public Types | Public Member Functions | Static Public Member Functions | Private Member Functions | Private Attributes | List of all members
IMScheduleCalculator Class Reference

#include <orea/simm/imschedulecalculator.hpp>

+ Collaboration diagram for IMScheduleCalculator:

Classes

struct  IMScheduleTradeData
 

Public Types

typedef CrifRecord::ProductClass ProductClass
 
typedef CrifRecord::RiskType RiskType
 
typedef SimmConfiguration::Regulation Regulation
 
typedef SimmConfiguration::SimmSide SimmSide
 

Public Member Functions

 IMScheduleCalculator (const Crif &crif, const std::string &calculationCcy="USD", const QuantLib::ext::shared_ptr< ore::data::Market > market=nullptr, const bool determineWinningRegulations=true, const bool enforceIMRegulations=false, const bool quiet=false, const std::map< SimmSide, std::set< NettingSetDetails > > &hasSEC=std::map< SimmSide, std::set< NettingSetDetails > >(), const std::map< SimmSide, std::set< NettingSetDetails > > &hasCFTC=std::map< SimmSide, std::set< NettingSetDetails > >())
 Construct the IMScheduleCalculator from a container of netted CRIF records. More...
 
const std::map< SimmSide, std::set< std::string > > finalTradeIds () const
 Give back the set of portfolio IDs and trade IDs for which we have IM results. More...
 
const std::string & winningRegulations (const SimmSide &side, const ore::data::NettingSetDetails &nettingSetDetails) const
 Return the winning regulation for each portfolioId. More...
 
const std::map< ore::data::NettingSetDetails, string > & winningRegulations (const SimmSide &side) const
 
const std::map< SimmSide, std::map< ore::data::NettingSetDetails, string > > & winningRegulations () const
 
const std::map< std::string, IMScheduleResults > & imScheduleSummaryResults (const SimmSide &side, const ore::data::NettingSetDetails &nsd) const
 Give back the IM Schedule results container for the given portfolioId and IM side. More...
 
const std::map< ore::data::NettingSetDetails, std::map< std::string, IMScheduleResults > > & imScheduleSummaryResults (const SimmSide &side) const
 
const std::map< SimmSide, std::map< ore::data::NettingSetDetails, std::map< std::string, IMScheduleResults > > > & imScheduleSummaryResults () const
 
const std::pair< std::string, IMScheduleResults > & finalImScheduleSummaryResults (const SimmSide &side, const ore::data::NettingSetDetails &nsd) const
 
const std::map< ore::data::NettingSetDetails, std::pair< std::string, IMScheduleResults > > & finalImScheduleSummaryResults (const SimmSide &side) const
 
const std::map< SimmSide, std::map< ore::data::NettingSetDetails, std::pair< std::string, IMScheduleResults > > > & finalImScheduleSummaryResults () const
 
const std::vector< IMScheduleTradeData > & imScheduleTradeResults (const std::string &tradeId) const
 Give back the IM Schedule results container for the given tradeId and IM side. More...
 
const std::map< std::string, std::vector< IMScheduleTradeData > > & imScheduleTradeResults () const
 
const IMScheduleTradeDatafinalImScheduleTradeResults (const std::string &tradeId) const
 
const std::map< std::string, IMScheduleTradeData > & finalImScheduleTradeResults () const
 
const std::string & calculationCurrency () const
 Return the calculator's calculation currency. More...
 
void populateFinalResults (const std::map< SimmSide, std::map< ore::data::NettingSetDetails, std::string > > &winningRegulations)
 

Static Public Member Functions

static const IMScheduleLabel label (const ProductClass &productClass, const QuantLib::Real &maturity)
 
static const std::string labelString (const IMScheduleLabel &label)
 

Private Member Functions

QuantLib::Real multiplier (const IMScheduleLabel &label)
 
void collectTradeData (const CrifRecord &cr, const bool enforceIMRegulations)
 Collect trade data as defined by the CRIF records. More...
 
void populateResults (const ore::data::NettingSetDetails &nsd, const string &regulation, const SimmSide &side)
 
void populateFinalResults ()
 
void add (const SimmSide &side, const ore::data::NettingSetDetails &nsd, const std::string &regulation, const CrifRecord::ProductClass &pc, const std::string &ccy, const QuantLib::Real &grossIM, const QuantLib::Real &grossRC=QuantLib::Null< QuantLib::Real >(), const QuantLib::Real &netRC=QuantLib::Null< QuantLib::Real >(), const QuantLib::Real &ngr=QuantLib::Null< QuantLib::Real >(), const QuantLib::Real &scheduleIM=QuantLib::Null< QuantLib::Real >())
 Add a margin result to either call or post results container depending on the SimmSide parameter. More...
 

Private Attributes

ore::analytics::Crif crif_
 The net sensitivities used in the calculation. More...
 
std::string calculationCcy_
 The SIMM calculation currency i.e. the currency of the SIMM results. More...
 
QuantLib::ext::shared_ptr< ore::data::Marketmarket_
 Market data for FX rates to use for converting amounts to USD. More...
 
bool quiet_
 If true, no logging is written out. More...
 
std::map< SimmSide, std::set< NettingSetDetails > > hasSEC_
 
std::map< SimmSide, std::set< NettingSetDetails > > hasCFTC_
 
std::map< ore::data::NettingSetDetails, boolcollectRegsIsEmpty_
 For each netting set, whether all CRIF records' collect regulations are empty. More...
 
std::map< ore::data::NettingSetDetails, boolpostRegsIsEmpty_
 For each netting set, whether all CRIF records' post regulations are empty. More...
 
std::map< SimmSide, std::map< ore::data::NettingSetDetails, std::map< std::string, IMScheduleResults > > > imScheduleResults_
 Containers, one for call and post, with an IMScheduleResults object for each regulation under each portfolio ID. More...
 
std::map< SimmSide, std::map< ore::data::NettingSetDetails, std::pair< std::string, IMScheduleResults > > > finalImScheduleResults_
 Containers, one for call and post, with an IMScheduleResults object for each portfolio ID. More...
 
std::map< SimmSide, std::map< ore::data::NettingSetDetails, std::map< std::string, set< string > > > > tradeIds_
 Container for keeping track of what trade IDs belong to each regulation. More...
 
std::map< SimmSide, set< string > > finalTradeIds_
 
std::map< SimmSide, std::map< ore::data::NettingSetDetails, std::string > > winningRegulations_
 Regulation with highest IM for each given netting set. More...
 
std::map< std::string, std::vector< IMScheduleTradeData > > finalTradeData_
 
std::map< SimmSide, std::map< ore::data::NettingSetDetails, std::map< std::string, std::map< std::string, IMScheduleTradeData > > > > nettingSetRegTradeData_
 Container for trade data, taking into account regulations applicable to each netting set. More...
 
std::map< IMScheduleLabel, QuantLib::Real > multiplierMap_
 

Detailed Description

A class to calculate Schedule IM given a set of aggregated CRIF results for one or more portfolios.

Definition at line 35 of file imschedulecalculator.hpp.

Member Typedef Documentation

◆ ProductClass

Definition at line 38 of file imschedulecalculator.hpp.

◆ RiskType

Definition at line 39 of file imschedulecalculator.hpp.

◆ Regulation

Definition at line 40 of file imschedulecalculator.hpp.

◆ SimmSide

Definition at line 41 of file imschedulecalculator.hpp.

Constructor & Destructor Documentation

◆ IMScheduleCalculator()

IMScheduleCalculator ( const Crif crif,
const std::string &  calculationCcy = "USD",
const QuantLib::ext::shared_ptr< ore::data::Market market = nullptr,
const bool  determineWinningRegulations = true,
const bool  enforceIMRegulations = false,
const bool  quiet = false,
const std::map< SimmSide, std::set< NettingSetDetails > > &  hasSEC = std::map<SimmSide, std::set<NettingSetDetails>>(),
const std::map< SimmSide, std::set< NettingSetDetails > > &  hasCFTC = std::map<SimmSide, std::set<NettingSetDetails>>() 
)

Construct the IMScheduleCalculator from a container of netted CRIF records.

Definition at line 53 of file imschedulecalculator.cpp.

59 : crif_(crif), calculationCcy_(calculationCcy), market_(market), quiet_(quiet),
60 hasSEC_(hasSEC), hasCFTC_(hasCFTC) {
61
63 "The calculation currency (" << calculationCcy_ << ") must be a valid ISO currency code");
64
65 QuantLib::Date today = QuantLib::Settings::instance().evaluationDate();
66 QuantLib::DayCounter dayCounter = QuantLib::ActualActual(QuantLib::ActualActual::ISDA);
67
68 // Collect Schedule CRIF records
69 Crif tmp;
70 for (const CrifRecord& cr : crif_) {
71 const bool isSchedule = cr.imModel == "Schedule";
72
73 if (!isSchedule) {
74 if (determineWinningRegulations) {
76 cr.tradeId, cr.tradeType, "IM Schedule calculator",
77 "Skipping over CRIF record without im_model=Schedule for portfolio [ " +
78 to_string(cr.nettingSetDetails) + "]")
79 .log();
80 }
81 continue;
82 }
83
84 // Check for each netting set whether post/collect regs are populated at all
85 if (collectRegsIsEmpty_.find(cr.nettingSetDetails) == collectRegsIsEmpty_.end()) {
86 collectRegsIsEmpty_[cr.nettingSetDetails] = cr.collectRegulations.empty();
87 } else if (collectRegsIsEmpty_.at(cr.nettingSetDetails) && !cr.collectRegulations.empty()) {
88 collectRegsIsEmpty_.at(cr.nettingSetDetails) = false;
89 }
90 if (postRegsIsEmpty_.find(cr.nettingSetDetails) == postRegsIsEmpty_.end()) {
91 postRegsIsEmpty_[cr.nettingSetDetails] = cr.postRegulations.empty();
92 } else if (postRegsIsEmpty_.at(cr.nettingSetDetails) && !cr.postRegulations.empty()) {
93 postRegsIsEmpty_.at(cr.nettingSetDetails) = false;
94 }
95
96 tmp.addRecord(cr);
97 }
98 crif_ = tmp;
99
100
101 // Separate out CRIF records by regulations and collect per-trade data
102 LOG("IMScheduleCalculator: Collecting CRIF trade data");
103 for (const auto& crifRecord : crif_)
104 collectTradeData(crifRecord, enforceIMRegulations);
105
106 // Remove (or modify) trades with incomplete data
107 for (auto& sv : nettingSetRegTradeData_) {
108 const SimmSide& side = sv.first;
109
110 for (auto& nv : sv.second) {
111 const NettingSetDetails& nsd = nv.first;
112
113 for (auto& rv : nv.second) {
114 const string& regulation = rv.first;
115 auto& tradeDataMap = rv.second;
116
117 // Remove (or modify) trades with incomplete Schedule data
118 set<string> tradesToRemove;
119 for (auto& td : tradeDataMap) {
120 if (td.second.incomplete()) {
121 auto subFields = map<string, string>({{"tradeId", td.first}});
122 // If missing PV, assume PV = 0
123 if (td.second.missingPVData()) {
124 td.second.presentValue = 0.0;
125 td.second.presentValueUsd = 0.0;
126 td.second.presentValueCcy = td.second.notionalCcy;
127 }
128 // If missing Notional, do not process the trade
129 if (td.second.missingNotionalData()) {
131 "IMSchedule", "Incomplete CRIF trade data",
132 "Missing Notional data. The trade will not be processed.", subFields)
133 .log();
134 tradesToRemove.insert(td.first);
135 }
136 }
137 }
138
139 for (const string& tid : tradesToRemove) {
140 tradeDataMap.erase(tid);
141 tradeIds_.at(side).at(nsd).at(regulation).erase(tid);
142 }
143
144 // Calculate Schedule data for each trade data obj
145 for (auto& td : tradeDataMap) {
146 IMScheduleTradeData& tradeData = td.second;
147
148 // Calculate gross IM for each IM Schedule trade
149 tradeData.maturity = dayCounter.yearFraction(today, tradeData.endDate);
150 tradeData.label = label(tradeData.productClass, tradeData.maturity);
151 tradeData.labelString = labelString(tradeData.label);
152 tradeData.multiplier = multiplier(tradeData.label);
153 tradeData.grossMarginUsd = tradeData.multiplier * tradeData.notionalUsd;
154
155 // Convert some trade data values into calculation currency
156 const Real usdSpot = calculationCcy_ != "USD" ? market_->fxRate(calculationCcy_ + "USD")->value() : 1.0;
157 tradeData.notionalCalc = tradeData.notionalUsd / usdSpot;
158 tradeData.presentValueCalc = tradeData.presentValueUsd / usdSpot;
159 tradeData.grossMarginCalc = tradeData.grossMarginUsd / usdSpot;
160 if (side == SimmSide::Call)
161 tradeData.collectRegulations = regulation;
162 if (side == SimmSide::Post)
163 tradeData.postRegulations = regulation;
164 }
165 }
166 }
167 }
168
169 // Some additional processing depending on the regulations applicable to each netting set
170 for (auto& sv : nettingSetRegTradeData_) {
171 const SimmSide& side = sv.first;
172
173 for (auto& s : sv.second) {
174 const NettingSetDetails& nettingDetails = s.first;
175
176 // Where there is SEC and CFTC in the portfolio, we add the CFTC trades to SEC,
177 // but still continue with CFTC calculations
178 const bool hasCFTCGlobal = hasCFTC_.at(side).find(nettingDetails) != hasCFTC_.at(side).end();
179 const bool hasSECGlobal = hasSEC_.at(side).find(nettingDetails) != hasSEC_.at(side).end();
180 const bool hasCFTCLocal = s.second.count("CFTC") > 0;
181 const bool hasSECLocal = s.second.count("SEC") > 0;
182
183 if ((hasSECLocal && hasCFTCLocal) || (hasCFTCGlobal && hasSECGlobal)) {
184 if (!hasSECLocal && !hasCFTCLocal)
185 continue;
186
187 if (hasCFTCLocal) {
188 // At this point, we expect to have CFTC trade data at least for the netting set
189 const map<string, IMScheduleTradeData>& tradeDataMapCFTC = s.second.at("CFTC");
190 map<string, IMScheduleTradeData>& tradeDataMapSEC = s.second["SEC"];
191 for (const auto& kv : tradeDataMapCFTC) {
192 // Only add CFTC records to SEC if the record was not already in SEC,
193 // i.e. we skip over CRIF records with regulations specified as e.g. "..., CFTC, SEC, ..."
194 if (tradeDataMapSEC.find(kv.first) == tradeDataMapSEC.end()) {
195 tradeDataMapSEC[kv.first] = kv.second;
196 }
197 }
198 }
199 }
200
201 // If netting set has "Unspecified" plus other regulations, the "Unspecified" sensis are to be excluded.
202 // If netting set only has "Unspecified", then no regulations were ever specified, so all trades are
203 // included.
204 if (s.second.count("Unspecified") > 0 && s.second.size() > 1)
205 s.second.erase("Unspecified");
206 }
207 }
208
209 // Calculate the higher level margins
210 LOG("IMScheduleCalculator: Populating higher level results")
211 for (const auto& sv : nettingSetRegTradeData_) {
212 const SimmSide side = sv.first;
213
214 for (const auto& nv : sv.second) {
215 const NettingSetDetails& nsd = nv.first;
216
217 for (const auto& rv : nv.second) {
218 const string& regulation = rv.first;
219 populateResults(nsd, regulation, side);
220 }
221 }
222 }
223
224 if (determineWinningRegulations) {
225 LOG("IMScheduleCalculator: Determining winning regulations");
226
227 // Determine winning call and post regulations
228 for (const auto& sv : imScheduleResults_) {
229 const SimmSide side = sv.first;
230
231 // Determine winning regulation for each netting set
232 // Collect margin amounts and determine the highest margin amount
233 for (const auto& nv : sv.second) {
234 const NettingSetDetails& nsd = nv.first;
235 Real winningMargin = std::numeric_limits<Real>::min();
236 map<string, Real> nettingSetMargins;
237 vector<Real> margins;
238
239 for (const auto& rv : nv.second) {
240 const string& regulation = rv.first;
241 const IMScheduleResults& schResult = rv.second;
242 const Real& im = schResult.get(ProductClass::All).scheduleIM;
243
244 nettingSetMargins[regulation] = im;
245 if (im > winningMargin)
246 winningMargin = im;
247 }
248
249 // Determine winning regulations, i.e. regulations under which we find the highest margin amount
250 vector<string> winningRegulations;
251 for (const auto& kv : nettingSetMargins) {
252 if (close_enough(kv.second, winningMargin))
253 winningRegulations.push_back(kv.first);
254 }
255
256 // In the case of multiple winning regulations, pick one based on the priority in the list
257 //const Regulation winningRegulation = getWinningRegulation(winningRegulations);
258 string winningRegulation = winningRegulations.size() > 1
260 : winningRegulations.at(0);
261
262 // Populate internal list of winning regulators
263 winningRegulations_[side][nsd] = ore::data::to_string(winningRegulation);
264 }
265 }
266
268 }
269}
std::map< SimmSide, std::map< ore::data::NettingSetDetails, std::map< std::string, IMScheduleResults > > > imScheduleResults_
Containers, one for call and post, with an IMScheduleResults object for each regulation under each po...
std::map< SimmSide, std::set< NettingSetDetails > > hasCFTC_
std::map< SimmSide, std::set< NettingSetDetails > > hasSEC_
std::map< SimmSide, std::map< ore::data::NettingSetDetails, std::string > > winningRegulations_
Regulation with highest IM for each given netting set.
std::map< ore::data::NettingSetDetails, bool > collectRegsIsEmpty_
For each netting set, whether all CRIF records' collect regulations are empty.
const std::map< SimmSide, std::map< ore::data::NettingSetDetails, string > > & winningRegulations() const
std::map< ore::data::NettingSetDetails, bool > postRegsIsEmpty_
For each netting set, whether all CRIF records' post regulations are empty.
static const IMScheduleLabel label(const ProductClass &productClass, const QuantLib::Real &maturity)
std::map< SimmSide, std::map< ore::data::NettingSetDetails, std::map< std::string, std::map< std::string, IMScheduleTradeData > > > > nettingSetRegTradeData_
Container for trade data, taking into account regulations applicable to each netting set.
QuantLib::ext::shared_ptr< ore::data::Market > market_
Market data for FX rates to use for converting amounts to USD.
bool quiet_
If true, no logging is written out.
static const std::string labelString(const IMScheduleLabel &label)
std::string calculationCcy_
The SIMM calculation currency i.e. the currency of the SIMM results.
ore::analytics::Crif crif_
The net sensitivities used in the calculation.
void collectTradeData(const CrifRecord &cr, const bool enforceIMRegulations)
Collect trade data as defined by the CRIF records.
std::map< SimmSide, std::map< ore::data::NettingSetDetails, std::map< std::string, set< string > > > > tradeIds_
Container for keeping track of what trade IDs belong to each regulation.
QuantLib::Real multiplier(const IMScheduleLabel &label)
void populateResults(const ore::data::NettingSetDetails &nsd, const string &regulation, const SimmSide &side)
bool checkCurrency(const string &code)
#define LOG(text)
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
SimmConfiguration::Regulation getWinningRegulation(const std::vector< string > &winningRegulations)
From a vector of regulations, determine the winning regulation based on order of priority.
IMScheduleCalculator::IMScheduleTradeData IMScheduleTradeData
std::string to_string(const LocationInfo &l)
+ Here is the call graph for this function:

Member Function Documentation

◆ finalTradeIds()

const std::map< SimmSide, std::set< std::string > > finalTradeIds ( ) const

Give back the set of portfolio IDs and trade IDs for which we have IM results.

Definition at line 121 of file imschedulecalculator.hpp.

121{ return finalTradeIds_; }
std::map< SimmSide, set< string > > finalTradeIds_

◆ winningRegulations() [1/3]

const string & winningRegulations ( const SimmSide side,
const ore::data::NettingSetDetails nettingSetDetails 
) const

Return the winning regulation for each portfolioId.

Definition at line 271 of file imschedulecalculator.cpp.

272 {
273 const auto& subWinningRegs = winningRegulations(side);
274 QL_REQUIRE(subWinningRegs.find(nettingSetDetails) != subWinningRegs.end(),
275 "IMScheduleCalculator::winningRegulations(): Could not find netting set in the list of "
276 << side << " schedule IM winning regulations: " << nettingSetDetails);
277 return subWinningRegs.at(nettingSetDetails);
278}
+ Here is the call graph for this function:

◆ winningRegulations() [2/3]

const map< NettingSetDetails, string > & winningRegulations ( const SimmSide side) const

Definition at line 280 of file imschedulecalculator.cpp.

280 {
281 QL_REQUIRE(winningRegulations_.find(side) != winningRegulations_.end(),
282 "IMScheduleCalculator::winningRegulations(): Could not find list of"
283 << side << " schedule IM winning regulations");
284 return winningRegulations_.at(side);
285}

◆ winningRegulations() [3/3]

const map< SimmConfiguration::SimmSide, map< NettingSetDetails, string > > & winningRegulations ( ) const

Definition at line 288 of file imschedulecalculator.cpp.

288 {
289 return winningRegulations_;
290}
+ Here is the caller graph for this function:

◆ imScheduleSummaryResults() [1/3]

const map< string, IMScheduleResults > & imScheduleSummaryResults ( const SimmSide side,
const ore::data::NettingSetDetails nsd 
) const

Give back the IM Schedule results container for the given portfolioId and IM side.

Definition at line 292 of file imschedulecalculator.cpp.

292 {
293 const auto& subResults = imScheduleSummaryResults(side);
294 QL_REQUIRE(subResults.find(nsd) != subResults.end(),
295 "IMScheduleCalculator::imScheduleSummaryResults(): Could not find netting set in the "
296 << side << " IM schedule results: " << nsd);
297 return subResults.at(nsd);
298}
const std::map< SimmSide, std::map< ore::data::NettingSetDetails, std::map< std::string, IMScheduleResults > > > & imScheduleSummaryResults() const
+ Here is the call graph for this function:

◆ imScheduleSummaryResults() [2/3]

const map< NettingSetDetails, map< string, IMScheduleResults > > & imScheduleSummaryResults ( const SimmSide side) const

Definition at line 300 of file imschedulecalculator.cpp.

300 {
301 QL_REQUIRE(imScheduleResults_.find(side) != imScheduleResults_.end(),
302 "IMScheduleCalculator::imScheduleSummaryResults(): Could not find " << side
303 << " IM in the IM Schedule results");
304 return imScheduleResults_.at(side);
305}

◆ imScheduleSummaryResults() [3/3]

const map< SimmConfiguration::SimmSide, map< NettingSetDetails, map< string, IMScheduleResults > > > & imScheduleSummaryResults ( ) const

Definition at line 308 of file imschedulecalculator.cpp.

308 {
309 return imScheduleResults_;
310};
+ Here is the caller graph for this function:

◆ finalImScheduleSummaryResults() [1/3]

const pair< string, IMScheduleResults > & finalImScheduleSummaryResults ( const SimmSide side,
const ore::data::NettingSetDetails nsd 
) const

Definition at line 312 of file imschedulecalculator.cpp.

313 {
314 const auto& subResults = finalImScheduleSummaryResults(side);
315 QL_REQUIRE(subResults.find(nsd) != subResults.end(),
316 "IMScheduleCalculator::finalImScheduleSummaryResults(): Could not find netting set in the final IM Schedule "
317 << side << " results: " << nsd);
318 return subResults.at(nsd);
319}
const std::map< SimmSide, std::map< ore::data::NettingSetDetails, std::pair< std::string, IMScheduleResults > > > & finalImScheduleSummaryResults() const
+ Here is the call graph for this function:

◆ finalImScheduleSummaryResults() [2/3]

const map< NettingSetDetails, pair< string, IMScheduleResults > > & finalImScheduleSummaryResults ( const SimmSide side) const

Definition at line 321 of file imschedulecalculator.cpp.

321 {
322 QL_REQUIRE(finalImScheduleResults_.find(side) != finalImScheduleResults_.end(),
323 "IMScheduleCalculator::finalImScheduleSummaryResults(): Could not find "
324 << side << " IM in the final IM Schedule results");
325 return finalImScheduleResults_.at(side);
326}
std::map< SimmSide, std::map< ore::data::NettingSetDetails, std::pair< std::string, IMScheduleResults > > > finalImScheduleResults_
Containers, one for call and post, with an IMScheduleResults object for each portfolio ID.

◆ finalImScheduleSummaryResults() [3/3]

const std::map< SimmSide, std::map< ore::data::NettingSetDetails, std::pair< std::string, IMScheduleResults > > > & finalImScheduleSummaryResults ( ) const

Definition at line 138 of file imschedulecalculator.hpp.

138 {
140 };
+ Here is the caller graph for this function:

◆ imScheduleTradeResults() [1/2]

const vector< IMScheduleCalculator::IMScheduleTradeData > & imScheduleTradeResults ( const std::string &  tradeId) const

Give back the IM Schedule results container for the given tradeId and IM side.

Definition at line 328 of file imschedulecalculator.cpp.

328 {
329 QL_REQUIRE(finalTradeData_.find(tradeId) != finalTradeData_.end(),
330 "IMScheduleCalculator::imScheduleTradeResults(): Could not find results for trade: " << tradeId);
331 return finalTradeData_.at(tradeId);
332}
std::map< std::string, std::vector< IMScheduleTradeData > > finalTradeData_

◆ imScheduleTradeResults() [2/2]

const map< string, vector< IMScheduleCalculator::IMScheduleTradeData > > & imScheduleTradeResults ( ) const

Definition at line 334 of file imschedulecalculator.cpp.

334 {
335 return finalTradeData_;
336}

◆ finalImScheduleTradeResults() [1/2]

const IMScheduleTradeData & finalImScheduleTradeResults ( const std::string &  tradeId) const

◆ finalImScheduleTradeResults() [2/2]

const std::map< std::string, IMScheduleTradeData > & finalImScheduleTradeResults ( ) const

◆ calculationCurrency()

const std::string & calculationCurrency ( ) const

Return the calculator's calculation currency.

Definition at line 150 of file imschedulecalculator.hpp.

150{ return calculationCcy_; }

◆ label()

const IMScheduleLabel label ( const ProductClass productClass,
const QuantLib::Real &  maturity 
)
static

Definition at line 338 of file imschedulecalculator.cpp.

338 {
339 if (pc == ProductClass::Credit) {
340 if (maturity >= 0.0 && maturity < 2.0) {
342 } else if (maturity < 5.0) {
344 } else {
346 }
347
348 } else if (pc == ProductClass::Commodity) {
350
351 } else if (pc == ProductClass::Equity) {
353
354 } else if (pc == ProductClass::FX) {
355 return IMScheduleLabel::FX;
356
357 } else if (pc == ProductClass::Rates) {
358 if (maturity >= 0.0 && maturity < 2.0) {
360 } else if (maturity < 5.0) {
362 } else {
364 }
365
366 } else if (pc == ProductClass::Other) {
368 } else {
369 QL_FAIL("IMSchedule::label() Invalid product class " << pc);
370 }
371}
+ Here is the caller graph for this function:

◆ labelString()

const string labelString ( const IMScheduleLabel label)
static

Definition at line 373 of file imschedulecalculator.cpp.

373 {
374 const map<IMScheduleLabel, string> labelStringMap_ = map<IMScheduleLabel, string>({
375 {IMScheduleLabel::Credit2, "Credit 0-2 years"},
376 {IMScheduleLabel::Credit5, "Credit 2-5 years"},
377 {IMScheduleLabel::Credit100, "Credit 5+ years"},
378 {IMScheduleLabel::Commodity, "Commodity"},
379 {IMScheduleLabel::Equity, "Equity"},
380 {IMScheduleLabel::FX, "FX"},
381 {IMScheduleLabel::Rates2, "Interest Rate 0-2 years"},
382 {IMScheduleLabel::Rates5, "Interest Rate 2-5 years"},
383 {IMScheduleLabel::Rates100, "Interest Rate 5+ years"},
384 {IMScheduleLabel::Other, "Other"},
385 });
386
387 return labelStringMap_.at(label);
388}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ populateFinalResults() [1/2]

void populateFinalResults ( const std::map< SimmSide, std::map< ore::data::NettingSetDetails, std::string > > &  winningRegulations)

◆ multiplier()

QuantLib::Real multiplier ( const IMScheduleLabel label)
private

Definition at line 220 of file imschedulecalculator.hpp.

220{ return multiplierMap_[label]; }
std::map< IMScheduleLabel, QuantLib::Real > multiplierMap_
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ collectTradeData()

void collectTradeData ( const CrifRecord cr,
const bool  enforceIMRegulations 
)
private

Collect trade data as defined by the CRIF records.

Definition at line 390 of file imschedulecalculator.cpp.

390 {
391
392 DLOG("Processing CRIF record for IMSchedule calculation: trade ID \'"
393 << cr.tradeId << "\', portfolio [" << cr.nettingSetDetails << "], product class " << cr.productClass
394 << ", risk type " << cr.riskType << ", end date " << cr.endDate);
395 QL_REQUIRE(cr.riskType == RiskType::PV || cr.riskType == RiskType::Notional,
396 "Unexpected risk type found in CRIF " << cr.riskType << " for trade ID " << cr.tradeId);
397
398 for (const auto& side : {SimmSide::Call, SimmSide::Post}) {
399 const NettingSetDetails& nettingSetDetails = cr.nettingSetDetails;
400
401 bool collectRegsIsEmpty = false;
402 bool postRegsIsEmpty = false;
403 if (collectRegsIsEmpty_.find(cr.nettingSetDetails) != collectRegsIsEmpty_.end())
404 collectRegsIsEmpty = collectRegsIsEmpty_.at(cr.nettingSetDetails);
405 if (postRegsIsEmpty_.find(cr.nettingSetDetails) != postRegsIsEmpty_.end())
406 postRegsIsEmpty = postRegsIsEmpty_.at(cr.nettingSetDetails);
407
408 string regsString;
409 if (enforceIMRegulations)
410 regsString = side == SimmSide::Call ? cr.collectRegulations : cr.postRegulations;
411 set<string> regs = parseRegulationString(regsString);
412
413 for (const string& r : regs) {
414 if (r == "Unspecified" && enforceIMRegulations && !(collectRegsIsEmpty && postRegsIsEmpty)) {
415 continue;
416 } else if (r != "Excluded") {
417 // Keep a record of trade IDs for each regulation
418 tradeIds_[side][nettingSetDetails][r].insert(cr.tradeId);
419
420 auto& tradeDataMap = nettingSetRegTradeData_[side][nettingSetDetails][r];
421 auto it = tradeDataMap.find(cr.tradeId);
422 if (it != tradeDataMap.end()) {
423 IMScheduleTradeData& tradeData = it->second;
424
425 QL_REQUIRE(cr.productClass == tradeData.productClass, "Product class is not matching for trade ID "
426 << cr.tradeId << ": " << cr.productClass
427 << " and " << tradeData.productClass);
428 QuantLib::Date incomingDate = parseDate(cr.endDate);
429 QL_REQUIRE(incomingDate == tradeData.endDate, "End date is not matching for trade ID "
430 << cr.tradeId << ": " << incomingDate << " and "
431 << tradeData.endDate);
432 if (cr.riskType == RiskType::PV) {
433 QL_REQUIRE(tradeData.missingPVData(), "Adding PV data for trade that already has PV data, i.e. "
434 "multiple PV records found for the same trade: "
435 << tradeData.tradeId);
436 tradeData.presentValue = cr.amount;
437 tradeData.presentValueUsd = cr.amountUsd;
438 tradeData.presentValueCcy = cr.amountCurrency;
439 } else {
440 QL_REQUIRE(tradeData.missingNotionalData(),
441 "Adding Notional data for trade that already has PV data, i.e. "
442 "multiple Notional records found for the same trade: "
443 << tradeData.tradeId);
444 tradeData.notional = cr.amount;
445 tradeData.notionalUsd = cr.amountUsd;
446 tradeData.notionalCcy = cr.amountCurrency;
447 }
448 } else {
449 const string collectRegs = side == SimmSide::Call ? cr.collectRegulations : "";
450 const string postRegs = side == SimmSide::Post ? cr.postRegulations : "";
451 tradeDataMap.insert(
452 {cr.tradeId, IMScheduleTradeData(cr.tradeId, cr.nettingSetDetails, cr.riskType, cr.productClass,
453 cr.amount, cr.amountCurrency, cr.amountUsd,
454 parseDate(cr.endDate), calculationCcy_, collectRegs, postRegs)});
455 }
456 }
457 }
458 }
459}
Date parseDate(const string &s)
#define DLOG(text)
set< string > parseRegulationString(const string &regsString, const set< string > &valueIfEmpty)
Reads a string containing regulations applicable for a given CRIF record.
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ populateResults()

void populateResults ( const ore::data::NettingSetDetails nsd,
const string &  regulation,
const SimmSide side 
)
private

Populate the results structure with the higher level results after the IMs have been calculated at the (product class, maturity) level for each portfolio

Definition at line 461 of file imschedulecalculator.cpp.

462 {
463
464 LOG("IMScheduleCalculator: Populating " << side << " IM for netting set [" << nettingSetDetails
465 << "] under regulation " << regulation);
466
467
468 const auto& regTradeData = nettingSetRegTradeData_.at(side).at(nettingSetDetails).at(regulation);
469
470 Real grossMarginCalc = 0;
471 Real grossRCCalc = 0;
472 Real presentValueCalc = 0;
473
474 // Populate results at the product class level
475 for (const auto& td : regTradeData) {
476 const IMScheduleTradeData& tradeData = td.second;
477 add(side, nettingSetDetails, regulation, tradeData.productClass, calculationCcy_, tradeData.grossMarginCalc);
478
479 // Sum up trade details to obtain netting set level values:
480 // - Gross margin, gross RC, net RC, PVs
481 grossMarginCalc += tradeData.grossMarginCalc;
482 grossRCCalc +=
483 side == SimmSide::Call ? max(0.0, tradeData.presentValueCalc) : min(0.0, tradeData.presentValueCalc);
484
485 presentValueCalc += tradeData.presentValueCalc;
486 }
487
488 // Calculate other amounts at the nettingSet-regulator level
489
490 // Net replacement cost
491 Real netRCCalc = side == SimmSide::Call ? max(0.0, presentValueCalc) : min(0.0, presentValueCalc);
492
493 // Net-to-gross ratio
494 Real netToGrossCalc = close_enough(grossRCCalc, 0.0) ? 1.0 : netRCCalc / grossRCCalc;
495
496 // Schedule IM
497 Real scheduleMarginCalc = grossMarginCalc * (0.4 + 0.6 * netToGrossCalc);
498
499 // Populate higher level results
500 imScheduleResults_.at(side)
501 .at(nettingSetDetails)
502 .at(regulation)
503 .add(ProductClass::All, calculationCcy_, grossMarginCalc, grossRCCalc, netRCCalc, netToGrossCalc,
504 scheduleMarginCalc);
505}
void add(const SimmSide &side, const ore::data::NettingSetDetails &nsd, const std::string &regulation, const CrifRecord::ProductClass &pc, const std::string &ccy, const QuantLib::Real &grossIM, const QuantLib::Real &grossRC=QuantLib::Null< QuantLib::Real >(), const QuantLib::Real &netRC=QuantLib::Null< QuantLib::Real >(), const QuantLib::Real &ngr=QuantLib::Null< QuantLib::Real >(), const QuantLib::Real &scheduleIM=QuantLib::Null< QuantLib::Real >())
Add a margin result to either call or post results container depending on the SimmSide parameter.
RandomVariable max(RandomVariable x, const RandomVariable &y)
RandomVariable min(RandomVariable x, const RandomVariable &y)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ populateFinalResults() [2/2]

void populateFinalResults ( )
private

Populate final (i.e. winning regulators') using own list of winning regulators, which were determined solely by the IMSchedule results (i.e. not including any external SIMM results)

Definition at line 572 of file imschedulecalculator.cpp.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ add()

void add ( const SimmSide side,
const ore::data::NettingSetDetails nsd,
const std::string &  regulation,
const CrifRecord::ProductClass pc,
const std::string &  ccy,
const QuantLib::Real &  grossIM,
const QuantLib::Real &  grossRC = QuantLib::Null<QuantLib::Real>(),
const QuantLib::Real &  netRC = QuantLib::Null<QuantLib::Real>(),
const QuantLib::Real &  ngr = QuantLib::Null<QuantLib::Real>(),
const QuantLib::Real &  scheduleIM = QuantLib::Null<QuantLib::Real>() 
)
private

Add a margin result to either call or post results container depending on the SimmSide parameter.

Definition at line 576 of file imschedulecalculator.cpp.

578 {
579
580 QuantLib::Real netToGrossRatio = ngr != Null<Real>() && close_enough(ngr, 0.0) ? 0.0 : ngr;
581 imScheduleResults_[side][nsd][regulation].add(pc, calcCcy, grossIM, grossRC, netRC, netToGrossRatio, scheduleIM);
582}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Member Data Documentation

◆ crif_

ore::analytics::Crif crif_
private

The net sensitivities used in the calculation.

Definition at line 160 of file imschedulecalculator.hpp.

◆ calculationCcy_

std::string calculationCcy_
private

The SIMM calculation currency i.e. the currency of the SIMM results.

Definition at line 163 of file imschedulecalculator.hpp.

◆ market_

QuantLib::ext::shared_ptr<ore::data::Market> market_
private

Market data for FX rates to use for converting amounts to USD.

Definition at line 166 of file imschedulecalculator.hpp.

◆ quiet_

bool quiet_
private

If true, no logging is written out.

Definition at line 169 of file imschedulecalculator.hpp.

◆ hasSEC_

std::map<SimmSide, std::set<NettingSetDetails> > hasSEC_
private

Definition at line 171 of file imschedulecalculator.hpp.

◆ hasCFTC_

std::map<SimmSide, std::set<NettingSetDetails> > hasCFTC_
private

Definition at line 171 of file imschedulecalculator.hpp.

◆ collectRegsIsEmpty_

std::map<ore::data::NettingSetDetails, bool> collectRegsIsEmpty_
private

For each netting set, whether all CRIF records' collect regulations are empty.

Definition at line 174 of file imschedulecalculator.hpp.

◆ postRegsIsEmpty_

std::map<ore::data::NettingSetDetails, bool> postRegsIsEmpty_
private

For each netting set, whether all CRIF records' post regulations are empty.

Definition at line 177 of file imschedulecalculator.hpp.

◆ imScheduleResults_

std::map<SimmSide, std::map<ore::data::NettingSetDetails, std::map<std::string, IMScheduleResults> > > imScheduleResults_
private

Containers, one for call and post, with an IMScheduleResults object for each regulation under each portfolio ID.

Definition at line 181 of file imschedulecalculator.hpp.

◆ finalImScheduleResults_

std::map<SimmSide, std::map<ore::data::NettingSetDetails, std::pair<std::string, IMScheduleResults> > > finalImScheduleResults_
private

Containers, one for call and post, with an IMScheduleResults object for each portfolio ID.

Definition at line 185 of file imschedulecalculator.hpp.

◆ tradeIds_

std::map<SimmSide, std::map<ore::data::NettingSetDetails, std::map<std::string, set<string> > > > tradeIds_
private

Container for keeping track of what trade IDs belong to each regulation.

Definition at line 189 of file imschedulecalculator.hpp.

◆ finalTradeIds_

std::map<SimmSide, set<string> > finalTradeIds_
private

Definition at line 191 of file imschedulecalculator.hpp.

◆ winningRegulations_

std::map<SimmSide, std::map<ore::data::NettingSetDetails, std::string> > winningRegulations_
private

Regulation with highest IM for each given netting set.

Definition at line 195 of file imschedulecalculator.hpp.

◆ finalTradeData_

std::map<std::string, std::vector<IMScheduleTradeData> > finalTradeData_
private

Container for trade data collected from CRIF report trade ID trade data

Definition at line 199 of file imschedulecalculator.hpp.

◆ nettingSetRegTradeData_

std::map<SimmSide, std::map<ore::data::NettingSetDetails, std::map<std::string, std::map<std::string, IMScheduleTradeData> > > > nettingSetRegTradeData_
private

Container for trade data, taking into account regulations applicable to each netting set.

Definition at line 203 of file imschedulecalculator.hpp.

◆ multiplierMap_

std::map<IMScheduleLabel, QuantLib::Real> multiplierMap_
private
Initial value:

Definition at line 205 of file imschedulecalculator.hpp.