Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
equitymarketdata.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2016 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 <boost/test/unit_test.hpp>
24#include <oret/toplevelfixture.hpp>
25
26#include <boost/algorithm/string.hpp>
27#include <boost/assign/list_of.hpp>
28
29using namespace std;
30using namespace QuantLib;
31
32namespace {
33
34std::vector<std::string> getMarketDataStrings() {
35 // clang-format off
36 return boost::assign::list_of
37 // borrow spread curve
38 ("20160226 EQUITY/PRICE/SP5/USD 1650.17")
39 ("20160226 EQUITY/PRICE/Lufthansa/EUR 17.56")
40 ("20160226 EQUITY_FWD/PRICE/SP5/USD/1Y 1678.54")
41 ("20160226 EQUITY_FWD/PRICE/SP5/USD/2017-02-26 1678.54")
42 ("20160226 EQUITY_FWD/PRICE/SP5/USD/20170226 1678.54")
43 ("20160226 EQUITY_FWD/PRICE/SP5/USD/365D 1678.54")
44 ("20160226 EQUITY_FWD/PRICE/SP5/USD/1678W5D 1900.50")
45 ("20160226 EQUITY_FWD/PRICE/Lufthansa/EUR/1Y1M 1678.54")
46 ("20160226 EQUITY_DIVIDEND/RATE/SP5/USD/1Y 0.025")
47 ("20160226 EQUITY_DIVIDEND/RATE/SP5/USD/2017-02-26 0.025")
48 ("20160226 EQUITY_DIVIDEND/RATE/SP5/USD/20170226 0.025")
49 ("20160226 EQUITY_DIVIDEND/RATE/SP5/USD/365D 0.025")
50 ("20160226 EQUITY_DIVIDEND/RATE/SP5/USD/1678W5D 0.025")
51 ("20160226 EQUITY_DIVIDEND/RATE/Lufthansa/EUR/1Y1M 0.013")
52 ("20160226 EQUITY_OPTION/RATE_LNVOL/SP5/USD/12M/ATMF 0.25")
53 ("20160226 EQUITY_OPTION/RATE_LNVOL/SP5/USD/2017-02-26/ATMF 0.25")
54 ("20160226 EQUITY_OPTION/RATE_LNVOL/SP5/USD/20170226/ATMF 0.25")
55 ("20160226 EQUITY_OPTION/RATE_LNVOL/SP5/USD/365D/ATMF 0.25")
56 ("20160226 EQUITY_OPTION/RATE_LNVOL/SP5/USD/1678W5D/ATMF 0.25")
57 ("20160226 EQUITY_OPTION/RATE_LNVOL/Lufthansa/EUR/1Y1M/ATMF 0.13");
58}
59
60std::vector<std::string> getBadMarketDataStrings() {
61 // clang-format off
62 return boost::assign::list_of
63 // borrow spread curve
64 ("20160226 EQUITY_SPOT/PRICE/SP5/USD 1650.17") // incorrect instrument type
65 ("20160226 EQUITY/RATE/Lufthansa/EUR 17.56") // incorrect quote type
66 ("20160226 EQUITY_FORWARD/PRICE/SP5/USD/1Y 1678.54") // incorrect instrument type
67 ("20160226 EQUITY_FWD/SPREAD/SP5/USD/2017-02-26 1678.54") // incorrect quote type
68 ("20160226 EQUITY_FWD/PRICE/SP5/USD/zzz 1678.54") // incorrect expiry
69 ("20160226 EQUITY_DIV_YIELD/RATE/SP5/USD/1Y 1678.54") // incorrect instrument type
70 ("20160226 EQUITY_DIVIDEND/PRICE/SP5/USD/2017-02-26 1678.54") // incorrect quote type
71 ("20160226 EQUITY_DIVIDEND/RATE/SP5/USD/zzz 1678.54") // incorrect expiry
72 ("20160226 EQUITY_OPTION_VOL/RATE_LNVOL/SP5/USD/12M/ATMF 0.25") // incorrect instrument type
73 ("20160226 EQUITY_OPTION/RATE_NVOL/SP5/USD/2017-02-26/ATMF 0.25") // normal vols not supported for equity
74 ("20160226 EQUITY_OPTION/RATE_LNVOL/SP5/USD/zzz/ATMF 0.25"); // invalid tenor/date input
75}
76
77std::string divYieldCurveConfigString =
78"<CurveConfiguration>"
79"<EquityCurves>"
80"<EquityCurve>"
81"<CurveId>SP5</CurveId>"
82"<ForecastingCurve>USD1D</ForecastingCurve>"
83"<CurveDescription>SP 500 equity price projection curve</CurveDescription>"
84"<Currency>USD</Currency> <!--is this really needed ? -->"
85"<Type>DividendYield</Type> <!-- {DividendYield, ForwardPrice} -->"
86"<SpotQuote>EQUITY/PRICE/SP5/USD</SpotQuote> <!--the spot quote from the market data file-->"
87"<Quotes>"
88"<Quote>EQUITY_DIVIDEND/RATE/SP5/USD/1M</Quote>"
89"<Quote>EQUITY_DIVIDEND/RATE/SP5/USD/2016-09-15</Quote>"
90"<Quote>EQUITY_DIVIDEND/RATE/SP5/USD/1Y</Quote>"
91"<Quote>EQUITY_DIVIDEND/RATE/SP5/USD/2Y</Quote>"
92"<Quote>EQUITY_DIVIDEND/RATE/SP5/USD/5Y</Quote>"
93"</Quotes>"
94"<DayCounter>A365</DayCounter>"
95"</EquityCurve>"
96"</EquityCurves>"
97"</CurveConfiguration>";
98
99std::string eqBadConfigString =
100"<CurveConfiguration>"
101"<EquityCurves>"
102"<EquityCurve>"
103"<CurveId>SP5Mini</CurveId>"
104"<ForecastCurve>USD1D</ForecastCurve>"
105"<CurveDescription>SP Mini equity price projection curve</CurveDescription>"
106"<Currency>USD</Currency> <!--is this really needed ? -->"
107"<Type>ForwardPrice</Type> <!-- {DividendYield, ForwardPrice} -->"
108"<Quotes>"
109"<Quote>EQUITY_FWD/PRICE/SP5Mini/USD/1M</Quote>"
110"<Quote>EQUITY_FWD/PRICE/SP5Mini/USD/2016-09-15</Quote>"
111"<Quote>EQUITY_FWD/PRICE/SP5Mini/USD/1Y</Quote>"
112"<Quote>EQUITY_FWD/PRICE/SP5Mini/USD/2Y</Quote>"
113"<Quote>EQUITY_FWD/PRICE/SP5Mini/USD/5Y</Quote>"
114"</Quotes>"
115"</EquityCurve>"
116"</EquityCurves>"
117"</CurveConfiguration>";
118
119}
120
121BOOST_FIXTURE_TEST_SUITE(OREDataTestSuite, ore::test::TopLevelFixture)
122
123BOOST_AUTO_TEST_SUITE(EquityMarketDataTests)
124
125BOOST_AUTO_TEST_CASE(testMarketDatumParser) {
126
127 BOOST_TEST_MESSAGE("Testing equity market data parsing...");
128 std::vector<std::string> marketDataStrings = getMarketDataStrings();
129 for (auto s : marketDataStrings) {
130 std::vector<std::string> tokens;
131 boost::trim(s);
132 boost::split(tokens, s, boost::is_any_of(" "), boost::token_compress_on);
133 Date quoteDate = ore::data::parseDate(tokens[0]);
134 const string& key = tokens[1];
135 Real value = ore::data::parseReal(tokens[2]);
136
137 BOOST_CHECK_NO_THROW(ore::data::parseMarketDatum(quoteDate, key, value));
138 QuantLib::ext::shared_ptr<ore::data::MarketDatum> md = ore::data::parseMarketDatum(quoteDate, key, value);
139 BOOST_CHECK(md);
140 BOOST_CHECK_EQUAL(md->name(), key);
141 BOOST_CHECK_EQUAL(md->asofDate(), quoteDate);
142 BOOST_CHECK_EQUAL(md->quote()->value(), value);
143 }
144}
145
146BOOST_AUTO_TEST_CASE(testBadMarketDatumStrings) {
147
148 BOOST_TEST_MESSAGE("Testing equity market data parsing (bad strings)...");
149 std::vector<std::string> marketDataStrings = getBadMarketDataStrings();
150 for (auto s : marketDataStrings) {
151 std::vector<std::string> tokens;
152 boost::trim(s);
153 boost::split(tokens, s, boost::is_any_of(" "), boost::token_compress_on);
154 Date quoteDate = ore::data::parseDate(tokens[0]);
155 const string& key = tokens[1];
156 Real value = ore::data::parseReal(tokens[2]);
157 BOOST_CHECK_THROW(ore::data::parseMarketDatum(quoteDate, key, value), QuantLib::Error);
158 }
159}
160
161BOOST_AUTO_TEST_CASE(testEqCurveConfigLoad) {
162
163 BOOST_TEST_MESSAGE("Testing equity curve config load...");
165 testDoc.fromXMLString(divYieldCurveConfigString);
166 // check that the root node is as expected
167 ore::data::XMLNode* node = testDoc.getFirstNode("CurveConfiguration");
168 BOOST_CHECK_NO_THROW(ore::data::XMLUtils::checkNode(node, "CurveConfiguration"));
169
171 BOOST_CHECK_NO_THROW(cc.fromXML(node));
172 QuantLib::ext::shared_ptr<ore::data::EquityCurveConfig> ec = cc.equityCurveConfig("SP5");
173 BOOST_CHECK(ec);
174 BOOST_CHECK_EQUAL("SP5", ec->curveID());
175 BOOST_CHECK_EQUAL("SP 500 equity price projection curve",
176 ec->curveDescription());
177 BOOST_CHECK_EQUAL("USD", ec->currency());
178 BOOST_CHECK_EQUAL("EQUITY/PRICE/SP5/USD", ec->equitySpotQuoteID());
179 bool testType = (ec->type() == ore::data::EquityCurveConfig::Type::DividendYield);
180 BOOST_CHECK(testType);
181 //BOOST_CHECK_EQUAL(ore::data::EquityCurveConfig::Type::DividendYield, ec->type());
182 BOOST_CHECK_EQUAL("A365", ec->dayCountID());
183 vector<string> anticipatedQuotes = boost::assign::list_of
184 ("EQUITY/PRICE/SP5/USD")
185 ("EQUITY_DIVIDEND/RATE/SP5/USD/1M")
186 ("EQUITY_DIVIDEND/RATE/SP5/USD/2016-09-15")
187 ("EQUITY_DIVIDEND/RATE/SP5/USD/1Y")
188 ("EQUITY_DIVIDEND/RATE/SP5/USD/2Y")
189 ("EQUITY_DIVIDEND/RATE/SP5/USD/5Y");
190 vector<string> actualQuotes = ec->quotes();
191 BOOST_CHECK_EQUAL_COLLECTIONS(anticipatedQuotes.begin(), anticipatedQuotes.end(),
192 actualQuotes.begin(), actualQuotes.end());
193 BOOST_CHECK(!ec->extrapolation());
194
195 // now test the toXML member function
196 ore::data::XMLDocument testDumpDoc;
197 BOOST_CHECK_NO_THROW(cc.toXML(testDumpDoc));
198 // TODO - query the XML to ensure that the curve configuration objects have been dumped correctly
199}
200
201BOOST_AUTO_TEST_CASE(testEqCurveConfigBadLoad) {
202
203 BOOST_TEST_MESSAGE("Testing equity curve config load (bad input)...");
204 ore::data::XMLDocument testBadDoc;
205 testBadDoc.fromXMLString(eqBadConfigString);
206 // check that the root node is as expected
207 ore::data::XMLNode* badNode = testBadDoc.getFirstNode("CurveConfiguration");
208 BOOST_CHECK_NO_THROW(ore::data::XMLUtils::checkNode(badNode, "CurveConfiguration"));
210 BOOST_CHECK_NO_THROW(cc.fromXML(badNode)); // the spot price is missing, but the correct behaviour is to log error and move on
211 BOOST_CHECK_THROW(cc.equityCurveConfig("SP5Mini"), QuantLib::Error); // this checks that the XML throws when we try to load
212}
213
214BOOST_AUTO_TEST_SUITE_END()
215
216BOOST_AUTO_TEST_SUITE_END()
Container class for all Curve Configurations.
QuantLib::ext::shared_ptr< EquityCurveConfig > equityCurveConfig(const string &curveID) const
void fromXML(XMLNode *node) override
XMLNode * toXML(XMLDocument &doc) const override
Small XML Document wrapper class.
Definition: xmlutils.hpp:65
void fromXMLString(const string &xmlString)
load a document from a hard-coded string
Definition: xmlutils.cpp:103
XMLNode * getFirstNode(const string &name) const
Definition: xmlutils.cpp:116
static void checkNode(XMLNode *n, const string &expectedName)
Definition: xmlutils.cpp:175
SafeStack< ValueType > value
Curve configuration repository.
BOOST_AUTO_TEST_CASE(testMarketDatumParser)
QuantLib::ext::shared_ptr< MarketDatum > parseMarketDatum(const Date &asof, const string &datumName, const Real &value)
Function to parse a market datum.
Date parseDate(const string &s)
Convert std::string to QuantLib::Date.
Definition: parsers.cpp:51
Real parseReal(const string &s)
Convert text to Real.
Definition: parsers.cpp:112
Market Datum parser.
Map text representations to QuantLib/QuantExt types.
XML utility functions.