Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
discountingcommodityforwardengine.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 "toplevelfixture.hpp"
20#include <boost/make_shared.hpp>
21#include <boost/test/unit_test.hpp>
22#include <ql/currencies/america.hpp>
23#include <ql/settings.hpp>
24#include <ql/termstructures/yield/discountcurve.hpp>
25
28
29using namespace std;
30using namespace boost::unit_test_framework;
31using namespace QuantLib;
32using namespace QuantExt;
33
34BOOST_FIXTURE_TEST_SUITE(QuantExtTestSuite, qle::test::TopLevelFixture)
35
36BOOST_AUTO_TEST_SUITE(DiscountingCommodityForwardEngineTest)
37
39
40 BOOST_TEST_MESSAGE("Testing discounting commodity forward engine pricing");
41
42 SavedSettings backup;
43
44 // Tolerance for npv comparison
45 Real tolerance = 1e-10;
46
47 // Commodity forward base data
48 Date asof(19, Feb, 2018);
49 string name("GOLD_USD");
50 USDCurrency currency;
51 Date maturity(19, Feb, 2019);
52
53 // Day counter for time
54 Actual365Fixed dayCounter;
55
56 // Discount curve
57 vector<Date> dates(2);
58 vector<DiscountFactor> dfs(2);
59 dates[0] = asof;
60 dfs[0] = 1.0;
61 dates[1] = maturity;
62 dfs[1] = 0.85;
63 Handle<YieldTermStructure> discountCurve(QuantLib::ext::make_shared<InterpolatedDiscountCurve<LogLinear> >(
64 InterpolatedDiscountCurve<LogLinear>(dates, dfs, dayCounter)));
65
66 // Commodity Price curve
67 vector<Real> prices(2);
68 prices[0] = 1346.0;
69 prices[1] = 1384.0;
70 Handle<PriceTermStructure> priceCurve(
71 QuantLib::ext::make_shared<InterpolatedPriceCurve<Linear> >(asof, dates, prices, dayCounter, USDCurrency()));
72
73 // Create the engine
74 QuantLib::ext::shared_ptr<DiscountingCommodityForwardEngine> engine =
75 QuantLib::ext::make_shared<DiscountingCommodityForwardEngine>(discountCurve);
76
77 // Set evaluation date
78 Settings::instance().evaluationDate() = asof;
79
80 // Long 100 units with strike 1380.0
81 QuantLib::ext::shared_ptr<CommodityIndex> index = QuantLib::ext::make_shared<CommoditySpotIndex>(
82 name, NullCalendar(), priceCurve);
83 Position::Type position = Position::Long;
84 Real quantity = 100;
85 Real strike = 1380.0;
86 QuantLib::ext::shared_ptr<CommodityForward> forward =
87 QuantLib::ext::make_shared<CommodityForward>(index, currency, position, quantity, maturity, strike);
88 forward->setPricingEngine(engine);
89 BOOST_CHECK_CLOSE(forward->NPV(), quantity * (prices[1] - strike) * dfs[1], tolerance);
90
91 // Short 100 units with strike 1380.0
92 position = Position::Short;
93 forward = QuantLib::ext::make_shared<CommodityForward>(index, currency, position, quantity, maturity, strike);
94 forward->setPricingEngine(engine);
95 BOOST_CHECK_CLOSE(forward->NPV(), -quantity * (prices[1] - strike) * dfs[1], tolerance);
96
97 // Short 50 units with strike 1380.0
98 quantity = 50.0;
99 forward = QuantLib::ext::make_shared<CommodityForward>(index, currency, position, quantity, maturity, strike);
100 forward->setPricingEngine(engine);
101 BOOST_CHECK_CLOSE(forward->NPV(), -quantity * (prices[1] - strike) * dfs[1], tolerance);
102
103 // Short 50 units with strike 1375.0
104 strike = 1375.0;
105 forward = QuantLib::ext::make_shared<CommodityForward>(index, currency, position, quantity, maturity, strike);
106 forward->setPricingEngine(engine);
107 BOOST_CHECK_CLOSE(forward->NPV(), -quantity * (prices[1] - strike) * dfs[1], tolerance);
108
109 // Bring maturity of forward in 6 months
110 maturity = Date(19, Aug, 2018);
111 forward = QuantLib::ext::make_shared<CommodityForward>(index, currency, position, quantity, maturity, strike);
112 forward->setPricingEngine(engine);
113 BOOST_CHECK_CLOSE(forward->NPV(),
114 -quantity * (priceCurve->price(maturity) - strike) * discountCurve->discount(maturity),
115 tolerance);
116
117 // Make maturity of forward equal to today
118 forward = QuantLib::ext::make_shared<CommodityForward>(index, currency, position, quantity, asof, strike);
119 // includeReferenceDateEvents_ of Settings is false by default => value should equal 0
120 forward->setPricingEngine(engine);
121 BOOST_CHECK_CLOSE(forward->NPV(), 0.0, tolerance);
122 // Set includeReferenceDateEvents_ of Settings to true => value should be today's price - strike
123 Settings::instance().includeReferenceDateEvents() = true;
124 forward->recalculate();
125 BOOST_CHECK_CLOSE(forward->NPV(), -quantity * (prices[0] - strike), tolerance);
126 // Override behaviour in engine i.e. don't include flows on reference date even when
127 // Settings::instance().includeReferenceDateEvents() is true
128 engine = QuantLib::ext::make_shared<DiscountingCommodityForwardEngine>(discountCurve, false);
129 forward->setPricingEngine(engine);
130 BOOST_CHECK_CLOSE(forward->NPV(), 0.0, tolerance);
131 // Trying the other way around should not work as the trade is marked as expired
132 Settings::instance().includeReferenceDateEvents() = false;
133 engine = QuantLib::ext::make_shared<DiscountingCommodityForwardEngine>(discountCurve, true);
134 forward->setPricingEngine(engine);
135 BOOST_CHECK_CLOSE(forward->NPV(), 0.0, tolerance);
136
137 // Reinstate original maturity and change the npv date in the engine to 2 days after asof
138 maturity = Date(19, Feb, 2019);
139 forward = QuantLib::ext::make_shared<CommodityForward>(index, currency, position, quantity, maturity, strike);
140 Date npvDate = asof + 2 * Days;
141 engine = QuantLib::ext::make_shared<DiscountingCommodityForwardEngine>(discountCurve, boost::none, npvDate);
142 forward->setPricingEngine(engine);
143 DiscountFactor npvDateDiscount = discountCurve->discount(npvDate);
144 BOOST_CHECK_CLOSE(forward->NPV(), -quantity * (prices[1] - strike) * dfs[1] / npvDateDiscount, tolerance);
145}
146
147BOOST_AUTO_TEST_SUITE_END()
148
149BOOST_AUTO_TEST_SUITE_END()
InterpolatedDiscountCurve based on loglinear interpolation of DiscountFactors.
Interpolated price curve.
Definition: pricecurve.hpp:50
Engine to value a commodity forward contract.
Interpolated price curve.
BOOST_AUTO_TEST_CASE(testPricing)
Fixture that can be used at top level.