Consider the following European option: Option::Type type(Option::Call); Real underlying = 30.07; Real strike = 35.0; Spread dividendYield = 0.0; Rate riskFreeRate = 0.0433; Date todaysDate(16, January, 2006); Date settlementDate(16, January, 2006); Date exerciseDate(18, February, 2006); DayCounter dayCounter = Actual360(); double optPx = 0.55; Compare results from: ** Option calculator http://www.888options.com/resources/options_calc.jsp (Bloomberg results are the same within 4th decimal) I.V. 0.549 Delta 0.2105 Gamma 0.0576 Vega 0.0261 Rho 0.0052 ** Quantlib: impliedVol: 0.549073 delta: 0.0567826 gamma: 0.0417672 theta: -0.00485107 vega: 0.0103857 rho: 0.150655 Attached is QuantLib default example with hardcoded parameters. ---8<----------------------------------------------------------------------------------------------------- /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /*! Copyright (C) 2003 Ferdinando Ametrano Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email <[hidden email]>. The license is also available online at <http://quantlib.org/reference/license.html>. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. */ #include <ql/quantlib.hpp> #include <iostream> using namespace QuantLib; #if defined(QL_ENABLE_SESSIONS) namespace QuantLib { Integer sessionId() { return 0; } } #endif // This will be included in the library after a bit of redesign class WeightedPayoff { public: WeightedPayoff(Option::Type type, Time maturity, Real strike, Real s0, Volatility sigma, Rate r, Rate q) : type_(type), maturity_(maturity), strike_(strike), s0_(s0), sigma_(sigma),r_(r), q_(q){} Real operator()(Real x) const { Real nuT = (r_-q_-0.5*sigma_*sigma_)*maturity_; return std::exp(-r_*maturity_) *PlainVanillaPayoff(type_, strike_)(s0_*std::exp(x)) *std::exp(-(x - nuT)*(x -nuT)/(2*sigma_*sigma_*maturity_)) /std::sqrt(2.0*M_PI*sigma_*sigma_*maturity_); } private: Option::Type type_; Time maturity_; Real strike_; Real s0_; Volatility sigma_; Rate r_,q_; }; int main(int, char* []) { try { QL_IO_INIT std::cout << "Using " << QL_VERSION << std::endl << std::endl; // our option Option::Type type(Option::Call); Real underlying = 30.07; //50.78; //51.69; Real strike = 35.0; // 52.5; Spread dividendYield = 0.0; // 0.0070964; //0.0; Rate riskFreeRate = 0.0433; //0.01; Date todaysDate(16, January, 2006); Date settlementDate(16, January, 2006); Settings::instance().evaluationDate() = todaysDate; Date exerciseDate(18, February, 2006); DayCounter dayCounter = Actual360(); Time maturity = dayCounter.yearFraction(settlementDate, exerciseDate); Volatility volatility = 0.3; std::cout << "option type = " << type << std::endl; std::cout << "Time to maturity = " << maturity << std::endl; std::cout << "Underlying price = " << underlying << std::endl; std::cout << "Strike = " << strike << std::endl; std::cout << "Risk-free interest rate = " << io::rate(riskFreeRate) << std::endl; std::cout << "Dividend yield = " << io::rate(dividendYield) << std::endl; std::cout << "Volatility = " << io::volatility(volatility) << std::endl; std::cout << std::endl; // Date midlifeDate(19, November, 1998); // std::vector<Date> exDates(2); // exDates[0]=midlifeDate; // exDates[1]=exerciseDate; // boost::shared_ptr<Exercise> exercise( new EuropeanExercise(exerciseDate)); // boost::shared_ptr<Exercise> amExercise( // new AmericanExercise(settlementDate, // exerciseDate)); // boost::shared_ptr<Exercise> berExercise(new BermudanExercise(exDates)); // // Handle<Quote> underlyingH( boost::shared_ptr<Quote>(new SimpleQuote(underlying))); // bootstrap the yield/dividend/vol curves Handle<YieldTermStructure> flatTermStructure( boost::shared_ptr<YieldTermStructure>( new FlatForward(settlementDate, riskFreeRate, dayCounter))); Handle<YieldTermStructure> flatDividendTS( boost::shared_ptr<YieldTermStructure>( new FlatForward(settlementDate, dividendYield, dayCounter))); Handle<BlackVolTermStructure> flatVolTS( boost::shared_ptr<BlackVolTermStructure>( new BlackConstantVol(settlementDate, volatility, dayCounter))); // // std::vector<Date> dates(4); // dates[0] = settlementDate + 1*Months; // dates[1] = exerciseDate; // dates[2] = exerciseDate + 6*Months; // dates[3] = exerciseDate + 12*Months; // std::vector<Real> strikes(4); // strikes[0] = underlying*0.9; // strikes[1] = underlying; // strikes[2] = underlying*1.1; // strikes[3] = underlying*1.2; // // Matrix vols(4,4); // vols[0][0] = volatility*1.1; // vols[0][1] = volatility; // vols[0][2] = volatility*0.9; // vols[0][3] = volatility*0.8; // vols[1][0] = volatility*1.1; // vols[1][1] = volatility; // vols[1][2] = volatility*0.9; // vols[1][3] = volatility*0.8; // vols[2][0] = volatility*1.1; // vols[2][1] = volatility; // vols[2][2] = volatility*0.9; // vols[2][3] = volatility*0.8; // vols[3][0] = volatility*1.1; // vols[3][1] = volatility; // vols[3][2] = volatility*0.9; // vols[3][3] = volatility*0.8; // // Handle<BlackVolTermStructure> blackSurface( // boost::shared_ptr<BlackVolTermStructure>( // new BlackVarianceSurface(settlementDate, dates, // strikes, vols, dayCounter))); boost::shared_ptr<StrikedTypePayoff> payoff(new PlainVanillaPayoff(type, strike)); boost::shared_ptr<BlackScholesProcess> stochasticProcess(new BlackScholesProcess(underlyingH, flatDividendTS, flatTermStructure, // blackSurface flatVolTS)); EuropeanOption option(stochasticProcess, payoff, exercise); std::string method; Real value, discrepancy, rightValue, relativeDiscrepancy; std::cout << std::endl << std::endl; // write column headings std::cout << "Method\t\tValue\t\tEstimatedError\tDiscrepancy" "\tRel. Discr." << std::endl; // method: Black-Scholes Engine method = "Black-Scholes"; option.setPricingEngine(boost::shared_ptr<PricingEngine>( new AnalyticEuropeanEngine())); double optPx = 0.55; //1.6; //1.75; double impliedVol = option.impliedVolatility( optPx ); double delta = option.delta(); double gamma = option.gamma(); double theta = option.theta()/365.0; double vega = option.vega()/100.0; double rho = option.rho(); double divRho = option.dividendRho(); std::cout << "impliedVol: " << "\t" << impliedVol << std::endl << "delta: " << "\t" << delta << std::endl << "gamma: " << "\t" << gamma << std::endl << "theta: " << "\t" << theta << std::endl << "vega: " << "\t" << vega << std::endl << "rho: " << "\t" << rho << std::endl << "divRho: " << "\t" << divRho << std::endl; rightValue = value = option.NPV(); discrepancy = std::fabs(value-rightValue); relativeDiscrepancy = discrepancy/rightValue; std::cout << method << "\t" << value << "\t" << "N/A\t\t" << discrepancy << "\t\t" << relativeDiscrepancy << std::endl; // method: Integral method = "Integral"; option.setPricingEngine(boost::shared_ptr<PricingEngine>( new IntegralEngine())); value = option.NPV(); discrepancy = std::fabs(value-rightValue); relativeDiscrepancy = discrepancy/rightValue; std::cout << method << "\t" << value << "\t" << "N/A\t\t" << discrepancy << "\t" << relativeDiscrepancy << std::endl; /* // method: Integral method = "Binary Cash"; option.setPricingEngine(boost::shared_ptr<PricingEngine>( new IntegralCashOrNothingEngine(1.0))); value = option.NPV(); discrepancy = std::fabs(value-rightValue); relativeDiscrepancy = discrepancy/rightValue; std::cout << method << "\t" << value << "\t" << "N/A\t\t" << discrepancy << "\t" << relativeDiscrepancy << std::endl; // method: Integral method = "Binary Asset"; option.setPricingEngine(boost::shared_ptr<PricingEngine>( new IntegralAssetOrNothingEngine())); value = option.NPV(); discrepancy = std::fabs(value-rightValue); relativeDiscrepancy = discrepancy/rightValue; std::cout << method << "\t" << value << "\t" << "N/A\t\t" << discrepancy << "\t" << relativeDiscrepancy << std::endl; */ Size timeSteps = 801; // Binomial Method (JR) method = "Binomial (JR)"; option.setPricingEngine(boost::shared_ptr<PricingEngine>( new BinomialVanillaEngine<JarrowRudd>(timeSteps))); value = option.NPV(); discrepancy = std::fabs(value-rightValue); relativeDiscrepancy = discrepancy/rightValue; std::cout << method << "\t" << value << "\t" << "N/A\t\t" << discrepancy << "\t" << relativeDiscrepancy << std::endl; // Binomial Method (CRR) method = "Binomial (CRR)"; option.setPricingEngine(boost::shared_ptr<PricingEngine>( new BinomialVanillaEngine<CoxRossRubinstein>(timeSteps))); value = option.NPV(); discrepancy = std::fabs(value-rightValue); relativeDiscrepancy = discrepancy/rightValue; std::cout << method << "\t" << value << "\t" << "N/A\t\t" << discrepancy << "\t" << relativeDiscrepancy << std::endl; // Equal Probability Additive Binomial Tree (EQP) method = "Additive (EQP)"; option.setPricingEngine(boost::shared_ptr<PricingEngine>( new BinomialVanillaEngine<AdditiveEQPBinomialTree>(timeSteps))); value = option.NPV(); discrepancy = std::fabs(value-rightValue); relativeDiscrepancy = discrepancy/rightValue; std::cout << method << "\t" << value << "\t" << "N/A\t\t" << discrepancy << "\t" << relativeDiscrepancy << std::endl; // Equal Jumps Additive Binomial Tree (Trigeorgis) method = "Bin. Trigeorgis"; option.setPricingEngine(boost::shared_ptr<PricingEngine>( new BinomialVanillaEngine<Trigeorgis>(timeSteps))); value = option.NPV(); discrepancy = std::fabs(value-rightValue); relativeDiscrepancy = discrepancy/rightValue; std::cout << method << "\t" << value << "\t" << "N/A\t\t" << discrepancy << "\t" << relativeDiscrepancy << std::endl; // Tian Binomial Tree (third moment matching) method = "Binomial Tian"; option.setPricingEngine(boost::shared_ptr<PricingEngine>( new BinomialVanillaEngine<Tian>(timeSteps))); value = option.NPV(); discrepancy = std::fabs(value-rightValue); relativeDiscrepancy = discrepancy/rightValue; std::cout << method << "\t" << value << "\t" << "N/A\t\t" << discrepancy << "\t" << relativeDiscrepancy << std::endl; // Leisen-Reimer Binomial Tree method = "Binomial LR"; option.setPricingEngine(boost::shared_ptr<PricingEngine>( new BinomialVanillaEngine<LeisenReimer>(timeSteps))); value = option.NPV(); discrepancy = std::fabs(value-rightValue); relativeDiscrepancy = discrepancy/rightValue; std::cout << method << "\t" << value << "\t" << "N/A\t\t" << discrepancy << "\t" << relativeDiscrepancy << std::endl; // Finite Differences method = "Finite Diff."; timeSteps = 100; Size gridPoints = 100; option.setPricingEngine(boost::shared_ptr<PricingEngine>( new FDEuropeanEngine(timeSteps, gridPoints))); value = option.NPV(); discrepancy = std::fabs(value-rightValue); relativeDiscrepancy = discrepancy/rightValue; std::cout << method << "\t" << value << "\t" << "N/A\t\t" << discrepancy << "\t" << relativeDiscrepancy << std::endl; // Monte Carlo Method timeSteps = 1; method = "MC (crude)"; Size mcSeed = 42; boost::shared_ptr<PricingEngine> mcengine1; mcengine1 = MakeMCEuropeanEngine<PseudoRandom>().withSteps(timeSteps) .withTolerance(0.02) .withSeed(mcSeed); option.setPricingEngine(mcengine1); value = option.NPV(); Real errorEstimate = option.errorEstimate(); discrepancy = std::fabs(value-rightValue); relativeDiscrepancy = discrepancy/rightValue; std::cout << method << "\t" << value << "\t" << errorEstimate << "\t" << discrepancy << "\t" << relativeDiscrepancy << std::endl; method = "MC (Sobol)"; timeSteps = 1; Size nSamples = 32768; // 2^15 boost::shared_ptr<PricingEngine> mcengine2; mcengine2 = MakeMCEuropeanEngine<LowDiscrepancy>().withSteps(timeSteps) .withSamples(nSamples); option.setPricingEngine(mcengine2); value = option.NPV(); discrepancy = std::fabs(value-rightValue); relativeDiscrepancy = discrepancy/rightValue; std::cout << method << "\t" << value << "\t" << "N/A\t\t" << discrepancy << "\t" << relativeDiscrepancy << std::endl; return 0; } catch (std::exception& e) { std::cout << e.what() << std::endl; return 1; } catch (...) { std::cout << "unknown error" << std::endl; return 1; } } ---8<----------------------------------------------------------------------------------------------------- |
Hi,
On 1/16/06, UNG <[hidden email]> wrote: > ** Option calculator > http://www.888options.com/resources/options_calc.jsp > (Bloomberg results are the same within 4th decimal) > I.V. 0.549 Delta 0.2105 Gamma 0.0576 Vega 0.0261 > Rho 0.0052 These are the results when the volatility is set to 0.549, aren't they? In QuantLib, calling the impliedVolatility() method returns the implied volatility, but it does not set the volatility of the option to the result. Therefore... > ** Quantlib: > impliedVol: 0.549073 > delta: 0.0567826 > gamma: 0.0417672 > theta: -0.00485107 > vega: 0.0103857 > rho: 0.150655 ...the above are still the results for the volatility you began with, namely, 0.30. You can compare them with the corresponding results from the calculator. If you want to set the volatility to the implied one, you have to do it yourself. A way to do it in your code is to replace Volatility volatility = 0.3; with boost::shared_ptr<SimpleQuote> volQuote(new SimpleQuote(0.30)); Handle<Quote> volatility(volQuote); so that you can modify the volatility. Later in the code, you can write double impliedVol = option.impliedVolatility(optPx ); // now set the new value... volQuote->setValue(impliedVol); // so that the results below are now those you want double delta = option.delta(); etc. etc Later, Luigi |
Free forum by Nabble | Edit this page |