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