QuantLib: a free/open-source library for quantitative finance
fully annotated source code - version 1.34
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 -*- */
/*!
Copyright (C) 2005, 2006, 2007, 2009 StatPro Italia srl
This file is part of QuantLib, a free-software/open-source library
for financial quantitative analysts and developers - http://quantlib.org/
QuantLib is free software: you can redistribute it and/or modify it
under the terms of the QuantLib license. You should have received a
copy of the license along with this program; if not, please email
<quantlib-dev@lists.sf.net>. The license is also available online at
<http://quantlib.org/license.shtml>.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the license for more details.
*/
#include <ql/qldefines.hpp>
#if !defined(BOOST_ALL_NO_LIB) && defined(BOOST_MSVC)
# include <ql/auto_link.hpp>
#endif
#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);
auto underlyingH = makeQuoteHandle(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;
}
}
Analytic European engine.
analytic Heston-model engine
Barone-Adesi and Whaley approximation engine.
analytic Bates model engine
Binomial option engine.
Bjerksund and Stensland approximation engine.
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.
output manipulators
ext::function< Real(Real)> b
Finite-differences Black Scholes vanilla option engine.
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
Integral option engine.
ext::shared_ptr< QuantLib::Payoff > payoff
American Monte Carlo engine.
Monte Carlo European option engine.
Definition: any.hpp:35
Global definitions and compiler switches.
TARGET calendar.
Vanilla option on a single asset.