Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
dimregressioncalculator.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2020 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
22#include <ql/errors.hpp>
23#include <ql/time/calendars/weekendsonly.hpp>
24
25#include <ql/math/distributions/normaldistribution.hpp>
26#include <ql/math/generallinearleastsquares.hpp>
27#include <ql/math/kernelfunctions.hpp>
28#include <ql/methods/montecarlo/lsmbasissystem.hpp>
29#include <ql/time/daycounters/actualactual.hpp>
30
33
34#include <boost/accumulators/accumulators.hpp>
35#include <boost/accumulators/statistics/error_of_mean.hpp>
36#include <boost/accumulators/statistics/mean.hpp>
37#include <boost/accumulators/statistics/stats.hpp>
38
39using namespace std;
40using namespace QuantLib;
41
42using namespace boost::accumulators;
43
44namespace ore {
45namespace analytics {
46
48 const QuantLib::ext::shared_ptr<InputParameters>& inputs,
49 const QuantLib::ext::shared_ptr<Portfolio>& portfolio, const QuantLib::ext::shared_ptr<NPVCube>& cube,
50 const QuantLib::ext::shared_ptr<CubeInterpretation>& cubeInterpretation,
51 const QuantLib::ext::shared_ptr<AggregationScenarioData>& scenarioData, Real quantile, Size horizonCalendarDays,
52 Size regressionOrder, std::vector<std::string> regressors, Size localRegressionEvaluations,
53 Real localRegressionBandWidth, const std::map<std::string, Real>& currentIM)
54: DynamicInitialMarginCalculator(inputs, portfolio, cube, cubeInterpretation, scenarioData, quantile, horizonCalendarDays,
55 currentIM),
56 regressionOrder_(regressionOrder), regressors_(regressors),
57 localRegressionEvaluations_(localRegressionEvaluations), localRegressionBandWidth_(localRegressionBandWidth) {
58 Size dates = cube_->dates().size();
59 Size samples = cube_->samples();
60 for (const auto& nettingSetId : nettingSetIds_) {
61 regressorArray_[nettingSetId] = vector<vector<Array>>(dates, vector<Array>(samples));
62 nettingSetLocalDIM_[nettingSetId] = vector<vector<Real>>(dates, vector<Real>(samples, 0.0));
63 nettingSetZeroOrderDIM_[nettingSetId] = vector<Real>(dates, 0.0);
64 nettingSetSimpleDIMh_[nettingSetId] = vector<Real>(dates, 0.0);
65 nettingSetSimpleDIMp_[nettingSetId] = vector<Real>(dates, 0.0);
66 }
67}
68
69const vector<vector<Real>>&
71 if (nettingSetLocalDIM_.find(nettingSet) != nettingSetLocalDIM_.end())
72 return nettingSetLocalDIM_[nettingSet];
73 else
74 QL_FAIL("netting set " << nettingSet << " not found in Local DIM results");
75}
76
77const vector<Real>& RegressionDynamicInitialMarginCalculator::zeroOrderResults(const std::string& nettingSet) {
78 if (nettingSetZeroOrderDIM_.find(nettingSet) != nettingSetZeroOrderDIM_.end())
79 return nettingSetZeroOrderDIM_[nettingSet];
80 else
81 QL_FAIL("netting set " << nettingSet << " not found in Zero Order DIM results");
82}
83
84const vector<Real>& RegressionDynamicInitialMarginCalculator::simpleResultsUpper(const std::string& nettingSet) {
85 if (nettingSetSimpleDIMp_.find(nettingSet) != nettingSetSimpleDIMp_.end())
86 return nettingSetSimpleDIMp_[nettingSet];
87 else
88 QL_FAIL("netting set " << nettingSet << " not found in Simple DIM (p) results");
89}
90
91const vector<Real>& RegressionDynamicInitialMarginCalculator::simpleResultsLower(const std::string& nettingSet) {
92 if (nettingSetSimpleDIMh_.find(nettingSet) != nettingSetSimpleDIMh_.end())
93 return nettingSetSimpleDIMh_[nettingSet];
94 else
95 QL_FAIL("netting set " << nettingSet << " not found in Simple DIM (c) results");
96}
97
99 LOG("DIM Analysis by polynomial regression");
100
101 map<string, Real> currentDim = unscaledCurrentDIM();
102
103 Size stopDatesLoop = datesLoopSize_;
104 Size samples = cube_->samples();
105
106 Size polynomOrder = regressionOrder_;
107 LOG("DIM regression polynom order = " << regressionOrder_);
108 LsmBasisSystem::PolynomialType polynomType = LsmBasisSystem::Monomial;
109 Size regressionDimension = regressors_.empty() ? 1 : regressors_.size();
110 LOG("DIM regression dimension = " << regressionDimension);
111 std::vector<ext::function<Real(Array)>> v(
112 LsmBasisSystem::multiPathBasisSystem(regressionDimension, polynomOrder, polynomType));
113 Real confidenceLevel = QuantLib::InverseCumulativeNormal()(quantile_);
114 LOG("DIM confidence level " << confidenceLevel);
115
116 Size simple_dim_index_h = Size(floor(quantile_ * (samples - 1) + 0.5));
117 Size simple_dim_index_p = Size(floor((1.0 - quantile_) * (samples - 1) + 0.5));
118
119 Size nettingSetCount = 0;
120 for (auto n : nettingSetIds_) {
121 LOG("Process netting set " << n);
122
123 if (inputs_) {
124 // Check whether a deterministic IM evolution was provided for this netting set
125 // If found then we use this external data to overwrite the following
126 // - nettingSetExpectedDIM_ by nettingSet and date
127 // - nettingSetZeroOrderDIM_ by nettingSet and date
128 // - nettingSetSimpleDIMh_ by nettingSet and date
129 // - nettingSetSimpleDIMp_ by nettingSet and date
130 // - nettingSetDIM_ by nettingSet, date and sample
131 // - dimCube_ by nettingSet, date and sample
132 TimeSeries<Real> im = inputs_->deterministicInitialMargin(n);
133 LOG("External IM evolution for netting set " << n << " has size " << im.size());
134 if (im.size() > 0) {
135 WLOG("Try overriding DIM with externally provided IM evolution for netting set " << n);
136 for (Size j = 0; j < stopDatesLoop; ++j) {
137 Date d = cube_->dates()[j];
138 try {
139 Real value = im[d];
144 for (Size k = 0; k < samples; ++k) {
145 dimCube_->set(value, nettingSetCount, j, k);
146 nettingSetDIM_[n][j][k] = value;
147 }
148 } catch(std::exception& ) {
149 QL_FAIL("Failed to lookup external IM for netting set " << n
150 << " at date " << io::iso_date(d));
151 }
152 }
153 WLOG("Overriding DIM for netting set " << n << " succeeded");
154 // continue to the next netting set
155 continue;
156 }
157 }
158
159 if (currentIM_.find(n) != currentIM_.end()) {
160 Real t0im = currentIM_[n];
161 QL_REQUIRE(currentDim.find(n) != currentDim.end(), "current DIM not found for netting set " << n);
162 Real t0dim = currentDim[n];
163 Real t0scaling = t0im / t0dim;
164 LOG("t0 scaling for netting set " << n << ": t0im" << t0im << " t0dim=" << t0dim
165 << " t0scaling=" << t0scaling);
166 nettingSetScaling_[n] = t0scaling;
167 }
168
169 Real nettingSetDimScaling =
170 nettingSetScaling_.find(n) == nettingSetScaling_.end() ? 1.0 : nettingSetScaling_[n];
171 LOG("Netting set DIM scaling factor: " << nettingSetDimScaling);
172
173 for (Size j = 0; j < stopDatesLoop; ++j) {
174 accumulator_set<double, stats<boost::accumulators::tag::mean, boost::accumulators::tag::variance>> accDiff;
175 accumulator_set<double, stats<boost::accumulators::tag::mean>> accOneOverNumeraire;
176 for (Size k = 0; k < samples; ++k) {
177 Real numDefault =
178 cubeInterpretation_->getDefaultAggregationScenarioData(AggregationScenarioDataType::Numeraire, j, k);
179 Real numCloseOut =
180 cubeInterpretation_->getCloseOutAggregationScenarioData(AggregationScenarioDataType::Numeraire, j, k);
181 Real npvDefault = nettingSetNPV_[n][j][k];
182 Real flow = nettingSetFLOW_[n][j][k];
183 Real npvCloseOut = nettingSetCloseOutNPV_[n][j][k];
184 accDiff((npvCloseOut * numCloseOut) + (flow * numDefault) - (npvDefault * numDefault));
185 accOneOverNumeraire(1.0 / numDefault);
186 }
187
188 Size mporCalendarDays = cubeInterpretation_->getMporCalendarDays(cube_, j);
189 Real horizonScaling = sqrt(1.0 * horizonCalendarDays_ / mporCalendarDays);
190
191 Real stdevDiff = sqrt(boost::accumulators::variance(accDiff));
192 Real E_OneOverNumeraire =
193 mean(accOneOverNumeraire); // "re-discount" (the stdev is calculated on non-discounted deltaNPVs)
194
195 nettingSetZeroOrderDIM_[n][j] = stdevDiff * horizonScaling * confidenceLevel;
196 nettingSetZeroOrderDIM_[n][j] *= E_OneOverNumeraire;
197
198 vector<Real> rx0(samples, 0.0);
199 vector<Array> rx(samples, Array());
200 vector<Real> ry1(samples, 0.0);
201 vector<Real> ry2(samples, 0.0);
202 for (Size k = 0; k < samples; ++k) {
203 Real numDefault =
204 cubeInterpretation_->getDefaultAggregationScenarioData(AggregationScenarioDataType::Numeraire, j, k);
205 Real numCloseOut =
206 cubeInterpretation_->getCloseOutAggregationScenarioData(AggregationScenarioDataType::Numeraire, j, k);
207 Real x = nettingSetNPV_[n][j][k] * numDefault;
208 Real f = nettingSetFLOW_[n][j][k] * numDefault;
209 Real y = nettingSetCloseOutNPV_[n][j][k] * numCloseOut;
210 Real z = (y + f - x);
211 rx[k] = regressors_.empty() ? Array(1, nettingSetNPV_[n][j][k]) : regressorArray(n, j, k);
212 rx0[k] = rx[k][0];
213 ry1[k] = z; // for local regression
214 ry2[k] = z * z; // for least squares regression
215 nettingSetDeltaNPV_[n][j][k] = z;
216 regressorArray_[n][j][k] = rx[k];
217 }
218 vector<Real> delNpvVec_copy = nettingSetDeltaNPV_[n][j];
219 sort(delNpvVec_copy.begin(), delNpvVec_copy.end());
220 Real simpleDim_h = delNpvVec_copy[simple_dim_index_h];
221 Real simpleDim_p = delNpvVec_copy[simple_dim_index_p];
222 simpleDim_h *= horizonScaling; // the usual scaling factors
223 simpleDim_p *= horizonScaling; // the usual scaling factors
224 nettingSetSimpleDIMh_[n][j] = simpleDim_h * E_OneOverNumeraire; // discounted DIM
225 nettingSetSimpleDIMp_[n][j] = simpleDim_p * E_OneOverNumeraire; // discounted DIM
226
227 QL_REQUIRE(rx.size() > v.size(), "not enough points for regression with polynom order " << polynomOrder);
228 if (close_enough(stdevDiff, 0.0)) {
229 LOG("DIM: Zero std dev estimation at step " << j);
230 // Skip IM calculation if all samples have zero NPV (e.g. after latest maturity)
231 for (Size k = 0; k < samples; ++k) {
232 nettingSetDIM_[n][j][k] = 0.0;
233 nettingSetLocalDIM_[n][j][k] = 0.0;
234 }
235 } else {
236 // Least squares polynomial regression with specified polynom order
238 LOG("DIM data normalisation at time step "
239 << j << ": " << scientific << setprecision(6) << " x-shift = " << ls.xShift() << " x-multiplier = "
240 << ls.xMultiplier() << " y-shift = " << ls.yShift() << " y-multiplier = " << ls.yMultiplier());
241 LOG("DIM regression coefficients at time step " << j << ": " << fixed << setprecision(6)
243
244 // Local regression versus first regression variable (i.e. we do not perform a
245 // multidimensional local regression):
246 // We evaluate this at a limited number of samples only for validation purposes.
247 // Note that computational effort scales quadratically with number of samples.
248 // NadarayaWatson needs a large number of samples for good results.
249 QuantExt::NadarayaWatson lr(rx0.begin(), rx0.end(), ry1.begin(),
250 GaussianKernel(0.0, localRegressionBandWidth_));
251 Size localRegressionSamples = samples;
253 localRegressionSamples = Size(floor(1.0 * samples / localRegressionEvaluations_ + .5));
254
255 // Evaluate regression function to compute DIM for each scenario
256 for (Size k = 0; k < samples; ++k) {
257 // Real num1 = scenarioData_->get(j, k, AggregationScenarioDataType::Numeraire);
258 Real numDefault = cubeInterpretation_->getDefaultAggregationScenarioData(
260 Array regressor = regressors_.empty() ? Array(1, nettingSetNPV_[n][j][k]) : regressorArray(n, j, k);
261 Real e = ls.eval(regressor, v);
262 if (e < 0.0)
263 LOG("Negative variance regression for date " << j << ", sample " << k
264 << ", regressor = " << regressor);
265
266 // Note:
267 // 1) We assume vanishing mean of "z", because the drift over a MPOR is usually small,
268 // and to avoid a second regression for the conditional mean
269 // 2) In particular the linear regression function can yield negative variance values in
270 // extreme scenarios where an exact analytical or delta VaR calculation would yield a
271 // variance approaching zero. We correct this here by taking the positive part.
272 Real std = sqrt(std::max(e, 0.0));
273 Real scalingFactor = horizonScaling * confidenceLevel * nettingSetDimScaling;
274 // Real dim = std * scalingFactor / num1;
275 Real dim = std * scalingFactor / numDefault;
276 dimCube_->set(dim, nettingSetCount, j, k);
277 nettingSetDIM_[n][j][k] = dim;
278 nettingSetExpectedDIM_[n][j] += dim / samples;
279
280 // Evaluate the Kernel regression for a subset of the samples only (performance)
281 if (localRegressionEvaluations_ > 0 && (k % localRegressionSamples == 0))
282 // nettingSetLocalDIM_[n][j][k] = lr.standardDeviation(regressor[0]) * scalingFactor / num1;
283 nettingSetLocalDIM_[n][j][k] = lr.standardDeviation(regressor[0]) * scalingFactor / numDefault;
284 else
285 nettingSetLocalDIM_[n][j][k] = 0.0;
286 }
287 }
288 }
289
290 nettingSetCount++;
291 }
292 LOG("DIM by polynomial regression done");
293}
294
295Array RegressionDynamicInitialMarginCalculator::regressorArray(string nettingSet, Size dateIndex,
296 Size sampleIndex) {
297 Array a(regressors_.size());
298 for (Size i = 0; i < regressors_.size(); ++i) {
299 string variable = regressors_[i];
300 if (boost::to_upper_copy(variable) ==
301 "NPV") // this allows possibility to include NPV as a regressor alongside more fundamental risk factors
302 a[i] = nettingSetNPV_[nettingSet][dateIndex][sampleIndex];
304 a[i] = cubeInterpretation_->getDefaultAggregationScenarioData(AggregationScenarioDataType::IndexFixing,
305 dateIndex, sampleIndex, variable);
306 else if (scenarioData_->has(AggregationScenarioDataType::FXSpot, variable))
307 a[i] = cubeInterpretation_->getDefaultAggregationScenarioData(AggregationScenarioDataType::FXSpot, dateIndex,
308 sampleIndex, variable);
310 a[i] = cubeInterpretation_->getDefaultAggregationScenarioData(AggregationScenarioDataType::Generic, dateIndex,
311 sampleIndex, variable);
312 else
313 QL_FAIL("scenario data does not provide data for " << variable);
314 }
315 return a;
316}
317
319 // In this function we proxy the model-implied T0 IM by looking at the
320 // cube grid horizon lying closest to t0+mpor. We measure diffs relative
321 // to the mean of the distribution at this same time horizon, thus avoiding
322 // any cashflow-specific jumps
323
324 Date today = cube_->asof();
325 Size relevantDateIdx = 0;
326 Real sqrtTimeScaling = 1.0;
327 for (Size i = 0; i < cube_->dates().size(); ++i) {
328 Size daysFromT0 = (cube_->dates()[i] - today);
329 if (daysFromT0 < horizonCalendarDays_) {
330 // iterate until we straddle t0+mpor
331 continue;
332 } else if (daysFromT0 == horizonCalendarDays_) {
333 // this date corresponds to t0+mpor, so use it
334 relevantDateIdx = i;
335 sqrtTimeScaling = 1.0;
336 break;
337 } else if (daysFromT0 > horizonCalendarDays_) {
338 // the first date greater than t0+MPOR, check if it is closest
339 Size lastIdx = (i == 0) ? 0 : (i - 1);
340 Size lastDaysFromT0 = (cube_->dates()[lastIdx] - today);
341 int daysFromT0CloseOut = static_cast<int>(daysFromT0 - horizonCalendarDays_);
342 int prevDaysFromT0CloseOut = static_cast<int>(lastDaysFromT0 - horizonCalendarDays_);
343 if (std::abs(daysFromT0CloseOut) <= std::abs(prevDaysFromT0CloseOut)) {
344 relevantDateIdx = i;
345 sqrtTimeScaling = std::sqrt(Real(horizonCalendarDays_) / Real(daysFromT0));
346 } else {
347 relevantDateIdx = lastIdx;
348 sqrtTimeScaling = std::sqrt(Real(horizonCalendarDays_) / Real(lastDaysFromT0));
349 }
350 break;
351 }
352 }
353 // set some reasonable bounds on the sqrt time scaling, so that we are not looking at a ridiculous time horizon
354 if (sqrtTimeScaling < std::sqrt(0.5) || sqrtTimeScaling > std::sqrt(2.0)) {
355 WLOG("T0 IM Estimation - The estimation time horizon from grid is not sufficiently close to t0+MPOR - "
356 << QuantLib::io::iso_date(cube_->dates()[relevantDateIdx])
357 << ", the T0 IM estimate might be inaccurate. Consider inserting a first grid tenor closer to the dim "
358 "horizon");
359 }
360
361 // TODO: Ensure that the simulation containers read-from below are indeed populated
362
363 Real confidenceLevel = QuantLib::InverseCumulativeNormal()(quantile_);
364 Size simple_dim_index_h = Size(floor(quantile_ * (cube_->samples() - 1) + 0.5));
365 map<string, Real> t0dimReg, t0dimSimple;
366 for (auto it_map = nettingSetNPV_.begin(); it_map != nettingSetNPV_.end(); ++it_map) {
367 string key = it_map->first;
368 vector<Real> t0_dist = it_map->second[relevantDateIdx];
369 Size dist_size = t0_dist.size();
370 QL_REQUIRE(dist_size == cube_->samples(),
371 "T0 IM - cube samples size mismatch - " << dist_size << ", " << cube_->samples());
372 Real mean_t0_dist = std::accumulate(t0_dist.begin(), t0_dist.end(), 0.0);
373 mean_t0_dist /= dist_size;
374 vector<Real> t0_delMtM_dist(dist_size, 0.0);
375 accumulator_set<double, stats<boost::accumulators::tag::mean, boost::accumulators::tag::variance>> acc_delMtm;
376 accumulator_set<double, stats<boost::accumulators::tag::mean>> acc_OneOverNum;
377 for (Size i = 0; i < dist_size; ++i) {
378 Real numeraire = scenarioData_->get(relevantDateIdx, i, AggregationScenarioDataType::Numeraire);
379 Real deltaMtmFromMean = numeraire * (t0_dist[i] - mean_t0_dist) * sqrtTimeScaling;
380 t0_delMtM_dist[i] = deltaMtmFromMean;
381 acc_delMtm(deltaMtmFromMean);
382 acc_OneOverNum(1.0 / numeraire);
383 }
384 Real E_OneOverNumeraire = mean(acc_OneOverNum);
385 Real variance_t0 = boost::accumulators::variance(acc_delMtm);
386 Real sqrt_t0 = sqrt(variance_t0);
387 t0dimReg[key] = (sqrt_t0 * confidenceLevel * E_OneOverNumeraire);
388 std::sort(t0_delMtM_dist.begin(), t0_delMtM_dist.end());
389 t0dimSimple[key] = (t0_delMtM_dist[simple_dim_index_h] * E_OneOverNumeraire);
390
391 LOG("T0 IM (Reg) - {" << key << "} = " << t0dimReg[key]);
392 LOG("T0 IM (Simple) - {" << key << "} = " << t0dimSimple[key]);
393 }
394 LOG("T0 IM Calculations Completed");
395
396 return t0dimReg;
397}
398
400
401 Size samples = dimCube_->samples();
402 Size stopDatesLoop = datesLoopSize_;
403 Date asof = cube_->asof();
404
405 dimEvolutionReport.addColumn("TimeStep", Size())
406 .addColumn("Date", Date())
407 .addColumn("DaysInPeriod", Size())
408 .addColumn("ZeroOrderDIM", Real(), 6)
409 .addColumn("AverageDIM", Real(), 6)
410 .addColumn("AverageFLOW", Real(), 6)
411 .addColumn("SimpleDIM", Real(), 6)
412 .addColumn("NettingSet", string())
413 .addColumn("Time", Real(), 6);
414
415 for (const auto& [nettingSet, _] : dimCube_->idsAndIndexes()) {
416
417 LOG("Export DIM evolution for netting set " << nettingSet);
418 for (Size i = 0; i < stopDatesLoop; ++i) {
419 Real expectedFlow = 0.0;
420 for (Size j = 0; j < samples; ++j) {
421 expectedFlow += nettingSetFLOW_.find(nettingSet)->second[i][j] / samples;
422 }
423
424 Date defaultDate = dimCube_->dates()[i];
425 Time t = ActualActual(ActualActual::ISDA).yearFraction(asof, defaultDate);
426 Size days = cubeInterpretation_->getMporCalendarDays(dimCube_, i);
427 dimEvolutionReport.next()
428 .add(i)
429 .add(defaultDate)
430 .add(days)
431 .add(nettingSetZeroOrderDIM_.find(nettingSet)->second[i])
432 .add(nettingSetExpectedDIM_.find(nettingSet)->second[i])
433 .add(expectedFlow)
434 .add(nettingSetSimpleDIMh_.find(nettingSet)->second[i])
435 .add(nettingSet)
436 .add(t);
437 }
438 }
439 dimEvolutionReport.end();
440 LOG("Exporting expected DIM through time done");
441}
442
444 const std::string& nettingSet, const std::vector<Size>& timeSteps,
445 const std::vector<QuantLib::ext::shared_ptr<ore::data::Report>>& dimRegReports) {
446
447 QL_REQUIRE(dimRegReports.size() == timeSteps.size(),
448 "number of file names (" << dimRegReports.size() << ") does not match number of time steps ("
449 << timeSteps.size() << ")");
450 for (Size ii = 0; ii < timeSteps.size(); ++ii) {
451 Size timeStep = timeSteps[ii];
452 LOG("Export DIM by sample for netting set " << nettingSet << " and time step " << timeStep);
453
454 Size dates = dimCube_->dates().size();
455 const std::map<std::string, Size>& ids = dimCube_->idsAndIndexes();
456
457 auto it = ids.find(nettingSet);
458
459 QL_REQUIRE(it != ids.end(), "netting set " << nettingSet << " not found in DIM cube");
460
461 QL_REQUIRE(timeStep < dates - 1, "selected time step " << timeStep << " out of range [0, " << dates - 1 << "]");
462
463 Size samples = cube_->samples();
464 vector<Real> numeraires(samples, 0.0);
465 for (Size k = 0; k < samples; ++k)
466 // numeraires[k] = scenarioData_->get(timeStep, k, AggregationScenarioDataType::Numeraire);
467 numeraires[k] =
468 cubeInterpretation_->getDefaultAggregationScenarioData(AggregationScenarioDataType::Numeraire, timeStep, k);
469
470 auto p = sort_permutation(regressorArray_[nettingSet][timeStep], lessThan);
471 vector<Array> reg = apply_permutation(regressorArray_[nettingSet][timeStep], p);
472 vector<Real> dim = apply_permutation(nettingSetDIM_[nettingSet][timeStep], p);
473 vector<Real> ldim = apply_permutation(nettingSetLocalDIM_[nettingSet][timeStep], p);
474 vector<Real> delta = apply_permutation(nettingSetDeltaNPV_[nettingSet][timeStep], p);
475 vector<Real> num = apply_permutation(numeraires, p);
476
477 QuantLib::ext::shared_ptr<ore::data::Report> regReport = dimRegReports[ii];
478 regReport->addColumn("Sample", Size());
479 for (Size k = 0; k < reg[0].size(); ++k) {
480 ostringstream o;
481 o << "Regressor_" << k << "_";
482 o << (regressors_.empty() ? "NPV" : regressors_[k]);
483 regReport->addColumn(o.str(), Real(), 6);
484 }
485 regReport->addColumn("RegressionDIM", Real(), 6)
486 .addColumn("LocalDIM", Real(), 6)
487 .addColumn("ExpectedDIM", Real(), 6)
488 .addColumn("ZeroOrderDIM", Real(), 6)
489 .addColumn("DeltaNPV", Real(), 6)
490 .addColumn("SimpleDIM", Real(), 6);
491
492 // Note that RegressionDIM, LocalDIM, DeltaNPV are _not_ reduced by the numeraire in this output,
493 // but ExpectedDIM, ZeroOrderDIM and SimpleDIM _are_ reduced by the numeraire.
494 // This is so that the regression formula can be manually validated
495
496 for (Size j = 0; j < reg.size(); ++j) {
497 regReport->next().add(j);
498 for (Size k = 0; k < reg[j].size(); ++k)
499 regReport->add(reg[j][k]);
500 regReport->add(dim[j] * num[j])
501 .add(ldim[j] * num[j])
502 .add(nettingSetExpectedDIM_[nettingSet][timeStep])
503 .add(nettingSetZeroOrderDIM_[nettingSet][timeStep])
504 .add(delta[j])
505 .add(nettingSetSimpleDIMh_[nettingSet][timeStep]);
506 }
507 regReport->end();
508 LOG("Exporting DIM by Sample done for");
509 }
510}
511
512} // namespace analytics
513} // namespace ore
Real standardDeviation(Real x) const
const Real yShift() const
const Array & transformedCoefficients() const
Real eval(xType x, vContainer &v, typename boost::enable_if< typename boost::is_arithmetic< xType >::type >::type *=0)
const Real yMultiplier() const
const Array & xMultiplier() const
const Array & xShift() const
Dynamic Initial Margin Calculator base class.
map< string, vector< vector< Real > > > nettingSetNPV_
map< string, vector< vector< Real > > > nettingSetCloseOutNPV_
map< string, vector< vector< Real > > > nettingSetDeltaNPV_
map< string, vector< Real > > nettingSetExpectedDIM_
QuantLib::ext::shared_ptr< AggregationScenarioData > scenarioData_
QuantLib::ext::shared_ptr< CubeInterpretation > cubeInterpretation_
QuantLib::ext::shared_ptr< NPVCube > dimCube_
map< string, vector< vector< Real > > > nettingSetFLOW_
QuantLib::ext::shared_ptr< InputParameters > inputs_
map< string, vector< vector< Real > > > nettingSetDIM_
QuantLib::ext::shared_ptr< NPVCube > cube_
const vector< Real > & zeroOrderResults(const string &nettingSet)
void exportDimRegression(const std::string &nettingSet, const std::vector< Size > &timeSteps, const std::vector< QuantLib::ext::shared_ptr< ore::data::Report > > &dimRegReports)
void exportDimEvolution(ore::data::Report &dimEvolutionReport) const override
DIM evolution report.
Array regressorArray(string nettingSet, Size dateIndex, Size sampleIndex)
Compile the array of DIM regressors for the specified netting set, date and sample index.
const vector< vector< Real > > & localRegressionResults(const string &nettingSet)
RegressionDynamicInitialMarginCalculator(const QuantLib::ext::shared_ptr< InputParameters > &inputs, const QuantLib::ext::shared_ptr< Portfolio > &portfolio, const QuantLib::ext::shared_ptr< NPVCube > &cube, const QuantLib::ext::shared_ptr< CubeInterpretation > &cubeInterpretation, const QuantLib::ext::shared_ptr< AggregationScenarioData > &scenarioData, Real quantile, Size horizonCalendarDays, Size regressionOrder, vector< string > regressors, Size localRegressionEvaluations=0, Real localRegressionBandWidth=0, const std::map< std::string, Real > &currentIM=std::map< std::string, Real >())
void build() override
Compute dynamic initial margin along all paths and fill result structures.
const vector< Real > & simpleResultsLower(const string &nettingSet)
const vector< Real > & simpleResultsUpper(const string &nettingSet)
map< string, Real > unscaledCurrentDIM() override
Model implied t0 DIM by netting set, does not need a call to build() before.
virtual Report & add(const ReportType &rt)=0
virtual Report & next()=0
virtual void end()=0
virtual Report & addColumn(const string &name, const ReportType &, Size precision=0)=0
SafeStack< ValueType > value
Dynamic Initial Margin calculator by regression.
std::vector< T > apply_permutation(const std::vector< T > &vec, const std::vector< std::size_t > &p)
std::vector< std::size_t > sort_permutation(const std::vector< T > &vec, Compare &compare)
#define LOG(text)
#define WLOG(text)
RandomVariable sqrt(RandomVariable x)
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
Size size(const ValueType &v)
bool lessThan(const string &s1, const string &s2)
Date asof(14, Jun, 2018)