270 {
271
272 BOOST_TEST_MESSAGE("Testing finite-difference engine "
273 "for American options...");
274
275
276
277
278
279
280 AmericanOptionData juValues[] = {
281
282 {Option::Put, 35.00, 40.00, 0.0, 0.0488, 0.0833, 0.2, 0.006},
283 {Option::Put, 35.00, 40.00, 0.0, 0.0488, 0.3333, 0.2, 0.201},
284 {Option::Put, 35.00, 40.00, 0.0, 0.0488, 0.5833, 0.2, 0.433},
285
286 {Option::Put, 40.00, 40.00, 0.0, 0.0488, 0.0833, 0.2, 0.851},
287 {Option::Put, 40.00, 40.00, 0.0, 0.0488, 0.3333, 0.2, 1.576},
288 {Option::Put, 40.00, 40.00, 0.0, 0.0488, 0.5833, 0.2, 1.984},
289
290 {Option::Put, 45.00, 40.00, 0.0, 0.0488, 0.0833, 0.2, 5.000},
291 {Option::Put, 45.00, 40.00, 0.0, 0.0488, 0.3333, 0.2, 5.084},
292 {Option::Put, 45.00, 40.00, 0.0, 0.0488, 0.5833, 0.2, 5.260},
293
294 {Option::Put, 35.00, 40.00, 0.0, 0.0488, 0.0833, 0.3, 0.078},
295 {Option::Put, 35.00, 40.00, 0.0, 0.0488, 0.3333, 0.3, 0.697},
296 {Option::Put, 35.00, 40.00, 0.0, 0.0488, 0.5833, 0.3, 1.218},
297
298 {Option::Put, 40.00, 40.00, 0.0, 0.0488, 0.0833, 0.3, 1.309},
299 {Option::Put, 40.00, 40.00, 0.0, 0.0488, 0.3333, 0.3, 2.477},
300 {Option::Put, 40.00, 40.00, 0.0, 0.0488, 0.5833, 0.3, 3.161},
301
302 {Option::Put, 45.00, 40.00, 0.0, 0.0488, 0.0833, 0.3, 5.059},
303 {Option::Put, 45.00, 40.00, 0.0, 0.0488, 0.3333, 0.3, 5.699},
304 {Option::Put, 45.00, 40.00, 0.0, 0.0488, 0.5833, 0.3, 6.231},
305
306 {Option::Put, 35.00, 40.00, 0.0, 0.0488, 0.0833, 0.4, 0.247},
307 {Option::Put, 35.00, 40.00, 0.0, 0.0488, 0.3333, 0.4, 1.344},
308 {Option::Put, 35.00, 40.00, 0.0, 0.0488, 0.5833, 0.4, 2.150},
309
310 {Option::Put, 40.00, 40.00, 0.0, 0.0488, 0.0833, 0.4, 1.767},
311 {Option::Put, 40.00, 40.00, 0.0, 0.0488, 0.3333, 0.4, 3.381},
312 {Option::Put, 40.00, 40.00, 0.0, 0.0488, 0.5833, 0.4, 4.342},
313
314 {Option::Put, 45.00, 40.00, 0.0, 0.0488, 0.0833, 0.4, 5.288},
315 {Option::Put, 45.00, 40.00, 0.0, 0.0488, 0.3333, 0.4, 6.501},
316 {Option::Put, 45.00, 40.00, 0.0, 0.0488, 0.5833, 0.4, 7.367},
317
318
319
320
321
322 {Option::Call, 100.00, 80.00, 0.07, 0.03, 3.0, 0.2, 2.605},
323 {Option::Call, 100.00, 90.00, 0.07, 0.03, 3.0, 0.2, 5.182},
324 {Option::Call, 100.00, 100.00, 0.07, 0.03, 3.0, 0.2, 9.065},
325 {Option::Call, 100.00, 110.00, 0.07, 0.03, 3.0, 0.2, 14.430},
326 {Option::Call, 100.00, 120.00, 0.07, 0.03, 3.0, 0.2, 21.398},
327
328 {Option::Call, 100.00, 80.00, 0.07, 0.03, 3.0, 0.4, 11.336},
329 {Option::Call, 100.00, 90.00, 0.07, 0.03, 3.0, 0.4, 15.711},
330 {Option::Call, 100.00, 100.00, 0.07, 0.03, 3.0, 0.4, 20.760},
331 {Option::Call, 100.00, 110.00, 0.07, 0.03, 3.0, 0.4, 26.440},
332 {Option::Call, 100.00, 120.00, 0.07, 0.03, 3.0, 0.4, 32.709},
333
334 {Option::Call, 100.00, 80.00, 0.07, 0.00001, 3.0, 0.3, 5.552},
335 {Option::Call, 100.00, 90.00, 0.07, 0.00001, 3.0, 0.3, 8.868},
336 {Option::Call, 100.00, 100.00, 0.07, 0.00001, 3.0, 0.3, 13.158},
337 {Option::Call, 100.00, 110.00, 0.07, 0.00001, 3.0, 0.3, 18.458},
338 {Option::Call, 100.00, 120.00, 0.07, 0.00001, 3.0, 0.3, 24.786},
339
340 {Option::Call, 100.00, 80.00, 0.03, 0.07, 3.0, 0.3, 12.177},
341 {Option::Call, 100.00, 90.00, 0.03, 0.07, 3.0, 0.3, 17.411},
342 {Option::Call, 100.00, 100.00, 0.03, 0.07, 3.0, 0.3, 23.402},
343 {Option::Call, 100.00, 110.00, 0.03, 0.07, 3.0, 0.3, 30.028},
344 {Option::Call, 100.00, 120.00, 0.03, 0.07, 3.0, 0.3, 37.177}};
345
346 Real tolerance = 8.0e-2;
347
348 for (auto& f : juValues) {
349
350 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>(f.s, f.q, f.r, f.v);
351 Date today = Settings::instance().evaluationDate();
352 Settings::instance().evaluationDate() = market->asofDate();
353
354
355 string maturityDate =
to_string(market->asofDate() + Integer(f.t * 360 + 0.5));
356 OptionData optionData(
"Long", f.type == Option::Call ?
"Call" :
"Put",
"American",
false,
357 vector<string>(1, maturityDate));
359 FxOption fxOption(env, optionData,
"JPY", 1,
360 "EUR", f.strike);
361
362 Real expectedNPV = f.result;
363
364
365 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
366 engineData->model("FxOptionAmerican") = "GarmanKohlhagen";
367 engineData->engine("FxOptionAmerican") = "FdBlackScholesVanillaEngine";
368 engineData->engineParameters("FxOptionAmerican") = {
369 {"Scheme", "Douglas"}, {"TimeGridPerYear", "100"}, {"XGrid", "100"}, {"DampingSteps", "0"}};
370
371 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
372
373 fxOption.build(engineFactory);
374
375 Real npv = fxOption.instrument()->NPV();
376
377 BOOST_TEST_MESSAGE("FX American Option, NPV Currency " << fxOption.npvCurrency());
378 BOOST_TEST_MESSAGE("NPV = " << npv);
379
380
381 QL_REQUIRE(fxOption.npvCurrency() == "EUR", "unexpected NPV currency ");
382
383 BOOST_CHECK_SMALL(npv - expectedNPV, tolerance);
384 Settings::instance().evaluationDate() = today;
385 }
386}