C++:实现量化dividend option股息期权 测试实例

#include "dividendoption.hpp"
#include "utilities.hpp"
#include <ql/instruments/dividendvanillaoption.hpp>
#include <ql/instruments/vanillaoption.hpp>
#include <ql/pricingengines/vanilla/analyticdividendeuropeanengine.hpp>
#include <ql/pricingengines/vanilla/analyticeuropeanengine.hpp>
#include <ql/pricingengines/vanilla/fdblackscholesvanillaengine.hpp>
#include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp>
#include <ql/termstructures/yield/flatforward.hpp>
#include <ql/time/daycounters/actual360.hpp>
#include <ql/utilities/dataformatters.hpp>
#include <map>using namespace QuantLib;
using namespace boost::unit_test_framework;#undef REPORT_FAILURE
#define REPORT_FAILURE(greekName, payoff, exercise, s, q, r, today, \v, expected, calculated, error, tolerance) \BOOST_ERROR(exerciseTypeToString(exercise) << " " \<< payoff->optionType() << " option with " \<< payoffTypeToString(payoff) << " payoff:\n" \<< "    spot value:       " << s << "\n" \<< "    strike:           " << payoff->strike() << "\n" \<< "    dividend yield:   " << io::rate(q) << "\n" \<< "    risk-free rate:   " << io::rate(r) << "\n" \<< "    reference date:   " << today << "\n" \<< "    maturity:         " << exercise->lastDate() << "\n" \<< "    volatility:       " << io::volatility(v) << "\n\n" \<< "    expected   " << greekName << ": " << expected << "\n" \<< "    calculated " << greekName << ": " << calculated << "\n"\<< "    error:            " << error << "\n" \<< "    tolerance:        " << tolerance);// testsvoid DividendOptionTest::testEuropeanValues() {BOOST_TEST_MESSAGE("Testing dividend European option values with no dividends...");SavedSettings backup;Real tolerance = 1.0e-5;Option::Type types[] = { Option::Call, Option::Put };Real strikes[] = { 50.0, 99.5, 100.0, 100.5, 150.0 };Real underlyings[] = { 100.0 };Rate qRates[] = { 0.00, 0.10, 0.30 };Rate rRates[] = { 0.01, 0.05, 0.15 };Integer lengths[] = { 1, 2 };Volatility vols[] = { 0.05, 0.20, 0.70 };DayCounter dc = Actual360();Date today = Date::todaysDate();Settings::instance().evaluationDate() = today;ext::shared_ptr<SimpleQuote> spot(new SimpleQuote(0.0));ext::shared_ptr<SimpleQuote> qRate(new SimpleQuote(0.0));Handle<YieldTermStructure> qTS(flatRate(qRate, dc));ext::shared_ptr<SimpleQuote> rRate(new SimpleQuote(0.0));Handle<YieldTermStructure> rTS(flatRate(rRate, dc));ext::shared_ptr<SimpleQuote> vol(new SimpleQuote(0.0));Handle<BlackVolTermStructure> volTS(flatVol(vol, dc));for (auto& type : types) {for (Real strike : strikes) {for (int length : lengths) {Date exDate = today + length * Years;ext::shared_ptr<Exercise> exercise(new EuropeanExercise(exDate));std::vector<Date> dividendDates;std::vector<Real> dividends;for (Date d = today + 3 * Months; d < exercise->lastDate(); d += 6 * Months) {dividendDates.push_back(d);dividends.push_back(0.0);}ext::shared_ptr<StrikedTypePayoff> payoff(new PlainVanillaPayoff(type, strike));ext::shared_ptr<BlackScholesMertonProcess> stochProcess(new BlackScholesMertonProcess(Handle<Quote>(spot), qTS, rTS, volTS));ext::shared_ptr<PricingEngine> ref_engine(new AnalyticEuropeanEngine(stochProcess));ext::shared_ptr<PricingEngine> engine(new AnalyticDividendEuropeanEngine(stochProcess));DividendVanillaOption option(payoff, exercise, dividendDates, dividends);option.setPricingEngine(engine);VanillaOption ref_option(payoff, exercise);ref_option.setPricingEngine(ref_engine);for (Real u : underlyings) {for (Real m : qRates) {for (Real n : rRates) {for (Real v : vols) {Rate q = m, r = n;spot->setValue(u);qRate->setValue(q);rRate->setValue(r);vol->setValue(v);Real calculated = option.NPV();Real expected = ref_option.NPV();Real error = std::fabs(calculated - expected);if (error > tolerance) {REPORT_FAILURE("value start limit", payoff, exercise, u, q, r,today, v, expected, calculated, error,tolerance);}}}}}}}}
}// Reference pg. 253 - Hull - Options, Futures, and Other Derivatives 5th ed
// Exercise 12.8void DividendOptionTest::testEuropeanKnownValue() {BOOST_TEST_MESSAGE("Testing dividend European option against known value...");SavedSettings backup;Real tolerance = 1.0e-2;Real expected = 3.67;DayCounter dc = Actual360();Date today = Date::todaysDate();Settings::instance().evaluationDate() = today;ext::shared_ptr<SimpleQuote> spot(new SimpleQuote(0.0));ext::shared_ptr<SimpleQuote> qRate(new SimpleQuote(0.0));Handle<YieldTermStructure> qTS(flatRate(qRate, dc));ext::shared_ptr<SimpleQuote> rRate(new SimpleQuote(0.0));Handle<YieldTermStructure> rTS(flatRate(rRate, dc));ext::shared_ptr<SimpleQuote> vol(new SimpleQuote(0.0));Handle<BlackVolTermStructure> volTS(flatVol(vol, dc));Date exDate = today + 180 * Days;ext::shared_ptr<Exercise> exercise(new EuropeanExercise(exDate));std::vector<Date> dividendDates = {today + 2 * 30 * Days, today + 5 * 30 * Days};std::vector<Real> dividends = {0.50, 0.50};ext::shared_ptr<StrikedTypePayoff> payoff(new PlainVanillaPayoff(Option::Call, 40.0));ext::shared_ptr<BlackScholesMertonProcess> stochProcess(new BlackScholesMertonProcess(Handle<Quote>(spot),qTS, rTS, volTS));ext::shared_ptr<PricingEngine> engine(new AnalyticDividendEuropeanEngine(stochProcess));DividendVanillaOption option(payoff, exercise,dividendDates, dividends);option.setPricingEngine(engine);Real u = 40.0;Rate q = 0.0, r = 0.09;Volatility v = 0.30;spot->setValue(u);qRate->setValue(q);rRate->setValue(r);vol->setValue(v);Real calculated = option.NPV();Real error = std::fabs(calculated-expected);if (error > tolerance) {REPORT_FAILURE("value start limit",payoff, exercise,u, q, r, today, v,expected, calculated,error, tolerance);}
}void DividendOptionTest::testEuropeanStartLimit() {BOOST_TEST_MESSAGE("Testing dividend European option with a dividend on today's date...");SavedSettings backup;Real tolerance = 1.0e-5;Real dividendValue = 10.0;Option::Type types[] = { Option::Call, Option::Put };Real strikes[] = { 50.0, 99.5, 100.0, 100.5, 150.0 };Real underlyings[] = { 100.0 };Rate qRates[] = { 0.00, 0.10, 0.30 };Rate rRates[] = { 0.01, 0.05, 0.15 };Integer lengths[] = { 1, 2 };Volatility vols[] = { 0.05, 0.20, 0.70 };DayCounter dc = Actual360();Date today = Date::todaysDate();Settings::instance().evaluationDate() = today;ext::shared_ptr<SimpleQuote> spot(new SimpleQuote(0.0));ext::shared_ptr<SimpleQuote> qRate(new SimpleQuote(0.0));Handle<YieldTermStructure> qTS(flatRate(qRate, dc));ext::shared_ptr<SimpleQuote> rRate(new SimpleQuote(0.0));Handle<YieldTermStructure> rTS(flatRate(rRate, dc));ext::shared_ptr<SimpleQuote> vol(new SimpleQuote(0.0));Handle<BlackVolTermStructure> volTS(flatVol(vol, dc));for (auto& type : types) {for (Real strike : strikes) {for (int length : lengths) {Date exDate = today + length * Years;ext::shared_ptr<Exercise> exercise(new EuropeanExercise(exDate));std::vector<Date> dividendDates = {today};std::vector<Real> dividends = {dividendValue};ext::shared_ptr<StrikedTypePayoff> payoff(new PlainVanillaPayoff(type, strike));ext::shared_ptr<BlackScholesMertonProcess> stochProcess(new BlackScholesMertonProcess(Handle<Quote>(spot), qTS, rTS, volTS));ext::shared_ptr<PricingEngine> engine(new AnalyticDividendEuropeanEngine(stochProcess));ext::shared_ptr<PricingEngine> ref_engine(new AnalyticEuropeanEngine(stochProcess));DividendVanillaOption option(payoff, exercise, dividendDates, dividends);option.setPricingEngine(engine);VanillaOption ref_option(payoff, exercise);ref_option.setPricingEngine(ref_engine);for (Real u : underlyings) {for (Real m : qRates) {for (Real n : rRates) {for (Real v : vols) {Rate q = m, r = n;spot->setValue(u);qRate->setValue(q);rRate->setValue(r);vol->setValue(v);Real calculated = option.NPV();spot->setValue(u - dividendValue);Real expected = ref_option.NPV();Real error = std::fabs(calculated - expected);if (error > tolerance) {REPORT_FAILURE("value", payoff, exercise, u, q, r, today, v,expected, calculated, error, tolerance);}}}}}}}}
}void DividendOptionTest::testEuropeanEndLimit() {BOOST_TEST_MESSAGE("Testing dividend European option values with end limits...");SavedSettings backup;Real tolerance = 1.0e-5;Real dividendValue = 10.0;Option::Type types[] = { Option::Call, Option::Put };Real strikes[] = { 50.0, 99.5, 100.0, 100.5, 150.0 };Real underlyings[] = { 100.0 };Rate qRates[] = { 0.00, 0.10, 0.30 };Rate rRates[] = { 0.01, 0.05, 0.15 };Integer lengths[] = { 1, 2 };Volatility vols[] = { 0.05, 0.20, 0.70 };DayCounter dc = Actual360();Date today = Date::todaysDate();Settings::instance().evaluationDate() = today;ext::shared_ptr<SimpleQuote> spot(new SimpleQuote(0.0));ext::shared_ptr<SimpleQuote> qRate(new SimpleQuote(0.0));Handle<YieldTermStructure> qTS(flatRate(qRate, dc));ext::shared_ptr<SimpleQuote> rRate(new SimpleQuote(0.0));Handle<YieldTermStructure> rTS(flatRate(rRate, dc));ext::shared_ptr<SimpleQuote> vol(new SimpleQuote(0.0));Handle<BlackVolTermStructure> volTS(flatVol(vol, dc));for (auto& type : types) {for (Real strike : strikes) {for (int length : lengths) {Date exDate = today + length * Years;ext::shared_ptr<Exercise> exercise(new EuropeanExercise(exDate));std::vector<Date> dividendDates = {exercise->lastDate()};std::vector<Real> dividends = {dividendValue};ext::shared_ptr<StrikedTypePayoff> payoff(new PlainVanillaPayoff(type, strike));ext::shared_ptr<StrikedTypePayoff> refPayoff(new PlainVanillaPayoff(type, strike + dividendValue));ext::shared_ptr<BlackScholesMertonProcess> stochProcess(new BlackScholesMertonProcess(Handle<Quote>(spot), qTS, rTS, volTS));ext::shared_ptr<PricingEngine> engine(new AnalyticDividendEuropeanEngine(stochProcess));ext::shared_ptr<PricingEngine> ref_engine(new AnalyticEuropeanEngine(stochProcess));DividendVanillaOption option(payoff, exercise, dividendDates, dividends);option.setPricingEngine(engine);VanillaOption ref_option(refPayoff, exercise);ref_option.setPricingEngine(ref_engine);for (Real u : underlyings) {for (Real m : qRates) {for (Real n : rRates) {for (Real v : vols) {Rate q = m, r = n;spot->setValue(u);qRate->setValue(q);rRate->setValue(r);vol->setValue(v);Real calculated = option.NPV();Real expected = ref_option.NPV();Real error = std::fabs(calculated - expected);if (error > tolerance) {REPORT_FAILURE("value", payoff, exercise, u, q, r, today, v,expected, calculated, error, tolerance);}}}}}}}}
}void DividendOptionTest::testEuropeanGreeks() {BOOST_TEST_MESSAGE("Testing dividend European option greeks...");SavedSettings backup;std::map<std::string,Real> calculated, expected, tolerance;tolerance["delta"] = 1.0e-5;tolerance["gamma"] = 1.0e-5;tolerance["theta"] = 1.0e-5;tolerance["rho"]   = 1.0e-5;tolerance["vega"]  = 1.0e-5;Option::Type types[] = { Option::Call, Option::Put };Real strikes[] = { 50.0, 99.5, 100.0, 100.5, 150.0 };Real underlyings[] = { 100.0 };Rate qRates[] = { 0.00, 0.10, 0.30 };Rate rRates[] = { 0.01, 0.05, 0.15 };Integer lengths[] = { 1, 2 };Volatility vols[] = { 0.05, 0.20, 0.40 };DayCounter dc = Actual360();Date today = Date::todaysDate();Settings::instance().evaluationDate() = today;ext::shared_ptr<SimpleQuote> spot(new SimpleQuote(0.0));ext::shared_ptr<SimpleQuote> qRate(new SimpleQuote(0.0));Handle<YieldTermStructure> qTS(flatRate(qRate, dc));ext::shared_ptr<SimpleQuote> rRate(new SimpleQuote(0.0));Handle<YieldTermStructure> rTS(flatRate(rRate, dc));ext::shared_ptr<SimpleQuote> vol(new SimpleQuote(0.0));Handle<BlackVolTermStructure> volTS(flatVol(vol, dc));for (auto& type : types) {for (Real strike : strikes) {for (int length : lengths) {Date exDate = today + length * Years;ext::shared_ptr<Exercise> exercise(new EuropeanExercise(exDate));std::vector<Date> dividendDates;std::vector<Real> dividends;for (Date d = today + 3 * Months; d < exercise->lastDate(); d += 6 * Months) {dividendDates.push_back(d);dividends.push_back(5.0);}ext::shared_ptr<StrikedTypePayoff> payoff(new PlainVanillaPayoff(type, strike));ext::shared_ptr<BlackScholesMertonProcess> stochProcess(new BlackScholesMertonProcess(Handle<Quote>(spot), qTS, rTS, volTS));ext::shared_ptr<PricingEngine> engine(new AnalyticDividendEuropeanEngine(stochProcess));DividendVanillaOption option(payoff, exercise, dividendDates, dividends);option.setPricingEngine(engine);for (Real u : underlyings) {for (Real m : qRates) {for (Real n : rRates) {for (Real v : vols) {Rate q = m, r = n;spot->setValue(u);qRate->setValue(q);rRate->setValue(r);vol->setValue(v);Real value = option.NPV();calculated["delta"] = option.delta();calculated["gamma"] = option.gamma();calculated["theta"] = option.theta();calculated["rho"] = option.rho();calculated["vega"] = option.vega();if (value > spot->value() * 1.0e-5) {// perturb spot and get delta and gammaReal du = u * 1.0e-4;spot->setValue(u + du);Real value_p = option.NPV(), delta_p = option.delta();spot->setValue(u - du);Real value_m = option.NPV(), delta_m = option.delta();spot->setValue(u);expected["delta"] = (value_p - value_m) / (2 * du);expected["gamma"] = (delta_p - delta_m) / (2 * du);// perturb risk-free rate and get rhoSpread dr = r * 1.0e-4;rRate->setValue(r + dr);value_p = option.NPV();rRate->setValue(r - dr);value_m = option.NPV();rRate->setValue(r);expected["rho"] = (value_p - value_m) / (2 * dr);// perturb volatility and get vegaSpread dv = v * 1.0e-4;vol->setValue(v + dv);value_p = option.NPV();vol->setValue(v - dv);value_m = option.NPV();vol->setValue(v);expected["vega"] = (value_p - value_m) / (2 * dv);// perturb date and get thetaTime dT = dc.yearFraction(today - 1, today + 1);Settings::instance().evaluationDate() = today - 1;value_m = option.NPV();Settings::instance().evaluationDate() = today + 1;value_p = option.NPV();Settings::instance().evaluationDate() = today;expected["theta"] = (value_p - value_m) / dT;// comparestd::map<std::string, Real>::iterator it;for (it = calculated.begin(); it != calculated.end(); ++it) {std::string greek = it->first;Real expct = expected[greek], calcl = calculated[greek],tol = tolerance[greek];Real error = relativeError(expct, calcl, u);if (error > tol) {REPORT_FAILURE(greek, payoff, exercise, u, q, r, today,v, expct, calcl, error, tol);}}}}}}}}}}
}void DividendOptionTest::testFdEuropeanValues() {BOOST_TEST_MESSAGE("Testing finite-difference dividend European option values...");SavedSettings backup;Real tolerance = 1.0e-2;Size gridPoints = 400;Size timeSteps = 40;Option::Type types[] = { Option::Call, Option::Put };Real strikes[] = { 50.0, 99.5, 100.0, 100.5, 150.0 };Real underlyings[] = { 100.0 };Rate qRates[] = { 0.00, 0.10, 0.30 };Rate rRates[] = { 0.01, 0.05, 0.15 };Integer lengths[] = { 1, 2 };Volatility vols[] = { 0.05, 0.20, 0.40 };DayCounter dc = Actual360();Date today = Date::todaysDate();Settings::instance().evaluationDate() = today;ext::shared_ptr<SimpleQuote> spot(new SimpleQuote(0.0));ext::shared_ptr<SimpleQuote> qRate(new SimpleQuote(0.0));Handle<YieldTermStructure> qTS(flatRate(qRate, dc));ext::shared_ptr<SimpleQuote> rRate(new SimpleQuote(0.0));Handle<YieldTermStructure> rTS(flatRate(rRate, dc));ext::shared_ptr<SimpleQuote> vol(new SimpleQuote(0.0));Handle<BlackVolTermStructure> volTS(flatVol(vol, dc));for (auto& type : types) {for (Real strike : strikes) {for (int length : lengths) {Date exDate = today + length * Years;ext::shared_ptr<Exercise> exercise(new EuropeanExercise(exDate));std::vector<Date> dividendDates;std::vector<Real> dividends;for (Date d = today + 3 * Months; d < exercise->lastDate(); d += 6 * Months) {dividendDates.push_back(d);dividends.push_back(5.0);}ext::shared_ptr<StrikedTypePayoff> payoff(new PlainVanillaPayoff(type, strike));ext::shared_ptr<BlackScholesMertonProcess> stochProcess(new BlackScholesMertonProcess(Handle<Quote>(spot), qTS, rTS, volTS));ext::shared_ptr<PricingEngine> engine =MakeFdBlackScholesVanillaEngine(stochProcess).withTGrid(timeSteps).withXGrid(gridPoints).withCashDividendModel(FdBlackScholesVanillaEngine::Escrowed);ext::shared_ptr<PricingEngine> ref_engine(new AnalyticDividendEuropeanEngine(stochProcess));DividendVanillaOption option(payoff, exercise, dividendDates, dividends);option.setPricingEngine(engine);DividendVanillaOption ref_option(payoff, exercise, dividendDates, dividends);ref_option.setPricingEngine(ref_engine);for (Real u : underlyings) {for (Real m : qRates) {for (Real n : rRates) {for (Real v : vols) {Rate q = m, r = n;spot->setValue(u);qRate->setValue(q);rRate->setValue(r);vol->setValue(v);// FLOATING_POINT_EXCEPTIONReal calculated = option.NPV();if (calculated > spot->value() * 1.0e-5) {Real expected = ref_option.NPV();Real error = std::fabs(calculated - expected);if (error > tolerance) {REPORT_FAILURE("value", payoff, exercise, u, q, r, today, v,expected, calculated, error, tolerance);}}}}}}}}}
}namespace {void testFdGreeks(const Date& today,const ext::shared_ptr<Exercise>& exercise,FdBlackScholesVanillaEngine::CashDividendModel model) {std::map<std::string,Real> calculated, expected, tolerance;tolerance["delta"] = 5.0e-3;tolerance["gamma"] = 7.0e-3;// tolerance["theta"] = 1.0e-2;Option::Type types[] = { Option::Call, Option::Put };Real strikes[] = { 50.0, 99.5, 100.0, 100.5, 150.0 };Real underlyings[] = { 100.0 };Rate qRates[] = { 0.00, 0.10, 0.20 };Rate rRates[] = { 0.01, 0.05, 0.15 };Volatility vols[] = { 0.05, 0.20, 0.50 };DayCounter dc = Actual365Fixed();ext::shared_ptr<SimpleQuote> spot(new SimpleQuote(0.0));ext::shared_ptr<SimpleQuote> qRate(new SimpleQuote(0.0));Handle<YieldTermStructure> qTS(flatRate(qRate, dc));ext::shared_ptr<SimpleQuote> rRate(new SimpleQuote(0.0));Handle<YieldTermStructure> rTS(flatRate(rRate, dc));ext::shared_ptr<SimpleQuote> vol(new SimpleQuote(0.0));Handle<BlackVolTermStructure> volTS(flatVol(vol, dc));for (auto& type : types) {for (Real strike : strikes) {std::vector<Date> dividendDates;std::vector<Real> dividends;for (Date d = today + 3*Months;d < exercise->lastDate();d += 6*Months) {dividendDates.push_back(d);dividends.push_back(5.0);}ext::shared_ptr<StrikedTypePayoff> payoff(new PlainVanillaPayoff(type, strike));ext::shared_ptr<BlackScholesMertonProcess> stochProcess(new BlackScholesMertonProcess(Handle<Quote>(spot),qTS, rTS, volTS));ext::shared_ptr<PricingEngine> engine =MakeFdBlackScholesVanillaEngine(stochProcess).withCashDividendModel(model);DividendVanillaOption option(payoff, exercise,dividendDates, dividends);option.setPricingEngine(engine);for (Real u : underlyings) {for (Real m : qRates) {for (Real n : rRates) {for (Real v : vols) {Rate q = m, r = n;spot->setValue(u);qRate->setValue(q);rRate->setValue(r);vol->setValue(v);// FLOATING_POINT_EXCEPTIONReal value = option.NPV();calculated["delta"] = option.delta();calculated["gamma"] = option.gamma();if (value > spot->value() * 1.0e-5) {// perturb spot and get delta and gammaReal du = u * 1.0e-4;spot->setValue(u + du);Real value_p = option.NPV(), delta_p = option.delta();spot->setValue(u - du);Real value_m = option.NPV(), delta_m = option.delta();spot->setValue(u);expected["delta"] = (value_p - value_m) / (2 * du);expected["gamma"] = (delta_p - delta_m) / (2 * du);// perturb date and get theta/*Time dT = dc.yearFraction(today-1, today+1);Settings::instance().evaluationDate() = today-1;value_m = option.NPV();Settings::instance().evaluationDate() = today+1;value_p = option.NPV();Settings::instance().evaluationDate() = today;expected["theta"] = (value_p - value_m)/dT;*/// comparestd::map<std::string, Real>::iterator it;for (it = calculated.begin(); it != calculated.end(); ++it) {std::string greek = it->first;Real expct = expected[greek], calcl = calculated[greek],tol = tolerance[greek];Real error = relativeError(expct, calcl, u);if (error > tol) {REPORT_FAILURE(greek, payoff, exercise, u, q, r, today,v, expct, calcl, error, tol);}}}}}}}}}}}void DividendOptionTest::testFdEuropeanGreeks() {BOOST_TEST_MESSAGE("Testing finite-differences dividend European option greeks...");SavedSettings backup;Date today = Date::todaysDate();Settings::instance().evaluationDate() = today;Integer lengths[] = { 1, 2 };for (int length : lengths) {Date exDate = today + length * Years;ext::shared_ptr<Exercise> exercise(new EuropeanExercise(exDate));testFdGreeks(today,exercise,FdBlackScholesVanillaEngine::Spot);testFdGreeks(today,exercise,FdBlackScholesVanillaEngine::Escrowed);}
}void DividendOptionTest::testFdAmericanGreeks() {BOOST_TEST_MESSAGE("Testing finite-differences dividend American option greeks...");SavedSettings backup;Date today = Date::todaysDate();Settings::instance().evaluationDate() = today;Integer lengths[] = { 1, 2 };for (int length : lengths) {Date exDate = today + length * Years;ext::shared_ptr<Exercise> exercise(new AmericanExercise(today,exDate));testFdGreeks(today,exercise,FdBlackScholesVanillaEngine::Spot);}
}namespace {void testFdDegenerate(const Date& today,const ext::shared_ptr<Exercise>& exercise,FdBlackScholesVanillaEngine::CashDividendModel model) {DayCounter dc = Actual360();ext::shared_ptr<SimpleQuote> spot(new SimpleQuote(54.625));Handle<YieldTermStructure> rTS(flatRate(0.052706, dc));Handle<YieldTermStructure> qTS(flatRate(0.0, dc));Handle<BlackVolTermStructure> volTS(flatVol(0.282922, dc));ext::shared_ptr<BlackScholesMertonProcess> process(new BlackScholesMertonProcess(Handle<Quote>(spot),qTS, rTS, volTS));Size timeSteps = 100;Size gridPoints = 300;ext::shared_ptr<PricingEngine> engine =MakeFdBlackScholesVanillaEngine(process).withTGrid(timeSteps).withXGrid(gridPoints).withCashDividendModel(model);ext::shared_ptr<StrikedTypePayoff> payoff(new PlainVanillaPayoff(Option::Call, 55.0));Real tolerance = 3.0e-3;std::vector<Rate> dividends;std::vector<Date> dividendDates;DividendVanillaOption option1(payoff, exercise,dividendDates, dividends);option1.setPricingEngine(engine);Real refValue = option1.NPV();for (Size i=1; i<=6; i++) {dividends.push_back(0.0);dividendDates.push_back(today+i);DividendVanillaOption option(payoff, exercise,dividendDates, dividends);option.setPricingEngine(engine);Real value = option.NPV();if (std::fabs(refValue-value) > tolerance)BOOST_FAIL("NPV changed by null dividend :\n"<< "    previous value: " << value << "\n"<< "    current value:  " << refValue << "\n"<< "    change:         " << value-refValue);}}}void DividendOptionTest::testFdEuropeanDegenerate() {BOOST_TEST_MESSAGE("Testing degenerate finite-differences dividend European option...");SavedSettings backup;Date today = Date(27,February,2005);Settings::instance().evaluationDate() = today;Date exDate(13,April,2005);ext::shared_ptr<Exercise> exercise(new EuropeanExercise(exDate));testFdDegenerate(today,exercise,FdBlackScholesVanillaEngine::Spot);testFdDegenerate(today,exercise,FdBlackScholesVanillaEngine::Escrowed);
}void DividendOptionTest::testFdAmericanDegenerate() {BOOST_TEST_MESSAGE("Testing degenerate finite-differences dividend American option...");SavedSettings backup;Date today = Date(27,February,2005);Settings::instance().evaluationDate() = today;Date exDate(13,April,2005);ext::shared_ptr<Exercise> exercise(new AmericanExercise(today,exDate));testFdDegenerate(today,exercise,FdBlackScholesVanillaEngine::Spot);testFdDegenerate(today,exercise,FdBlackScholesVanillaEngine::Escrowed);
}namespace {void testFdDividendAtTZero(const Date& today,const ext::shared_ptr<Exercise>& exercise,FdBlackScholesVanillaEngine::CashDividendModel model) {DayCounter dc = Actual360();ext::shared_ptr<SimpleQuote> spot(new SimpleQuote(54.625));Handle<YieldTermStructure> rTS(flatRate(0.0, dc));Handle<BlackVolTermStructure> volTS(flatVol(0.282922, dc));ext::shared_ptr<BlackScholesMertonProcess> process(new BlackScholesMertonProcess(Handle<Quote>(spot),rTS, rTS, volTS));Size timeSteps = 50;Size gridPoints = 400;ext::shared_ptr<PricingEngine> engine =MakeFdBlackScholesVanillaEngine(process).withTGrid(timeSteps).withXGrid(gridPoints).withCashDividendModel(model);ext::shared_ptr<StrikedTypePayoff> payoff(new PlainVanillaPayoff(Option::Call, 55.0));// today's dividend must by taken into accountstd::vector<Rate> dividends(1, 1.0);std::vector<Date> dividendDates(1, today);DividendVanillaOption option(payoff, exercise,dividendDates, dividends);option.setPricingEngine(engine);Real calculated = option.NPV();switch(model) {case FdBlackScholesVanillaEngine::Spot:BOOST_CHECK_THROW(option.theta(), QuantLib::Error);break;case FdBlackScholesVanillaEngine::Escrowed:BOOST_CHECK_NO_THROW(option.theta());break;default:QL_FAIL("unknown dividend model type");}ext::shared_ptr<Exercise> europeanExercise =ext::make_shared<EuropeanExercise>(exercise->lastDate());DividendVanillaOption europeanOption(payoff, europeanExercise, dividendDates, dividends);europeanOption.setPricingEngine(ext::make_shared<AnalyticDividendEuropeanEngine>(process));Real expected = europeanOption.NPV();const Real tol = 1e-4;if (std::fabs(calculated-expected) > tol) {BOOST_ERROR("Can not reproduce reference values ""from analytic dividend engine :\n"<< "    calculated: " << calculated << "\n"<< "    expected  : " << expected << "\n"<< "    diff:       " << tol);}}
}void DividendOptionTest::testFdEuropeanWithDividendToday() {BOOST_TEST_MESSAGE("Testing finite-differences dividend European option with dividend on today's date...");SavedSettings backup;Date today = Date(27,February,2005);Settings::instance().evaluationDate() = today;Date exDate(13,April,2005);ext::shared_ptr<Exercise> exercise(new EuropeanExercise(exDate));testFdDividendAtTZero(today,exercise,FdBlackScholesVanillaEngine::Spot);testFdDividendAtTZero(today,exercise,FdBlackScholesVanillaEngine::Escrowed);
}void DividendOptionTest::testFdAmericanWithDividendToday() {BOOST_TEST_MESSAGE("Testing finite-differences dividend American option with dividend on today's date...");SavedSettings backup;Date today = Date(27,February,2005);Settings::instance().evaluationDate() = today;Date exDate(13,April,2005);ext::shared_ptr<Exercise> exercise(new AmericanExercise(today,exDate));testFdDividendAtTZero(today,exercise,FdBlackScholesVanillaEngine::Spot);
}void DividendOptionTest::testEscrowedDividendModel() {BOOST_TEST_MESSAGE("Testing finite-difference European engine ""with the escrowed dividend model...");SavedSettings backup;const DayCounter dc = Actual365Fixed();const Date today = Date(12, October, 2019);Settings::instance().evaluationDate() = today;const Handle<Quote> spot(ext::make_shared<SimpleQuote>(100.0));const Handle<YieldTermStructure> qTS(flatRate(today, 0.063, dc));const Handle<YieldTermStructure> rTS(flatRate(today, 0.094, dc));const Handle<BlackVolTermStructure> volTS(flatVol(today, 0.3, dc));const Date maturity = today + Period(1, Years);const ext::shared_ptr<BlackScholesMertonProcess> process =ext::make_shared<BlackScholesMertonProcess>(spot, qTS, rTS, volTS);const ext::shared_ptr<PlainVanillaPayoff> payoff(ext::make_shared<PlainVanillaPayoff>(Option::Put, spot->value()));const ext::shared_ptr<Exercise> exercise(ext::make_shared<EuropeanExercise>(maturity));std::vector<Date> dividendDates = {today + Period(3, Months), today + Period(9, Months)};std::vector<Real> dividendAmounts = {8.3, 6.8};DividendVanillaOption option(payoff, exercise, dividendDates, dividendAmounts);option.setPricingEngine(ext::make_shared<AnalyticDividendEuropeanEngine>(process));const Real analyticNPV = option.NPV();const Real analyticDelta = option.delta();option.setPricingEngine(MakeFdBlackScholesVanillaEngine(process).withTGrid(50).withXGrid(200).withDampingSteps(1).withCashDividendModel(FdBlackScholesVanillaEngine::Escrowed));const Real pdeNPV = option.NPV();const Real pdeDelta = option.delta();const Real tol = 0.0025;if (std::fabs(pdeNPV - analyticNPV) > tol) {BOOST_FAIL("Failed to reproduce European option values ""with the escrowed dividend model and the ""FdBlackScholesVanillaEngine engine"<< "\n    calculated: " << pdeNPV<< "\n    expected:   " << analyticNPV<< "\n    difference: " << std::fabs(pdeNPV - analyticNPV)<< "\n    tolerance:  " << tol);}if (std::fabs(pdeDelta - analyticDelta) > tol) {BOOST_FAIL("Failed to reproduce European option deltas ""with the escrowed dividend model and the ""FdBlackScholesVanillaEngine engine"<< "\n    calculated: " << pdeNPV<< "\n    expected:   " << analyticNPV<< "\n    difference: " << std::fabs(pdeNPV - analyticNPV)<< "\n    tolerance:  " << tol);}
}test_suite* DividendOptionTest::suite() {auto* suite = BOOST_TEST_SUITE("Dividend European option tests");suite->add(QUANTLIB_TEST_CASE(&DividendOptionTest::testEuropeanValues));suite->add(QUANTLIB_TEST_CASE(&DividendOptionTest::testEuropeanKnownValue));suite->add(QUANTLIB_TEST_CASE(&DividendOptionTest::testEuropeanStartLimit));// Doesn't quite work.  Need to use discounted values//suite->add(QUANTLIB_TEST_CASE(&DividendOptionTest::testEuropeanEndLimit));suite->add(QUANTLIB_TEST_CASE(&DividendOptionTest::testEuropeanGreeks));suite->add(QUANTLIB_TEST_CASE(&DividendOptionTest::testFdEuropeanValues));suite->add(QUANTLIB_TEST_CASE(&DividendOptionTest::testFdEuropeanGreeks));suite->add(QUANTLIB_TEST_CASE(&DividendOptionTest::testFdAmericanGreeks));suite->add(QUANTLIB_TEST_CASE(&DividendOptionTest::testFdEuropeanDegenerate));suite->add(QUANTLIB_TEST_CASE(&DividendOptionTest::testFdAmericanDegenerate));suite->add(QUANTLIB_TEST_CASE(&DividendOptionTest::testFdEuropeanWithDividendToday));suite->add(QUANTLIB_TEST_CASE(&DividendOptionTest::testFdAmericanWithDividendToday));suite->add(QUANTLIB_TEST_CASE(&DividendOptionTest::testEscrowedDividendModel));return suite;
}

该博文为原创文章,未经博主同意不得转。
本文章博客地址:https://cplusplus.blog.csdn.net/article/details/128360320

C++:实现量化dividend option股息期权 测试实例相关推荐

  1. C++:实现量化cliquet option棘轮期权测试实例

    C++:实现量化cliquet option棘轮期权测试实例 #include "cliquetoption.hpp" #include "utilities.hpp&q ...

  2. C++:实现量化compound option复合期权测试实例

    C++:实现量化compound option复合期权测试实例 #include "compoundoption.hpp" #include "utilities.hpp ...

  3. C++:实现量化Forward option远期合约期权测试实例

    C++:实现量化Forward option远期合约期权测试实例 #include "forwardoption.hpp" #include "utilities.hpp ...

  4. C++:实现量化Lookback option 回顾式期权测试实例

    C++:实现量化Lookback option 回顾式期权测试实例 #include "lookbackoptions.hpp" #include "utilities. ...

  5. C++:实现量化doublebarrier option双障碍期权 测试实例

    C++:实现量化doublebarrier option双障碍期权 测试实例 #include "doublebarrieroption.hpp" #include "u ...

  6. C++:实现量化barrieroption障碍期权测试实例

    C++:实现量化barrieroption障碍期权测试实例 #include "barrieroption.hpp" #include "utilities.hpp&qu ...

  7. C++:实现量化Partial-time barrier部分时间障碍期权测试实例

    C++:实现量化Partial-time barrier部分时间障碍期权测试实例 #include "partialtimebarrieroption.hpp" #include ...

  8. C++:实现量化SMM Caplet均匀校准测试实例

    C++:实现量化SMM Caplet均匀校准测试实例 #include "markovfunctional.hpp" #include "utilities.hpp&qu ...

  9. C++:实现量化相关的Interpolation插值测试实例

    C++:实现量化相关的Interpolation插值测试实例 #include "interpolations.hpp" #include "utilities.hpp& ...

最新文章

  1. python3爬虫小型代码_python3简单爬虫实现代码
  2. XBOX ONE游戏开发之登陆服务器(一)
  3. scrapy-splash抓取动态数据例子十三
  4. eas 在linux下安装_Linux下SVN的安装以及配置
  5. 《剑指offer》把二叉树打印成多行
  6. 微软同步框架入门开篇(附SnapShot快照Demo)
  7. linux搭建springBoot环境,SpringBoot Linux服务化部署
  8. mysql dql_Mysql中的DQL查询语句
  9. javaweb实训第四天下午——JDBC深入理解
  10. cr2格式缩略图不显示_cr2缩略图补丁 佳能相机RAW文件CR2原片格式缩略图显示补丁- 游侠下载站...
  11. C语言的sqrt函数的调用
  12. 关于android RTP驱动的问题
  13. 《一》微信小程序简介
  14. [搬运]MATLAB newff函数训练模式
  15. 微信语音麦克风静音_微信中打电话静音是我被静音还是对方被静音,具体这个静音是什么意思...
  16. 【转载】测试面试知识点
  17. c语言 求奇数和
  18. 什么是软件测试及其分类?
  19. python中秋月饼
  20. Laurent(洛朗或者劳伦)多项式,泰勒展开式

热门文章

  1. 用友GRP-u8 XXE 漏洞复现
  2. 基于SPM12对fMRI数据进行预处理及其批处理
  3. 职工信息管理系统c语言报告,职工信息管理系统(c语言实现)
  4. Milvus 2.0 Knowhere 概览
  5. 《疯狂Java讲义》第5章 面向对象(上)——课后练习
  6. 开发常用linux命令
  7. 卷积神经网络-猫狗识别(附源码)
  8. js实现一个时分秒计时器
  9. 《七哥说道》第三章:志远淋雨怒辞职,误入保险黄老萍
  10. C#从入门到精通____5.1字符类Char的使用