EquityOption.cpp
This example evaluates European, American and Bermudan options using different methods
#include <ql/quantlib.hpp>
#ifdef BOOST_MSVC
#endif
#include <boost/timer.hpp>
#include <iostream>
#include <iomanip>
using namespace QuantLib;
#if defined(QL_ENABLE_SESSIONS)
namespace QuantLib {
Integer sessionId() { return 0; }
}
#endif
int main(int, char* []) {
try {
boost::timer timer;
std::cout << std::endl;
Calendar calendar = TARGET();
Date todaysDate(15, May, 1998);
Date settlementDate(17, May, 1998);
Settings::instance().evaluationDate() = todaysDate;
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 ;
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);
boost::shared_ptr<Exercise> europeanExercise(
new EuropeanExercise(maturity));
boost::shared_ptr<Exercise> bermudanExercise(
new BermudanExercise(exerciseDates));
boost::shared_ptr<Exercise> americanExercise(
new AmericanExercise(settlementDate,
maturity));
Handle<Quote> underlyingH(
boost::shared_ptr<Quote>(new SimpleQuote(underlying)));
Handle<YieldTermStructure> flatTermStructure(
boost::shared_ptr<YieldTermStructure>(
new FlatForward(settlementDate, riskFreeRate, dayCounter)));
Handle<YieldTermStructure> flatDividendTS(
boost::shared_ptr<YieldTermStructure>(
new FlatForward(settlementDate, dividendYield, dayCounter)));
Handle<BlackVolTermStructure> flatVolTS(
boost::shared_ptr<BlackVolTermStructure>(
new BlackConstantVol(settlementDate, calendar, volatility,
dayCounter)));
boost::shared_ptr<StrikedTypePayoff> payoff(
new PlainVanillaPayoff(type, strike));
boost::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(boost::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 = "Barone-Adesi/Whaley";
americanOption.setPricingEngine(boost::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(boost::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(boost::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;
Size timeSteps = 801;
method = "Finite differences";
europeanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
new FDEuropeanEngine(bsmProcess,timeSteps,timeSteps-1)));
bermudanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
new FDBermudanEngine(bsmProcess,timeSteps,timeSteps-1)));
americanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
new FDAmericanEngine(bsmProcess,timeSteps,timeSteps-1)));
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(boost::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<JarrowRudd>(bsmProcess,timeSteps)));
bermudanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<JarrowRudd>(bsmProcess,timeSteps)));
americanOption.setPricingEngine(boost::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(boost::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<CoxRossRubinstein>(bsmProcess,
timeSteps)));
bermudanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<CoxRossRubinstein>(bsmProcess,
timeSteps)));
americanOption.setPricingEngine(boost::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(boost::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<AdditiveEQPBinomialTree>(bsmProcess,
timeSteps)));
bermudanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<AdditiveEQPBinomialTree>(bsmProcess,
timeSteps)));
americanOption.setPricingEngine(boost::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(boost::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<Trigeorgis>(bsmProcess,timeSteps)));
bermudanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<Trigeorgis>(bsmProcess,timeSteps)));
americanOption.setPricingEngine(boost::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(boost::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<Tian>(bsmProcess,timeSteps)));
bermudanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<Tian>(bsmProcess,timeSteps)));
americanOption.setPricingEngine(boost::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(boost::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<LeisenReimer>(bsmProcess,timeSteps)));
bermudanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<LeisenReimer>(bsmProcess,timeSteps)));
americanOption.setPricingEngine(boost::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(boost::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<Joshi4>(bsmProcess,timeSteps)));
bermudanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
new BinomialVanillaEngine<Joshi4>(bsmProcess,timeSteps)));
americanOption.setPricingEngine(boost::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)";
Size mcSeed = 42;
boost::shared_ptr<PricingEngine> mcengine1;
mcengine1 = MakeMCEuropeanEngine<PseudoRandom>(bsmProcess)
.withSteps(timeSteps)
.withTolerance(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)";
Size nSamples = 32768;
boost::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)";
boost::shared_ptr<PricingEngine> mcengine3;
mcengine3 = MakeMCAmericanEngine<PseudoRandom>(bsmProcess)
.withSteps(100)
.withAntitheticVariate()
.withCalibrationSamples(4096)
.withTolerance(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;
Real seconds = timer.elapsed();
Integer hours = int(seconds/3600);
seconds -= hours * 3600;
Integer minutes = int(seconds/60);
seconds -= minutes * 60;
std::cout << " \nRun completed in ";
if (hours > 0)
std::cout << hours << " h ";
if (hours > 0 || minutes > 0)
std::cout << minutes << " m ";
std::cout << std::fixed << std::setprecision(0)
<< seconds << " s\n" << std::endl;
return 0;
} catch (std::exception& e) {
std::cout << e.what() << std::endl;
return 1;
} catch (...) {
std::cout << "unknown error" << std::endl;
return 1;
}
}