246 {
247 BOOST_TEST_MESSAGE("Testing Sensitivity Par Conversion");
248
249 SavedSettings backup;
250
251 Date today = Date(14, April, 2016);
252 Settings::instance().evaluationDate() = today;
253
254 BOOST_TEST_MESSAGE("Today is " << today);
255
256
257 string baseCcy = "EUR";
258 vector<string> ccys;
259 ccys.push_back(baseCcy);
260 ccys.push_back("GBP");
261 ccys.push_back("CHF");
262 ccys.push_back("USD");
263 ccys.push_back("JPY");
264
265
266 QuantLib::ext::shared_ptr<Market> initMarket = QuantLib::ext::make_shared<TestMarket>(today);
267
268
270
271
273
274
276 QuantLib::ext::shared_ptr<analytics::ScenarioSimMarket> simMarket =
277 QuantLib::ext::make_shared<analytics::ScenarioSimMarket>(initMarket, simMarketData);
278
279
280 QuantLib::ext::shared_ptr<Scenario> baseScenario = simMarket->baseScenario();
281 QuantLib::ext::shared_ptr<ScenarioFactory> scenarioFactory = QuantLib::ext::make_shared<CloneScenarioFactory>(baseScenario);
282
283
284 QuantLib::ext::shared_ptr<StressScenarioGenerator> scenarioGenerator =
285 QuantLib::ext::make_shared<StressScenarioGenerator>(stressData, baseScenario, simMarketData, simMarket, scenarioFactory);
286 simMarket->scenarioGenerator() = scenarioGenerator;
287
288
289 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
290 engineData->model("Swap") = "DiscountedCashflows";
291 engineData->engine("Swap") = "DiscountingSwapEngine";
292 engineData->model("CrossCurrencySwap") = "DiscountedCashflows";
293 engineData->engine("CrossCurrencySwap") = "DiscountingCrossCurrencySwapEngine";
294 engineData->model("EuropeanSwaption") = "BlackBachelier";
295 engineData->engine("EuropeanSwaption") = "BlackBachelierSwaptionEngine";
296 engineData->model("FxForward") = "DiscountedCashflows";
297 engineData->engine("FxForward") = "DiscountingFxForwardEngine";
298 engineData->model("FxOption") = "GarmanKohlhagen";
299 engineData->engine("FxOption") = "AnalyticEuropeanEngine";
300 engineData->model("CapFloor") = "IborCapModel";
301 engineData->engine("CapFloor") = "IborCapEngine";
302 engineData->model("CapFlooredIborLeg") = "BlackOrBachelier";
303 engineData->engine("CapFlooredIborLeg") = "BlackIborCouponPricer";
304 QuantLib::ext::shared_ptr<EngineFactory> factory = QuantLib::ext::make_shared<EngineFactory>(engineData, simMarket);
305
306
307 QuantLib::ext::shared_ptr<Portfolio> portfolio(
new Portfolio());
308 portfolio->add(
buildSwap(
"1_Swap_EUR",
"EUR",
true, 10000000.0, 0, 10, 0.03, 0.00,
"1Y",
"30/360",
"6M",
"A360",
309 "EUR-EURIBOR-6M"));
310 portfolio->add(
buildSwap(
"2_Swap_USD",
"USD",
true, 10000000.0, 0, 15, 0.02, 0.00,
"6M",
"30/360",
"3M",
"A360",
311 "USD-LIBOR-3M"));
312 portfolio->add(
buildSwap(
"3_Swap_GBP",
"GBP",
true, 10000000.0, 0, 20, 0.04, 0.00,
"6M",
"30/360",
"3M",
"A360",
313 "GBP-LIBOR-6M"));
314 portfolio->add(
buildSwap(
"4_Swap_JPY",
"JPY",
true, 1000000000.0, 0, 5, 0.01, 0.00,
"6M",
"30/360",
"3M",
"A360",
315 "JPY-LIBOR-6M"));
316 portfolio->add(
buildEuropeanSwaption(
"5_Swaption_EUR",
"Long",
"EUR",
true, 1000000.0, 10, 10, 0.03, 0.00,
"1Y",
317 "30/360", "6M", "A360", "EUR-EURIBOR-6M"));
318 portfolio->add(
buildEuropeanSwaption(
"6_Swaption_EUR",
"Long",
"EUR",
true, 1000000.0, 2, 5, 0.03, 0.00,
"1Y",
319 "30/360", "6M", "A360", "EUR-EURIBOR-6M"));
320 portfolio->add(
buildFxOption(
"7_FxOption_EUR_USD",
"Long",
"Call", 3,
"EUR", 10000000.0,
"USD", 11000000.0));
321 portfolio->add(
buildFxOption(
"8_FxOption_EUR_GBP",
"Long",
"Call", 7,
"EUR", 10000000.0,
"GBP", 11000000.0));
322 portfolio->add(
buildCap(
"9_Cap_EUR",
"EUR",
"Long", 0.05, 1000000.0, 0, 10,
"6M",
"A360",
"EUR-EURIBOR-6M"));
323 portfolio->add(
buildFloor(
"10_Floor_USD",
"USD",
"Long", 0.01, 1000000.0, 0, 10,
"3M",
"A360",
"USD-LIBOR-3M"));
324 portfolio->build(factory);
325
326 BOOST_TEST_MESSAGE("Portfolio size after build: " << portfolio->size());
327
328
330
331 std::map<std::string, Real> baseNPV = analysis.baseNPV();
332 std::map<std::pair<std::string, std::string>, Real> shiftedNPV = analysis.shiftedNPV();
333
334 QL_REQUIRE(shiftedNPV.size() > 0, "no shifted results");
335
336 struct Results {
337 string id;
338 string label;
339 Real shift;
340 };
341
342 std::vector<Results> cachedResults = {{"10_Floor_USD", "stresstest_1", -2487.75},
343 {"1_Swap_EUR", "stresstest_1", 629406},
344 {"2_Swap_USD", "stresstest_1", 599846},
345 {"3_Swap_GBP", "stresstest_1", 1.11005e+06},
346 {"4_Swap_JPY", "stresstest_1", 186736},
347 {"5_Swaption_EUR", "stresstest_1", 13623.1},
348 {"6_Swaption_EUR", "stresstest_1", 5041.52},
349 {"7_FxOption_EUR_USD", "stresstest_1", 748160},
350 {"8_FxOption_EUR_GBP", "stresstest_1", 1.21724e+06},
351 {"9_Cap_EUR", "stresstest_1", 1175.5}};
352
353 std::map<pair<string, string>, Real> stressMap;
354 for (Size i = 0; i < cachedResults.size(); ++i) {
355 pair<string, string> p(cachedResults[i].id, cachedResults[i].label);
356 stressMap[p] = cachedResults[i].shift;
357 }
358
359 Real tolerance = 0.01;
361 for (auto data : shiftedNPV) {
362 pair<string, string> p =
data.first;
363 string id =
data.first.first;
364 Real npv =
data.second;
365 QL_REQUIRE(baseNPV.find(id) != baseNPV.end(), "base npv not found for trade " << id);
366 Real base = baseNPV[id];
367 Real delta = npv - base;
368 if (fabs(delta) > 0.0) {
370 QL_REQUIRE(stressMap.find(p) != stressMap.end(),
371 "pair (" << p.first << ", " << p.second << ") not found in sensi map");
372 BOOST_CHECK_MESSAGE(fabs(delta - stressMap[p]) < tolerance ||
373 fabs((delta - stressMap[p]) / delta) < tolerance,
374 "stress test regression failed for pair (" << p.first << ", " << p.second
375 << "): " << delta << " vs " << stressMap[p]);
376 }
377 }
378 BOOST_CHECK_MESSAGE(count == cachedResults.size(), "number of non-zero stress impacts ("
379 << count << ") do not match regression data ("
380 << cachedResults.size() << ")");
381 IndexManager::instance().clearHistories();
382}
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 > buildFxOption(string id, string longShort, string putCall, Size expiry, string boughtCcy, Real boughtAmount, string soldCcy, Real soldAmount, Real premium, string premiumCcy, string premiumDate)
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 > 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 > buildEuropeanSwaption(string id, string longShort, string ccy, bool isPayer, Real notional, int start, Size term, Real rate, Real spread, string fixedFreq, string fixedDC, string floatFreq, string floatDC, string index, string cashPhysical, Real premium, string premiumCcy, string premiumDate)
QuantLib::ext::shared_ptr< data::Conventions > stressConv()
QuantLib::ext::shared_ptr< analytics::ScenarioSimMarketParameters > setupStressSimMarketData()
QuantLib::ext::shared_ptr< StressTestScenarioData > setupStressScenarioData()