99 {
100
101 BOOST_TEST_MESSAGE("Testing commodity Asian option trade building with constant vol term structure");
102
103
104
105
106
107
108
109
110
111
112
113
114
115 std::vector<DiscreteAsianTestData> asians = {
116 {Option::Put, 90.0, 87.0, 0.06, 0.025, 0.0, 11.0 / 12.0, 2, 0.13, 1.3942835683},
117 {Option::Put, 90.0, 87.0, 0.06, 0.025, 0.0, 11.0 / 12.0, 4, 0.13, 1.5852442983},
118 {Option::Put, 90.0, 87.0, 0.06, 0.025, 0.0, 11.0 / 12.0, 8, 0.13, 1.66970673},
119 {Option::Put, 90.0, 87.0, 0.06, 0.025, 0.0, 11.0 / 12.0, 12, 0.13, 1.6980019214},
120 {Option::Put, 90.0, 87.0, 0.06, 0.025, 0.0, 11.0 / 12.0, 26, 0.13, 1.7255070456},
121 {Option::Put, 90.0, 87.0, 0.06, 0.025, 0.0, 11.0 / 12.0, 52, 0.13, 1.7401553533},
122 {Option::Put, 90.0, 87.0, 0.06, 0.025, 0.0, 11.0 / 12.0, 100, 0.13, 1.7478303712},
123 {Option::Put, 90.0, 87.0, 0.06, 0.025, 1.0 / 12.0, 11.0 / 12.0, 2, 0.13, 1.8496053697},
124 {Option::Put, 90.0, 87.0, 0.06, 0.025, 1.0 / 12.0, 11.0 / 12.0, 4, 0.13, 2.0111495205},
125 {Option::Put, 90.0, 87.0, 0.06, 0.025, 1.0 / 12.0, 11.0 / 12.0, 8, 0.13, 2.0852138818},
126 {Option::Put, 90.0, 87.0, 0.06, 0.025, 1.0 / 12.0, 11.0 / 12.0, 12, 0.13, 2.1105094397},
127 {Option::Put, 90.0, 87.0, 0.06, 0.025, 1.0 / 12.0, 11.0 / 12.0, 26, 0.13, 2.1346526695},
128 {Option::Put, 90.0, 87.0, 0.06, 0.025, 1.0 / 12.0, 11.0 / 12.0, 52, 0.13, 2.147489651},
129 {Option::Put, 90.0, 87.0, 0.06, 0.025, 1.0 / 12.0, 11.0 / 12.0, 100, 0.13, 2.154728109},
130 {Option::Put, 90.0, 87.0, 0.06, 0.025, 3.0 / 12.0, 11.0 / 12.0, 2, 0.13, 2.63315092584},
131 {Option::Put, 90.0, 87.0, 0.06, 0.025, 3.0 / 12.0, 11.0 / 12.0, 4, 0.13, 2.76723962361},
132 {Option::Put, 90.0, 87.0, 0.06, 0.025, 3.0 / 12.0, 11.0 / 12.0, 8, 0.13, 2.83124836881},
133 {Option::Put, 90.0, 87.0, 0.06, 0.025, 3.0 / 12.0, 11.0 / 12.0, 12, 0.13, 2.84290301412},
134 {Option::Put, 90.0, 87.0, 0.06, 0.025, 3.0 / 12.0, 11.0 / 12.0, 26, 0.13, 2.88179560417},
135 {Option::Put, 90.0, 87.0, 0.06, 0.025, 3.0 / 12.0, 11.0 / 12.0, 52, 0.13, 2.88447044543},
136 {Option::Put, 90.0, 87.0, 0.06, 0.025, 3.0 / 12.0, 11.0 / 12.0, 100, 0.13, 2.89985329603}};
137
138 Date asof = Date(01, Feb, 2021);
140 QuantLib::ext::shared_ptr<EngineFactory> engineFactory;
141 QuantLib::ext::shared_ptr<Market> market;
142
143 for (const auto& a : asians) {
144 Time deltaT = a.length / (a.fixings - 1);
145 Date expiry;
146 vector<Date> fixingDates(a.fixings);
147 vector<std::string> strFixingDates(a.fixings);
148 for (Size i = 0; i < a.fixings; ++i) {
149 fixingDates[i] = (asof + static_cast<Integer>((a.firstFixing + i * deltaT) * 360 + 0.5));
150 strFixingDates[i] =
to_string(fixingDates[i]);
151 }
152 expiry = fixingDates[a.fixings - 1];
153
154 ScheduleDates scheduleDates(
"NullCalendar",
"",
"", strFixingDates);
156
157 market = QuantLib::ext::make_shared<TestMarket>(a.spot, expiry, a.riskFreeRate, a.convenienceYield, a.volatility);
158 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
159 std::string productName = "CommodityAsianOptionArithmeticPrice";
160 engineData->model(productName) = "BlackScholesMerton";
161 engineData->engine(productName) = "MCDiscreteArithmeticAPEngine";
162 engineData->engineParameters(productName) = {{"ProcessType", "Discrete"}, {"BrownianBridge", "True"},
163 {"AntitheticVariate", "False"}, {"ControlVariate", "True"},
164 {"RequiredSamples", "2047"}, {"Seed", "0"}};
165 engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
166
167
168 Settings::instance().evaluationDate() = market->asofDate();
169
170
172 OptionData optionData(
"Long",
to_string(a.type),
"European",
true, {to_string(expiry)},
"Cash",
"",
173 premiumData, vector<Real>(), vector<Real>(), "", "", "", vector<string>(),
174 vector<string>(), "", "", "", "Asian", "Arithmetic", boost::none, boost::none,
175 boost::none);
176
177 QuantLib::ext::shared_ptr<CommodityAsianOption> asianOption = QuantLib::ext::make_shared<CommodityAsianOption>(
178 env,
"CommodityAsianOption", 1.0,
TradeStrike(a.strike,
"USD"), optionData, scheduleData,
179 QuantLib::ext::make_shared<CommodityUnderlying>("ALU_USD", 1.0, "Spot", 0, 0, ""), Date(), "USD");
180 BOOST_CHECK_NO_THROW(asianOption->build(engineFactory));
181
182
183 QuantLib::ext::shared_ptr<Instrument> qlInstrument = asianOption->instrument()->qlInstrument();
184
185 QuantLib::ext::shared_ptr<DiscreteAveragingAsianOption> discreteAsian =
186 QuantLib::ext::dynamic_pointer_cast<DiscreteAveragingAsianOption>(qlInstrument);
187
188 BOOST_CHECK(discreteAsian);
189 BOOST_CHECK_EQUAL(discreteAsian->exercise()->type(), Exercise::Type::European);
190 BOOST_CHECK_EQUAL(discreteAsian->exercise()->dates().size(), 1);
191 BOOST_CHECK_EQUAL(discreteAsian->exercise()->dates()[0], expiry);
192
193 QuantLib::ext::shared_ptr<TypePayoff> payoff = QuantLib::ext::dynamic_pointer_cast<TypePayoff>(discreteAsian->payoff());
194 BOOST_CHECK(payoff);
195 BOOST_CHECK_EQUAL(payoff->optionType(), a.type);
196
197 Real expectedPrice = a.expectedNPV;
198
199
200 BOOST_CHECK_SMALL(asianOption->instrument()->NPV() - expectedPrice, 2e-2);
201 }
202 }
Serializable object holding generic trade data, reporting dimensions.
Serializable object holding option data.
Serializable object holding premium data.
Serializable schedule data.
Serializable object holding schedule Dates data.
std::string to_string(const LocationInfo &l)