19#include <boost/make_shared.hpp>
21#include <boost/test/unit_test.hpp>
22#include <boost/test/data/test_case.hpp>
24#include <oret/datapaths.hpp>
25#include <oret/toplevelfixture.hpp>
27#include <ql/math/comparison.hpp>
28#include <ql/math/interpolations/linearinterpolation.hpp>
29#include <ql/math/interpolations/loginterpolation.hpp>
30#include <ql/time/daycounters/actualactual.hpp>
42using namespace boost::unit_test_framework;
52vector<string> curveConfigFiles = {
"curveconfig_linear.xml",
"curveconfig_linear_flat.xml",
53 "curveconfig_loglinear.xml",
"curveconfig_loglinear_flat.xml",
54 "curveconfig_cubic.xml",
"curveconfig_cubic_flat.xml"};
57map<Date, Real> expectedCurve = {{Date(29, Jul, 2019), 1417.8998900}, {Date(30, Jul, 2019), 1417.9999450},
58 {Date(31, Jul, 2019), 1418.1000000}, {Date(1, Aug, 2019), 1418.2000550},
59 {Date(30, Aug, 2019), 1421.1016535}, {Date(30, Sep, 2019), 1424.1312750}};
62map<Date, Real> expectedInterpCurvePillars = {{Date(31, Jul, 2019), 1418.1000000},
63 {Date(1, Aug, 2019), 1418.2000550},
64 {Date(30, Aug, 2019), 1421.1016535},
65 {Date(30, Sep, 2019), 1424.1312750}};
69vector<Date> offPillarDates = {Date(29, Jul, 2019), Date(15, Sep, 2019), Date(1, Nov, 2019)};
71map<string, vector<Real>> expectedInterpCurveOffPillars = {
72 {
"curveconfig_linear.xml", {1417.89989, 1422.6653291129, 1427.2586262258}},
73 {
"curveconfig_linear_flat.xml", {1418.1, 1422.6653291129, 1424.131275}},
74 {
"curveconfig_loglinear.xml", {1417.89991117635, 1422.66452345277, 1427.26540106042}},
75 {
"curveconfig_loglinear_flat.xml", {1418.1, 1422.66452345277, 1424.131275}},
76 {
"curveconfig_cubic.xml", {1417.89988981896, 1422.67192914531, 1427.25983144911}},
77 {
"curveconfig_cubic_flat.xml", {1418.1, 1422.67192914531, 1424.131275}}};
79QuantLib::ext::shared_ptr<CommodityCurve> createCurve(
const string& inputDir,
80 const string& curveConfigFile =
"curveconfig.xml") {
83 Date asof(29, Jul, 2019);
85 QuantLib::ext::shared_ptr<Conventions> conventions = QuantLib::ext::make_shared<Conventions>();
86 string filename = inputDir +
"/conventions.xml";
87 conventions->fromFile(TEST_INPUT_FILE(filename));
88 InstrumentConventions::instance().setConventions(conventions);
91 filename = inputDir +
"/" + curveConfigFile;
93 filename = inputDir +
"/market.txt";
94 CSVLoader loader(TEST_INPUT_FILE(filename), TEST_INPUT_FILE(
"fixings.txt"),
false);
100 QuantLib::ext::shared_ptr<CommodityCurve> curve;
101 BOOST_REQUIRE_NO_THROW(curve = QuantLib::ext::make_shared<CommodityCurve>(asof, curveSpec, loader,
curveConfigs));
106QuantLib::ext::shared_ptr<TodaysMarket> createTodaysMarket(
const Date& asof,
const string& inputDir) {
108 auto conventions = QuantLib::ext::make_shared<Conventions>();
109 conventions->fromFile(TEST_INPUT_FILE(
string(inputDir +
"/conventions.xml")));
110 InstrumentConventions::instance().setConventions(conventions);
112 auto curveConfigs = QuantLib::ext::make_shared<CurveConfigurations>();
113 curveConfigs->fromFile(TEST_INPUT_FILE(
string(inputDir +
"/curveconfig.xml")));
115 auto todaysMarketParameters = QuantLib::ext::make_shared<TodaysMarketParameters>();
116 todaysMarketParameters->fromFile(TEST_INPUT_FILE(
string(inputDir +
"/todaysmarket.xml")));
118 string fixingsFile = inputDir +
"/fixings_" +
to_string(io::iso_date(asof)) +
".txt";
119 auto loader = QuantLib::ext::make_shared<CSVLoader>(TEST_INPUT_FILE(
string(inputDir +
"/market.txt")),
120 TEST_INPUT_FILE(fixingsFile),
false);
122 return QuantLib::ext::make_shared<TodaysMarket>(asof, todaysMarketParameters, loader,
curveConfigs);
125void checkCurve(
const QuantLib::ext::shared_ptr<PriceTermStructure>& priceCurve,
const map<Date, Real>& expectedValues) {
127 for (
const auto& kv : expectedValues) {
128 Real price = priceCurve->price(kv.first);
129 BOOST_CHECK_CLOSE(price, kv.second, 1e-12);
135BOOST_FIXTURE_TEST_SUITE(OREDataTestSuite, ore::test::TopLevelFixture)
137BOOST_AUTO_TEST_SUITE(CommodityCurveTests)
141 BOOST_TEST_MESSAGE(
"Testing commodity curve building with tenor based points quotes including ON and TN");
143 QuantLib::ext::shared_ptr<CommodityCurve> curve = createCurve(
"tenor_based_on_tn_points");
144 checkCurve(curve->commodityPriceCurve(), expectedCurve);
149 BOOST_TEST_MESSAGE(
"Testing commodity curve building with fixed date quotes");
151 QuantLib::ext::shared_ptr<CommodityCurve> curve = createCurve(
"fixed_date_points");
152 checkCurve(curve->commodityPriceCurve(), expectedCurve);
158 BOOST_TEST_MESSAGE(
"Testing with configuration file: " << curveConfigFile);
160 QuantLib::ext::shared_ptr<CommodityCurve> curve = createCurve(
"different_interpolations", curveConfigFile);
161 checkCurve(curve->commodityPriceCurve(), expectedInterpCurvePillars);
163 BOOST_REQUIRE(expectedInterpCurveOffPillars.count(curveConfigFile) == 1);
164 for (Size i = 0; i < offPillarDates.size(); i++) {
165 Real price = curve->commodityPriceCurve()->price(offPillarDates[i]);
166 Real expPrice = expectedInterpCurveOffPillars.at(curveConfigFile)[i];
167 BOOST_CHECK_CLOSE(price, expPrice, 1e-12);
174struct CommodityCurveTestCase {
182 {Date(30, Sep, 2019),
"basis/wti_midland_cm",
"NYMEX:FF"},
183 {Date(30, Sep, 2019),
"basis/wti_midland_tm",
"NYMEX:WTT"},
184 {Date(30, Sep, 2019),
"basis/wti_midland_cm_base_ave",
"NYMEX:FF"},
185 {Date(30, Sep, 2019),
"basis/houston_ship_channel",
"ICE:HXS"},
186 {Date(23, Jan, 2020),
"basis/wti_midland_cm",
"NYMEX:FF"},
187 {Date(23, Jan, 2020),
"basis/wti_midland_tm",
"NYMEX:WTT"},
188 {Date(23, Jan, 2020),
"basis/wti_midland_cm_base_ave",
"NYMEX:FF"},
189 {Date(23, Jan, 2020),
"basis/houston_ship_channel",
"ICE:HXS"},
190 {Date(27, Apr, 2020),
"power/pjm_wh_rt_peak_linear_flat",
"ICE:PDQ"},
191 {Date(27, Apr, 2020),
"power/pjm_wh_rt_peak_backward_flat",
"ICE:PDQ"},
192 {Date(27, Apr, 2020),
"power/pjm_wh_rt_peak_linear_flat_switch_priority",
"ICE:PDQ"}
196ostream&
operator<<(ostream& os, CommodityCurveTestCase testCase) {
197 return os <<
"[" << io::iso_date(testCase.asof) <<
"," << testCase.name <<
"," << testCase.curveName <<
"]";
202 BOOST_TEST_MESSAGE(
"Testing commodity curve building " << testCase <<
"...");
204 Settings::instance().evaluationDate() = testCase.asof;
205 QuantLib::ext::shared_ptr<TodaysMarket> tm;
206 BOOST_REQUIRE_NO_THROW(tm = createTodaysMarket(testCase.asof, testCase.name));
208 auto pts = tm->commodityPriceCurve(testCase.curveName);
210 for (
const Date& d : pts->pillarDates()) {
211 BOOST_TEST_MESSAGE(io::iso_date(d) <<
"," << fixed << setprecision(12) << pts->price(d));
218 vector<Date> expPillarDates;
219 string filename = testCase.name +
"/expected_" +
to_string(io::iso_date(testCase.asof)) +
".csv";
223 while (reader.
next()) {
227 expPillarDates.push_back(expiry);
230 Real calcPrice = pts->price(expiry);
231 BOOST_TEST_MESSAGE(io::iso_date(expiry) <<
"," << fixed << setprecision(12) << calcPrice);
232 BOOST_CHECK_SMALL(price - calcPrice, tol);
235 vector<Date> calcPillarDates = pts->pillarDates();
236 BOOST_CHECK_EQUAL_COLLECTIONS(expPillarDates.begin(), expPillarDates.end(),
237 calcPillarDates.begin(), calcPillarDates.end());
240 Real lastPrice = pts->price(calcPillarDates.back());
241 Date extrapDate = calcPillarDates.back() + 1 * Years;
242 Real extrapPrice = pts->price(extrapDate);
243 BOOST_CHECK_SMALL(lastPrice - extrapPrice, tol);
248BOOST_AUTO_TEST_SUITE_END()
250BOOST_AUTO_TEST_SUITE_END()
Utility class for loading market quotes and fixings from a file.
Size numberOfColumns() const
std::string get(const std::string &field) const
Commodity curve description.
Container class for all Curve Configurations.
Class for building a commodity price curve.
utility class to access CSV files
Market Datum Loader Implementation.
Curve configuration repository.
Curve requirements specification.
Date parseDate(const string &s)
Convert std::string to QuantLib::Date.
Real parseReal(const string &s)
Convert text to Real.
Market Datum Loader Interface.
std::string to_string(const LocationInfo &l)
ostream & operator<<(ostream &os, CommodityCurveTestCase testCase)
BOOST_DATA_TEST_CASE(testCommodityInterpolations, bdata::make(curveConfigFiles), curveConfigFile)
vector< CommodityCurveTestCase > commodityCurveTestCases
BOOST_AUTO_TEST_CASE(testCommodityCurveTenorBasedOnTnPoints)
vector< string > curveConfigs
string conversion utilities
An concrete implementation of the Market class that loads todays market and builds the required curve...