Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
cdsindexoption.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2021 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
19#include <oret/toplevelfixture.hpp>
20#include <boost/test/unit_test.hpp>
21#include <oret/datapaths.hpp>
22
33
34using namespace QuantLib;
35using namespace QuantExt;
36using namespace ore::data;
37
40
41using std::fixed;
42using std::setprecision;
43using std::string;
44using std::vector;
45
46
47namespace {
48
49// Create portfolio from input files.
50QuantLib::ext::shared_ptr<Portfolio> buildPortfolio(const Date& asof, const string& inputDir) {
51
52 Settings::instance().evaluationDate() = asof;
53
54 auto conventions = QuantLib::ext::make_shared<Conventions>();
55 conventions->fromFile(TEST_INPUT_FILE(string(inputDir + "/conventions.xml")));
56 InstrumentConventions::instance().setConventions(conventions);
57
58 auto curveConfigs = QuantLib::ext::make_shared<CurveConfigurations>();
59 curveConfigs->fromFile(TEST_INPUT_FILE(string(inputDir + "/curveconfig.xml")));
60
61 auto todaysMarketParameters = QuantLib::ext::make_shared<TodaysMarketParameters>();
62 todaysMarketParameters->fromFile(TEST_INPUT_FILE(string(inputDir + "/todaysmarket.xml")));
63
64 auto loader = QuantLib::ext::make_shared<CSVLoader>(TEST_INPUT_FILE(string(inputDir + "/market.txt")),
65 TEST_INPUT_FILE(string(inputDir + "/fixings.txt")), false);
66
67 auto tm = QuantLib::ext::make_shared<TodaysMarket>(asof, todaysMarketParameters, loader, curveConfigs);
68
69 QuantLib::ext::shared_ptr<EngineData> data = QuantLib::ext::make_shared<EngineData>();
70 data->fromFile(TEST_INPUT_FILE(string(inputDir + "/pricingengine.xml")));
71
72 auto rdm = QuantLib::ext::make_shared<BasicReferenceDataManager>(
73 TEST_INPUT_FILE(string(inputDir + "/reference_data.xml")));
74
75 map<MarketContext, string> configurations;
76 vector<QuantLib::ext::shared_ptr<EngineBuilder>> extraEngineBuilders{
77 QuantLib::ext::make_shared<MidPointIndexCdsEngineBuilder>(),
78 QuantLib::ext::make_shared<BlackIndexCdsOptionEngineBuilder>()
79 };
80 vector<QuantLib::ext::shared_ptr<LegBuilder>> extraLegBuilders;
81 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(data, tm, configurations, rdm);
82
83 auto portfolio = QuantLib::ext::make_shared<Portfolio>();
84 portfolio->fromFile(TEST_INPUT_FILE(string(inputDir + "/portfolio.xml")));
85 portfolio->build(engineFactory);
86
87 return portfolio;
88}
89
90// Check portfolio prices are within tolerance
91void checkNpvs(const QuantLib::ext::shared_ptr<Portfolio>& portfolio, Real tol, Real relTol = Null<Real>()) {
92 for (const auto& [tradeId, trade] : portfolio->trades()) {
93 auto npv = trade->instrument()->NPV();
94 if (relTol != Null<Real>()) {
95 auto opt = QuantLib::ext::dynamic_pointer_cast<ore::data::IndexCreditDefaultSwapOption>(trade);
96 Real expNpv = opt->option().premiumData().premiumData().front().amount;
97 Real relDiff = npv / expNpv;
98 BOOST_TEST_CONTEXT("trade_id,npv,expNpv,relDiff:" << tradeId << fixed << setprecision(2) <<
99 "," << npv << "," << expNpv << "," << setprecision(6) << relDiff) {
100 BOOST_CHECK(std::abs(npv) < tol || std::abs(relDiff) < relTol);
101 }
102 } else {
103 BOOST_TEST_CONTEXT("trade_id,npv:" << tradeId << fixed << setprecision(2) << "," << npv) {
104 BOOST_CHECK_SMALL(npv, tol);
105 }
106 }
107 }
108}
109
110}
111
112BOOST_FIXTURE_TEST_SUITE(OREDataTestSuite, ore::test::TopLevelFixture)
113
114BOOST_AUTO_TEST_SUITE(CdsIndexOptionTest)
115
116/* The 4 test cases below perform the same steps to check index CDS option pricing for different scenarios against
117 Markit data for the given valuation date. The differing scenarios are:
118 - strike is quoted in terms of spread or price
119 - pricing engine uses the index CDS spread curve or the underlying CDS spread curves (without bias correction)
120
121 The portfolio is built from data in the given directories. Markit CDS spreads and volatilities are used to price
122 the index CDS options across a range of strikes, including deeply in-the-money and out-of-the-money strikes, and
123 a range of option expiries from 3M to 12M. The trades in the portfolio have a notional of 10K and the associated
124 Markit premium in the `PremiumAmount` field. The NPV of the trade is therefore the difference between the Markit
125 premium and our calculated value in bps. We check this difference against a tolerance.
126*/
127BOOST_AUTO_TEST_CASE(testSpreadStrikeNoDefaultsIndexCurve) {
128 BOOST_TEST_MESSAGE("Testing pricing for spread strike, no existing defaults, using index curve ...");
129 checkNpvs(buildPortfolio(Date(22, Apr, 2021), "cdx_ig_36_v1_2021-04-22_index"), 6.5);
130}
131
132BOOST_AUTO_TEST_CASE(testSpreadStrikeNoDefaultsUnderlyingCurves) {
133 BOOST_TEST_MESSAGE("Testing pricing for spread strike, no existing defaults, using underlying curves ...");
134 checkNpvs(buildPortfolio(Date(22, Apr, 2021), "cdx_ig_36_v1_2021-04-22_underlyings"), 12.0);
135}
136
137BOOST_AUTO_TEST_CASE(testPriceStrikeNoDefaultsIndexCurve) {
138 BOOST_TEST_MESSAGE("Testing pricing for price strike, no existing defaults, using index curve ...");
139 checkNpvs(buildPortfolio(Date(22, Apr, 2021), "cdx_hy_36_v1_2021-04-22_index"), 10, 0.105);
140}
141
142// Large relative tolerance used here. We see large differences with Markit due to a difference in the front end
143// adjusted forward price that we calculate vs. the forward price that they use.
144BOOST_AUTO_TEST_CASE(testPriceStrikeNoDefaultsUnderlyingCurves) {
145 BOOST_TEST_MESSAGE("Testing pricing for price strike, no existing defaults, using underlying curves ...");
146 checkNpvs(buildPortfolio(Date(22, Apr, 2021), "cdx_hy_36_v1_2021-04-22_underlyings"), 20, 0.25);
147}
148
149BOOST_AUTO_TEST_SUITE_END()
150BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_CASE(testSpreadStrikeNoDefaultsIndexCurve)
Black CDS option engine builder for index CDS options.
Midpoint Engine Builder class for IndexCreditDefaultSwaps.
Market Datum Loader Implementation.
A class to hold pricing engine parameters.
Pricing Engine Factory.
@ data
Definition: log.hpp:77
Portfolio class.
Reference data model and serialization.
vector< string > curveConfigs
An concrete implementation of the Market class that loads todays market and builds the required curve...