Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
Functions
commodityoption.cpp File Reference
#include <boost/test/unit_test.hpp>
#include <oret/toplevelfixture.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/make_shared.hpp>
#include <ql/currencies/america.hpp>
#include <ql/instruments/vanillaoption.hpp>
#include <ql/math/interpolations/linearinterpolation.hpp>
#include <ql/pricingengines/blackformula.hpp>
#include <ql/termstructures/volatility/equityfx/blackvariancecurve.hpp>
#include <ql/termstructures/yield/flatforward.hpp>
#include <qle/termstructures/pricecurve.hpp>
#include <ored/marketdata/marketimpl.hpp>
#include <ored/portfolio/builders/commodityoption.hpp>
#include <ored/portfolio/commodityoption.hpp>
#include <ored/portfolio/portfolio.hpp>

Go to the source code of this file.

Functions

 BOOST_AUTO_TEST_CASE (testCommodityOptionTradeBuilding)
 
 BOOST_AUTO_TEST_CASE (testCommodityOptionFromXml)
 
 BOOST_AUTO_TEST_CASE (testLongShortCallPutPrices)
 
 BOOST_AUTO_TEST_CASE (testCommodityOptionBuildExceptions)
 
 BOOST_AUTO_TEST_CASE (testCommodityOptionPremium)
 

Function Documentation

◆ BOOST_AUTO_TEST_CASE() [1/5]

BOOST_AUTO_TEST_CASE ( testCommodityOptionTradeBuilding  )

Definition at line 120 of file commodityoption.cpp.

120 {
121
122 BOOST_TEST_MESSAGE("Testing commodity option trade building");
123
124 // Common test data and setup
125 CommonData td;
126
127 // Test the building of a commodity option doesn't throw
128 OptionData optionData("Long", "Call", "European", td.payOffAtExpiry, td.expiry);
129 QuantLib::ext::shared_ptr<CommodityOption> option = QuantLib::ext::make_shared<CommodityOption>(
130 td.envelope, optionData, td.commodityName, td.currency, td.quantity, td.strike);
131 BOOST_CHECK_NO_THROW(option->build(td.engineFactory));
132
133 // Check the underlying instrument was built as expected
134 QuantLib::ext::shared_ptr<Instrument> qlInstrument = option->instrument()->qlInstrument();
135
136 QuantLib::ext::shared_ptr<VanillaOption> vanillaOption = QuantLib::ext::dynamic_pointer_cast<VanillaOption>(qlInstrument);
137 BOOST_CHECK(vanillaOption);
138 BOOST_CHECK_EQUAL(vanillaOption->exercise()->type(), Exercise::Type::European);
139 BOOST_CHECK_EQUAL(vanillaOption->exercise()->dates().size(), 1);
140 BOOST_CHECK_EQUAL(vanillaOption->exercise()->dates()[0], td.expiryDate);
141
142 QuantLib::ext::shared_ptr<TypePayoff> payoff = QuantLib::ext::dynamic_pointer_cast<TypePayoff>(vanillaOption->payoff());
143 BOOST_CHECK(payoff);
144 BOOST_CHECK_EQUAL(payoff->optionType(), Option::Type::Call);
145
146 // Calculate the expected price and check against cached price
147 // This is an extra check of the market etc.
148 // Know it is then safe to use the cached price elsewhere in this suite
149 Real forwardPrice = td.market->commodityPriceCurve(td.commodityName)->price(td.expiryDate);
150 DiscountFactor discount = td.market->discountCurve(td.currency)->discount(td.expiryDate);
151 Real variance = td.market->commodityVolatility(td.commodityName)->blackVariance(td.expiryDate, td.strike.value());
152 Real expectedPrice =
153 td.quantity * blackFormula(Option::Type::Call, td.strike.value(), forwardPrice, sqrt(variance), discount);
154 BOOST_CHECK_CLOSE(expectedPrice, cachedCallPrice, testTolerance);
155
156 // Check the price
157 BOOST_CHECK_CLOSE(option->instrument()->NPV(), expectedPrice, testTolerance);
158}
Serializable object holding option data.
Definition: optiondata.hpp:42
RandomVariable sqrt(RandomVariable x)
RandomVariable variance(const RandomVariable &r)
+ Here is the call graph for this function:

◆ BOOST_AUTO_TEST_CASE() [2/5]

BOOST_AUTO_TEST_CASE ( testCommodityOptionFromXml  )

Definition at line 160 of file commodityoption.cpp.

