44#include <oret/toplevelfixture.hpp>
46#include <ql/time/date.hpp>
53using namespace boost::unit_test_framework;
60QuantLib::ext::shared_ptr<EngineFactory> registerBuilders(QuantLib::ext::shared_ptr<EngineData> engineData,
61 QuantLib::ext::shared_ptr<Market> market) {
62 QuantLib::ext::shared_ptr<EngineFactory> factory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
66void parSensiBumpAnalysis(QuantLib::ext::shared_ptr<Portfolio>& portfolio, QuantLib::ext::shared_ptr<EngineData>& engineData,
67 QuantLib::ext::shared_ptr<Market>& initMarket, map<string, Real>& baseManualPv,
string& baseCcy,
68 vector<Handle<Quote>>& parValVecBase, vector<string>& labelVec, Real shiftSize,
69 ShiftType shiftType, std::map<std::pair<std::string, std::string>, Real>& parDelta,
70 std::map<std::pair<std::string, std::string>, Real>& zeroDelta, map<string, Real>& basePv) {
72 Size tradeCount = portfolio->size();
73 Real basePvTol = 0.00001;
74 Real sensiThold = 0.0001;
75 Real sensiRelTol = 1.0;
76 Real sensiAbsTol = 0.2;
77 Real relAbsTolBoundary = 10.0;
79 vector<Real> baseValues;
80 for (Size i = 0; i < parValVecBase.size(); ++i) {
81 Handle<Quote> q = parValVecBase[i];
82 Real baseVal = q->value();
83 baseValues.push_back(baseVal);
84 QuantLib::ext::dynamic_pointer_cast<SimpleQuote>(*q)->setValue(baseVal);
86 QuantLib::ext::shared_ptr<EngineFactory> manualFactory2 = registerBuilders(engineData, initMarket);
88 portfolio->build(manualFactory2);
89 BOOST_CHECK_MESSAGE(portfolio->size() == tradeCount,
90 "Some trades not built correctly," << portfolio->size() <<
" vs. " << tradeCount);
91 for (
auto& [tradeId, trade] : portfolio->trades()) {
93 if (trade->npvCurrency() !=
"EUR") {
94 string ccyPair = trade->npvCurrency() + baseCcy;
95 fx = initMarket->fxRate(ccyPair)->value();
97 BOOST_CHECK_MESSAGE(std::fabs(baseManualPv[tradeId] - (fx * trade->instrument()->NPV())) <= basePvTol,
98 "Equality error for trade " << tradeId <<
"; got " << (fx * trade->instrument()->NPV())
99 <<
", but expected " << baseManualPv[tradeId]);
102 for (Size i = 0; i < parValVecBase.size(); ++i) {
104 string sensiLabel = labelVec[i];
106 for (Size j = 0; j < parValVecBase.size(); ++j) {
108 Real newVal = (shiftType == ShiftType::Absolute) ? (baseValues[j] + shiftSize)
109 : (baseValues[j] * (1.0 + shiftSize));
110 QuantLib::ext::dynamic_pointer_cast<SimpleQuote>(*parValVecBase[j])->setValue(newVal);
112 QuantLib::ext::dynamic_pointer_cast<SimpleQuote>(*parValVecBase[j])->setValue(baseValues[j]);
115 QuantLib::ext::shared_ptr<EngineFactory> manualFactoryDisc = registerBuilders(engineData, initMarket);
117 portfolio->build(manualFactoryDisc);
118 BOOST_CHECK_MESSAGE(portfolio->size() == tradeCount,
119 "Some trades not built correctly," << portfolio->size() <<
" vs. " << tradeCount);
120 for (
auto [tradeId, trade] : portfolio->trades()) {
122 if (trade->npvCurrency() !=
"EUR") {
123 string ccyPair = trade->npvCurrency() + baseCcy;
124 fx = initMarket->fxRate(ccyPair)->value();
126 Real shiftedNPV = fx * trade->instrument()->NPV();
127 Real anticipatedParDelta = shiftedNPV - baseManualPv[tradeId];
128 Real computedParDelta = 0.0;
129 if (parDelta.find(std::make_pair(tradeId, sensiLabel)) != parDelta.end())
130 computedParDelta = parDelta[std::make_pair(tradeId, sensiLabel)];
132 if ((std::fabs(anticipatedParDelta) > sensiThold) || (std::fabs(computedParDelta) > sensiThold)) {
133 BOOST_TEST_MESSAGE(
"#reportrow," << tradeId <<
"," << sensiLabel <<
"," << baseManualPv[tradeId]
134 <<
"," << basePv[tradeId] <<
"," << anticipatedParDelta <<
","
135 << computedParDelta <<
","
136 << zeroDelta[std::make_pair(tradeId, sensiLabel)]);
138 if ((std::fabs(anticipatedParDelta) > relAbsTolBoundary) &&
139 (std::fabs(computedParDelta) > relAbsTolBoundary))
140 BOOST_CHECK_CLOSE(anticipatedParDelta, computedParDelta, sensiRelTol);
142 BOOST_CHECK(std::fabs(anticipatedParDelta - computedParDelta) < sensiAbsTol);
147 for (Size i = 0; i < parValVecBase.size(); ++i) {
148 QuantLib::ext::dynamic_pointer_cast<SimpleQuote>(*parValVecBase[i])->setValue(baseValues[i]);
150 QuantLib::ext::shared_ptr<EngineFactory> manualFactory3 = registerBuilders(engineData, initMarket);
153 portfolio->build(manualFactory3);
154 BOOST_CHECK_MESSAGE(portfolio->size() == tradeCount,
155 "Some trades not built correctly," << portfolio->size() <<
" vs. " << tradeCount);
156 for (
auto [tradeId, trade] : portfolio->trades()) {
158 if (trade->npvCurrency() !=
"EUR") {
159 string ccyPair = trade->npvCurrency() + baseCcy;
160 fx = initMarket->fxRate(ccyPair)->value();
162 BOOST_CHECK_MESSAGE(std::fabs(baseManualPv[tradeId] - (fx * trade->instrument()->NPV())) <= basePvTol,
163 "Equality error for trade " << tradeId <<
"; got " << (fx * trade->instrument()->NPV())
164 <<
", but expected " << baseManualPv[tradeId]);
173 BOOST_TEST_MESSAGE(
"Testing swap par sensitivities against manual bump of par curve instruments");
174 SavedSettings backup;
178 ObservationMode::instance().setMode(om);
180 Date today = Date(14, April, 2016);
181 Settings::instance().evaluationDate() = today;
182 BOOST_TEST_MESSAGE(
"Today is " << today);
185 string baseCcy =
"EUR";
187 ccys.push_back(baseCcy);
188 ccys.push_back(
"GBP");
189 ccys.push_back(
"CHF");
190 ccys.push_back(
"USD");
191 ccys.push_back(
"JPY");
194 QuantLib::ext::shared_ptr<Market> initMarket = QuantLib::ext::make_shared<TestMarketParCurves>(today);
197 QuantLib::ext::shared_ptr<ore::analytics::ScenarioSimMarketParameters> simMarketData =
201 QuantLib::ext::shared_ptr<SensitivityScenarioData> sensiData =
204 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
205 engineData->model(
"Swap") =
"DiscountedCashflows";
206 engineData->engine(
"Swap") =
"DiscountingSwapEngine";
207 engineData->model(
"CrossCurrencySwap") =
"DiscountedCashflows";
208 engineData->engine(
"CrossCurrencySwap") =
"DiscountingCrossCurrencySwapEngine";
209 engineData->model(
"EuropeanSwaption") =
"BlackBachelier";
210 engineData->engine(
"EuropeanSwaption") =
"BlackBachelierSwaptionEngine";
211 engineData->model(
"FxForward") =
"DiscountedCashflows";
212 engineData->engine(
"FxForward") =
"DiscountingFxForwardEngine";
213 engineData->model(
"FxOption") =
"GarmanKohlhagen";
214 engineData->engine(
"FxOption") =
"AnalyticEuropeanEngine";
215 engineData->model(
"CapFloor") =
"IborCapModel";
216 engineData->engine(
"CapFloor") =
"IborCapEngine";
217 engineData->model(
"CapFlooredIborLeg") =
"BlackOrBachelier";
218 engineData->engine(
"CapFlooredIborLeg") =
"BlackIborCouponPricer";
219 engineData->model(
"CreditDefaultSwap") =
"DiscountedCashflows";
220 engineData->engine(
"CreditDefaultSwap") =
"MidPointCdsEngine";
222 engineData->model(
"IndexCreditDefaultSwapOption") =
"Black";
223 engineData->engine(
"IndexCreditDefaultSwapOption") =
"BlackIndexCdsOptionEngine";
224 map<string, string> engineParamMap1;
225 engineParamMap1[
"Curve"] =
"Underlying";
226 engineData->engineParameters(
"IndexCreditDefaultSwapOption") = engineParamMap1;
228 engineData->model(
"IndexCreditDefaultSwap") =
"DiscountedCashflows";
229 engineData->engine(
"IndexCreditDefaultSwap") =
"MidPointIndexCdsEngine";
230 map<string, string> engineParamMap2;
231 engineParamMap2[
"Curve"] =
"Underlying";
232 engineData->engineParameters(
"IndexCreditDefaultSwap") = engineParamMap2;
234 engineData->model(
"CMS") =
"LinearTSR";
235 engineData->engine(
"CMS") =
"LinearTSRPricer";
236 map<string, string> engineparams;
237 engineparams[
"MeanReversion"] =
"0.0";
238 engineparams[
"Policy"] =
"RateBound";
239 engineparams[
"LowerRateBoundNormal"] =
"-2.0000";
240 engineparams[
"UpperRateBoundNormal"] =
"2.0000";
241 engineData->engineParameters(
"CMS") = engineparams;
242 engineData->model(
"SyntheticCDO") =
"GaussCopula";
243 engineData->engine(
"SyntheticCDO") =
"Bucketing";
244 map<string, string> modelParamMap3;
245 map<string, string> engineParamMap3;
246 modelParamMap3[
"correlation"] =
"0.0";
247 modelParamMap3[
"min"] =
"-5.0";
248 modelParamMap3[
"max"] =
"5.0";
249 modelParamMap3[
"steps"] =
"64";
250 engineParamMap3[
"buckets"] =
"200";
251 engineParamMap3[
"homogeneousPoolWhenJustified"] =
"N";
252 engineData->modelParameters(
"SyntheticCDO") = modelParamMap3;
253 engineData->engineParameters(
"SyntheticCDO") = engineParamMap3;
255 engineData->model(
"EquityOption") =
"BlackScholesMerton";
256 engineData->engine(
"EquityOption") =
"AnalyticEuropeanEngine";
258 std::vector<QuantLib::ext::shared_ptr<EngineBuilder>> builders;
261 builders.push_back(QuantLib::ext::make_shared<ore::data::GaussCopulaBucketingCdoEngineBuilder>());
263 QuantLib::ext::shared_ptr<EngineFactory> factory = registerBuilders(engineData, initMarket);
264 QuantLib::ext::shared_ptr<Portfolio> portfolio(
new Portfolio());
265 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
266 QuantLib::ext::shared_ptr<IRSwapConvention> eurConv =
267 QuantLib::ext::dynamic_pointer_cast<IRSwapConvention>(conventions->get(
"EUR-6M-SWAP-CONVENTIONS"));
268 string eurIdx =
"EUR-EURIBOR-6M";
269 Period eurFloatTenor = initMarket->iborIndex(eurIdx)->tenor();
270 QuantLib::ext::shared_ptr<IRSwapConvention> usdConv =
271 QuantLib::ext::dynamic_pointer_cast<IRSwapConvention>(conventions->get(
"USD-6M-SWAP-CONVENTIONS"));
272 string usdIdx =
"USD-LIBOR-6M";
273 Period usdFloatTenor = initMarket->iborIndex(usdIdx)->tenor();
274 QuantLib::ext::shared_ptr<IRSwapConvention> jpyConv =
275 QuantLib::ext::dynamic_pointer_cast<IRSwapConvention>(conventions->get(
"JPY-6M-SWAP-CONVENTIONS"));
276 string jpyIdx =
"JPY-LIBOR-6M";
277 Period jpyFloatTenor = initMarket->iborIndex(jpyIdx)->tenor();
278 QuantLib::ext::shared_ptr<CrossCcyBasisSwapConvention> chfBasisConv =
279 QuantLib::ext::dynamic_pointer_cast<CrossCcyBasisSwapConvention>(conventions->get(
"CHF-XCCY-BASIS-CONVENTIONS"));
280 QuantLib::ext::shared_ptr<CdsConvention> cdsConv =
281 QuantLib::ext::dynamic_pointer_cast<CdsConvention>(conventions->get(
"CDS-STANDARD-CONVENTIONS"));
283 string chfIdx = chfBasisConv->spreadIndexName();
284 string otherIdx = chfBasisConv->flatIndexName();
285 Period chfFloatTenor = initMarket->iborIndex(chfIdx)->tenor();
286 Period otherFloatTenor = initMarket->iborIndex(otherIdx)->tenor();
289 "1_Swap_EUR",
"EUR",
true, 10000000.0, 0, 10, 0.02, 0.00,
292 initMarket->iborIndex(eurIdx)->fixingDays(),
true));
294 "2_Swap_USD",
"USD",
true, 10000000.0, 0, 15, 0.03, 0.00,
297 initMarket->iborIndex(usdIdx)->fixingDays(),
true));
299 "9_Cap_EUR",
"EUR",
"Long", 0.02, 1000000.0, 0, 10,
ore::data::to_string(eurFloatTenor),
"A360", eurIdx,
300 eurConv->fixedCalendar(), initMarket->iborIndex(eurIdx)->fixingDays(),
true));
302 "10_Floor_USD",
"USD",
"Long", 0.03, 1000000.0, 0, 10,
ore::data::to_string(usdFloatTenor),
"A360", usdIdx,
303 usdConv->fixedCalendar(), initMarket->iborIndex(usdIdx)->fixingDays(),
true));
305 "3_Swap_EUR",
"EUR",
false, 10000000.0, 1, 12, 0.025, 0.00,
308 initMarket->iborIndex(eurIdx)->fixingDays(),
true));
310 "4_XCCY_SWAP",
"CHF", 10000000,
"EUR", 10000000, 0, 15, 0.0000, 0.0000,
ore::data::to_string(chfFloatTenor),
311 "A360", chfIdx, chfBasisConv->settlementCalendar(),
ore::data::to_string(otherFloatTenor),
"A360", otherIdx,
312 chfBasisConv->settlementCalendar(), chfBasisConv->settlementDays(),
true));
314 "5_XCCY_SWAP_WithPrincipal",
"CHF", 10000000,
"EUR", 10000000, 0, 15, 0.0000, 0.0000,
317 chfBasisConv->settlementDays(),
true,
true,
true,
true,
false));
319 "6_Swap_JPY",
"JPY",
true, 1000000000.0, 0, 10, 0.005, 0.00,
322 initMarket->iborIndex(jpyIdx)->fixingDays(),
true));
324 "7_XCCY_SWAP_OffMarket",
"EUR", 10000000,
"CHF", 10500000, 0, 15, 0.0000, 0.0010,
327 chfBasisConv->settlementDays(),
true));
329 "8_XCCY_SWAP_RESET",
"CHF", 10000000,
"EUR", 10000000, 0, 15, 0.0000, 0.0000,
332 chfBasisConv->settlementDays(),
true,
true,
true,
false,
false,
true));
337 "9_CDS_EUR",
"EUR",
"dc2",
"dc2",
true, 10000000, 0, 15, 0.4, 0.009,
340 "10_CDS_USD",
"USD",
"dc",
"dc",
true, 10000000, 0, 10, 0.4, 0.001,
343 "10_CDS_EUR",
"EUR",
"dc2",
"dc2",
true, 10000000, 0, 10, 0.4, 0.001,
346 "11_CDS_EUR",
"EUR",
"dc2",
"dc2",
true, 10000000, 0, 5, 0.4, 0.001,
355 "12_CDS_EUR",
"EUR",
"dc2",
"dc2",
true, 10000000, 0, 2, 0.4, 0.001,
358 "13_CDS_USD",
"USD",
"dc",
"dc",
true, 10000000, 0, 15, 0.4, 0.001,
361 "13_CDS_EUR",
"EUR",
"dc2",
"dc2",
true, 10000000, 0, 15, 0.4, 0.001,
364 vector<string> names = {
"dc",
"dc2",
"dc3"};
365 vector<string> indexCcys = {
"USD",
"EUR",
"GBP"};
366 vector<Real> notionals = {3000000, 3000000, 3000000};
373 vector<string> names2(1,
"dc2");
374 vector<string> indexCcys2(1,
"EUR");
375 vector<Real> notionals2(1, 10000000.0);
381 portfolio->add(
buildSyntheticCDO(
"16_SyntheticCDO_EUR",
"dc2", names2,
"Long",
"EUR", indexCcys2,
382 true, notionals2, 1000000.0, 0, 5, 0.03, 0.01,
"1Y",
"30/360"));
384 portfolio->add(
buildCmsCapFloor(
"17_CMS_EUR",
"EUR",
"EUR-CMS-30Y",
true, 2000000, 0, 5, 0.0, 1,
388 buildEquityOption(
"18_EquityOption_SP5",
"Long",
"Call", 2,
"SP5",
"USD", 2147.56, 775));
391 0.0,
"6M",
"ACT/ACT",
"GBP-LIBOR-6M",
"1Y",
"ACT/ACT",
392 "UKRPI", 201.0,
"2M",
false, 0.005));
394 0.0,
"1Y",
"ACT/ACT",
"GBP-LIBOR-6M",
"1Y",
"ACT/ACT",
397 Size tradeCount = portfolio->size();
398 portfolio->build(factory);
399 BOOST_CHECK_MESSAGE(portfolio->size() == tradeCount,
400 "Some trades not built correctly," << portfolio->size() <<
" vs. " << tradeCount);
402 QuantLib::ext::shared_ptr<SensitivityAnalysis> zeroAnalysis =
404 simMarketData, sensiData,
405 false,
nullptr,
nullptr,
false,
nullptr);
408 zeroAnalysis->overrideTenors(
true);
409 zeroAnalysis->generateSensitivities();
411 QuantLib::ext::shared_ptr<ParSensitivityConverter> parConverter =
413 QuantLib::ext::shared_ptr<SensitivityCube> sensiCube = zeroAnalysis->sensiCube();
416 std::map<std::pair<std::string, std::string>, Real> parDelta;
417 std::map<std::pair<std::string, std::string>, Real> zeroDelta;
418 map<string, Real> baseManualPv;
419 map<string, Real> basePv;
420 for (
const auto& tradeId : portfolio->ids()) {
421 basePv[tradeId] = sensiCube->npv(tradeId);
422 for (
const auto& f : sensiCube->factors()) {
423 string des = sensiCube->factorDescription(f);
424 zeroDelta[make_pair(tradeId, des)] = sensiCube->delta(tradeId, f);
428 for (
const auto& kv : temp) {
429 string des = sensiCube->factorDescription(kv.first);
430 parDelta[make_pair(tradeId, des)] = kv.second;
433 QuantLib::ext::shared_ptr<EngineFactory> manualFactory = registerBuilders(engineData, initMarket);
436 portfolio->build(manualFactory);
438 for (
auto [tradeId, trade] : portfolio->trades()) {
440 if (trade->npvCurrency() !=
"EUR") {
441 string ccyPair = trade->npvCurrency() + baseCcy;
442 fx = initMarket->fxRate(ccyPair)->value();
444 baseManualPv[tradeId] = fx * trade->instrument()->NPV();
445 Real tradeNotional = fx * trade->notional();
447 1.e-5 * tradeNotional;
449 BOOST_TEST_MESSAGE(
"Base PV check for trade " << tradeId <<
"; got " << baseManualPv[tradeId]
450 <<
", expected " << basePv[tradeId]);
451 BOOST_CHECK_MESSAGE(std::fabs(baseManualPv[tradeId] - basePv[tradeId]) < simMarketTol,
452 "Base PV check error for trade " << tradeId <<
"; got " << baseManualPv[tradeId]
453 <<
", but expected " << basePv[tradeId]);
456 QuantLib::ext::shared_ptr<TestMarketParCurves> initParMarket = QuantLib::ext::dynamic_pointer_cast<TestMarketParCurves>(initMarket);
457 BOOST_ASSERT(initParMarket);
458 BOOST_TEST_MESSAGE(
"testing discount curve par sensis");
460 for (
auto d_it : initParMarket->discountRateHelpersInstMap()) {
461 string ccy = d_it.first;
462 Real shiftSize = zeroAnalysis->sensitivityData()->discountCurveShiftData()[ccy]->shiftSize;
463 ShiftType shiftType = zeroAnalysis->sensitivityData()->discountCurveShiftData()[ccy]->shiftType;
464 vector<Period> parTenorVec = initParMarket->discountRateHelperTenorsMap().find(ccy)->second;
465 vector<Handle<Quote>> parValVecBase = initParMarket->discountRateHelperValuesMap().find(ccy)->second;
466 vector<string> sensiLabels(parValVecBase.size());
467 for (Size i = 0; i < parValVecBase.size(); i++) {
468 sensiLabels[i] =
"DiscountCurve/" + ccy +
"/" +
to_string(i) +
"/" +
to_string(parTenorVec[i]);
470 parSensiBumpAnalysis(portfolio, engineData, initMarket, baseManualPv, baseCcy, parValVecBase, sensiLabels,
471 shiftSize, shiftType, parDelta, zeroDelta, basePv);
473 BOOST_TEST_MESSAGE(
"testing index curve par sensis");
475 for (
auto d_it : initParMarket->indexCurveRateHelperInstMap()) {
476 string idxName = d_it.first;
477 BOOST_TEST_MESSAGE(idxName);
478 auto itr = zeroAnalysis->sensitivityData()->indexCurveShiftData().find(idxName);
479 if (itr == zeroAnalysis->sensitivityData()->indexCurveShiftData().end())
480 zeroAnalysis->sensitivityData()->indexCurveShiftData()[idxName] =
481 QuantLib::ext::make_shared<SensitivityScenarioData::CurveShiftData>();
482 Real shiftSize = zeroAnalysis->sensitivityData()->indexCurveShiftData()[idxName]->shiftSize;
483 ShiftType shiftType = zeroAnalysis->sensitivityData()->indexCurveShiftData()[idxName]->shiftType;
484 vector<Period> parTenorVec = initParMarket->indexCurveRateHelperTenorsMap().find(idxName)->second;
485 vector<Handle<Quote>> parValVecBase = initParMarket->indexCurveRateHelperValuesMap().find(idxName)->second;
486 vector<string> sensiLabels(parValVecBase.size());
487 for (Size i = 0; i < parValVecBase.size(); i++) {
488 sensiLabels[i] =
"IndexCurve/" + idxName +
"/" +
to_string(i) +
"/" +
to_string(parTenorVec[i]);
490 parSensiBumpAnalysis(portfolio, engineData, initMarket, baseManualPv, baseCcy, parValVecBase, sensiLabels,
491 shiftSize, shiftType, parDelta, zeroDelta, basePv);
493 BOOST_TEST_MESSAGE(
"testing default curve par sensis");
495 for (
auto d_it : initParMarket->defaultRateHelpersInstMap()) {
496 string name = d_it.first;
497 auto itr = zeroAnalysis->sensitivityData()->creditCurveShiftData().find(
name);
498 if (itr == zeroAnalysis->sensitivityData()->creditCurveShiftData().end())
499 zeroAnalysis->sensitivityData()->creditCurveShiftData()[
name] =
500 QuantLib::ext::make_shared<SensitivityScenarioData::CurveShiftData>();
501 Real shiftSize = zeroAnalysis->sensitivityData()->creditCurveShiftData()[
name]->shiftSize;
502 ShiftType shiftType = zeroAnalysis->sensitivityData()->creditCurveShiftData()[
name]->shiftType;
503 vector<Period> parTenorVec = initParMarket->defaultRateHelperTenorsMap().find(
name)->second;
504 vector<Handle<Quote>> parValVecBase = initParMarket->defaultRateHelperValuesMap().find(
name)->second;
505 vector<string> sensiLabels(parValVecBase.size());
506 for (Size i = 0; i < parValVecBase.size(); i++) {
509 parSensiBumpAnalysis(portfolio, engineData, initMarket, baseManualPv, baseCcy, parValVecBase, sensiLabels,
510 shiftSize, shiftType, parDelta, zeroDelta, basePv);
512 BOOST_TEST_MESSAGE(
"testing cds par sensis");
514 for (
auto d_it : initParMarket->cdsVolRateHelperValuesMap()) {
515 string name = d_it.first;
516 Real shiftSize = zeroAnalysis->sensitivityData()->cdsVolShiftData()[
name].shiftSize;
517 ShiftType shiftType = zeroAnalysis->sensitivityData()->cdsVolShiftData()[
name].shiftType;
518 vector<Period> parTenorVec = initParMarket->cdsVolRateHelperTenorsMap().find(
name)->second;
519 vector<Handle<Quote>> parValVecBase = initParMarket->cdsVolRateHelperValuesMap().find(
name)->second;
520 vector<string> sensiLabels(parValVecBase.size());
521 for (Size i = 0; i < parValVecBase.size(); i++) {
524 parSensiBumpAnalysis(portfolio, engineData, initMarket, baseManualPv, baseCcy, parValVecBase, sensiLabels,
525 shiftSize, shiftType, zeroDelta, zeroDelta, basePv);
527 BOOST_TEST_MESSAGE(
"testing eqVol curve par sensis");
529 for (
auto d_it : initParMarket->equityVolRateHelperValuesMap()) {
530 string name = d_it.first;
531 Real shiftSize = zeroAnalysis->sensitivityData()->equityVolShiftData()[
name].shiftSize;
532 ShiftType shiftType = zeroAnalysis->sensitivityData()->equityVolShiftData()[
name].shiftType;
533 vector<Period> parTenorVec = initParMarket->equityVolRateHelperTenorsMap().find(
name)->second;
534 vector<Handle<Quote>> parValVecBase = initParMarket->equityVolRateHelperValuesMap().find(
name)->second;
535 vector<string> sensiLabels(parValVecBase.size());
536 for (Size i = 0; i < parValVecBase.size(); i++) {
537 sensiLabels[i] =
"EquityVolatility/" +
name +
"/" +
to_string(i) +
"/" +
to_string(parTenorVec[i]) +
"/ATM";
539 parSensiBumpAnalysis(portfolio, engineData, initMarket, baseManualPv, baseCcy, parValVecBase, sensiLabels,
540 shiftSize, shiftType, zeroDelta, zeroDelta, basePv);
542 BOOST_TEST_MESSAGE(
"testing swaption vol par sensis");
544 for (
auto d_it : initParMarket->swaptionVolRateHelperValuesMap()) {
545 string name = d_it.first;
546 Real shiftSize = zeroAnalysis->sensitivityData()->swaptionVolShiftData()[
name].shiftSize;
547 ShiftType shiftType = zeroAnalysis->sensitivityData()->swaptionVolShiftData()[
name].shiftType;
548 vector<Period> parTenorVec = initParMarket->swaptionVolRateHelperTenorsMap().find(
name)->second;
549 vector<Period> swapTenorVec = initParMarket->swaptionVolRateHelperSwapTenorsMap().find(
name)->second;
550 vector<Real> strikeSpreadVec = zeroAnalysis->sensitivityData()->swaptionVolShiftData()[
name].shiftStrikes;
551 vector<Handle<Quote>> parValVecBase = initParMarket->swaptionVolRateHelperValuesMap().find(
name)->second;
552 vector<string> sensiLabels(parValVecBase.size());
553 Size j = swapTenorVec.size();
554 Size k = zeroAnalysis->sensitivityData()->swaptionVolShiftData()[
name].shiftStrikes.size();
556 for (Size i = 0; i < parValVecBase.size(); i++) {
558 Size parTenor = i / (j * k);
559 Size swapTenor = (i - parTenor * j * k - strike) / k;
560 std::ostringstream o;
562 o <<
"SwaptionVolatility/" <<
name <<
"/" << i <<
"/" << parTenorVec[parTenor] <<
"/"
563 << swapTenorVec[swapTenor] <<
"/ATM";
565 o <<
"SwaptionVolatility/" <<
name <<
"/" << i <<
"/" << parTenorVec[parTenor] <<
"/"
566 << swapTenorVec[swapTenor] <<
"/" << std::setprecision(4) << strikeSpreadVec[strike];
567 sensiLabels[i] = o.str();
570 parSensiBumpAnalysis(portfolio, engineData, initMarket, baseManualPv, baseCcy, parValVecBase, sensiLabels,
571 shiftSize, shiftType, zeroDelta, zeroDelta, basePv);
573 BOOST_TEST_MESSAGE(
"testing base correlation par sensis");
575 for (
auto d_it : initParMarket->baseCorrRateHelperValuesMap()) {
576 string name = d_it.first;
577 Real shiftSize = zeroAnalysis->sensitivityData()->baseCorrelationShiftData()[
name].shiftSize;
578 ShiftType shiftType = zeroAnalysis->sensitivityData()->baseCorrelationShiftData()[
name].shiftType;
579 vector<Period> parTenorVec = initParMarket->baseCorrRateHelperTenorsMap().find(
name)->second;
580 vector<string> lossLevelVec = initParMarket->baseCorrLossLevelsMap().find(
name)->second;
581 vector<Handle<Quote>> parValVecBase = initParMarket->baseCorrRateHelperValuesMap().find(
name)->second;
582 vector<string> sensiLabels(parValVecBase.size());
583 Size j = lossLevelVec.size();
584 for (Size i = 0; i < parValVecBase.size(); i++) {
585 sensiLabels[i] =
"BaseCorrelation/" +
name +
"/" +
to_string(i) +
"/" + lossLevelVec[i % j] +
"/" +
588 parSensiBumpAnalysis(portfolio, engineData, initMarket, baseManualPv, baseCcy, parValVecBase, sensiLabels,
589 shiftSize, shiftType, zeroDelta, zeroDelta, basePv);
591 BOOST_TEST_MESSAGE(
"testing zero inflation par sensis");
593 for (
auto d_it : initParMarket->zeroInflationRateHelperInstMap()) {
594 string idxName = d_it.first;
595 Real shiftSize = zeroAnalysis->sensitivityData()->zeroInflationCurveShiftData()[idxName]->shiftSize;
596 ShiftType shiftType = zeroAnalysis->sensitivityData()->zeroInflationCurveShiftData()[idxName]->shiftType;
597 vector<Period> parTenorVec = initParMarket->zeroInflationRateHelperTenorsMap().find(idxName)->second;
598 vector<Handle<Quote>> parValVecBase = initParMarket->zeroInflationRateHelperValuesMap().find(idxName)->second;
599 vector<string> sensiLabels(parValVecBase.size());
600 for (Size i = 0; i < parValVecBase.size(); i++) {
601 sensiLabels[i] =
"ZeroInflationCurve/" + idxName +
"/" +
to_string(i) +
"/" +
to_string(parTenorVec[i]);
603 parSensiBumpAnalysis(portfolio, engineData, initMarket, baseManualPv, baseCcy, parValVecBase, sensiLabels,
604 shiftSize, shiftType, parDelta, zeroDelta, basePv);
606 BOOST_TEST_MESSAGE(
"testing yoy inflation par sensis");
608 for (
auto d_it : initParMarket->yoyInflationRateHelperInstMap()) {
609 string idxName = d_it.first;
610 Real shiftSize = zeroAnalysis->sensitivityData()->yoyInflationCurveShiftData()[idxName]->shiftSize;
611 ShiftType shiftType = zeroAnalysis->sensitivityData()->yoyInflationCurveShiftData()[idxName]->shiftType;
612 vector<Period> parTenorVec = initParMarket->yoyInflationRateHelperTenorsMap().find(idxName)->second;
613 vector<Handle<Quote>> parValVecBase = initParMarket->yoyInflationRateHelperValuesMap().find(idxName)->second;
614 vector<string> sensiLabels(parValVecBase.size());
615 for (Size i = 0; i < parValVecBase.size(); i++) {
616 sensiLabels[i] =
"YoYInflationCurve/" + idxName +
"/" +
to_string(i) +
"/" +
to_string(parTenorVec[i]);
618 parSensiBumpAnalysis(portfolio, engineData, initMarket, baseManualPv, baseCcy, parValVecBase, sensiLabels,
619 shiftSize, shiftType, parDelta, zeroDelta, basePv);
623 ObservationMode::instance().setMode(backupMode);
624 IndexManager::instance().clearHistories();
629BOOST_AUTO_TEST_SUITE(ParSensitivityAnalysisManual)
632 BOOST_TEST_MESSAGE(
"Testing ParSwapBenchmark");
636BOOST_AUTO_TEST_SUITE_END()
638BOOST_AUTO_TEST_SUITE_END()
Par Sensitivity Analysis.
void alignPillars()
align pillars in scenario simulation market parameters with those of the par instruments
const ParContainer & parSensitivities() const
Return computed par sensitivities. Empty if they have not been computed yet.
std::map< ore::analytics::RiskFactorKey, std::pair< QuantLib::Real, QuantLib::Real > > shiftSizes() const
Return the zero rate and par rate absolute shift size for each risk factor key.
void computeParInstrumentSensitivities(const QuantLib::ext::shared_ptr< ore::analytics::ScenarioSimMarket > &simMarket)
Compute par instrument sensitivities.
std::map< ore::analytics::RiskFactorKey, QuantLib::Real > parDeltas(const std::string &tradeId) const
Return the non-zero par deltas for the given tradeId.
static const string defaultConfiguration
OREAnalytics Top level fixture.
static void testParSwapBenchmark()
Benchmark par conversion against brute-force bump on the par instruments ("None" observation mode)
static QuantLib::ext::shared_ptr< ore::analytics::SensitivityScenarioData > setupSensitivityScenarioData(bool hasSwapVolCube=false, bool hasYYCapVols=false, bool parConversion=false)
SensitivityScenarioData instance.
static QuantLib::ext::shared_ptr< ore::analytics::ScenarioSimMarketParameters > setupSimMarketData(bool hasSwapVolCube=false, bool hasYYCapVols=false)
ScenarioSimMarketParameters instance.
factory class for cloning a cached scenario
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
std::string to_string(const LocationInfo &l)
QuantLib::ext::shared_ptr< Trade > buildCreditDefaultSwap(string id, string ccy, string issuerId, string creditCurveId, bool isPayer, Real notional, int start, Size term, Real rate, Real spread, string fixedFreq, string fixedDC)
QuantLib::ext::shared_ptr< Trade > buildSyntheticCDO(string id, string name, vector< string > names, string longShort, string ccy, vector< string > ccys, bool isPayer, vector< Real > notionals, Real notional, int start, Size term, Real rate, Real spread, string fixedFreq, string fixedDC)
QuantLib::ext::shared_ptr< Trade > buildCap(string id, string ccy, string longShort, Real capRate, Real notional, int start, Size term, string floatFreq, string floatDC, string index, Calendar calendar, Natural spotDays, bool spotStartLag)
QuantLib::ext::shared_ptr< Trade > buildCmsCapFloor(string id, string ccy, string indexId, bool isPayer, Real notional, int start, Size term, Real capRate, Real floorRate, Real spread, string freq, string dc)
QuantLib::ext::shared_ptr< Trade > buildSwap(string id, string ccy, bool isPayer, Real notional, int start, Size term, Real rate, Real spread, string fixedFreq, string fixedDC, string floatFreq, string floatDC, string index, Calendar calendar, Natural spotDays, bool spotStartLag)
QuantLib::ext::shared_ptr< Trade > buildCPIInflationSwap(string id, string ccy, bool isPayer, Real notional, int start, Size term, Real spread, string floatFreq, string floatDC, string index, string cpiFreq, string cpiDC, string cpiIndex, Real baseRate, string observationLag, bool interpolated, Real cpiRate)
QuantLib::ext::shared_ptr< Trade > buildEquityOption(string id, string longShort, string putCall, Size expiry, string equityName, string currency, Real strike, Real quantity, Real premium, string premiumCcy, string premiumDate)
QuantLib::ext::shared_ptr< Trade > buildFloor(string id, string ccy, string longShort, Real floorRate, Real notional, int start, Size term, string floatFreq, string floatDC, string index, Calendar calendar, Natural spotDays, bool spotStartLag)
QuantLib::ext::shared_ptr< Trade > buildCrossCcyBasisSwap(string id, string recCcy, Real recNotional, string payCcy, Real payNotional, int start, Size term, Real recLegSpread, Real payLegSpread, string recFreq, string recDC, string recIndex, Calendar recCalendar, string payFreq, string payDC, string payIndex, Calendar payCalendar, Natural spotDays, bool spotStartLag, bool notionalInitialExchange, bool notionalFinalExchange, bool notionalAmortizingExchange, bool isRecLegFXResettable, bool isPayLegFXResettable)
QuantLib::ext::shared_ptr< Trade > buildYYInflationSwap(string id, string ccy, bool isPayer, Real notional, int start, Size term, Real spread, string floatFreq, string floatDC, string index, string yyFreq, string yyDC, string yyIndex, string observationLag, Size fixDays)
BOOST_AUTO_TEST_CASE(ZeroShifts1d)
Singleton class to hold global Observation Mode.
Perfrom sensitivity analysis for a given portfolio.
Fixture that can be used at top level of OREAnalytics test suites.
More par Sensitivity analysis tests.
A Market class that can be updated by Scenarios.
Class for converting zero sensitivities to par sensitivities.