QuantLib: a free/open-source library for quantitative finance
Fully annotated sources - version 1.32
Loading...
Searching...
No Matches
EquityOption.cpp

For a given set of option parameters, this example computes the value of three different equity options types (with european, bermudan and american exercise features) using different valuation algorithms. The calculation methods are Black-Scholes (for european options only), Barone-Adesi/Whaley (american-only), Bjerksund/Stensland (american), Integral (european), finite differences, binomial trees, crude Monte Carlo (european-only) and Sobol-sequence Monte Carlo (european-only).

/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include <ql/qldefines.hpp>
#if !defined(BOOST_ALL_NO_LIB) && defined(BOOST_MSVC)
# include <ql/auto_link.hpp>
#endif
#include <ql/instruments/vanillaoption.hpp>
#include <ql/math/integrals/tanhsinhintegral.hpp>
#include <ql/pricingengines/vanilla/analyticeuropeanengine.hpp>
#include <ql/pricingengines/vanilla/analyticeuropeanvasicekengine.hpp>
#include <ql/pricingengines/vanilla/analytichestonengine.hpp>
#include <ql/pricingengines/vanilla/baroneadesiwhaleyengine.hpp>
#include <ql/pricingengines/vanilla/batesengine.hpp>
#include <ql/pricingengines/vanilla/binomialengine.hpp>
#include <ql/pricingengines/vanilla/bjerksundstenslandengine.hpp>
#include <ql/pricingengines/vanilla/fdblackscholesvanillaengine.hpp>
#include <ql/pricingengines/vanilla/integralengine.hpp>
#include <ql/pricingengines/vanilla/mcamericanengine.hpp>
#include <ql/pricingengines/vanilla/mceuropeanengine.hpp>
#include <ql/pricingengines/vanilla/qdfpamericanengine.hpp>
#include <ql/time/calendars/target.hpp>
#include <ql/utilities/dataformatters.hpp>
#include <iostream>
#include <iomanip>
using namespace QuantLib;
int main(int, char* []) {
try {
std::cout << std::endl;
// set up dates
Calendar calendar = TARGET();
Date todaysDate(15, May, 1998);
Date settlementDate(17, May, 1998);
Settings::instance().evaluationDate() = todaysDate;
// our options
Option::Type type(Option::Put);
Real underlying = 36;
Real strike = 40;
Spread dividendYield = 0.00;
Rate riskFreeRate = 0.06;
Volatility volatility = 0.20;
Date maturity(17, May, 1999);
DayCounter dayCounter = Actual365Fixed();
std::cout << "Option type = " << type << std::endl;
std::cout << "Maturity = " << maturity << std::endl;
std::cout << "Underlying price = " << underlying << std::endl;
std::cout << "Strike = " << strike << std::endl;
std::cout << "Risk-free interest rate = " << io::rate(riskFreeRate)
<< std::endl;
std::cout << "Dividend yield = " << io::rate(dividendYield)
<< std::endl;
std::cout << "Volatility = " << io::volatility(volatility)
<< std::endl;
std::cout << std::endl;
std::string method;
std::cout << std::endl ;
// write column headings
Size widths[] = { 35, 14, 14, 14 };
std::cout << std::setw(widths[0]) << std::left << "Method"
<< std::setw(widths[1]) << std::left << "European"
<< std::setw(widths[2]) << std::left << "Bermudan"
<< std::setw(widths[3]) << std::left << "American"
<< std::endl;
std::vector<Date> exerciseDates;
for (Integer i=1; i<=4; i++)
exerciseDates.push_back(settlementDate + 3*i*Months);
auto europeanExercise = ext::make_shared<EuropeanExercise>(maturity);
auto bermudanExercise = ext::make_shared<BermudanExercise>(exerciseDates);
auto americanExercise = ext::make_shared<AmericanExercise>(settlementDate, maturity);
Handle<Quote> underlyingH(ext::make_shared<SimpleQuote>(underlying));
// bootstrap the yield/dividend/vol curves
Handle<YieldTermStructure> flatTermStructure(
ext::make_shared<FlatForward>(settlementDate, riskFreeRate, dayCounter));
ext::make_shared<FlatForward>(settlementDate, dividendYield, dayCounter));
ext::make_shared<BlackConstantVol>(settlementDate, calendar, volatility,
dayCounter));
auto payoff = ext::make_shared<PlainVanillaPayoff>(type, strike);
auto bsmProcess = ext::make_shared<BlackScholesMertonProcess>(
underlyingH, flatDividendTS, flatTermStructure, flatVolTS);
// options
VanillaOption europeanOption(payoff, europeanExercise);
VanillaOption bermudanOption(payoff, bermudanExercise);
VanillaOption americanOption(payoff, americanExercise);
// Analytic formulas:
// Black-Scholes for European
method = "Black-Scholes";
europeanOption.setPricingEngine(ext::make_shared<AnalyticEuropeanEngine>(bsmProcess));
std::cout << std::setw(widths[0]) << std::left << method
<< std::fixed
<< std::setw(widths[1]) << std::left << europeanOption.NPV()
<< std::setw(widths[2]) << std::left << "N/A"
<< std::setw(widths[3]) << std::left << "N/A"
<< std::endl;
//Vasicek rates model for European
method = "Black Vasicek Model";
Real r0 = riskFreeRate;
Real a = 0.3;
Real b = 0.3;
Real sigma_r = 0.15;
Real riskPremium = 0.0;
Real correlation = 0.5;
auto vasicekProcess = ext::make_shared<Vasicek>(r0, a, b, sigma_r, riskPremium);
europeanOption.setPricingEngine(ext::make_shared<AnalyticBlackVasicekEngine>(bsmProcess, vasicekProcess, correlation));
std::cout << std::setw(widths[0]) << std::left << method
<< std::fixed
<< std::setw(widths[1]) << std::left << europeanOption.NPV()
<< std::setw(widths[2]) << std::left << "N/A"
<< std::setw(widths[3]) << std::left << "N/A"
<< std::endl;
// semi-analytic Heston for European
method = "Heston semi-analytic";
auto hestonProcess = ext::make_shared<HestonProcess>(flatTermStructure, flatDividendTS,
underlyingH, volatility*volatility,
1.0, volatility*volatility, 0.001, 0.0);
auto hestonModel = ext::make_shared<HestonModel>(hestonProcess);
europeanOption.setPricingEngine(ext::make_shared<AnalyticHestonEngine>(hestonModel));
std::cout << std::setw(widths[0]) << std::left << method
<< std::fixed
<< std::setw(widths[1]) << std::left << europeanOption.NPV()
<< std::setw(widths[2]) << std::left << "N/A"
<< std::setw(widths[3]) << std::left << "N/A"
<< std::endl;
// semi-analytic Bates for European
method = "Bates semi-analytic";
auto batesProcess = ext::make_shared<BatesProcess>(flatTermStructure, flatDividendTS,
underlyingH, volatility*volatility,
1.0, volatility*volatility, 0.001, 0.0,
1e-14, 1e-14, 1e-14);
auto batesModel = ext::make_shared<BatesModel>(batesProcess);
europeanOption.setPricingEngine(ext::make_shared<BatesEngine>(batesModel));
std::cout << std::setw(widths[0]) << std::left << method
<< std::fixed
<< std::setw(widths[1]) << std::left << europeanOption.NPV()
<< std::setw(widths[2]) << std::left << "N/A"
<< std::setw(widths[3]) << std::left << "N/A"
<< std::endl;
// Barone-Adesi and Whaley approximation for American
method = "Barone-Adesi/Whaley";
americanOption.setPricingEngine(ext::make_shared<BaroneAdesiWhaleyApproximationEngine>(bsmProcess));
std::cout << std::setw(widths[0]) << std::left << method
<< std::fixed
<< std::setw(widths[1]) << std::left << "N/A"
<< std::setw(widths[2]) << std::left << "N/A"
<< std::setw(widths[3]) << std::left << americanOption.NPV()
<< std::endl;
// Bjerksund and Stensland approximation for American
method = "Bjerksund/Stensland";
americanOption.setPricingEngine(ext::make_shared<BjerksundStenslandApproximationEngine>(bsmProcess));
std::cout << std::setw(widths[0]) << std::left << method
<< std::fixed
<< std::setw(widths[1]) << std::left << "N/A"
<< std::setw(widths[2]) << std::left << "N/A"
<< std::setw(widths[3]) << std::left << americanOption.NPV()
<< std::endl;
// QD+ fixed-point engine for American
method = "QD+ fixed-point (fast)";
americanOption.setPricingEngine(ext::make_shared<QdFpAmericanEngine>
(bsmProcess, QdFpAmericanEngine::fastScheme()));
std::cout << std::setw(widths[0]) << std::left << method
<< std::fixed
<< std::setw(widths[1]) << std::left << "N/A"
<< std::setw(widths[2]) << std::left << "N/A"
<< std::setw(widths[3]) << std::left << americanOption.NPV()
<< std::endl;
method = "QD+ fixed-point (accurate)";
americanOption.setPricingEngine(ext::make_shared<QdFpAmericanEngine>
(bsmProcess, QdFpAmericanEngine::accurateScheme()));
std::cout << std::setw(widths[0]) << std::left << method
<< std::fixed
<< std::setw(widths[1]) << std::left << "N/A"
<< std::setw(widths[2]) << std::left << "N/A"
<< std::setw(widths[3]) << std::left << americanOption.NPV()
<< std::endl;
method = "QD+ fixed-point (high precision)";
americanOption.setPricingEngine(ext::make_shared<QdFpAmericanEngine>
(bsmProcess, QdFpAmericanEngine::highPrecisionScheme()));
std::cout << std::setw(widths[0]) << std::left << method
<< std::fixed
<< std::setw(widths[1]) << std::left << "N/A"
<< std::setw(widths[2]) << std::left << "N/A"
<< std::setw(widths[3]) << std::left << americanOption.NPV()
<< std::endl;
// Integral
method = "Integral";
europeanOption.setPricingEngine(ext::make_shared<IntegralEngine>(bsmProcess));
std::cout << std::setw(widths[0]) << std::left << method
<< std::fixed
<< std::setw(widths[1]) << std::left << europeanOption.NPV()
<< std::setw(widths[2]) << std::left << "N/A"
<< std::setw(widths[3]) << std::left << "N/A"
<< std::endl;
// Finite differences
Size timeSteps = 801;
method = "Finite differences";
auto fdengine =
ext::make_shared<FdBlackScholesVanillaEngine>(bsmProcess,
timeSteps,
timeSteps-1);
europeanOption.setPricingEngine(fdengine);
bermudanOption.setPricingEngine(fdengine);
americanOption.setPricingEngine(fdengine);
std::cout << std::setw(widths[0]) << std::left << method
<< std::fixed
<< std::setw(widths[1]) << std::left << europeanOption.NPV()
<< std::setw(widths[2]) << std::left << bermudanOption.NPV()
<< std::setw(widths[3]) << std::left << americanOption.NPV()
<< std::endl;
// Binomial method: Jarrow-Rudd
method = "Binomial Jarrow-Rudd";
auto jrEngine = ext::make_shared<BinomialVanillaEngine<JarrowRudd>>(bsmProcess, timeSteps);
europeanOption.setPricingEngine(jrEngine);
bermudanOption.setPricingEngine(jrEngine);
americanOption.setPricingEngine(jrEngine);
std::cout << std::setw(widths[0]) << std::left << method
<< std::fixed
<< std::setw(widths[1]) << std::left << europeanOption.NPV()
<< std::setw(widths[2]) << std::left << bermudanOption.NPV()
<< std::setw(widths[3]) << std::left << americanOption.NPV()
<< std::endl;
// Binomial method: Cox-Ross-Rubinstein
method = "Binomial Cox-Ross-Rubinstein";
auto crrEngine = ext::make_shared<BinomialVanillaEngine<CoxRossRubinstein>>(bsmProcess, timeSteps);
europeanOption.setPricingEngine(crrEngine);
bermudanOption.setPricingEngine(crrEngine);
americanOption.setPricingEngine(crrEngine);
std::cout << std::setw(widths[0]) << std::left << method
<< std::fixed
<< std::setw(widths[1]) << std::left << europeanOption.NPV()
<< std::setw(widths[2]) << std::left << bermudanOption.NPV()
<< std::setw(widths[3]) << std::left << americanOption.NPV()
<< std::endl;
// Binomial method: Additive equiprobabilities
method = "Additive equiprobabilities";
auto aeqpEngine = ext::make_shared<BinomialVanillaEngine<AdditiveEQPBinomialTree>>(bsmProcess, timeSteps);
europeanOption.setPricingEngine(aeqpEngine);
bermudanOption.setPricingEngine(aeqpEngine);
americanOption.setPricingEngine(aeqpEngine);
std::cout << std::setw(widths[0]) << std::left << method
<< std::fixed
<< std::setw(widths[1]) << std::left << europeanOption.NPV()
<< std::setw(widths[2]) << std::left << bermudanOption.NPV()
<< std::setw(widths[3]) << std::left << americanOption.NPV()
<< std::endl;
// Binomial method: Binomial Trigeorgis
method = "Binomial Trigeorgis";
auto trigeorgisEngine = ext::make_shared<BinomialVanillaEngine<Trigeorgis>>(bsmProcess, timeSteps);
europeanOption.setPricingEngine(trigeorgisEngine);
bermudanOption.setPricingEngine(trigeorgisEngine);
americanOption.setPricingEngine(trigeorgisEngine);
std::cout << std::setw(widths[0]) << std::left << method
<< std::fixed
<< std::setw(widths[1]) << std::left << europeanOption.NPV()
<< std::setw(widths[2]) << std::left << bermudanOption.NPV()
<< std::setw(widths[3]) << std::left << americanOption.NPV()
<< std::endl;
// Binomial method: Binomial Tian
method = "Binomial Tian";
auto tianEngine = ext::make_shared<BinomialVanillaEngine<Tian>>(bsmProcess, timeSteps);
europeanOption.setPricingEngine(tianEngine);
bermudanOption.setPricingEngine(tianEngine);
americanOption.setPricingEngine(tianEngine);
std::cout << std::setw(widths[0]) << std::left << method
<< std::fixed
<< std::setw(widths[1]) << std::left << europeanOption.NPV()
<< std::setw(widths[2]) << std::left << bermudanOption.NPV()
<< std::setw(widths[3]) << std::left << americanOption.NPV()
<< std::endl;
// Binomial method: Binomial Leisen-Reimer
method = "Binomial Leisen-Reimer";
auto lrEngine = ext::make_shared<BinomialVanillaEngine<LeisenReimer>>(bsmProcess, timeSteps);
europeanOption.setPricingEngine(lrEngine);
bermudanOption.setPricingEngine(lrEngine);
americanOption.setPricingEngine(lrEngine);
std::cout << std::setw(widths[0]) << std::left << method
<< std::fixed
<< std::setw(widths[1]) << std::left << europeanOption.NPV()
<< std::setw(widths[2]) << std::left << bermudanOption.NPV()
<< std::setw(widths[3]) << std::left << americanOption.NPV()
<< std::endl;
// Binomial method: Binomial Joshi
method = "Binomial Joshi";
auto joshiEngine = ext::make_shared<BinomialVanillaEngine<Joshi4>>(bsmProcess, timeSteps);
europeanOption.setPricingEngine(joshiEngine);
bermudanOption.setPricingEngine(joshiEngine);
americanOption.setPricingEngine(joshiEngine);
std::cout << std::setw(widths[0]) << std::left << method
<< std::fixed
<< std::setw(widths[1]) << std::left << europeanOption.NPV()
<< std::setw(widths[2]) << std::left << bermudanOption.NPV()
<< std::setw(widths[3]) << std::left << americanOption.NPV()
<< std::endl;
// Monte Carlo Method: MC (crude)
timeSteps = 1;
method = "MC (crude)";
Size mcSeed = 42;
auto mcengine1 = MakeMCEuropeanEngine<PseudoRandom>(bsmProcess)
.withSteps(timeSteps)
.withSeed(mcSeed);
europeanOption.setPricingEngine(mcengine1);
// Real errorEstimate = europeanOption.errorEstimate();
std::cout << std::setw(widths[0]) << std::left << method
<< std::fixed
<< std::setw(widths[1]) << std::left << europeanOption.NPV()
<< std::setw(widths[2]) << std::left << "N/A"
<< std::setw(widths[3]) << std::left << "N/A"
<< std::endl;
// Monte Carlo Method: QMC (Sobol)
method = "QMC (Sobol)";
Size nSamples = 32768; // 2^15
auto mcengine2 = MakeMCEuropeanEngine<LowDiscrepancy>(bsmProcess)
.withSteps(timeSteps)
.withSamples(nSamples);
europeanOption.setPricingEngine(mcengine2);
std::cout << std::setw(widths[0]) << std::left << method
<< std::fixed
<< std::setw(widths[1]) << std::left << europeanOption.NPV()
<< std::setw(widths[2]) << std::left << "N/A"
<< std::setw(widths[3]) << std::left << "N/A"
<< std::endl;
// Monte Carlo Method: MC (Longstaff Schwartz)
method = "MC (Longstaff Schwartz)";
auto mcengine3 = MakeMCAmericanEngine<PseudoRandom>(bsmProcess)
.withSteps(100)
.withSeed(mcSeed);
americanOption.setPricingEngine(mcengine3);
std::cout << std::setw(widths[0]) << std::left << method
<< std::fixed
<< std::setw(widths[1]) << std::left << "N/A"
<< std::setw(widths[2]) << std::left << "N/A"
<< std::setw(widths[3]) << std::left << americanOption.NPV()
<< std::endl;
// End test
return 0;
} catch (std::exception& e) {
std::cerr << e.what() << std::endl;
return 1;
} catch (...) {
std::cerr << "unknown error" << std::endl;
return 1;
}
}
Actual/365 (Fixed) day count convention.
calendar class
Definition: calendar.hpp:61
Concrete date class.
Definition: date.hpp:125
day counter class
Definition: daycounter.hpp:44
Shared handle to an observable.
Definition: handle.hpp:41
Real NPV() const
returns the net present value of the instrument.
Definition: instrument.hpp:167
void setPricingEngine(const ext::shared_ptr< PricingEngine > &)
set the pricing engine to be used.
Definition: instrument.cpp:35
Monte Carlo American engine factory.
MakeMCAmericanEngine & withCalibrationSamples(Size calibrationSamples)
MakeMCAmericanEngine & withAbsoluteTolerance(Real tolerance)
MakeMCAmericanEngine & withSeed(BigNatural seed)
MakeMCAmericanEngine & withAntitheticVariate(bool b=true)
MakeMCAmericanEngine & withSteps(Size steps)
Monte Carlo European engine factory.
MakeMCEuropeanEngine & withSeed(BigNatural seed)
MakeMCEuropeanEngine & withSteps(Size steps)
MakeMCEuropeanEngine & withAbsoluteTolerance(Real tolerance)
MakeMCEuropeanEngine & withSamples(Size samples)
TARGET calendar
Definition: target.hpp:50
Vanilla option (no discrete dividends, no barriers) on a single asset.
QL_REAL Real
real number
Definition: types.hpp:50
Real Volatility
volatility
Definition: types.hpp:78
QL_INTEGER Integer
integer number
Definition: types.hpp:35
Real Spread
spreads on interest rates
Definition: types.hpp:74
Real Rate
interest rates
Definition: types.hpp:70
std::size_t Size
size of a container
Definition: types.hpp:58
Definition: any.hpp:35