160 {
161
162 BOOST_TEST_MESSAGE("Testing parsing of commodity option trade from XML");
163
164 // Common test data and setup
165 CommonData td;
166
167 // Create an XML string representation of the trade
168 string tradeXml;
169 tradeXml.append("<Portfolio>");
170 tradeXml.append(" <Trade id=\"CommodityOption_Gold\">");
171 tradeXml.append(" <TradeType>CommodityOption</TradeType>");
172 tradeXml.append(" <Envelope>");
173 tradeXml.append(" <CounterParty>CPTY_A</CounterParty>");
174 tradeXml.append(" <NettingSetId>CPTY_A</NettingSetId>");
175 tradeXml.append(" <AdditionalFields/>");
176 tradeXml.append(" </Envelope>");
177 tradeXml.append(" <CommodityOptionData>");
178 tradeXml.append(" <OptionData>");
179 tradeXml.append(" <LongShort>Long</LongShort>");
180 tradeXml.append(" <OptionType>Call</OptionType>");
181 tradeXml.append(" <Style>European</Style>");
182 tradeXml.append(" <Settlement>Cash</Settlement>");
183 tradeXml.append(" <PayOffAtExpiry>false</PayOffAtExpiry>");
184 tradeXml.append(" <ExerciseDates>");
185 tradeXml.append(" <ExerciseDate>2019-02-19</ExerciseDate>");
186 tradeXml.append(" </ExerciseDates>");
187 tradeXml.append(" </OptionData>");
188 tradeXml.append(" <Name>GOLD_USD</Name>");
189 tradeXml.append(" <Currency>USD</Currency>");
190 tradeXml.append(" <Strike>1340</Strike>");
191 tradeXml.append(" <Quantity>100</Quantity>");
192 tradeXml.append(" </CommodityOptionData>");
193 tradeXml.append(" </Trade>");
194 tradeXml.append("</Portfolio>");
195
196 // Load portfolio from XML string
197 Portfolio portfolio;
198 portfolio.fromXMLString(tradeXml);
199
200 // Extract CommodityOption trade from portfolio
201 QuantLib::ext::shared_ptr<Trade> trade = portfolio.trades().begin()->second;
202 QuantLib::ext::shared_ptr<CommodityOption> option = QuantLib::ext::dynamic_pointer_cast<ore::data::CommodityOption>(trade);
203
204 // Check fields after checking that the cast was successful
205 BOOST_CHECK(option);
206 BOOST_CHECK_EQUAL(option->tradeType(), "CommodityOption");
207 BOOST_CHECK_EQUAL(option->id(), "CommodityOption_Gold");
208 BOOST_CHECK_EQUAL(option->asset(), "GOLD_USD");
209 BOOST_CHECK_EQUAL(option->currency(), "USD");
210 BOOST_CHECK_CLOSE(option->strike().value(), 1340, testTolerance);
211 BOOST_CHECK_CLOSE(option->quantity(), 100, testTolerance);
212 BOOST_CHECK_EQUAL(option->option().longShort(), "Long");
213 BOOST_CHECK_EQUAL(option->option().callPut(), "Call");
214 BOOST_CHECK_EQUAL(option->option().style(), "European");
215 BOOST_CHECK_EQUAL(option->option().exerciseDates().size(), 1);
216 BOOST_CHECK_EQUAL(option->option().exerciseDates()[0], "2019-02-19");
217
218 // Build the option and check the price
219 BOOST_CHECK_NO_THROW(option->build(td.engineFactory));
220 BOOST_CHECK_CLOSE(option->instrument()->NPV(), cachedCallPrice, testTolerance);
221
222 // Make trade short call and test price is negated
223 replace_all(tradeXml, ">Long<", ">Short<");
224 portfolio.clear();
225 portfolio.fromXMLString(tradeXml);
226 trade = portfolio.trades().begin()->second;
227 BOOST_CHECK_NO_THROW(trade->build(td.engineFactory));
228 BOOST_CHECK_CLOSE(trade->instrument()->NPV(), -cachedCallPrice, testTolerance);
229
230 // Make trade short put and test price
231 replace_all(tradeXml, ">Call<", ">Put<");
232 portfolio.clear();
233 portfolio.fromXMLString(tradeXml);
234 trade = portfolio.trades().begin()->second;
235 BOOST_CHECK_NO_THROW(trade->build(td.engineFactory));
236 BOOST_CHECK_CLOSE(trade->instrument()->NPV(), -cachedPutPrice, testTolerance);
237
238 // Make trade long put and test price
239 replace_all(tradeXml, ">Short<", ">Long<");
240 portfolio.clear();
241 portfolio.fromXMLString(tradeXml);
242 trade = portfolio.trades().begin()->second;
243 BOOST_CHECK_NO_THROW(trade->build(td.engineFactory));
244 BOOST_CHECK_CLOSE(trade->instrument()->NPV(), cachedPutPrice, testTolerance);
245}
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 clear()
Clear the portfolio.
Definition: portfolio.cpp:39
void fromXMLString(const std::string &xml)
Parse from XML string.
Definition: xmlutils.cpp:162
+ Here is the call graph for this function:

◆ BOOST_AUTO_TEST_CASE() [3/5]

BOOST_AUTO_TEST_CASE ( testLongShortCallPutPrices  )

Definition at line 247 of file commodityoption.cpp.

