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).
#include <ql/qldefines.hpp>
#ifdef BOOST_MSVC
# include <ql/auto_link.hpp>
#endif
#include <ql/instruments/vanillaoption.hpp>
#include <ql/pricingengines/vanilla/binomialengine.hpp>
#include <ql/pricingengines/vanilla/analyticeuropeanengine.hpp>
#include <ql/pricingengines/vanilla/analytichestonengine.hpp>
#include <ql/pricingengines/vanilla/baroneadesiwhaleyengine.hpp>
#include <ql/pricingengines/vanilla/bjerksundstenslandengine.hpp>
#include <ql/pricingengines/vanilla/batesengine.hpp>
#include <ql/pricingengines/vanilla/integralengine.hpp>
#include <ql/pricingengines/vanilla/fdblackscholesvanillaengine.hpp>
#include <ql/pricingengines/vanilla/mceuropeanengine.hpp>
#include <ql/pricingengines/vanilla/mcamericanengine.hpp>
#include <ql/pricingengines/vanilla/analyticeuropeanvasicekengine.hpp>
#include <ql/time/calendars/target.hpp>
#include <ql/utilities/dataformatters.hpp>
#include <ql/models/shortrate/onefactormodels/vasicek.hpp>
#include <iostream>
#include <iomanip>
#if defined(QL_ENABLE_SESSIONS)
ThreadKey sessionId() { return 0; }
}
#endif
int main(int, char* []) {
try {
std::cout << std::endl;
Calendar calendar = TARGET();
Date todaysDate(15, May, 1998);
Date settlementDate(17, May, 1998);
Option::Type type(Option::Put);
Rate riskFreeRate = 0.06;
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::endl;
std::cout << std::endl;
std::string method;
std::cout << std::endl ;
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;
exerciseDates.push_back(settlementDate + 3*i*Months);
ext::shared_ptr<Exercise> europeanExercise(
new EuropeanExercise(maturity));
ext::shared_ptr<Exercise> bermudanExercise(
new BermudanExercise(exerciseDates));
ext::shared_ptr<Exercise> americanExercise(
new AmericanExercise(settlementDate,
maturity));
Handle<Quote> underlyingH(
ext::shared_ptr<Quote>(new SimpleQuote(underlying)));
Handle<YieldTermStructure> flatTermStructure(
ext::shared_ptr<YieldTermStructure>(
new FlatForward(settlementDate, riskFreeRate, dayCounter)));
Handle<YieldTermStructure> flatDividendTS(
ext::shared_ptr<YieldTermStructure>(
new FlatForward(settlementDate, dividendYield, dayCounter)));
Handle<BlackVolTermStructure> flatVolTS(
ext::shared_ptr<BlackVolTermStructure>(
new BlackConstantVol(settlementDate, calendar,
volatility,
dayCounter)));
ext::shared_ptr<StrikedTypePayoff> payoff(
new PlainVanillaPayoff(type, strike));
ext::shared_ptr<BlackScholesMertonProcess> bsmProcess(
new BlackScholesMertonProcess(underlyingH, flatDividendTS,
flatTermStructure, flatVolTS));
VanillaOption europeanOption(payoff, europeanExercise);
VanillaOption bermudanOption(payoff, bermudanExercise);
VanillaOption americanOption(payoff, americanExercise);
method = "Black-Scholes";
europeanOption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new 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;
method = "Black Vasicek Model";
ext::shared_ptr<Vasicek> vasicekProcess(new Vasicek(r0, a, b, sigma_r, riskPremium));
europeanOption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new 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;
method = "Heston semi-analytic";
ext::shared_ptr<HestonProcess> hestonProcess(
new HestonProcess(flatTermStructure, flatDividendTS,
ext::shared_ptr<HestonModel> hestonModel(
new HestonModel(hestonProcess));
europeanOption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new 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;
method = "Bates semi-analytic";
ext::shared_ptr<BatesProcess> batesProcess(
new BatesProcess(flatTermStructure, flatDividendTS,
1e-14, 1e-14, 1e-14));
ext::shared_ptr<BatesModel> batesModel(new BatesModel(batesProcess));
europeanOption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new 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;
method = "Barone-Adesi/Whaley";
americanOption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new 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;
method = "Bjerksund/Stensland";
americanOption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new 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;
method = "Integral";
europeanOption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new 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;
method = "Finite differences";
ext::shared_ptr<PricingEngine> 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;
method = "Binomial Jarrow-Rudd";
europeanOption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<JarrowRudd>(bsmProcess,timeSteps)));
bermudanOption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<JarrowRudd>(bsmProcess,timeSteps)));
americanOption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<JarrowRudd>(bsmProcess,timeSteps)));
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;
method = "Binomial Cox-Ross-Rubinstein";
europeanOption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<CoxRossRubinstein>(bsmProcess,
timeSteps)));
bermudanOption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<CoxRossRubinstein>(bsmProcess,
timeSteps)));
americanOption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<CoxRossRubinstein>(bsmProcess,
timeSteps)));
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;
method = "Additive equiprobabilities";
europeanOption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<AdditiveEQPBinomialTree>(bsmProcess,
timeSteps)));
bermudanOption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<AdditiveEQPBinomialTree>(bsmProcess,
timeSteps)));
americanOption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<AdditiveEQPBinomialTree>(bsmProcess,
timeSteps)));
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;
method = "Binomial Trigeorgis";
europeanOption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<Trigeorgis>(bsmProcess,timeSteps)));
bermudanOption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<Trigeorgis>(bsmProcess,timeSteps)));
americanOption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<Trigeorgis>(bsmProcess,timeSteps)));
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;
method = "Binomial Tian";
europeanOption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<Tian>(bsmProcess,timeSteps)));
bermudanOption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<Tian>(bsmProcess,timeSteps)));
americanOption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<Tian>(bsmProcess,timeSteps)));
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;
method = "Binomial Leisen-Reimer";
europeanOption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<LeisenReimer>(bsmProcess,timeSteps)));
bermudanOption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<LeisenReimer>(bsmProcess,timeSteps)));
americanOption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<LeisenReimer>(bsmProcess,timeSteps)));
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;
method = "Binomial Joshi";
europeanOption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<Joshi4>(bsmProcess,timeSteps)));
bermudanOption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<Joshi4>(bsmProcess,timeSteps)));
americanOption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<Joshi4>(bsmProcess,timeSteps)));
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;
timeSteps = 1;
method = "MC (crude)";
ext::shared_ptr<PricingEngine> mcengine1;
mcengine1 = MakeMCEuropeanEngine<PseudoRandom>(bsmProcess)
.withSteps(timeSteps)
.withAbsoluteTolerance(0.02)
.withSeed(mcSeed);
europeanOption.setPricingEngine(mcengine1);
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;
method = "QMC (Sobol)";
ext::shared_ptr<PricingEngine> mcengine2;
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;
method = "MC (Longstaff Schwartz)";
ext::shared_ptr<PricingEngine> mcengine3;
mcengine3 = MakeMCAmericanEngine<PseudoRandom>(bsmProcess)
.withSteps(100)
.withAntitheticVariate()
.withCalibrationSamples(4096)
.withAbsoluteTolerance(0.02)
.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;
return 0;
} catch (std::exception& e) {
std::cerr << e.what() << std::endl;
return 1;
} catch (...) {
std::cerr << "unknown error" << std::endl;
return 1;
}
}