Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
commodityschwartzmodel.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2022 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 "utilities.hpp"
20#include "toplevelfixture.hpp"
21
22#include <boost/test/unit_test.hpp>
23#include <boost/make_shared.hpp>
24#include <boost/test/data/test_case.hpp>
25
26#include <ql/currencies/america.hpp>
27#include <ql/math/interpolations/linearinterpolation.hpp>
28#include <ql/math/optimization/levenbergmarquardt.hpp>
29#include <ql/math/randomnumbers/rngtraits.hpp>
30#include <ql/math/statistics/incrementalstatistics.hpp>
31#include <ql/methods/montecarlo/multipathgenerator.hpp>
32#include <ql/methods/montecarlo/pathgenerator.hpp>
33#include <ql/quotes/simplequote.hpp>
34#include <ql/termstructures/yield/flatforward.hpp>
35#include <ql/time/calendars/target.hpp>
36#include <ql/time/daycounters/actual360.hpp>
37#include <ql/time/daycounters/actualactual.hpp>
38#include <ql/time/daycounters/thirty360.hpp>
39
45
46#include <fstream>
47#include <iostream>
48
49// fix for boost 1.64, see https://lists.boost.org/Archives/boost/2016/11/231756.php
50#if BOOST_VERSION >= 106400
51#include <boost/serialization/array_wrapper.hpp>
52#endif
53#include <boost/accumulators/accumulators.hpp>
54#include <boost/accumulators/statistics/covariance.hpp>
55#include <boost/accumulators/statistics/density.hpp>
56#include <boost/accumulators/statistics/error_of_mean.hpp>
57#include <boost/accumulators/statistics/mean.hpp>
58#include <boost/accumulators/statistics/stats.hpp>
59#include <boost/accumulators/statistics/variates/covariate.hpp>
60#include <boost/make_shared.hpp>
61
62using namespace QuantLib;
63using namespace QuantExt;
64
65using namespace boost::accumulators;
67
68namespace {
69
70std::vector<Period> periods = { 1*Days, 1*Years, 2*Years, 3*Years, 5*Years, 10*Years, 15*Years, 20*Years, 30*Years };
71std::vector<Real> prices { 100, 101, 102, 103, 105, 110, 115, 120, 130 };
72
73struct CommoditySchwartzModelTestData : public qle::test::TopLevelFixture {
74 CommoditySchwartzModelTestData(bool driftFreeState) :
75 ts(QuantLib::ext::make_shared<InterpolatedPriceCurve<Linear>>(periods, prices, ActualActual(ActualActual::ISDA), USDCurrency())) {
76
77 referenceDate = Date(10, November, 2022);
78 Settings::instance().evaluationDate() = referenceDate;
79
80 Handle<Quote> fx(QuantLib::ext::make_shared<SimpleQuote>(1.0));
81 sigma = 0.1;
82 kappa = 0.05;
83
84 parametrization = QuantLib::ext::make_shared<CommoditySchwartzParametrization>(USDCurrency(), "WTI", ts, fx, sigma, kappa, driftFreeState);
85 QL_REQUIRE(parametrization != NULL, "CommoditySchwartzParametrization has null pointer");
86
87 // TODO test Euler discretization
88 model =
89 QuantLib::ext::make_shared<CommoditySchwartzModel>(parametrization, CommoditySchwartzModel::Discretization::Exact);
90 }
91
92 SavedSettings backup;
93
94 Date referenceDate;
95 Handle<QuantExt::PriceTermStructure> ts;
96 Real kappa, sigma;
97 QuantLib::ext::shared_ptr<CommoditySchwartzParametrization> parametrization;
98 QuantLib::ext::shared_ptr<CommoditySchwartzModel> model;
99}; // CommoditySchwarzModelTestData
100
101} // namespace
102
103//BOOST_FIXTURE_TEST_SUITE(QuantExtTestSuite, CommoditySchwartzModelTestData)
104BOOST_FIXTURE_TEST_SUITE(QuantExtTestSuite, qle::test::TopLevelFixture)
105
106BOOST_AUTO_TEST_SUITE(CommoditySchwartzModelTest)
107
108std::vector<bool> driftFreeState{ true, false };
109std::vector<Size> steps{ 1, 52 };
110
111BOOST_DATA_TEST_CASE(testMartingaleProperty,
112 bdata::make(driftFreeState) * bdata::make(steps),
114
115 //BOOST_AUTO_TEST_CASE(testMartingaleProperty) {
116
117 BOOST_TEST_MESSAGE("Testing martingale property in the COM Schwartz model ...");
118
119 CommoditySchwartzModelTestData data(driftFreeState);
120 QuantLib::ext::shared_ptr<StochasticProcess> process = data.model->stateProcess();
121 QL_REQUIRE(process != NULL, "process has null pointer!");
122
123 Size n = 100000; // number of paths
124 Size seed = 42; // rng seed
125 Time t = 10.0; // simulation horizon
126 Time T = 20.0; // forward price maturity
127 //Size steps = 1;
128
129 TimeGrid grid(t, steps);
130 LowDiscrepancy::rsg_type sg = LowDiscrepancy::make_sequence_generator(steps, seed);
131 MultiPathGenerator<LowDiscrepancy::rsg_type> pg(process, grid, sg, false);
132 //MultiPathGeneratorMersenneTwister pg(process, grid, seed, true);
133
134 accumulator_set<double, stats<tag::mean, tag::variance, tag::error_of<tag::mean>>> acc_price, acc_state;
135
136 Array state(1);
137 for (Size j = 0; j < n; ++j) {
138 Sample<MultiPath> path = pg.next();
139 Size l = path.value[0].length() - 1;
140 state[0] = path.value[0][l];
141 Real price = data.model->forwardPrice(t, T, state);
142 acc_price(price);
143 acc_state(state[0]);
144 }
145
146 BOOST_TEST_MESSAGE("sigma = " << data.model->parametrization()->sigmaParameter());
147 BOOST_TEST_MESSAGE("kappa = " << data.model->parametrization()->kappaParameter());
148 BOOST_TEST_MESSAGE("samples = " << n);
149 BOOST_TEST_MESSAGE("steps = " << steps);
150 BOOST_TEST_MESSAGE("t = " << t);
151 BOOST_TEST_MESSAGE("T = " << T);
152
153 // Martingale test for F(t,T)
154 {
155 Real found = mean(acc_price);
156 Real expected = data.parametrization->priceCurve()->price(T);
157 Real error = error_of<tag::mean>(acc_price);
158
159 BOOST_TEST_MESSAGE("Check that E[F(t,T)] = F(0,T)");
160 BOOST_TEST_MESSAGE("Avg = " << found
161 << " +- " << error
162 << " vs expected " << expected);
163 BOOST_TEST(fabs(found - expected) < error, "Martingale test failed for F(t,T) evolution, found " << found << ", expected " << expected);
164 }
165
166 // Martingale test for the state variable
167 {
168 Real found = mean(acc_state);
169 Real expected = 0;
170 Real error = error_of<tag::mean>(acc_state);
171
172 BOOST_TEST_MESSAGE("Check that the mean of the state variable is zero");
173 BOOST_TEST_MESSAGE("Avg = " << found
174 << " +- " << error_of<tag::mean>(acc_state)
175 << " vs expected " << expected);
176 BOOST_TEST(fabs(found - expected) < error, "Martingale test failed for the state variable, found " << found << ", expected " << expected);
177 }
178
179 // Variance test for the state variable, implicit in the first test above
180 {
181 Real found = variance(acc_state);
182 Real expected = data.parametrization->variance(t);
183 // FIXME: What's the MC error here? I assume that the mean error is smaller than the error of variance estimate, so re-using it.
184 Real error = error_of<tag::mean>(acc_state);
185
186 QuantLib::ext::shared_ptr<CommoditySchwartzStateProcess> stateProcess = QuantLib::ext::dynamic_pointer_cast<CommoditySchwartzStateProcess>(process);
187 QL_REQUIRE(stateProcess, "state process is null");
188 Real expected2 = stateProcess->variance(0.0, 0.0, t);
189
190 // consistency check, should be identical
191 BOOST_TEST(fabs(expected - expected2) < 1e-10, "Inconsistent state variable variance " << expected << " vs " << expected2);
192
193 BOOST_TEST_MESSAGE("Check that the variance of the state variable matches expectation");
194 BOOST_TEST_MESSAGE("Var = " << found
195 << " +- " << error
196 << " vs expected " << expected);
197 BOOST_TEST(fabs(found - expected2) < error,
198 "Simulated variance of the state variable does match expectation, found " << found << ", expected " << expected);
199
200 }
201
202} // testMartingaleProperty
203
204
205BOOST_AUTO_TEST_SUITE_END()
206
207BOOST_AUTO_TEST_SUITE_END()
Interpolated price curve.
Definition: pricecurve.hpp:50
Schwartz (1997) one-factor model of the commodity price termstructure.
Schwartz commodity model parametrization.
COM state process for the one-factor Schwartz model.
base class for multi path generators
RandomVariable variance(const RandomVariable &r)
Interpolated price curve.
BOOST_DATA_TEST_CASE(testMartingaleProperty, bdata::make(driftFreeState) *bdata::make(steps), driftFreeState, steps)
std::vector< bool > driftFreeState
std::vector< Size > steps
Fixture that can be used at top level.
helper macros and methods for tests