C++:实现量化european option欧式期权 测试实例
#include "europeanoption.hpp"
#include "utilities.hpp"
#include <ql/time/calendars/target.hpp>
#include <ql/time/daycounters/actual360.hpp>
#include <ql/instruments/europeanoption.hpp>
#include <ql/math/randomnumbers/rngtraits.hpp>
#include <ql/math/interpolations/bicubicsplineinterpolation.hpp>
#include <ql/math/interpolations/bilinearinterpolation.hpp>
#include <ql/pricingengines/vanilla/analyticeuropeanengine.hpp>
#include <ql/pricingengines/vanilla/binomialengine.hpp>
#include <ql/pricingengines/vanilla/fdblackscholesvanillaengine.hpp>
#include <ql/experimental/variancegamma/fftvanillaengine.hpp>
#include <ql/pricingengines/vanilla/mceuropeanengine.hpp>
#include <ql/pricingengines/vanilla/integralengine.hpp>
#include <ql/termstructures/yield/flatforward.hpp>
#include <ql/termstructures/yield/zerocurve.hpp>
#include <ql/termstructures/yield/forwardcurve.hpp>
#include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp>
#include <ql/termstructures/volatility/equityfx/blackvariancesurface.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);
namespace european_option_test {
struct EuropeanOptionData {
Option::Type type;
Real strike;
Real s;
Rate q;
Rate r;
Time t;
Volatility v;
Real result;
Real tol;
};
enum EngineType {
Analytic,
JR, CRR, EQP, TGEO, TIAN, LR, JOSHI,
FiniteDifferences,
Integral,
PseudoMonteCarlo, QuasiMonteCarlo,
FFT };
ext::shared_ptr<GeneralizedBlackScholesProcess>
makeProcess(const ext::shared_ptr<Quote>& u,
const ext::shared_ptr<YieldTermStructure>& q,
const ext::shared_ptr<YieldTermStructure>& r,
const ext::shared_ptr<BlackVolTermStructure>& vol) {
return ext::make_shared<BlackScholesMertonProcess>(
Handle<Quote>(u),
Handle<YieldTermStructure>(q),
Handle<YieldTermStructure>(r),
Handle<BlackVolTermStructure>(vol));
}
ext::shared_ptr<VanillaOption>
makeOption(const ext::shared_ptr<StrikedTypePayoff>& payoff,
const ext::shared_ptr<Exercise>& exercise,
const ext::shared_ptr<Quote>& u,
const ext::shared_ptr<YieldTermStructure>& q,
const ext::shared_ptr<YieldTermStructure>& r,
const ext::shared_ptr<BlackVolTermStructure>& vol,
EngineType engineType,
Size binomialSteps,
Size samples) {
ext::shared_ptr<GeneralizedBlackScholesProcess> stochProcess =
makeProcess(u,q,r,vol);
ext::shared_ptr<PricingEngine> engine;
switch (engineType) {
case Analytic:
engine = ext::shared_ptr<PricingEngine>(
new AnalyticEuropeanEngine(stochProcess));
break;
case JR:
engine = ext::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<JarrowRudd>(stochProcess,
binomialSteps));
break;
case CRR:
engine = ext::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<CoxRossRubinstein>(stochProcess,
binomialSteps));
break;
case EQP:
engine = ext::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<AdditiveEQPBinomialTree>(
stochProcess,
binomialSteps));
break;
case TGEO:
engine = ext::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<Trigeorgis>(stochProcess,
binomialSteps));
break;
case TIAN:
engine = ext::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<Tian>(stochProcess, binomialSteps));
break;
case LR:
engine = ext::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<LeisenReimer>(stochProcess,
binomialSteps));
break;
case JOSHI:
engine = ext::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<Joshi4>(stochProcess, binomialSteps));
break;
case FiniteDifferences:
engine = ext::shared_ptr<PricingEngine>(
new FdBlackScholesVanillaEngine(stochProcess,
binomialSteps,
samples));
break;
case Integral:
engine = ext::shared_ptr<PricingEngine>(
new IntegralEngine(stochProcess));
break;
case PseudoMonteCarlo:
engine = MakeMCEuropeanEngine<PseudoRandom>(stochProcess)
.withSteps(1)
.withSamples(samples)
.withSeed(42);
break;
case QuasiMonteCarlo:
engine = MakeMCEuropeanEngine<LowDiscrepancy>(stochProcess)
.withSteps(1)
.withSamples(samples);
break;
case FFT:
engine = ext::shared_ptr<PricingEngine>(
new FFTVanillaEngine(stochProcess));
break;
default:
QL_FAIL("unknown engine type");
}
ext::shared_ptr<VanillaOption> option(
new EuropeanOption(payoff, exercise));
option->setPricingEngine(engine);
return option;
}
}
void EuropeanOptionTest::testValues() {
BOOST_TEST_MESSAGE("Testing European option values...");
using namespace european_option_test;
SavedSettings backup;
EuropeanOptionData values[] = {
{
Option::Call, 65.00, 60.00, 0.00, 0.08, 0.25, 0.30, 2.1334, 1.0e-4},
{
Option::Put, 95.00, 100.00, 0.05, 0.10, 0.50, 0.20, 2.4648, 1.0e-4},
{
Option::Put, 19.00, 19.00, 0.10, 0.10, 0.75, 0.28, 1.7011, 1.0e-4},
{
Option::Call, 19.00, 19.00, 0.10, 0.10, 0.75, 0.28, 1.7011, 1.0e-4},
{
Option::Call, 1.60, 1.56, 0.08, 0.06, 0.50, 0.12, 0.0291, 1.0e-4},
{
Option::Put, 70.00, 75.00, 0.05, 0.10, 0.50, 0.35, 4.0870, 1.0e-4},
{
Option::Call, 100.00, 90.00, 0.10, 0.10, 0.10, 0.15, 0.0205, 1.0e-4},
{
Option::Call, 100.00, 100.00, 0.10, 0.10, 0.10, 0.15, 1.8734, 1.0e-4},
{
Option::Call, 100.00, 110.00, 0.10, 0.10, 0.10, 0.15, 9.9413, 1.0e-4},
{
Option::Call, 100.00, 90.00, 0.10, 0.10, 0.10, 0.25, 0.3150, 1.0e-4},
{
Option::Call, 100.00, 100.00, 0.10, 0.10, 0.10, 0.25, 3.1217, 1.0e-4},
{
Option::Call, 100.00, 110.00, 0.10, 0.10, 0.10, 0.25, 10.3556, 1.0e-4},
{
Option::Call, 100.00, 90.00, 0.10, 0.10, 0.10, 0.35, 0.9474, 1.0e-4},
{
Option::Call, 100.00, 100.00, 0.10, 0.10, 0.10, 0.35, 4.3693, 1.0e-4},
{
Option::Call, 100.00, 110.00, 0.10, 0.10, 0.10, 0.35, 11.1381, 1.0e-4},
{
Option::Call, 100.00, 90.00, 0.10, 0.10, 0.50, 0.15, 0.8069, 1.0e-4},
{
Option::Call, 100.00, 100.00, 0.10, 0.10, 0.50, 0.15, 4.0232, 1.0e-4},
{
Option::Call, 100.00, 110.00, 0.10, 0.10, 0.50, 0.15, 10.5769, 1.0e-4},
{
Option::Call, 100.00, 90.00, 0.10, 0.10, 0.50, 0.25, 2.7026, 1.0e-4},
{
Option::Call, 100.00, 100.00, 0.10, 0.10, 0.50, 0.25, 6.6997, 1.0e-4},
{
Option::Call, 100.00, 110.00, 0.10, 0.10, 0.50, 0.25, 12.7857, 1.0e-4},
{
Option::Call, 100.00, 90.00, 0.10, 0.10, 0.50, 0.35, 4.9329, 1.0e-4},
{
Option::Call, 100.00, 100.00, 0.10, 0.10, 0.50, 0.35, 9.3679, 1.0e-4},
{
Option::Call, 100.00, 110.00, 0.10, 0.10, 0.50, 0.35, 15.3086, 1.0e-4},
{
Option::Put, 100.00, 90.00, 0.10, 0.10, 0.10, 0.15, 9.9210, 1.0e-4},
{
Option::Put, 100.00, 100.00, 0.10, 0.10, 0.10, 0.15, 1.8734, 1.0e-4},
{
Option::Put, 100.00, 110.00, 0.10, 0.10, 0.10, 0.15, 0.0408, 1.0e-4},
{
Option::Put, 100.00, 90.00, 0.10, 0.10, 0.10, 0.25, 10.2155, 1.0e-4},
{
Option::Put, 100.00, 100.00, 0.10, 0.10, 0.10, 0.25, 3.1217, 1.0e-4},
{
Option::Put, 100.00, 110.00, 0.10, 0.10, 0.10, 0.25, 0.4551, 1.0e-4},
{
Option::Put, 100.00, 90.00, 0.10, 0.10, 0.10, 0.35, 10.8479, 1.0e-4},
{
Option::Put, 100.00, 100.00, 0.10, 0.10, 0.10, 0.35, 4.3693, 1.0e-4},
{
Option::Put, 100.00, 110.00, 0.10, 0.10, 0.10, 0.35, 1.2376, 1.0e-4},
{
Option::Put, 100.00, 90.00, 0.10, 0.10, 0.50, 0.15, 10.3192, 1.0e-4},
{
Option::Put, 100.00, 100.00, 0.10, 0.10, 0.50, 0.15, 4.0232, 1.0e-4},
{
Option::Put, 100.00, 110.00, 0.10, 0.10, 0.50, 0.15, 1.0646, 1.0e-4},
{
Option::Put, 100.00, 90.00, 0.10, 0.10, 0.50, 0.25, 12.2149, 1.0e-4},
{
Option::Put, 100.00, 100.00, 0.10, 0.10, 0.50, 0.25, 6.6997, 1.0e-4},
{
Option::Put, 100.00, 110.00, 0.10, 0.10, 0.50, 0.25, 3.2734, 1.0e-4},
{
Option::Put, 100.00, 90.00, 0.10, 0.10, 0.50, 0.35, 14.4452, 1.0e-4},
{
Option::Put, 100.00, 100.00, 0.10, 0.10, 0.50, 0.35, 9.3679, 1.0e-4},
{
Option::Put, 100.00, 110.00, 0.10, 0.10, 0.50, 0.35, 5.7963, 1.0e-4},
{
Option::Call, 40.00, 42.00, 0.08, 0.04, 0.75, 0.35, 5.0975, 1.0e-4}
};
DayCounter dc = Actual360();
Date today = Date::todaysDate();
ext::shared_ptr<SimpleQuote> spot(new SimpleQuote(0.0));
ext::shared_ptr<SimpleQuote> qRate(new SimpleQuote(0.0));
ext::shared_ptr<YieldTermStructure> qTS = flatRate(today, qRate, dc);
ext::shared_ptr<SimpleQuote> rRate(new SimpleQuote(0.0));
ext::shared_ptr<YieldTermStructure> rTS = flatRate(today, rRate, dc);
ext::shared_ptr<SimpleQuote> vol(new SimpleQuote(0.0));
ext::shared_ptr<BlackVolTermStructure> volTS = flatVol(today, vol, dc);
for (auto& value : values) {
ext::shared_ptr<StrikedTypePayoff> payoff(new PlainVanillaPayoff(value.type, value.strike));
Date exDate = today + timeToDays(value.t);
ext::shared_ptr<Exercise> exercise(new EuropeanExercise(exDate));
spot->setValue(value.s);
qRate->setValue(value.q);
rRate->setValue(value.r);
vol->setValue(value.v);
ext::shared_ptr<BlackScholesMertonProcess> stochProcess(new
BlackScholesMertonProcess(Handle<Quote>(spot),
Handle<YieldTermStructure>(qTS),
Handle<YieldTermStructure>(rTS),
Handle<BlackVolTermStructure>(volTS)));
ext::shared_ptr<PricingEngine> engine(
new AnalyticEuropeanEngine(stochProcess));
EuropeanOption option(payoff, exercise);
option.setPricingEngine(engine);
Real calculated = option.NPV();
Real error = std::fabs(calculated - value.result);
Real tolerance = value.tol;
if (error>tolerance) {
REPORT_FAILURE("value", payoff, exercise, value.s, value.q, value.r, today, value.v,
value.result, calculated, error, tolerance);
}
engine = ext::shared_ptr<PricingEngine>(
new FdBlackScholesVanillaEngine(stochProcess,200,400));
option.setPricingEngine(engine);
calculated = option.NPV();
error = std::fabs(calculated - value.result);
tolerance = 1.0e-3;
if (error>tolerance) {
REPORT_FAILURE("value", payoff, exercise, value.s, value.q, value.r, today, value.v,
value.result, calculated, error, tolerance);
}
}
}
void EuropeanOptionTest::testGreekValues() {
BOOST_TEST_MESSAGE("Testing European option greek values...");
using namespace european_option_test;
SavedSettings backup;
EuropeanOptionData values[] = {
{
Option::Call, 100.00, 105.00, 0.10, 0.10, 0.500000, 0.36, 0.5946, 0 },
{
Option::Put, 100.00, 105.00, 0.10, 0.10, 0.500000, 0.36, -0.3566, 0 },
{
Option::Put, 100.00, 105.00, 0.10, 0.10, 0.500000, 0.36, -4.8775, 0 },
{
Option::Call, 60.00, 55.00,