30#include <oret/toplevelfixture.hpp>
31#include <boost/test/unit_test.hpp>
32#include <boost/timer/timer.hpp>
33#include <ql/currencies/america.hpp>
34#include <ql/exercise.hpp>
35#include <ql/math/interpolations/linearinterpolation.hpp>
36#include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp>
37#include <ql/termstructures/yield/flatforward.hpp>
38#include <ql/time/calendars/unitedstates.hpp>
46using boost::unit_test_framework::test_suite;
50 QuantLib::Option::Type optionType;
53BOOST_FIXTURE_TEST_SUITE(OREPlusCommodityTestSuite, ore::test::TopLevelFixture)
55BOOST_AUTO_TEST_SUITE(CommodityApoTest)
59 BOOST_TEST_MESSAGE(
"Testing Commodity APO Analytical Approximation vs MC Pricing");
63 Date today(5, Feb, 2019);
64 Settings::instance().evaluationDate() = today;
65 Calendar cal = UnitedStates(UnitedStates::Settlement);
68 std::vector<Date> dates = {today + 1 * Years, today + 5 * Years, today + 10 * Years};
69 std::vector<Real> prices = {100.0, 100.0, 100.0};
70 DayCounter dc = Actual365Fixed();
71 Handle<QuantExt::PriceTermStructure> priceCurve(
73 priceCurve->enableExtrapolation();
76 Handle<Quote> rateQuote(QuantLib::ext::make_shared<SimpleQuote>(0.01));
77 Handle<YieldTermStructure> discountCurve(QuantLib::ext::make_shared<FlatForward>(today, rateQuote, dc, Compounded, Annual));
80 Handle<QuantLib::BlackVolTermStructure> vol(QuantLib::ext::make_shared<QuantLib::BlackConstantVol>(today, cal, 0.3, dc));
84 QuantLib::ext::shared_ptr<PricingEngine> analyticalEngine =
85 QuantLib::ext::make_shared<CommodityAveragePriceOptionAnalyticalEngine>(discountCurve, vol, beta);
89 QuantLib::ext::shared_ptr<PricingEngine> mcEngine =
90 QuantLib::ext::make_shared<CommodityAveragePriceOptionMonteCarloEngine>(discountCurve, vol, samples, beta);
94 std::string
name =
"CL";
95 Period term = 1 * Months;
98 std::vector<ApoTestCase> cases = {{100.0, Option::Call}, {120.0, Option::Call}, {80.0, Option::Call},
99 {100.0, Option::Put}, {120.0, Option::Put}, {80.0, Option::Put}};
101 for (Size k = 0; k < cases.size(); ++k) {
103 Real strikePrice = cases[k].strikePrice;
104 QuantLib::Option::Type optionType = cases[k].optionType;
105 std::string optionTypeString = (optionType == Option::Call ?
"Call" :
"Put");
108 for (Size i = 1; i <= 10; ++i) {
111 Period startTerm = i * Years;
112 Date startDate = today + startTerm;
113 Date endDate = startDate + term;
114 Date payDate = endDate;
115 QuantLib::ext::shared_ptr<CommoditySpotIndex> index = QuantLib::ext::make_shared<CommoditySpotIndex>(
name, cal, priceCurve);
116 QuantLib::ext::shared_ptr<CommodityIndexedAverageCashFlow> flow =
117 QuantLib::ext::make_shared<CommodityIndexedAverageCashFlow>(quantity, startDate, endDate, payDate, index);
118 QuantLib::ext::shared_ptr<Exercise> exercise = QuantLib::ext::make_shared<EuropeanExercise>(endDate);
120 QuantLib::ext::shared_ptr<CommodityAveragePriceOption> apo =
121 QuantLib::ext::make_shared<CommodityAveragePriceOption>(flow, exercise, quantity, strikePrice, optionType);
123 boost::timer::cpu_timer tan;
124 apo->setPricingEngine(analyticalEngine);
125 Real anPrice = apo->NPV();
127 Real anTime = tan.elapsed().wall * 1e-6;
129 boost::timer::cpu_timer tmc;
130 apo->setPricingEngine(mcEngine);
131 Real mcPrice = apo->NPV();
132 Real mcTime = tmc.elapsed().wall * 1e-6;
134 Real error1 = 100.0 * fabs(mcPrice - anPrice) / mcPrice;
135 Real error2 = 100.0 * fabs(mcPrice - anPrice) / anPrice;
137 BOOST_TEST_MESSAGE(optionTypeString <<
" " << std::fixed << std::setprecision(2) << strikePrice <<
" "
138 << startTerm <<
" Analytical vs MC price: " << std::fixed
139 << std::setprecision(2) << anPrice <<
" vs " << mcPrice <<
" diff "
140 << anPrice - mcPrice <<
" error " << std::max(error1, error2) <<
"% ("
141 << anTime <<
" ms, " << mcTime <<
" ms)");
142 BOOST_CHECK_CLOSE(anPrice, mcPrice, 1.0);
147BOOST_AUTO_TEST_SUITE_END()
148BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_CASE(testCommodityAPO)