EuropeanOption.cpp

This example calculates European options using different methods while testing call-put parity.

00001 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 
00021 #include <ql/quantlib.hpp>
00022 #include <iostream>
00023 
00024 using namespace QuantLib;
00025 
00026 #if defined(QL_ENABLE_SESSIONS)
00027 namespace QuantLib {
00028 
00029     Integer sessionId() { return 0; }
00030 
00031 }
00032 #endif
00033 
00034 
00035 // This will be included in the library after a bit of redesign
00036 class WeightedPayoff {
00037     public:
00038         WeightedPayoff(Option::Type type,
00039                Time maturity,
00040                Real strike,
00041                Real s0,
00042                Volatility sigma,
00043                Rate r,
00044                Rate q)
00045         : type_(type), maturity_(maturity),
00046         strike_(strike),
00047         s0_(s0),
00048         sigma_(sigma),r_(r), q_(q){}
00049 
00050         Real operator()(Real x) const {
00051            Real nuT = (r_-q_-0.5*sigma_*sigma_)*maturity_;
00052            return std::exp(-r_*maturity_)
00053                *PlainVanillaPayoff(type_, strike_)(s0_*std::exp(x))
00054                *std::exp(-(x - nuT)*(x -nuT)/(2*sigma_*sigma_*maturity_))
00055                /std::sqrt(2.0*M_PI*sigma_*sigma_*maturity_);
00056         }
00057 private:
00058     Option::Type type_;
00059     Time maturity_;
00060     Real strike_;
00061     Real s0_;
00062     Volatility sigma_;
00063     Rate r_,q_;
00064 };
00065 
00066 
00067 int main(int, char* [])
00068 {
00069     try {
00070         QL_IO_INIT
00071 
00072         std::cout << "Using " << QL_VERSION << std::endl << std::endl;
00073 
00074         // our option
00075         Option::Type type(Option::Call);
00076         Real underlying = 7;
00077         Real strike = 8;
00078         Spread dividendYield = 0.05;
00079         Rate riskFreeRate = 0.05;
00080 
00081         Date todaysDate(15, May, 1998);
00082         Date settlementDate(17, May, 1998);
00083         Settings::instance().evaluationDate() = todaysDate;
00084 
00085         Date exerciseDate(17, May, 1999);
00086         DayCounter dayCounter = Actual365Fixed();
00087         Time maturity = dayCounter.yearFraction(settlementDate,
00088                                                 exerciseDate);
00089 
00090         Volatility volatility = 0.10;
00091         std::cout << "option type = "  << type << std::endl;
00092         std::cout << "Time to maturity = "        << maturity
00093                   << std::endl;
00094         std::cout << "Underlying price = "        << underlying
00095                   << std::endl;
00096         std::cout << "Strike = "                  << strike
00097                   << std::endl;
00098         std::cout << "Risk-free interest rate = " << io::rate(riskFreeRate)
00099                   << std::endl;
00100         std::cout << "Dividend yield = " << io::rate(dividendYield)
00101                   << std::endl;
00102         std::cout << "Volatility = " << io::volatility(volatility)
00103                   << std::endl;
00104         std::cout << std::endl;
00105 
00106         Date midlifeDate(19, November, 1998);
00107         std::vector<Date> exDates(2);
00108         exDates[0]=midlifeDate;
00109         exDates[1]=exerciseDate;
00110 
00111         boost::shared_ptr<Exercise> exercise(
00112                                           new EuropeanExercise(exerciseDate));
00113         boost::shared_ptr<Exercise> amExercise(
00114                                           new AmericanExercise(settlementDate,
00115                                                                exerciseDate));
00116         boost::shared_ptr<Exercise> berExercise(new BermudanExercise(exDates));
00117 
00118 
00119         Handle<Quote> underlyingH(
00120             boost::shared_ptr<Quote>(new SimpleQuote(underlying)));
00121 
00122         // bootstrap the yield/dividend/vol curves
00123         Handle<YieldTermStructure> flatTermStructure(
00124             boost::shared_ptr<YieldTermStructure>(
00125                 new FlatForward(settlementDate, riskFreeRate, dayCounter)));
00126         Handle<YieldTermStructure> flatDividendTS(
00127             boost::shared_ptr<YieldTermStructure>(
00128                 new FlatForward(settlementDate, dividendYield, dayCounter)));
00129         Handle<BlackVolTermStructure> flatVolTS(
00130             boost::shared_ptr<BlackVolTermStructure>(
00131                 new BlackConstantVol(settlementDate, volatility, dayCounter)));
00132 
00133         std::vector<Date> dates(4);
00134         dates[0] = settlementDate + 1*Months;
00135         dates[1] = exerciseDate;
00136         dates[2] = exerciseDate + 6*Months;
00137         dates[3] = exerciseDate + 12*Months;
00138         std::vector<Real> strikes(4);
00139         strikes[0] = underlying*0.9;
00140         strikes[1] = underlying;
00141         strikes[2] = underlying*1.1;
00142         strikes[3] = underlying*1.2;
00143 
00144         Matrix vols(4,4);
00145         vols[0][0] = volatility*1.1;
00146                      vols[0][1] = volatility;
00147                                   vols[0][2] = volatility*0.9;
00148                                                vols[0][3] = volatility*0.8;
00149         vols[1][0] = volatility*1.1;
00150                      vols[1][1] = volatility;
00151                                   vols[1][2] = volatility*0.9;
00152                                                vols[1][3] = volatility*0.8;
00153         vols[2][0] = volatility*1.1;
00154                      vols[2][1] = volatility;
00155                                   vols[2][2] = volatility*0.9;
00156                                                vols[2][3] = volatility*0.8;
00157         vols[3][0] = volatility*1.1;
00158                      vols[3][1] = volatility;
00159                                   vols[3][2] = volatility*0.9;
00160                                                vols[3][3] = volatility*0.8;
00161 
00162         Handle<BlackVolTermStructure> blackSurface(
00163             boost::shared_ptr<BlackVolTermStructure>(
00164                 new BlackVarianceSurface(settlementDate, dates,
00165                                          strikes, vols, dayCounter)));
00166 
00167 
00168         boost::shared_ptr<StrikedTypePayoff> payoff(new
00169             PlainVanillaPayoff(type, strike));
00170 
00171         boost::shared_ptr<BlackScholesProcess> stochasticProcess(new
00172             BlackScholesProcess(underlyingH, flatDividendTS,
00173                                 flatTermStructure,
00174                                 //  blackSurface
00175                                 flatVolTS));
00176 
00177         EuropeanOption option(stochasticProcess, payoff, exercise);
00178 
00179 
00180         std::string method;
00181         Real value, discrepancy, rightValue, relativeDiscrepancy;
00182 
00183         std::cout << std::endl << std::endl;
00184 
00185         // write column headings
00186         std::cout << "Method\t\tValue\t\tEstimatedError\tDiscrepancy"
00187                      "\tRel. Discr." << std::endl;
00188 
00189         // method: Black-Scholes Engine
00190         method = "Black-Scholes";
00191         option.setPricingEngine(boost::shared_ptr<PricingEngine>(
00192             new AnalyticEuropeanEngine()));
00193         rightValue = value = option.NPV();
00194         discrepancy = std::fabs(value-rightValue);
00195         relativeDiscrepancy = discrepancy/rightValue;
00196         std::cout << method << "\t"
00197                   << value << "\t" << "N/A\t\t"
00198                   << discrepancy << "\t\t" << relativeDiscrepancy << std::endl;
00199 
00200 
00201         // method: Integral
00202         method = "Integral";
00203         option.setPricingEngine(boost::shared_ptr<PricingEngine>(
00204             new IntegralEngine()));
00205         value = option.NPV();
00206         discrepancy = std::fabs(value-rightValue);
00207         relativeDiscrepancy = discrepancy/rightValue;
00208         std::cout << method << "\t"
00209                   << value << "\t" << "N/A\t\t"
00210                   << discrepancy << "\t" << relativeDiscrepancy << std::endl;
00211 
00212 /*
00213         // method: Integral
00214         method = "Binary Cash";
00215         option.setPricingEngine(boost::shared_ptr<PricingEngine>(
00216             new IntegralCashOrNothingEngine(1.0)));
00217         value = option.NPV();
00218         discrepancy = std::fabs(value-rightValue);
00219         relativeDiscrepancy = discrepancy/rightValue;
00220         std::cout << method << "\t"
00221                   << value << "\t" << "N/A\t\t"
00222                   << discrepancy << "\t" << relativeDiscrepancy << std::endl;
00223 
00224         // method: Integral
00225         method = "Binary Asset";
00226         option.setPricingEngine(boost::shared_ptr<PricingEngine>(
00227             new IntegralAssetOrNothingEngine()));
00228         value = option.NPV();
00229         discrepancy = std::fabs(value-rightValue);
00230         relativeDiscrepancy = discrepancy/rightValue;
00231         std::cout << method << "\t"
00232                   << value << "\t" << "N/A\t\t"
00233                   << discrepancy << "\t" << relativeDiscrepancy << std::endl;
00234 
00235 */
00236         Size timeSteps = 801;
00237 
00238         // Binomial Method (JR)
00239         method = "Binomial (JR)";
00240         option.setPricingEngine(boost::shared_ptr<PricingEngine>(
00241             new BinomialVanillaEngine<JarrowRudd>(timeSteps)));
00242         value = option.NPV();
00243         discrepancy = std::fabs(value-rightValue);
00244         relativeDiscrepancy = discrepancy/rightValue;
00245         std::cout << method << "\t"
00246                   << value << "\t" << "N/A\t\t"
00247                   << discrepancy << "\t" << relativeDiscrepancy << std::endl;
00248 
00249 
00250         // Binomial Method (CRR)
00251         method = "Binomial (CRR)";
00252         option.setPricingEngine(boost::shared_ptr<PricingEngine>(
00253             new BinomialVanillaEngine<CoxRossRubinstein>(timeSteps)));
00254         value = option.NPV();
00255         discrepancy = std::fabs(value-rightValue);
00256         relativeDiscrepancy = discrepancy/rightValue;
00257         std::cout << method << "\t"
00258                   << value << "\t" << "N/A\t\t"
00259                   << discrepancy << "\t" << relativeDiscrepancy << std::endl;
00260 
00261         // Equal Probability Additive Binomial Tree (EQP)
00262         method = "Additive (EQP)";
00263         option.setPricingEngine(boost::shared_ptr<PricingEngine>(
00264             new BinomialVanillaEngine<AdditiveEQPBinomialTree>(timeSteps)));
00265         value = option.NPV();
00266         discrepancy = std::fabs(value-rightValue);
00267         relativeDiscrepancy = discrepancy/rightValue;
00268         std::cout << method << "\t"
00269                   << value << "\t" << "N/A\t\t"
00270                   << discrepancy << "\t" << relativeDiscrepancy << std::endl;
00271 
00272         // Equal Jumps Additive Binomial Tree (Trigeorgis)
00273         method = "Bin. Trigeorgis";
00274         option.setPricingEngine(boost::shared_ptr<PricingEngine>(
00275             new BinomialVanillaEngine<Trigeorgis>(timeSteps)));
00276         value = option.NPV();
00277         discrepancy = std::fabs(value-rightValue);
00278         relativeDiscrepancy = discrepancy/rightValue;
00279         std::cout << method << "\t"
00280                   << value << "\t" << "N/A\t\t"
00281                   << discrepancy << "\t" << relativeDiscrepancy << std::endl;
00282 
00283         // Tian Binomial Tree (third moment matching)
00284         method = "Binomial Tian";
00285         option.setPricingEngine(boost::shared_ptr<PricingEngine>(
00286             new BinomialVanillaEngine<Tian>(timeSteps)));
00287         value = option.NPV();
00288         discrepancy = std::fabs(value-rightValue);
00289         relativeDiscrepancy = discrepancy/rightValue;
00290         std::cout << method << "\t"
00291                   << value << "\t" << "N/A\t\t"
00292                   << discrepancy << "\t" << relativeDiscrepancy << std::endl;
00293 
00294         // Leisen-Reimer Binomial Tree
00295         method = "Binomial LR";
00296         option.setPricingEngine(boost::shared_ptr<PricingEngine>(
00297             new BinomialVanillaEngine<LeisenReimer>(timeSteps)));
00298         value = option.NPV();
00299         discrepancy = std::fabs(value-rightValue);
00300         relativeDiscrepancy = discrepancy/rightValue;
00301         std::cout << method << "\t"
00302                   << value << "\t" << "N/A\t\t"
00303                   << discrepancy << "\t" << relativeDiscrepancy << std::endl;
00304 
00305         // Finite Differences
00306 
00307         method = "Finite Diff.";
00308         timeSteps = 100;
00309         Size gridPoints = 100;
00310         option.setPricingEngine(boost::shared_ptr<PricingEngine>(
00311             new FDEuropeanEngine(timeSteps, gridPoints)));
00312         value = option.NPV();
00313         discrepancy = std::fabs(value-rightValue);
00314         relativeDiscrepancy = discrepancy/rightValue;
00315         std::cout << method << "\t"
00316                   << value << "\t" << "N/A\t\t"
00317                   << discrepancy << "\t" << relativeDiscrepancy << std::endl;
00318 
00319         // Monte Carlo Method
00320         timeSteps = 1;
00321 
00322         method = "MC (crude)";
00323         Size mcSeed = 42;
00324 
00325         boost::shared_ptr<PricingEngine> mcengine1;
00326         mcengine1 =
00327             MakeMCEuropeanEngine<PseudoRandom>().withSteps(timeSteps)
00328                                                 .withTolerance(0.02)
00329                                                 .withSeed(mcSeed);
00330         option.setPricingEngine(mcengine1);
00331 
00332         value = option.NPV();
00333         Real errorEstimate = option.errorEstimate();
00334         discrepancy = std::fabs(value-rightValue);
00335         relativeDiscrepancy = discrepancy/rightValue;
00336         std::cout << method << "\t"
00337                   << value << "\t" << errorEstimate << "\t"
00338                   << discrepancy << "\t" << relativeDiscrepancy << std::endl;
00339 
00340         method = "MC (Sobol)";
00341         timeSteps = 1;
00342         Size nSamples = 32768;  // 2^15
00343 
00344         boost::shared_ptr<PricingEngine> mcengine2;
00345         mcengine2 =
00346             MakeMCEuropeanEngine<LowDiscrepancy>().withSteps(timeSteps)
00347                                                   .withSamples(nSamples);
00348         option.setPricingEngine(mcengine2);
00349 
00350         value = option.NPV();
00351         discrepancy = std::fabs(value-rightValue);
00352         relativeDiscrepancy = discrepancy/rightValue;
00353         std::cout << method << "\t"
00354                   << value << "\t" << "N/A\t\t"
00355                   << discrepancy << "\t" << relativeDiscrepancy << std::endl;
00356 
00357         return 0;
00358     } catch (std::exception& e) {
00359         std::cout << e.what() << std::endl;
00360         return 1;
00361     } catch (...) {
00362         std::cout << "unknown error" << std::endl;
00363         return 1;
00364     }
00365 }

QuantLib.org
QuantLib
Hosted by
SourceForge.net Logo
Documentation generated by
doxygen