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
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 [ " +
80 }
81 continue;
82 }
83
84
87 }
else if (
collectRegsIsEmpty_.at(cr.nettingSetDetails) && !cr.collectRegulations.empty()) {
89 }
92 }
else if (
postRegsIsEmpty_.at(cr.nettingSetDetails) && !cr.postRegulations.empty()) {
94 }
95
96 tmp.addRecord(cr);
97 }
99
100
101
102 LOG(
"IMScheduleCalculator: Collecting CRIF trade data");
103 for (
const auto& crifRecord :
crif_)
105
106
109
110 for (auto& nv : sv.second) {
112
113 for (auto& rv : nv.second) {
114 const string& regulation = rv.first;
115 auto& tradeDataMap = rv.second;
116
117
118 set<string> tradesToRemove;
119 for (auto& td : tradeDataMap) {
120 if (td.second.incomplete()) {
121 auto subFields = map<string, string>({{"tradeId", td.first}});
122
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
129 if (td.second.missingNotionalData()) {
131 "IMSchedule", "Incomplete CRIF trade data",
132 "Missing Notional data. The trade will not be processed.", subFields)
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
145 for (auto& td : tradeDataMap) {
147
148
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
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
172
173 for (auto& s : sv.second) {
175
176
177
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
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
193
194 if (tradeDataMapSEC.find(kv.first) == tradeDataMapSEC.end()) {
195 tradeDataMapSEC[kv.first] = kv.second;
196 }
197 }
198 }
199 }
200
201
202
203
204 if (s.second.count("Unspecified") > 0 && s.second.size() > 1)
205 s.second.erase("Unspecified");
206 }
207 }
208
209
210 LOG(
"IMScheduleCalculator: Populating higher level results")
213
214 for (const auto& nv : sv.second) {
216
217 for (const auto& rv : nv.second) {
218 const string& regulation = rv.first;
220 }
221 }
222 }
223
224 if (determineWinningRegulations) {
225 LOG(
"IMScheduleCalculator: Determining winning regulations");
226
227
230
231
232
233 for (const auto& nv : sv.second) {
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
251 for (const auto& kv : nettingSetMargins) {
254 }
255
256
257
261
262
264 }
265 }
266
268 }
269}
void populateFinalResults()
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 ®ulation, const SimmSide &side)
SimmConfiguration::SimmSide SimmSide
bool checkCurrency(const string &code)
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)