EquityOption.cpp

This example evaluates European, American and Bermudan options using different methods

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