19#include <boost/test/unit_test.hpp>
20#include <boost/timer/timer.hpp>
38#include <oret/toplevelfixture.hpp>
39#include <ql/math/randomnumbers/mt19937uniformrng.hpp>
40#include <ql/time/calendars/target.hpp>
41#include <ql/time/date.hpp>
42#include <ql/time/daycounters/actualactual.hpp>
59#include <ql/time/date.hpp>
60#include <ql/utilities/dataparsers.hpp>
66using namespace boost::unit_test_framework;
75BOOST_AUTO_TEST_SUITE(CollateralisedExposureTest)
78 QuantLib::ext::shared_ptr<data::Conventions> conventions(
new data::Conventions());
80 QuantLib::ext::shared_ptr<data::Convention> swapIndexConv(
82 conventions->add(swapIndexConv);
84 QuantLib::ext::shared_ptr<data::Convention> swapConv(
85 new data::IRSwapConvention(
"EUR-6M-SWAP-CONVENTIONS",
"TARGET",
"Annual",
"MF",
"30/360",
"EUR-EURIBOR-6M"));
86 conventions->add(swapConv);
88 InstrumentConventions::instance().setConventions(conventions);
93QuantLib::ext::shared_ptr<Portfolio>
buildPortfolio(Size portfolioSize, QuantLib::ext::shared_ptr<EngineFactory>& factory) {
95 QuantLib::ext::shared_ptr<Portfolio> portfolio(
new Portfolio());
97 vector<string> ccys = {
"EUR"};
99 map<string, vector<string>> indices = {{
"EUR", {
"EUR-EURIBOR-6M"}}};
101 vector<string> fixedTenors = {
"1Y"};
104 MersenneTwisterUniformRng rng(seed);
106 Date today = Settings::instance().evaluationDate();
108 Calendar cal = TARGET();
109 string calStr =
"TARGET";
111 string rule =
"Forward";
113 string fixDC =
"30/360";
114 string floatDC =
"ACT/365";
116 vector<double> notional(1, 1000000);
117 vector<double> spread(1, 0);
119 for (Size i = 0; i < portfolioSize; i++) {
122 Date startDate = cal.adjust(today);
123 Date endDate = cal.adjust(startDate + term * Years);
127 oss << io::iso_date(startDate);
128 string start(oss.str());
131 oss << io::iso_date(endDate);
132 string end(oss.str());
136 string index =
"EUR-EURIBOR-6M";
137 string floatFreq =
"6M";
141 string fixedTenor =
"1Y";
142 fixedTenor = fixedTenor +
"_";
145 Real fixedRate = 0.02 ;
146 string fixFreq =
"1Y";
158 LegData fixedLeg(QuantLib::ext::make_shared<FixedLegData>(vector<double>(1, fixedRate)), isPayer, ccy, fixedSchedule,
162 vector<double> spreads(1, 0);
163 LegData floatingLeg(QuantLib::ext::make_shared<FloatingLegData>(index, days,
false, spread), !isPayer, ccy,
164 floatSchedule, floatDC, notional);
166 QuantLib::ext::shared_ptr<Trade> swap(
new data::Swap(env, floatingLeg, fixedLeg));
171 oss <<
"Trade_" << i + 1;
172 swap->id() = oss.str();
174 portfolio->add(swap);
178 portfolio->build(factory);
180 if (portfolio->size() != portfolioSize)
181 BOOST_ERROR(
"Failed to build portfolio (got " << portfolio->size() <<
" expected " << portfolioSize <<
")");
185 DayCounter dc = ActualActual(ActualActual::ISDA);
186 map<string, Size> fixedFreqs;
187 map<string, Size> floatFreqs;
188 for (
const auto& [tradeId, trade] : portfolio->trades()) {
189 maturity += dc.yearFraction(today, trade->maturity());
192 QuantLib::ext::shared_ptr<data::Swap> swap = QuantLib::ext::dynamic_pointer_cast<data::Swap>(trade);
193 string floatFreq = swap->legData()[0].schedule().rules().front().tenor();
194 string fixFreq = swap->legData()[1].schedule().rules().front().tenor();
195 QL_REQUIRE(swap->legData()[0].legType() ==
"Floating" && swap->legData()[1].legType() ==
"Fixed",
"Leg mixup");
196 if (fixedFreqs.find(fixFreq) == fixedFreqs.end())
197 fixedFreqs[fixFreq] = 1;
199 fixedFreqs[fixFreq]++;
200 if (floatFreqs.find(floatFreq) == floatFreqs.end())
201 floatFreqs[floatFreq] = 1;
203 floatFreqs[floatFreq]++;
206 BOOST_TEST_MESSAGE(
"Portfolio Size : " << portfolioSize);
207 BOOST_TEST_MESSAGE(
"Maturity : " <<
maturity);
209 for (Size i = 0; i < ccys.size(); i++)
210 oss << ccys[i] <<
" ";
211 BOOST_TEST_MESSAGE(
"Currencies : " << oss.str());
213 map<string, Size>::iterator it;
214 BOOST_TEST_MESSAGE(
"Fixed Tenors : "<< fixedFreqs.begin()->first);
215 BOOST_TEST_MESSAGE(
"Floating Tenors : "<< floatFreqs.begin()->first);
225 vector<string> swaptionExpiries = {
"1Y",
"2Y",
"3Y",
"5Y",
"7Y",
"10Y",
"15Y",
"20Y",
"30Y"};
226 vector<string> swaptionTerms = {
"5Y",
"5Y",
"5Y",
"5Y",
"5Y",
"5Y",
"5Y",
"5Y",
"5Y"};
227 vector<string> swaptionStrikes(swaptionExpiries.size(),
"ATM");
228 vector<Time> hTimes = {};
229 vector<Time> aTimes = {};
231 std::vector<QuantLib::ext::shared_ptr<IrModelData>> irConfigs;
233 vector<Real> hValues = {0.02};
234 vector<Real> aValues = {0.008};
235 irConfigs.push_back(QuantLib::ext::make_shared<IrLgmData>(
236 "EUR", calibrationType, revType, volType,
false, ParamType::Constant, hTimes, hValues,
true,
237 ParamType::Piecewise, aTimes, aValues, 0.0, 1.0, swaptionExpiries, swaptionTerms, swaptionStrikes));
241 irConfigs.push_back(QuantLib::ext::make_shared<IrLgmData>(
242 "USD", calibrationType, revType, volType,
false, ParamType::Constant, hTimes, hValues,
true,
243 ParamType::Piecewise, aTimes, aValues, 0.0, 1.0, swaptionExpiries, swaptionTerms, swaptionStrikes));
247 vector<string> optionExpiries = {
"1Y",
"2Y",
"3Y",
"5Y",
"7Y",
"10Y"};
248 vector<string> optionStrikes(optionExpiries.size(),
"ATMF");
249 vector<Time> sigmaTimes = {};
251 std::vector<QuantLib::ext::shared_ptr<FxBsData>> fxConfigs;
253 vector<Real> sigmaValues = {0.15};
254 fxConfigs.push_back(QuantLib::ext::make_shared<FxBsData>(
"USD",
"EUR", calibrationType,
true, ParamType::Piecewise,
255 sigmaTimes, sigmaValues, optionExpiries, optionStrikes));
257 map<CorrelationKey, Handle<Quote>> corr;
260 corr[make_pair(f_1, f_2)] = Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(0.6));
262 QuantLib::ext::shared_ptr<CrossAssetModelData> config(QuantLib::ext::make_shared<CrossAssetModelData>(irConfigs, fxConfigs, corr));
266 QuantLib::ext::shared_ptr<CrossAssetModelBuilder> modelBuilder(
new CrossAssetModelBuilder(initMarket, config));
267 return *modelBuilder->model();
271QuantLib::ext::shared_ptr<analytics::ScenarioSimMarket>
buildScenarioSimMarket(QuantLib::ext::shared_ptr<DateGrid> dateGrid,
272 QuantLib::ext::shared_ptr<Market>& initMarket,
273 QuantLib::ext::shared_ptr<CrossAssetModel>& model,
276 bool antithetic=
false){
278 Date today = initMarket->asofDate();
280 string baseCcy =
"EUR";
282 ccys.push_back(baseCcy);
283 ccys.push_back(
"USD");
286 parameters->baseCcy() = baseCcy;
287 parameters->setDiscountCurveNames(ccys);
288 parameters->setYieldCurveTenors(
"",
289 {1 * Months, 6 * Months, 1 * Years, 2 * Years, 5 * Years, 10 * Years, 20 * Years});
290 parameters->setIndices({
"EUR-EONIA",
"EUR-EURIBOR-6M",
"USD-LIBOR-3M"});
292 parameters->interpolation() =
"LogLinear";
294 parameters->setSimulateSwapVols(
false);
295 parameters->setSwapVolTerms(
"", {6 * Months, 1 * Years});
296 parameters->setSwapVolExpiries(
"", {1 * Years, 2 * Years});
297 parameters->swapVolKeys() = ccys;
298 parameters->swapVolDecayMode() =
"ForwardVariance";
300 parameters->setFxVolExpiries(
"",
301 vector<Period>{1 * Months, 3 * Months, 6 * Months, 2 * Years, 3 * Years, 4 * Years, 5 * Years});
302 parameters->setFxVolDecayMode(
string(
"ConstantVariance"));
303 parameters->setSimulateFXVols(
false);
305 parameters->setFxVolCcyPairs({
"USDEUR"});
306 parameters->setFxCcyPairs({
"USDEUR"});
308 parameters->setAdditionalScenarioDataIndices({
"EUR-EONIA"});
309 parameters->setAdditionalScenarioDataCcys({
"EUR"});
312 if (
auto tmp = QuantLib::ext::dynamic_pointer_cast<CrossAssetStateProcess>(model->stateProcess())) {
313 tmp->resetCache(dateGrid->timeGrid().size() - 1);
315 QuantLib::ext::shared_ptr<QuantExt::MultiPathGeneratorBase> pathGen =
316 QuantLib::ext::make_shared<MultiPathGeneratorMersenneTwister>(model->stateProcess(), dateGrid->timeGrid(), seed, antithetic);
319 QuantLib::ext::shared_ptr<ScenarioFactory> scenarioFactory = QuantLib::ext::make_shared<SimpleScenarioFactory>();
320 QuantLib::ext::shared_ptr<ScenarioGenerator> scenarioGenerator = QuantLib::ext::make_shared<CrossAssetModelScenarioGenerator>(model,
330 auto simMarket = QuantLib::ext::make_shared<analytics::ScenarioSimMarket>(initMarket, parameters);
331 simMarket->scenarioGenerator() = scenarioGenerator;
333 QuantLib::ext::shared_ptr<AggregationScenarioData> scenarioData = QuantLib::ext::make_shared<InMemoryAggregationScenarioData>(dateGrid->timeGrid().size(), samples);
334 simMarket->aggregationScenarioData() = scenarioData;
339QuantLib::ext::shared_ptr<NPVCube>
buildNPVCube(QuantLib::ext::shared_ptr<DateGrid> dateGrid,
340 bool withCloseOutGrid,
341 QuantLib::ext::shared_ptr<analytics::ScenarioSimMarket>& simMarket,
342 QuantLib::ext::shared_ptr<Portfolio>& portfolio,
343 bool mporStickyDate=
false,
347 Date today = Settings::instance().evaluationDate();
352 if (withCloseOutGrid)
356 boost::timer::cpu_timer t;
358 QuantLib::ext::shared_ptr<NPVCube> cube =
359 QuantLib::ext::make_shared<DoublePrecisionInMemoryCubeN>(today, portfolio->ids(), dateGrid->valuationDates(), samples, depth);
361 vector<QuantLib::ext::shared_ptr<ValuationCalculator>> calculators;
362 QuantLib::ext::shared_ptr<NPVCalculator> npvCalc = QuantLib::ext::make_shared<NPVCalculator>(
"EUR");
363 calculators.push_back(npvCalc);
364 if (withCloseOutGrid)
365 calculators.push_back(QuantLib::ext::make_shared<MPORCalculator>(npvCalc));
366 BOOST_TEST_MESSAGE(
"mporStickyDate "<<mporStickyDate);
367 valEngine.
buildCube(portfolio, cube, calculators, mporStickyDate);
369 double elapsed = t.elapsed().wall * 1e-9;
371 if (withCloseOutGrid){
372 std::string fileName =
"scenarioData_closeout.csv";
374 fileName =
"cube_closeout.csv";
377 std::string fileName =
"scenarioData.csv";
379 fileName =
"cube.csv";
383 BOOST_TEST_MESSAGE(
"Cube generated in " << elapsed <<
" seconds");
389 TestData(Date referenceDate, QuantLib::ext::shared_ptr<DateGrid> dateGrid,
bool withCloseOutGrid =
false,
bool mporStickyDate =
false, Size samples=1, Size seed=5){
391 BOOST_TEST_MESSAGE(
"Setting initial market ...");
392 this->initMarket_ = QuantLib::ext::make_shared<TestMarket>(referenceDate);
393 BOOST_TEST_MESSAGE(
"Setting initial market done!");
395 BOOST_TEST_MESSAGE(
"Building CAM ...");
397 BOOST_TEST_MESSAGE(
"Building CAM done!");
399 BOOST_TEST_MESSAGE(
"Building SimMarket ...");
401 BOOST_TEST_MESSAGE(
"Building SimMarket done!");
404 BOOST_TEST_MESSAGE(
"Building Portfolio ...");
405 QuantLib::ext::shared_ptr<EngineData>
data = QuantLib::ext::make_shared<EngineData>();
406 data->model(
"Swap") =
"DiscountedCashflows";
407 data->engine(
"Swap") =
"DiscountingSwapEngine";
408 QuantLib::ext::shared_ptr<EngineFactory> factory = QuantLib::ext::make_shared<EngineFactory>(data, this->simMarket_);
410 Size portfolioSize = 1;
412 BOOST_TEST_MESSAGE(
"Building Portfolio done!");
413 BOOST_TEST_MESSAGE(
"Portfolio size after build: " << this->portfolio_->size());
415 BOOST_TEST_MESSAGE(
"Building NPV cube ...");
416 this->cube_ =
buildNPVCube(dateGrid, withCloseOutGrid, this->simMarket_, this->portfolio_, mporStickyDate, samples, seed);
417 BOOST_TEST_MESSAGE(
"Building NPV done!");
420 QuantLib::ext::shared_ptr<Market> initMarket_;
421 QuantLib::ext::shared_ptr<analytics::ScenarioSimMarket> simMarket_;
422 QuantLib::ext::shared_ptr<QuantExt::CrossAssetModel>
model_;
423 QuantLib::ext::shared_ptr<NPVCube> cube_;
424 QuantLib::ext::shared_ptr<Portfolio> portfolio_;
431 tuple<string, string, string, string, string, string> key;
432 key = make_tuple(
"13,1W",
"1W",
"woCloseOutGrid",
"ActualDate",
"Symmetric",
"woCompounding");
433 vector<Date> defaultDate = {Date(42481),Date(42488),Date(42495),Date(42502),Date(42509),Date(42516),Date(42523),Date(42530),Date(42537),Date(42544),Date(42551),Date(42558),Date(42565)};
434 vector<Real> defaultValue = {-5187.5422,-4905.1896,-4546.209,-4934.3538,-4719.8216,-4726.7086,-4942.2042,-4829.1002,-4871.8577,-4660.3374,-4835.9162,-5210.7846,-5112.2817};
435 vector<Date> closeOutDate = {};
436 vector<Real> closeOutValue = {-4964.2459,-5187.5422,-4905.1896,-4546.209,-4934.3538,-4719.8216,-4726.7086,-4942.2042,-4829.1002,-4871.8577,-4660.3374,-4835.9162,-5210.7846};
437 defaultDates[key] = defaultDate;
438 defaultValues[key] = defaultValue;
439 closeOutDates[key] = closeOutDate;
440 closeOutValues[key] = closeOutValue;
442 key = make_tuple(
"13,1W",
"1W",
"woCloseOutGrid",
"ActualDate",
"AsymmetricCVA",
"woCompounding");
443 defaultDate = {Date(42481),Date(42488),Date(42495),Date(42502),Date(42509),Date(42516),Date(42523),Date(42530),Date(42537),Date(42544),Date(42551),Date(42558),Date(42565)};
444 defaultValue = {-5187.5422,-4905.1896,-4546.209,-4934.3538,-4719.8216,-4726.7086,-4942.2042,-4829.1002,-4871.8577,-4660.3374,-4835.9162,-5210.7846,-5112.2817};
445 closeOutValue = {-5187.5422,-5187.5422,-4905.1896,-4934.3538,-4934.3538,-4726.7086,-4942.2042,-4942.2042,-4871.8577,-4871.8577,-4835.9162,-5210.7846,-5210.7846};
446 defaultDates[key] = defaultDate;
447 defaultValues[key] = defaultValue;
448 closeOutDates[key] = closeOutDate;
449 closeOutValues[key] = closeOutValue;
452 key = make_tuple(
"13,1W",
"1W",
"woCloseOutGrid",
"ActualDate",
"AsymmetricDVA",
"woCompounding");
453 defaultDate = {Date(42481),Date(42488),Date(42495),Date(42502),Date(42509),Date(42516),Date(42523),Date(42530),Date(42537),Date(42544),Date(42551),Date(42558),Date(42565)};
454 defaultValue = {-5187.5422,-4905.1896,-4546.209,-4934.3538,-4719.8216,-4726.7086,-4942.2042,-4829.1002,-4871.8577,-4660.3374,-4835.9162,-5210.7846,-5112.2817};
455 closeOutValue = {-4964.2459,-4905.1896,-4546.209,-4546.209,-4719.8216,-4719.8216,-4726.7086,-4829.1002,-4829.1002,-4660.3374,-4660.3374,-4835.9162,-5112.2817};
456 defaultDates[key] = defaultDate;
457 defaultValues[key] = defaultValue;
458 closeOutDates[key] = closeOutDate;
459 closeOutValues[key] = closeOutValue;
462 key = make_tuple(
"13,1M",
"1W",
"withCloseOutGrid",
"ActualDate",
"NoLag",
"woCompounding");
463 defaultDate = {Date(42506),Date(42535),Date(42565),Date(42597),Date(42627),Date(42657),Date(42688),Date(42718),Date(42751),Date(42780),Date(42808),Date(42843),Date(42870)};
464 defaultValue = {-5202.1081,-4824.2195,-4475.0983,-4839.8679,-4781.7627,-10033.828,-10034.132,-10042.506,-10051.002,-10029.219,-10053.942,0,0};
465 closeOutValue = {-5482.992,-4430.4454,-4466.1567,-4952.8999,-4984.8645,-10026.681,-10030.382,-10036.444,-10049.344,-10024.172,-10050.758,0,0};
466 defaultDates[key] = defaultDate;
467 defaultValues[key] = defaultValue;
468 closeOutDates[key] = closeOutDate;
469 closeOutValues[key] = closeOutValue;
471 key = make_tuple(
"13,1M",
"1W",
"withCloseOutGrid",
"ActualDate",
"NoLag",
"withCompounding");
472 defaultDate = {Date(42506),Date(42535),Date(42565),Date(42597),Date(42627),Date(42657),Date(42688),Date(42718),Date(42751),Date(42780),Date(42808),Date(42843),Date(42870)};
473 defaultValue = {-5201.05244612274,-4824.95292840006,-4477.84062127441,-4840.59273964169,-4783.19175595342,-10033.5472051449,-10033.8518374855,-10042.17634737,-10050.6267511171,-10028.9670934353,-10053.5482862015,0,0};
474 closeOutValue = {-5480.43076439459,-4433.281369965,-4468.94866890169,-4953.02218430623,-4985.17359043462,-10026.4183374549,-10030.1017618035,-10036.1263742983,-10048.9573202704,-10023.9263145357,-10050.3607175246,0,0};
475 defaultDates[key] = defaultDate;
476 defaultValues[key] = defaultValue;
477 closeOutDates[key] = closeOutDate;
478 closeOutValues[key] = closeOutValue;
485 string nettingSetMporStr;
486 string closeOutGridStr;
489 string compoundingStr;
490 vector<Date> defaultDate;
491 vector<Real> defaultValue;
492 vector<Date> closeOutDate;
493 vector<Real> closeOutValue;
496std::map<tuple<string, string, string, string, string, string>, vector<Date>> defaultDates;
497std::map<tuple<string, string, string, string, string, string>, vector<Real>> defaultValues;
498std::map<tuple<string, string, string, string, string, string>, vector<Date>> closeOutDates;
499std::map<tuple<string, string, string, string, string, string>, vector<Real>> closeOutValues;
508 CachedResultsData cachedResults;
509 std::map<tuple<string, string, string, string, string, string>, vector<Date>> cachedDefaultDates = cachedResults.defaultDates;
510 std::map<tuple<string, string, string, string, string, string>, vector<Real>> cachedDefaultValues = cachedResults.defaultValues;
511 std::map<tuple<string, string, string, string, string, string>, vector<Date>> cachedCloseOutDates = cachedResults.closeOutDates;
512 std::map<tuple<string, string, string, string, string, string>, vector<Real>> cachedCloseOutValues = cachedResults.closeOutValues;
515 BOOST_TEST_MESSAGE(
"Running NettedExposureCalculatorTestWithCloseOutGrid...");
517 BOOST_TEST_MESSAGE(
"Reference Date is "<<QuantLib::io::iso_date(
referenceDate));
521 QuantLib::ext::shared_ptr<DateGrid> dateGrid;
522 std::string nettingSetMpor =
"1W";
523 BOOST_TEST_MESSAGE(
"Neting-set mpor is "<< nettingSetMpor);
524 vector<bool> withCloseOutGrid = {
false,
true};
525 bool mporStickyDate =
false;
526 string mporModeStr = mporStickyDate ?
"StickyDate":
"ActualDate";
527 bool withCompounding =
false;
528 string compoundingStr = withCompounding ?
"withCompounding" :
"woCompounding";
531 for(Size k = 0; k<withCloseOutGrid.size(); k++){
533 string closeOutGridStr = withCloseOutGrid[k] ?
"withCloseOutGrid":
"woCloseOutGrid";
534 std::vector<CollateralExposureHelper::CalculationType> calcTypes;
535 if (withCloseOutGrid[k]){
536 dateGridStr =
"13,1M";
537 dateGrid = QuantLib::ext::make_shared<DateGrid>(dateGridStr);
538 calcTypes= {CollateralExposureHelper::CalculationType::NoLag};
541 dateGridStr =
"13,1W";
542 dateGrid = QuantLib::ext::make_shared<DateGrid>(dateGridStr);
543 calcTypes= {CollateralExposureHelper::CalculationType::Symmetric,
544 CollateralExposureHelper::CalculationType::AsymmetricCVA,
545 CollateralExposureHelper::CalculationType::AsymmetricDVA
548 Period Mpor(1, Weeks);
549 if (withCloseOutGrid[k]){
550 BOOST_TEST_MESSAGE(
"With close-out grid!");
551 BOOST_TEST_MESSAGE(
"MPOR in close-out grid= "<< Mpor);
552 dateGrid->addCloseOutDates(Mpor);
554 BOOST_TEST_MESSAGE(
"With mpor mode sticky date!");
556 BOOST_TEST_MESSAGE(
"With mpor mode actual date!");
558 BOOST_TEST_MESSAGE(
"Without close-out grid!");
560 TestData td(
referenceDate, dateGrid, withCloseOutGrid[k], mporStickyDate);
562 BOOST_TEST_MESSAGE(
"DateGrid: ");
564 for(Size i=0; i<dateGrid->times().
size(); i++)
565 BOOST_TEST_MESSAGE(
"t_"<<i+1<<
", "<<QuantLib::io::iso_date(dateGrid->dates()[i]));
567 QuantLib::ext::shared_ptr<Market> initMarket = td.initMarket_;
568 QuantLib::ext::shared_ptr<NPVCube> cube = td.cube_;
569 QuantLib::ext::shared_ptr<Portfolio> portfolio = td.portfolio_;
571 std::string nettingSetId = portfolio->trades().begin()->second->envelope().nettingSetId();
574 if (withCloseOutGrid[k]){
575 Period nettingSetMporPeriod = PeriodParser::parse(nettingSetMpor);
576 QL_REQUIRE(nettingSetMporPeriod == Mpor,
"Netting-set mpor is not consistent with the closeout grid!");
579 std::vector<std::string> elgColls = {
"EUR"};
580 QuantLib::ext::shared_ptr<NettingSetDefinition> nettingSetDefinition = QuantLib::ext::make_shared<NettingSetDefinition>(nettingSetDetails,
581 "Bilateral",
"EUR",
"EUR-EONIA",
582 0.0, 0.0, 0.0, 0.0, 0.0,
584 nettingSetMpor, 0.0, 0.0, elgColls);
585 QuantLib::ext::shared_ptr<NettingSetManager> nettingSetManager = QuantLib::ext::make_shared<NettingSetManager>();
586 nettingSetManager->add(nettingSetDefinition);
589 QuantLib::ext::shared_ptr<CollateralBalances> collateralBalances = QuantLib::ext::make_shared<CollateralBalances>();
591 map<string, vector<vector<Real>>> nettingSetDefaultValue;
592 map<string, vector<vector<Real>>> nettingSetCloseOutValue;
593 map<string, vector<vector<Real>>> nettingSetMporPositiveFlow;
594 map<string, vector<vector<Real>>> nettingSetMporNegativeFlow;
595 map<string, vector<vector<Real>>> nettingSetValue;
596 vector<Real> collateralBalance;
597 vector<vector<Real>> defaultValue;
599 std::string fileName;
600 Handle<AggregationScenarioData> asd;
601 QuantLib::ext::shared_ptr<CubeInterpretation> cubeInterpreter;
602 if (withCloseOutGrid[k]) {
603 fileName =
"scenarioData_closeout.csv";
605 cubeInterpreter = QuantLib::ext::make_shared<CubeInterpretation>(
true,
true, asd, dateGrid);
607 fileName =
"scenarioData.csv";
609 cubeInterpreter = QuantLib::ext::make_shared<CubeInterpretation>(
true,
false, asd);
612 if (!withCompounding){
613 compoundingStr =
"woCompounding";
614 for (Size i =0; i<cube->dates().
size(); i++)
615 asd->set(i, 0, 0, AggregationScenarioDataType::IndexFixing,
"EUR-EONIA");
618 vector<string> regressors = {
"EUR-EURIBOR-6M"};
619 QuantLib::ext::shared_ptr<InputParameters> inputs = QuantLib::ext::make_shared<InputParameters>();
620 QuantLib::ext::shared_ptr<RegressionDynamicInitialMarginCalculator> dimCalculator =
621 QuantLib::ext::make_shared<RegressionDynamicInitialMarginCalculator>(inputs, portfolio, cube, cubeInterpreter, *asd,
622 0.99, 14, 2, regressors);
624 BOOST_TEST_MESSAGE(
"initial NPV at "<< QuantLib::io::iso_date(
referenceDate)<<
": "<<cube->getT0(0));
625 for (Size i = 0; i<cube->dates().
size(); i++)
626 BOOST_TEST_MESSAGE(
"defaultValue at "<< QuantLib::io::iso_date(dateGrid->valuationDates()[i])<<
": "<<cubeInterpreter->getDefaultNpv(cube, 0, i, 0));
628 for (Size i = 0; i<cube->dates().
size(); i++){
629 if (withCloseOutGrid[k]){
630 if (i != cube->dates().size()-1)
631 BOOST_TEST_MESSAGE(
"closeOutValue at "<< QuantLib::io::iso_date(dateGrid->closeOutDates()[i])<<
": "<<cubeInterpreter->getCloseOutNpv(cube, 0, i, 0));
634 if (i != cube->dates().size()-1)
635 BOOST_TEST_MESSAGE(
"closeOutValue at "<< QuantLib::io::iso_date(dateGrid->valuationDates()[i])<<
": "<<cubeInterpreter->getCloseOutNpv(cube, 0, i, 0));
640 for(
auto calcType : calcTypes){
642 calcTypeStr =
"Symmetric";
644 calcTypeStr =
"AsymmetricCVA";
646 calcTypeStr =
"AsymmetricDVA";
648 calcTypeStr =
"NoLag";
650 QL_FAIL(
"Collateral calculation type not covered");
651 BOOST_TEST_MESSAGE(
"Calculation type: "<< calcTypeStr);
653 QuantLib::ext::shared_ptr<ExposureCalculator> exposureCalculator = QuantLib::ext::make_shared<ExposureCalculator>(portfolio, cube, cubeInterpreter,
654 initMarket,
false,
"EUR",
"Market",
655 0.99, calcType,
false,
false);
656 exposureCalculator->build();
657 nettingSetDefaultValue = exposureCalculator->nettingSetDefaultValue();
658 nettingSetCloseOutValue = exposureCalculator->nettingSetCloseOutValue();
659 nettingSetMporPositiveFlow = exposureCalculator->nettingSetMporPositiveFlow();
660 nettingSetMporNegativeFlow = exposureCalculator->nettingSetMporNegativeFlow();
661 QuantLib::ext::shared_ptr<NettedExposureCalculator> nettedExposureCalculator =
662 QuantLib::ext::make_shared<NettedExposureCalculator>(
663 portfolio, initMarket, cube,
"EUR",
"Market", 0.99, calcType,
false, nettingSetManager, collateralBalances,
664 nettingSetDefaultValue, nettingSetCloseOutValue, nettingSetMporPositiveFlow,
665 nettingSetMporNegativeFlow, *asd, cubeInterpreter,
false, dimCalculator,
false,
false, 0.1,
666 exposureCalculator->exposureCube(), 0, 0,
false, mporStickyDate, MporCashFlowMode::Unspecified);
667 nettedExposureCalculator->build();
668 nettingSetValue = (calcType == CollateralExposureHelper::CalculationType::NoLag
669 ? nettedExposureCalculator->nettingSetCloseOutValue()
670 : nettedExposureCalculator->nettingSetDefaultValue());
671 collateralBalance = nettedExposureCalculator->expectedCollateral(nettingSetId);
672 BOOST_TEST_MESSAGE(
"defaultDate, defaultValue, closeOutDate, collateralBalance");
673 auto key = make_tuple(dateGridStr, nettingSetMpor, closeOutGridStr, mporModeStr, calcTypeStr, compoundingStr);
675 vector<Date> cdd = cachedDefaultDates[key];
676 vector<Real> cdv = cachedDefaultValues[key];
677 vector<Date> ccd = cachedCloseOutDates[key];
678 vector<Real> ccv = cachedCloseOutValues[key];
679 BOOST_TEST_MESSAGE(
"cdd "<<cdd.size());
680 BOOST_TEST_MESSAGE(
"cdv "<<cdv.size());
681 BOOST_TEST_MESSAGE(
"ccd "<<ccd.size());
682 BOOST_TEST_MESSAGE(
"ccv "<<ccv.size());
683 Real tolerance = 1E-2;
684 for (
auto n : nettingSetValue){
685 vector<vector<Real>> defaultValue = n.second;
686 for (Size j = 0; j < cube->dates().
size(); j++){
687 BOOST_TEST_MESSAGE(io::iso_date(dateGrid->valuationDates()[j])<<
", "<<defaultValue[j][0] <<
", "<< collateralBalance[j+1]);
689 BOOST_CHECK_MESSAGE(dateGrid->valuationDates()[j] == cdd[j],
690 "default date "<< dateGrid->valuationDates()[j] <<
" does not match with cashed default date "<< cdd[j]);
691 BOOST_CHECK_MESSAGE(fabs(defaultValue[j][0] - cdv[j]) < tolerance,
692 "default value "<< defaultValue[j][0] <<
" does not match with cashed default value "<< cdv[j]);
693 BOOST_CHECK_MESSAGE(fabs(collateralBalance[j+1] - ccv[j]) < tolerance,
694 "collateral balance "<< collateralBalance[j+1] <<
" does not match with cashed collateral balance "<< ccv[j]);
701BOOST_AUTO_TEST_SUITE_END()
702BOOST_AUTO_TEST_SUITE_END()
this class holds data associated to scenarios
ScenarioSimMarket description.
void buildCube(const QuantLib::ext::shared_ptr< data::Portfolio > &portfolio, QuantLib::ext::shared_ptr< analytics::NPVCube > outputCube, std::vector< QuantLib::ext::shared_ptr< ValuationCalculator > > calculators, bool mporStickyDate=true, QuantLib::ext::shared_ptr< analytics::NPVCube > outputCubeNettingSet=nullptr, QuantLib::ext::shared_ptr< analytics::NPVCube > outputCptyCube=nullptr, std::vector< QuantLib::ext::shared_ptr< CounterpartyCalculator > > cptyCalculators={}, bool dryRun=false)
Build NPV cube.
OREAnalytics Top level fixture.
Simple flat market setup to be used in the test suite.
const QuantLib::ext::shared_ptr< ModelCG > model_
Scenario generation using cross asset model paths.
QuantLib::ext::shared_ptr< Portfolio > buildPortfolio(Size portfolioSize, QuantLib::ext::shared_ptr< EngineFactory > &factory)
load / save cubes and agg scen data from / to disk
Dynamic Initial Margin calculator base class.
Dynamic Initial Margin calculator by regression.
A cube implementation that stores the cube in memory.
The cube valuation calculator interface.
QuantLib::ext::shared_ptr< AggregationScenarioData > loadAggregationScenarioData(const std::string &filename)
void saveCube(const std::string &filename, const NPVCubeWithMetaData &cube, const bool doublePrecision)
void saveAggregationScenarioData(const std::string &filename, const AggregationScenarioData &cube)
Size size(const ValueType &v)
QuantLib::ext::shared_ptr< CrossAssetModel > buildCrossAssetModel(QuantLib::ext::shared_ptr< Market > &initMarket)
QuantLib::ext::shared_ptr< Portfolio > buildPortfolio(Size portfolioSize, QuantLib::ext::shared_ptr< EngineFactory > &factory)
BOOST_AUTO_TEST_CASE(NettedExposureCalculatorTest)
QuantLib::ext::shared_ptr< NPVCube > buildNPVCube(QuantLib::ext::shared_ptr< DateGrid > dateGrid, bool withCloseOutGrid, QuantLib::ext::shared_ptr< analytics::ScenarioSimMarket > &simMarket, QuantLib::ext::shared_ptr< Portfolio > &portfolio, bool mporStickyDate=false, Size samples=1, Size seed=5)
QuantLib::ext::shared_ptr< analytics::ScenarioSimMarket > buildScenarioSimMarket(QuantLib::ext::shared_ptr< DateGrid > dateGrid, QuantLib::ext::shared_ptr< Market > &initMarket, QuantLib::ext::shared_ptr< CrossAssetModel > &model, Size samples=1, Size seed=5, bool antithetic=false)
QuantLib::ext::shared_ptr< data::Conventions > convs()
Fixture that can be used at top level of OREAnalytics test suites.
Scenario generator configuration.
A Market class that can be updated by Scenarios.
A class to hold Scenario parameters for scenarioSimMarket.
factory classes for simple scenarios
The counterparty cube calculator interface.