I recently came across a discrepancy between the implied volatilities returned by a VanillaOption and a DividendVanillaOption. I'm using identical inputs for both except for empty date/amount vectors being passed in for the latter. I would expect my code (attached below) to return the same result in both cases, but I'm seeing differences (albeit small).
In both cases, the impliedVolatility call is going to use the Crank Nicolson pricing model, but the VanillaOption instrument uses the FDAmericanEngine, whereas the DividendVanillaOption is using the FDDividendAmericanEngine.
- Has this topic been covered before? If so, can someone point me to that discussion (didn't see it in the archive)
- Shouldn't a VanillaOption have the same implied volatility as a DividendVanillaOption with no dividends and otherwise identical inputs?
Here's the code:
//Built on Debian Wheezy, g++ 4.7.2, Boost 104900
#include <ql/quantlib.hpp>
int main(int argc, char** argv)
{
QuantLib::Option::Type optionType = QuantLib::Option::Call ;
double value = 1.00 ;
double underlying = 100.0 ;
double strike = 100.0 ;
QuantLib::Spread dividendYield = 0.00 ;
QuantLib::Rate riskFreeRate = 0.00 ;
int length = 2 ;
double volguess = 0.4 ;
QuantLib::Date today = QuantLib::Date::todaysDate();
QuantLib::Settings::instance().evaluationDate() = today;
QuantLib::DayCounter dc = QuantLib::Actual360();
boost::shared_ptr<QuantLib::SimpleQuote> spot(new QuantLib::SimpleQuote(underlying));
boost::shared_ptr<QuantLib::SimpleQuote> vol(new QuantLib::SimpleQuote(volguess));
boost::shared_ptr<QuantLib::BlackVolTermStructure> volTS =
boost::shared_ptr<QuantLib::BlackVolTermStructure>(
new QuantLib::BlackConstantVol(today,
QuantLib::NullCalendar(),
QuantLib::Handle<QuantLib::Quote>(vol), dc));
boost::shared_ptr<QuantLib::SimpleQuote> qRate(new QuantLib::SimpleQuote(dividendYield));
boost::shared_ptr<QuantLib::YieldTermStructure> qTS = boost::shared_ptr<QuantLib::YieldTermStructure>(new QuantLib::FlatForward(today, QuantLib::Handle<QuantLib::Quote>(qRate), dc));
boost::shared_ptr<QuantLib::SimpleQuote> rRate(new QuantLib::SimpleQuote(riskFreeRate));
boost::shared_ptr<QuantLib::YieldTermStructure> rTS = boost::shared_ptr<QuantLib::YieldTermStructure>(new QuantLib::FlatForward(today, QuantLib::Handle<QuantLib::Quote>(rRate), dc));
QuantLib::Date exDate = today + length;
QuantLib::Settings::instance().evaluationDate() = today;
boost::shared_ptr<QuantLib::Exercise> exercise(new QuantLib::AmericanExercise(today, exDate));
boost::shared_ptr<QuantLib::StrikedTypePayoff> payoff(new QuantLib::PlainVanillaPayoff(optionType, strike));
typedef QuantLib::BlackScholesMertonProcess BSMProcess;
boost::shared_ptr<QuantLib::GeneralizedBlackScholesProcess> process =
boost::shared_ptr<BSMProcess>(new BSMProcess(QuantLib::Handle<QuantLib::Quote>(spot),
QuantLib::Handle<QuantLib::YieldTermStructure>(qTS),
QuantLib::Handle<QuantLib::YieldTermStructure>(rTS),
QuantLib::Handle<QuantLib::BlackVolTermStructure>(volTS)));
boost::shared_ptr<QuantLib::VanillaOption> vanillaOption(new QuantLib::VanillaOption(payoff, exercise)) ;
double vanillaImplied = vanillaOption->impliedVolatility(value, process) ;
std::cout << "'VanillaOption' Implied Volatility: " << vanillaImplied << std::endl ;
std::vector< QuantLib::Date > myDividendDates ;
std::vector< QuantLib::Real > myDividendAmounts ;
boost::shared_ptr<QuantLib::DividendVanillaOption> dividendVanillaOption(new QuantLib::DividendVanillaOption(payoff, exercise,myDividendDates,myDividendAmounts)) ;
double dividendVanillaImplied = dividendVanillaOption->impliedVolatility(value, process) ;
std::cout << "'DividendVanillaOption' Implied Volatility: " << dividendVanillaImplied << std::endl ;
return 0 ;
}