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 }