Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
ored_commodityforward.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2018 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>
20#include <oret/toplevelfixture.hpp>
21
22#include <boost/make_shared.hpp>
23
24#include <ql/currencies/america.hpp>
25#include <ql/math/interpolations/linearinterpolation.hpp>
26#include <ql/termstructures/yield/flatforward.hpp>
27
29
34
35using namespace std;
36using namespace boost::unit_test_framework;
37using namespace QuantLib;
38using namespace QuantExt;
39using namespace ore::data;
40
41namespace {
42
43// testTolerance for Real comparison
44Real testTolerance = 1e-10;
45
46class TestMarket : public MarketImpl {
47public:
48 TestMarket() : MarketImpl(false) {
49 // Reference date and common day counter
50 asof_ = Date(19, Feb, 2018);
51 Actual365Fixed dayCounter;
52
53 // Add USD discount curve, discount = 1.0 everywhere
54 Handle<YieldTermStructure> discount(QuantLib::ext::make_shared<FlatForward>(asof_, 0.0, dayCounter));
55 yieldCurves_[make_tuple(Market::defaultConfiguration, YieldCurveType::Discount, "USD")] = discount;
56
57 // Add GOLD_USD price curve
58 vector<Date> dates = {asof_, Date(19, Feb, 2019)};
59 vector<Real> prices = {1346.0, 1348.0};
60 Handle<PriceTermStructure> priceCurve(
61 QuantLib::ext::make_shared<InterpolatedPriceCurve<Linear>>(asof_, dates, prices, dayCounter, USDCurrency()));
62 Handle<CommodityIndex> commIdx(QuantLib::ext::make_shared<CommoditySpotIndex>("GOLD_USD", NullCalendar(), priceCurve));
63 commodityIndices_[make_pair(Market::defaultConfiguration, "GOLD_USD")] = commIdx;
64 }
65};
66
67} // namespace
68
69BOOST_FIXTURE_TEST_SUITE(OREDataTestSuite, ore::test::TopLevelFixture)
70
71BOOST_AUTO_TEST_SUITE(CommodityForwardTests)
72
73BOOST_AUTO_TEST_CASE(testCommodityForwardTradeBuilding) {
74
75 BOOST_TEST_MESSAGE("Testing commodity forward trade building");
76
77 // Create market
78 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>();
79 Settings::instance().evaluationDate() = market->asofDate();
80
81 // Create engine factory
82 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
83 engineData->model("CommodityForward") = "DiscountedCashflows";
84 engineData->engine("CommodityForward") = "DiscountingCommodityForwardEngine";
85 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
86
87 // Base commodity values
88 string position = "Long";
89 string commodityName = "GOLD_USD";
90 string currency = "USD";
91 Real quantity = 100.0;
92 string maturity = "2019-02-19";
93 Real strike = 1340.0;
94
95 // Test the building of a commodity forward doesn't throw
96 Envelope envelope;
97 QuantLib::ext::shared_ptr<ore::data::CommodityForward> forward = QuantLib::ext::make_shared<ore::data::CommodityForward>(
98 envelope, position, commodityName, currency, quantity, maturity, strike);
99 BOOST_CHECK_NO_THROW(forward->build(engineFactory));
100
101 // Check the instrument was built as expected
102 QuantLib::ext::shared_ptr<Instrument> qlInstrument = forward->instrument()->qlInstrument();
103 QuantLib::ext::shared_ptr<QuantExt::CommodityForward> commodityForward =
104 QuantLib::ext::dynamic_pointer_cast<QuantExt::CommodityForward>(qlInstrument);
105 BOOST_CHECK(commodityForward);
106 BOOST_CHECK_EQUAL(commodityForward->position(), Position::Type::Long);
107 BOOST_CHECK_EQUAL(commodityForward->index()->name(), "COMM-GOLD_USD");
108 BOOST_CHECK_EQUAL(commodityForward->currency(), USDCurrency());
109 BOOST_CHECK_CLOSE(commodityForward->quantity(), 100.0, testTolerance);
110 BOOST_CHECK_EQUAL(commodityForward->maturityDate(), Date(19, Feb, 2019));
111 BOOST_CHECK_CLOSE(commodityForward->strike(), 1340.0, testTolerance);
112
113 // Check the price (simple because DF = 1.0, 100 * (1348 - 1340))
114 BOOST_CHECK_CLOSE(commodityForward->NPV(), 800.0, testTolerance);
115
116 // Check short
117 forward = QuantLib::ext::make_shared<ore::data::CommodityForward>(envelope, "Short", commodityName, currency, quantity,
118 maturity, strike);
119 BOOST_CHECK_NO_THROW(forward->build(engineFactory));
120 qlInstrument = forward->instrument()->qlInstrument();
121 commodityForward = QuantLib::ext::dynamic_pointer_cast<QuantExt::CommodityForward>(qlInstrument);
122 BOOST_CHECK(commodityForward);
123 BOOST_CHECK_EQUAL(commodityForward->position(), Position::Type::Short);
124 BOOST_CHECK_CLOSE(commodityForward->NPV(), -800.0, testTolerance);
125
126 // Check that negative quantity throws an error
127 forward = QuantLib::ext::make_shared<ore::data::CommodityForward>(envelope, position, commodityName, currency, -quantity,
128 maturity, strike);
129 BOOST_CHECK_THROW(forward->build(engineFactory), Error);
130
131 // Check that negative strike throws an error
132 forward = QuantLib::ext::make_shared<ore::data::CommodityForward>(envelope, position, commodityName, currency, quantity,
133 maturity, -strike);
134 BOOST_CHECK_THROW(forward->build(engineFactory), Error);
135
136 // Check that build fails when commodity name does not match that in the market
137 forward = QuantLib::ext::make_shared<ore::data::CommodityForward>(envelope, position, "GOLD", currency, quantity, maturity,
138 strike);
139 BOOST_CHECK_THROW(forward->build(engineFactory), Error);
140}
141
142BOOST_AUTO_TEST_CASE(testCommodityForwardFromXml) {
143
144 BOOST_TEST_MESSAGE("Testing parsing of commodity forward trade from XML");
145
146 // Create an XML string representation of the trade
147 string tradeXml;
148 tradeXml.append("<Portfolio>");
149 tradeXml.append(" <Trade id=\"CommodityForward_WTI_Oct_21\">");
150 tradeXml.append(" <TradeType>CommodityForward</TradeType>");
151 tradeXml.append(" <Envelope>");
152 tradeXml.append(" <CounterParty>CPTY_A</CounterParty>");
153 tradeXml.append(" <NettingSetId>CPTY_A</NettingSetId>");
154 tradeXml.append(" <AdditionalFields/>");
155 tradeXml.append(" </Envelope>");
156 tradeXml.append(" <CommodityForwardData>");
157 tradeXml.append(" <Position>Short</Position>");
158 tradeXml.append(" <Maturity>2021-10-31</Maturity>");
159 tradeXml.append(" <Name>COMDTY_WTI_USD</Name>");
160 tradeXml.append(" <Currency>USD</Currency>");
161 tradeXml.append(" <Strike>49.75</Strike>");
162 tradeXml.append(" <Quantity>500000</Quantity>");
163 tradeXml.append(" </CommodityForwardData>");
164 tradeXml.append(" </Trade>");
165 tradeXml.append("</Portfolio>");
166
167 // Load portfolio from XML string
168 Portfolio portfolio;
169 portfolio.fromXMLString(tradeXml);
170
171 // Extract CommodityForward trade from portfolio
172 QuantLib::ext::shared_ptr<Trade> trade = portfolio.trades().begin()->second;
173 QuantLib::ext::shared_ptr<ore::data::CommodityForward> commodityForward =
174 QuantLib::ext::dynamic_pointer_cast<ore::data::CommodityForward>(trade);
175
176 // Check fields after checking that the cast was successful
177 BOOST_CHECK(commodityForward);
178 BOOST_CHECK_EQUAL(commodityForward->tradeType(), "CommodityForward");
179 BOOST_CHECK_EQUAL(commodityForward->id(), "CommodityForward_WTI_Oct_21");
180 BOOST_CHECK_EQUAL(commodityForward->position(), "Short");
181 BOOST_CHECK_EQUAL(commodityForward->maturityDate(), "2021-10-31");
182 BOOST_CHECK_EQUAL(commodityForward->commodityName(), "COMDTY_WTI_USD");
183 BOOST_CHECK_EQUAL(commodityForward->currency(), "USD");
184 BOOST_CHECK_CLOSE(commodityForward->strike(), 49.75, testTolerance);
185 BOOST_CHECK_CLOSE(commodityForward->quantity(), 500000.0, testTolerance);
186}
187
188BOOST_AUTO_TEST_SUITE_END()
189
190BOOST_AUTO_TEST_SUITE_END()
Engine builder for commodity forward.
Serializable object holding generic trade data, reporting dimensions.
Definition: envelope.hpp:51
static const string defaultConfiguration
Default configuration label.
Definition: market.hpp:296
Market Implementation.
Definition: marketimpl.hpp:53
map< tuple< string, YieldCurveType, string >, Handle< YieldTermStructure > > yieldCurves_
Definition: marketimpl.hpp:208
map< pair< string, string >, QuantLib::Handle< QuantExt::CommodityIndex > > commodityIndices_
Definition: marketimpl.hpp:230
Serializable portfolio.
Definition: portfolio.hpp:43
const std::map< std::string, QuantLib::ext::shared_ptr< Trade > > & trades() const
Return the map tradeId -> trade.
Definition: portfolio.cpp:162
void fromXMLString(const std::string &xml)
Parse from XML string.
Definition: xmlutils.cpp:162
Commodity forward representation.
An implementation of the Market class that stores the required objects in maps.
Time maturity
Definition: utilities.cpp:66
BOOST_AUTO_TEST_CASE(testCommodityForwardTradeBuilding)
Portfolio class.