EquityOption.cpp
This example evaluates European, American and Bermudan options using different methods
00001
00002
00020
00021 #define BOOST_LIB_DIAGNOSTIC
00022 # include <ql/quantlib.hpp>
00023 #undef BOOST_LIB_DIAGNOSTIC
00024
00025 #ifdef BOOST_MSVC
00026
00027
00028
00029
00030
00031
00032
00033
00034 #endif
00035
00036 #include <boost/timer.hpp>
00037 #include <iostream>
00038 #include <iomanip>
00039
00040 using namespace QuantLib;
00041
00042 #if defined(QL_ENABLE_SESSIONS)
00043 namespace QuantLib {
00044
00045 Integer sessionId() { return 0; }
00046
00047 }
00048 #endif
00049
00050
00051 int main(int, char* [])
00052 {
00053 try {
00054 QL_IO_INIT
00055
00056 boost::timer timer;
00057 std::cout << std::endl;
00058
00059
00060 Option::Type type(Option::Put);
00061 Real underlying = 36;
00062 Real strike = 40;
00063 Spread dividendYield = 0.00;
00064 Rate riskFreeRate = 0.06;
00065 Volatility volatility = 0.20;
00066
00067 Date todaysDate(15, May, 1998);
00068 Date settlementDate(17, May, 1998);
00069 Settings::instance().evaluationDate() = todaysDate;
00070
00071 Date maturity(17, May, 1999);
00072 DayCounter dayCounter = Actual365Fixed();
00073
00074 std::cout << "Option type = " << type << std::endl;
00075 std::cout << "Maturity = " << maturity << std::endl;
00076 std::cout << "Underlying price = " << underlying << std::endl;
00077 std::cout << "Strike = " << strike << std::endl;
00078 std::cout << "Risk-free interest rate = " << io::rate(riskFreeRate)
00079 << std::endl;
00080 std::cout << "Dividend yield = " << io::rate(dividendYield)
00081 << std::endl;
00082 std::cout << "Volatility = " << io::volatility(volatility)
00083 << std::endl;
00084 std::cout << std::endl;
00085
00086 std::string method;
00087
00088 std::cout << std::endl ;
00089
00090
00091 Size widths[] = { 35, 14, 14, 14 };
00092 std::cout << std::setw(widths[0]) << std::left << "Method"
00093 << std::setw(widths[1]) << std::left << "European"
00094 << std::setw(widths[2]) << std::left << "Bermudan"
00095 << std::setw(widths[3]) << std::left << "American"
00096 << std::endl;
00097
00098 std::vector<Date> exerciseDates;
00099 for (Integer i=1; i<=4; i++)
00100 exerciseDates.push_back(settlementDate + 3*i*Months);
00101
00102 boost::shared_ptr<Exercise> europeanExercise(
00103 new EuropeanExercise(maturity));
00104
00105 boost::shared_ptr<Exercise> bermudanExercise(
00106 new BermudanExercise(exerciseDates));
00107
00108 boost::shared_ptr<Exercise> americanExercise(
00109 new AmericanExercise(settlementDate,
00110 maturity));
00111
00112 Handle<Quote> underlyingH(
00113 boost::shared_ptr<Quote>(new SimpleQuote(underlying)));
00114
00115
00116 Handle<YieldTermStructure> flatTermStructure(
00117 boost::shared_ptr<YieldTermStructure>(
00118 new FlatForward(settlementDate, riskFreeRate, dayCounter)));
00119 Handle<YieldTermStructure> flatDividendTS(
00120 boost::shared_ptr<YieldTermStructure>(
00121 new FlatForward(settlementDate, dividendYield, dayCounter)));
00122 Handle<BlackVolTermStructure> flatVolTS(
00123 boost::shared_ptr<BlackVolTermStructure>(
00124 new BlackConstantVol(settlementDate, volatility, dayCounter)));
00125
00126 boost::shared_ptr<StrikedTypePayoff> payoff(
00127 new PlainVanillaPayoff(type, strike));
00128
00129 boost::shared_ptr<StochasticProcess> stochasticProcess(
00130 new BlackScholesMertonProcess(underlyingH, flatDividendTS,
00131 flatTermStructure, flatVolTS));
00132
00133
00134
00135 VanillaOption europeanOption(stochasticProcess, payoff,
00136 europeanExercise);
00137
00138 VanillaOption bermudanOption(stochasticProcess, payoff,
00139 bermudanExercise);
00140
00141 VanillaOption americanOption(stochasticProcess, payoff,
00142 americanExercise);
00143
00144
00145
00146
00147 method = "Black-Scholes";
00148 europeanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
00149 new AnalyticEuropeanEngine));
00150 std::cout << std::setw(widths[0]) << std::left << method
00151 << std::fixed
00152 << std::setw(widths[1]) << std::left << europeanOption.NPV()
00153 << std::setw(widths[2]) << std::left << "N/A"
00154 << std::setw(widths[3]) << std::left << "N/A"
00155 << std::endl;
00156
00157
00158 method = "Barone-Adesi/Whaley";
00159 americanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
00160 new BaroneAdesiWhaleyApproximationEngine));
00161 std::cout << std::setw(widths[0]) << std::left << method
00162 << std::fixed
00163 << std::setw(widths[1]) << std::left << "N/A"
00164 << std::setw(widths[2]) << std::left << "N/A"
00165 << std::setw(widths[3]) << std::left << americanOption.NPV()
00166 << std::endl;
00167
00168
00169 method = "Bjerksund/Stensland";
00170 americanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
00171 new BjerksundStenslandApproximationEngine));
00172 std::cout << std::setw(widths[0]) << std::left << method
00173 << std::fixed
00174 << std::setw(widths[1]) << std::left << "N/A"
00175 << std::setw(widths[2]) << std::left << "N/A"
00176 << std::setw(widths[3]) << std::left << americanOption.NPV()
00177 << std::endl;
00178
00179
00180
00181 method = "Integral";
00182 europeanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
00183 new IntegralEngine));
00184 std::cout << std::setw(widths[0]) << std::left << method
00185 << std::fixed
00186 << std::setw(widths[1]) << std::left << europeanOption.NPV()
00187 << std::setw(widths[2]) << std::left << "N/A"
00188 << std::setw(widths[3]) << std::left << "N/A"
00189 << std::endl;
00190
00191
00192
00193 Size timeSteps = 801;
00194
00195 method = "Finite differences";
00196 europeanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
00197 new FDEuropeanEngine(timeSteps,timeSteps-1)));
00198 bermudanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
00199 new FDBermudanEngine(timeSteps,timeSteps-1)));
00200 americanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
00201 new FDAmericanEngine(timeSteps,timeSteps-1)));
00202 std::cout << std::setw(widths[0]) << std::left << method
00203 << std::fixed
00204 << std::setw(widths[1]) << std::left << europeanOption.NPV()
00205 << std::setw(widths[2]) << std::left << bermudanOption.NPV()
00206 << std::setw(widths[3]) << std::left << americanOption.NPV()
00207 << std::endl;
00208
00209
00210
00211 method = "Binomial Jarrow-Rudd";
00212 europeanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
00213 new BinomialVanillaEngine<JarrowRudd>(timeSteps)));
00214 bermudanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
00215 new BinomialVanillaEngine<JarrowRudd>(timeSteps)));
00216 americanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
00217 new BinomialVanillaEngine<JarrowRudd>(timeSteps)));
00218 std::cout << std::setw(widths[0]) << std::left << method
00219 << std::fixed
00220 << std::setw(widths[1]) << std::left << europeanOption.NPV()
00221 << std::setw(widths[2]) << std::left << bermudanOption.NPV()
00222 << std::setw(widths[3]) << std::left << americanOption.NPV()
00223 << std::endl;
00224
00225 method = "Binomial Cox-Ross-Rubinstein";
00226 europeanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
00227 new BinomialVanillaEngine<CoxRossRubinstein>(timeSteps)));
00228 bermudanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
00229 new BinomialVanillaEngine<CoxRossRubinstein>(timeSteps)));
00230 americanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
00231 new BinomialVanillaEngine<CoxRossRubinstein>(timeSteps)));
00232 std::cout << std::setw(widths[0]) << std::left << method
00233 << std::fixed
00234 << std::setw(widths[1]) << std::left << europeanOption.NPV()
00235 << std::setw(widths[2]) << std::left << bermudanOption.NPV()
00236 << std::setw(widths[3]) << std::left << americanOption.NPV()
00237 << std::endl;
00238
00239 method = "Additive equiprobabilities";
00240 europeanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
00241 new BinomialVanillaEngine<AdditiveEQPBinomialTree>(timeSteps)));
00242 bermudanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
00243 new BinomialVanillaEngine<AdditiveEQPBinomialTree>(timeSteps)));
00244 americanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
00245 new BinomialVanillaEngine<AdditiveEQPBinomialTree>(timeSteps)));
00246 std::cout << std::setw(widths[0]) << std::left << method
00247 << std::fixed
00248 << std::setw(widths[1]) << std::left << europeanOption.NPV()
00249 << std::setw(widths[2]) << std::left << bermudanOption.NPV()
00250 << std::setw(widths[3]) << std::left << americanOption.NPV()
00251 << std::endl;
00252
00253 method = "Binomial Trigeorgis";
00254 europeanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
00255 new BinomialVanillaEngine<Trigeorgis>(timeSteps)));
00256 bermudanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
00257 new BinomialVanillaEngine<Trigeorgis>(timeSteps)));
00258 americanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
00259 new BinomialVanillaEngine<Trigeorgis>(timeSteps)));
00260 std::cout << std::setw(widths[0]) << std::left << method
00261 << std::fixed
00262 << std::setw(widths[1]) << std::left << europeanOption.NPV()
00263 << std::setw(widths[2]) << std::left << bermudanOption.NPV()
00264 << std::setw(widths[3]) << std::left << americanOption.NPV()
00265 << std::endl;
00266
00267 method = "Binomial Tian";
00268 europeanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
00269 new BinomialVanillaEngine<Tian>(timeSteps)));
00270 bermudanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
00271 new BinomialVanillaEngine<Tian>(timeSteps)));
00272 americanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
00273 new BinomialVanillaEngine<Tian>(timeSteps)));
00274 std::cout << std::setw(widths[0]) << std::left << method
00275 << std::fixed
00276 << std::setw(widths[1]) << std::left << europeanOption.NPV()
00277 << std::setw(widths[2]) << std::left << bermudanOption.NPV()
00278 << std::setw(widths[3]) << std::left << americanOption.NPV()
00279 << std::endl;
00280
00281 method = "Binomial Leisen-Reimer";
00282 europeanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
00283 new BinomialVanillaEngine<LeisenReimer>(timeSteps)));
00284 bermudanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
00285 new BinomialVanillaEngine<LeisenReimer>(timeSteps)));
00286 americanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
00287 new BinomialVanillaEngine<LeisenReimer>(timeSteps)));
00288 std::cout << std::setw(widths[0]) << std::left << method
00289 << std::fixed
00290 << std::setw(widths[1]) << std::left << europeanOption.NPV()
00291 << std::setw(widths[2]) << std::left << bermudanOption.NPV()
00292 << std::setw(widths[3]) << std::left << americanOption.NPV()
00293 << std::endl;
00294
00295
00296
00297 timeSteps = 1;
00298
00299 method = "MC (crude)";
00300 Size mcSeed = 42;
00301
00302 boost::shared_ptr<PricingEngine> mcengine1;
00303 mcengine1 =
00304 MakeMCEuropeanEngine<PseudoRandom>().withSteps(timeSteps)
00305 .withTolerance(0.02)
00306 .withSeed(mcSeed);
00307 europeanOption.setPricingEngine(mcengine1);
00308
00309 std::cout << std::setw(widths[0]) << std::left << method
00310 << std::fixed
00311 << std::setw(widths[1]) << std::left << europeanOption.NPV()
00312 << std::setw(widths[2]) << std::left << "N/A"
00313 << std::setw(widths[3]) << std::left << "N/A"
00314 << std::endl;
00315
00316 method = "MC (Sobol)";
00317 Size nSamples = 32768;
00318
00319 boost::shared_ptr<PricingEngine> mcengine2;
00320 mcengine2 =
00321 MakeMCEuropeanEngine<LowDiscrepancy>().withSteps(timeSteps)
00322 .withSamples(nSamples);
00323 europeanOption.setPricingEngine(mcengine2);
00324 std::cout << std::setw(widths[0]) << std::left << method
00325 << std::fixed
00326 << std::setw(widths[1]) << std::left << europeanOption.NPV()
00327 << std::setw(widths[2]) << std::left << "N/A"
00328 << std::setw(widths[3]) << std::left << "N/A"
00329 << std::endl;
00330
00331 #if !defined(QL_PATCH_MSVC6) && !defined(QL_PATCH_BORLAND)
00332 method = "MC (Longstaff Schwartz)";
00333 boost::shared_ptr<PricingEngine> mcengine3;
00334 mcengine3 =
00335 MakeMCAmericanEngine<PseudoRandom>().withSteps(100)
00336 .withAntitheticVariate()
00337 .withCalibrationSamples(4096)
00338 .withTolerance(0.02)
00339 .withSeed(mcSeed);
00340 americanOption.setPricingEngine(mcengine3);
00341 std::cout << std::setw(widths[0]) << std::left << method
00342 << std::fixed
00343 << std::setw(widths[1]) << std::left << "N/A"
00344 << std::setw(widths[2]) << std::left << "N/A"
00345 << std::setw(widths[3]) << std::left << americanOption.NPV()
00346 << std::endl;
00347 #endif
00348
00349 Real seconds = timer.elapsed();
00350 Integer hours = int(seconds/3600);
00351 seconds -= hours * 3600;
00352 Integer minutes = int(seconds/60);
00353 seconds -= minutes * 60;
00354 std::cout << " \nRun completed in ";
00355 if (hours > 0)
00356 std::cout << hours << " h ";
00357 if (hours > 0 || minutes > 0)
00358 std::cout << minutes << " m ";
00359 std::cout << std::fixed << std::setprecision(0)
00360 << seconds << " s\n" << std::endl;
00361
00362 return 0;
00363 } catch (std::exception& e) {
00364 std::cout << e.what() << std::endl;
00365 return 1;
00366 } catch (...) {
00367 std::cout << "unknown error" << std::endl;
00368 return 1;
00369 }
00370 }