247 {
248
249 BOOST_TEST_MESSAGE("Testing commodity option prices");
250
251 // Common test data and setup
252 CommonData td;
253
254 // Option
255 QuantLib::ext::shared_ptr<CommodityOption> option;
256
257 // Long call
258 OptionData optionData("Long", "Call", "European", td.payOffAtExpiry, td.expiry);
259 option = QuantLib::ext::make_shared<CommodityOption>(td.envelope, optionData, td.commodityName, td.currency,
260 td.quantity, td.strike);
261 option->build(td.engineFactory);
262 BOOST_CHECK_CLOSE(option->instrument()->NPV(), cachedCallPrice, testTolerance);
263
264 // Short call
265 optionData = OptionData("Short", "Call", "European", td.payOffAtExpiry, td.expiry);
266 option = QuantLib::ext::make_shared<CommodityOption>(td.envelope, optionData, td.commodityName, td.currency,
267 td.quantity, td.strike);
268 option->build(td.engineFactory);
269 BOOST_CHECK_CLOSE(option->instrument()->NPV(), -cachedCallPrice, testTolerance);
270
271 // Long put
272 optionData = OptionData("Long", "Put", "European", td.payOffAtExpiry, td.expiry);
273 option = QuantLib::ext::make_shared<CommodityOption>(td.envelope, optionData, td.commodityName, td.currency,
274 td.quantity, td.strike);
275 option->build(td.engineFactory);
276 BOOST_CHECK_CLOSE(option->instrument()->NPV(), cachedPutPrice, testTolerance);
277
278 // Short put
279 optionData = OptionData("Short", "Put", "European", td.payOffAtExpiry, td.expiry);
280 option = QuantLib::ext::make_shared<CommodityOption>(td.envelope, optionData, td.commodityName, td.currency, td.quantity,
281 td.strike);
282 option->build(td.engineFactory);
283 BOOST_CHECK_CLOSE(option->instrument()->NPV(), -cachedPutPrice, testTolerance);
284}

◆ BOOST_AUTO_TEST_CASE() [4/5]

BOOST_AUTO_TEST_CASE ( testCommodityOptionBuildExceptions  )

Definition at line 286 of file commodityoption.cpp.

286 {
287
288 BOOST_TEST_MESSAGE("Testing commodity option exceptions during building");
289
290 // Common test data and setup
291 CommonData td;
292
293 // Option
294 QuantLib::ext::shared_ptr<CommodityOption> option;
295
296 // Negative strike throws
297 OptionData optionData("Long", "Call", "European", td.payOffAtExpiry, td.expiry);
298 TradeStrike ts(TradeStrike::Type::Price, -td.strike.value());
299 option = QuantLib::ext::make_shared<CommodityOption>(td.envelope, optionData, td.commodityName, td.currency, td.quantity, ts);
300 BOOST_CHECK_THROW(option->build(td.engineFactory), Error);
301
302
303 // Name of commodity with no market data throws
304 option = QuantLib::ext::make_shared<CommodityOption>(td.envelope, optionData, "GOLD_USD_MISSING", td.currency,
305 td.quantity, td.strike);
306 BOOST_CHECK_THROW(option->build(td.engineFactory), Error);
307
308 // Non-European OptionData style throws
309 optionData = OptionData("Long", "Call", "American", td.payOffAtExpiry, td.expiry);
310 option = QuantLib::ext::make_shared<CommodityOption>(td.envelope, optionData, td.commodityName, td.currency, td.quantity,
311 td.strike);
312 BOOST_CHECK_THROW(option->build(td.engineFactory), Error);
313
314 // More than one expiry date throws
315 vector<string> extraExpiries = td.expiry;
316 extraExpiries.push_back("2019-08-19");
317 optionData = OptionData("Long", "Call", "European", td.payOffAtExpiry, extraExpiries);
318 option = QuantLib::ext::make_shared<CommodityOption>(td.envelope, optionData, td.commodityName, td.currency,
319 td.quantity, td.strike);
320 BOOST_CHECK_THROW(option->build(td.engineFactory), Error);
321}

◆ BOOST_AUTO_TEST_CASE() [5/5]

BOOST_AUTO_TEST_CASE ( testCommodityOptionPremium  )

Definition at line 323 of file commodityoption.cpp.

323 {
324
325 BOOST_TEST_MESSAGE("Testing commodity option premium works");
326
327 // Common test data and setup
328 CommonData td;
329
330 // Premium
331 Real premium = 5000;
332 Date premiumDate(21, Feb, 2018);
333
334 // Create option
335 OptionData optionData("Long", "Call", "European", td.payOffAtExpiry, td.expiry, "Cash", "",
336 PremiumData{premium, td.currency, Date(21, Feb, 2018)});
337 QuantLib::ext::shared_ptr<CommodityOption> option = QuantLib::ext::make_shared<CommodityOption>(
338 td.envelope, optionData, td.commodityName, td.currency, td.quantity, td.strike);
339
340 // Test building succeeds
341 BOOST_CHECK_NO_THROW(option->build(td.engineFactory));
342
343 // Test that price is correct
344 DiscountFactor premiumDiscount = td.market->discountCurve(td.currency)->discount(premiumDate);
345 BOOST_CHECK_CLOSE(option->instrument()->NPV(), cachedCallPrice - premiumDiscount * premium, testTolerance);
346}
Serializable object holding premium data.
Definition: premiumdata.hpp:37