195 {
196
197 BOOST_TEST_MESSAGE(
198 "Testing equity Asian option trade building with constant vol term structure with average-strike");
199
200
201
202
203 std::vector<DiscreteAsianTestData> asians = {
204 {Option::Call, 90.0, 87.0, 0.06, 0.025, 0.0, 11.0 / 12.0, 2, 0.13, 1.51917595129},
205 {Option::Call, 90.0, 87.0, 0.06, 0.025, 0.0, 11.0 / 12.0, 4, 0.13, 1.67940165674},
206 {Option::Call, 90.0, 87.0, 0.06, 0.025, 0.0, 11.0 / 12.0, 8, 0.13, 1.75371215251},
207 {Option::Call, 90.0, 87.0, 0.06, 0.025, 0.0, 11.0 / 12.0, 12, 0.13, 1.77595318693},
208 {Option::Call, 90.0, 87.0, 0.06, 0.025, 0.0, 11.0 / 12.0, 26, 0.13, 1.81430536630},
209 {Option::Call, 90.0, 87.0, 0.06, 0.025, 0.0, 11.0 / 12.0, 52, 0.13, 1.82269246898},
210 {Option::Call, 90.0, 87.0, 0.06, 0.025, 0.0, 11.0 / 12.0, 100, 0.13, 1.83822402464},
211 {Option::Call, 90.0, 87.0, 0.06, 0.025, 1.0 / 12.0, 11.0 / 12.0, 2, 0.13, 1.51154400089},
212 {Option::Call, 90.0, 87.0, 0.06, 0.025, 1.0 / 12.0, 11.0 / 12.0, 4, 0.13, 1.67103508506},
213 {Option::Call, 90.0, 87.0, 0.06, 0.025, 1.0 / 12.0, 11.0 / 12.0, 8, 0.13, 1.74529684070},
214 {Option::Call, 90.0, 87.0, 0.06, 0.025, 1.0 / 12.0, 11.0 / 12.0, 12, 0.13, 1.76667074564},
215 {Option::Call, 90.0, 87.0, 0.06, 0.025, 1.0 / 12.0, 11.0 / 12.0, 26, 0.13, 1.80528400613},
216 {Option::Call, 90.0, 87.0, 0.06, 0.025, 1.0 / 12.0, 11.0 / 12.0, 52, 0.13, 1.81400883891},
217 {Option::Call, 90.0, 87.0, 0.06, 0.025, 1.0 / 12.0, 11.0 / 12.0, 100, 0.13, 1.82922901451},
218 {Option::Call, 90.0, 87.0, 0.06, 0.025, 3.0 / 12.0, 11.0 / 12.0, 2, 0.13, 1.49648170891},
219 {Option::Call, 90.0, 87.0, 0.06, 0.025, 3.0 / 12.0, 11.0 / 12.0, 4, 0.13, 1.65443100462},
220 {Option::Call, 90.0, 87.0, 0.06, 0.025, 3.0 / 12.0, 11.0 / 12.0, 8, 0.13, 1.72817806731},
221 {Option::Call, 90.0, 87.0, 0.06, 0.025, 3.0 / 12.0, 11.0 / 12.0, 12, 0.13, 1.74877367895},
222 {Option::Call, 90.0, 87.0, 0.06, 0.025, 3.0 / 12.0, 11.0 / 12.0, 26, 0.13, 1.78733801988},
223 {Option::Call, 90.0, 87.0, 0.06, 0.025, 3.0 / 12.0, 11.0 / 12.0, 52, 0.13, 1.79624826757},
224 {Option::Call, 90.0, 87.0, 0.06, 0.025, 3.0 / 12.0, 11.0 / 12.0, 100, 0.13, 1.81114186876}};
225
226 Date asof = Date(01, Feb, 2021);
228 QuantLib::ext::shared_ptr<EngineFactory> engineFactory;
229 QuantLib::ext::shared_ptr<Market> market;
230
231 for (const auto& a : asians) {
232 Time deltaT = a.length / (a.fixings - 1);
233 Date expiry;
234 vector<Date> fixingDates(a.fixings);
235 vector<std::string> strFixingDates(a.fixings);
236 for (Size i = 0; i < a.fixings; ++i) {
237 fixingDates[i] = (asof + static_cast<Integer>((a.firstFixing + i * deltaT) * 360 + 0.5));
238 strFixingDates[i] =
to_string(fixingDates[i]);
239 }
240 expiry = fixingDates[a.fixings - 1];
241
242 ScheduleDates scheduleDates(
"NullCalendar",
"",
"", strFixingDates);
244
245 market = QuantLib::ext::make_shared<TestMarket>(a.spot, expiry, a.riskFreeRate, a.dividendYield, a.volatility);
246 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
247 std::string productName = "EquityAsianOptionArithmeticStrike";
248 engineData->model(productName) = "BlackScholesMerton";
249 engineData->engine(productName) = "MCDiscreteArithmeticASEngine";
250 engineData->engineParameters(productName) = {{"ProcessType", "Discrete"},
251 {"BrownianBridge", "True"},
252 {"AntitheticVariate", "False"},
253 {"RequiredSamples", "1000"},
254 {"Seed", "3456789"}};
255 engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
256
257
258 Settings::instance().evaluationDate() = market->asofDate();
259
260
262 OptionData optionData(
"Long",
to_string(a.type),
"European",
true, {to_string(expiry)},
"Cash",
"",
263 premiumData, vector<Real>(), vector<Real>(), "", "", "", vector<string>(),
264 vector<string>(), "", "", "", "AverageStrike", "Arithmetic", boost::none, boost::none,
265 boost::none);
266
267 QuantLib::ext::shared_ptr<EquityAsianOption> asianOption = QuantLib::ext::make_shared<EquityAsianOption>(
268 env,
"EquityAsianOption", 1.0,
TradeStrike(a.strike,
"USD"), optionData, scheduleData,
269 QuantLib::ext::make_shared<EquityUnderlying>("COMPANY"), Date(), "USD");
270 BOOST_CHECK_NO_THROW(asianOption->build(engineFactory));
271
272
273 QuantLib::ext::shared_ptr<Instrument> qlInstrument = asianOption->instrument()->qlInstrument();
274
275 QuantLib::ext::shared_ptr<DiscreteAveragingAsianOption> discreteAsian =
276 QuantLib::ext::dynamic_pointer_cast<DiscreteAveragingAsianOption>(qlInstrument);
277
278 BOOST_CHECK(discreteAsian);
279 BOOST_CHECK_EQUAL(discreteAsian->exercise()->type(), Exercise::Type::European);
280 BOOST_CHECK_EQUAL(discreteAsian->exercise()->dates().size(), 1);
281 BOOST_CHECK_EQUAL(discreteAsian->exercise()->dates()[0], expiry);
282
283 QuantLib::ext::shared_ptr<TypePayoff> payoff = QuantLib::ext::dynamic_pointer_cast<TypePayoff>(discreteAsian->payoff());
284 BOOST_CHECK(payoff);
285 BOOST_CHECK_EQUAL(payoff->optionType(), a.type);
286
287 Real expectedPrice = a.expectedNPV;
288
289
290 BOOST_CHECK_SMALL(asianOption->instrument()->NPV() - expectedPrice, 2e-2);
291 }
292 }