Numerical Greeks

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Numerical Greeks

DPaulino
Hello,

I'm new to quantlib and have been trying to write a code to calculate a
numerical approximation to the greeks of an one-asset option.

For Delta, Gamma and Vega, what I have this far works great, but both rho
and theta are completely off the mark, even for an European vanilla.

I´ve read both this topic and this topic and as far as I can tell, it should work.

Can anyone give any clue as to what is not working?

The relevant part of the code is:


                Calendar calNACIONAL = Brazil();
                Calendar calBOVESPA = Brazil(Brazil::Exchange);
                Date todaysDate(18, Sep, 2015);
                Date maturity(16, Dec, 2015);
                DayCounter dayCounter = Business252();
                Natural settlementDays = 0;
                Settings::instance().evaluationDate() = todaysDate;

                Option::Type type
                type = Option::Call;

                Real underlying = 4869.00;
                Real strike = 5000.00;
                Spread dividendYield = 0.0;
                Rate riskFreeRate = .1427;
                Volatility volatility = .24679;
                Real dF=0,01
                Real dvol=0,0001
                Real dr=0,0001
 
               boost::shared_ptr<Exercise> europeanExercise(
                        new EuropeanExercise(maturity));

                // Create the quotes

                boost::shared_ptr<SimpleQuote> underlyingQ(new SimpleQuote(underlying));
                boost::shared_ptr<SimpleQuote> volatilityQ(new SimpleQuote(volatility));
                boost::shared_ptr<SimpleQuote> riskFreeRateQ(new SimpleQuote(riskFreeRate));
                boost::shared_ptr<SimpleQuote> dividendYieldQ(new SimpleQuote(dividendYield));
               

                // bootstrap the yield/dividend/vol curves
               
               
                boost::shared_ptr<YieldTermStructure>  flatTermStructure(
                        new FlatForward(settlementDays, calNACIONAL,
                        Handle<Quote>(riskFreeRateQ), dayCounter));
                Handle<YieldTermStructure> flatDividendTS(
                        boost::shared_ptr<YieldTermStructure>(
                        new FlatForward(settlementDays, calNACIONAL,
                        Handle<Quote>(dividendYieldQ), dayCounter)));
                 
                boost::shared_ptr<BlackVolTermStructure> flatVolTS(
                        new BlackConstantVol(settlementDays, calBOVESPA,
                           Handle<Quote>(volatilityQ),dayCounter));
                boost::shared_ptr<StrikedTypePayoff> payoff(
                        new PlainVanillaPayoff(type, strike));
                boost::shared_ptr<BlackProcess> bsmProcess(
                        new BlackProcess(Handle<Quote>(underlyingQ),
                                                         Handle<YieldTermStructure>(flatTermStructure),
                                                         Handle<BlackVolTermStructure>(flatVolTS)));

                // option
                VanillaOption europeanOption(payoff, europeanExercise);

                Real P;
                Real Pu;
                Real Pd;
               
                // Numerical Delta
                underlyingQ->setValue(underlying + dF);
                Pu = europeanOption.NPV();
                underlyingQ->setValue(underlying - dF);
                Pd = europeanOption.NPV();
                std::cout << "Delta = " << underlyingQ->value()*(Pu-Pd)/(2*dF)
                << std::endl; underlyingQ->setValue(underlying);

                // Numerical Gamma
                P = europeanOption.NPV();
                underlyingQ->setValue(underlying + dF);
                Pu = europeanOption.NPV();
                underlyingQ->setValue(underlying - dF);
                Pd = europeanOption.NPV();
                std::cout << "Gamma = " << underlyingQ->value()*underlyingQ->value()*(Pu +
                      Pd - 2 * P) / (100*dF*dF) << std::endl;underlyingQ->setValue(underlying);

                // Numerical Vega
                volatilityQ->setValue(volatility + dvol);
                Pu = europeanOption.NPV();
                volatilityQ->setValue(volatility - dvol);
                Pd = europeanOption.NPV();
                std::cout << "Vega = " << (Pu - Pd) / (200 * dvol) << std::endl;
                volatilityQ->setValue(volatility);
               
                //Numerical Rho
                riskFreeRateQ->setValue(riskFreeRate + dr);
                Pu = europeanOption.NPV();
                riskFreeRateQ->setValue(riskFreeRate - dr);
                Pd = europeanOption.NPV();
                std::cout << "Rho = " << (Pu - Pd) / (200 * dr) << std::endl;
                riskFreeRateQ->setValue(riskFreeRate);
               

                //Numerical Theta
                Settings::instance().evaluationDate() = todaysDate + 1;
                std::cout << "Theta = " << (europeanOption.NPV() - P) << std::endl;
                Settings::instance().evaluationDate() = todaysDate;

                std::cout << std::endl;
Reply | Threaded
Open this post in threaded view
|

Re: Numerical Greeks

Luigi Ballabio
Hello,
    as for theta, it might be a matter of how it's defined. You're calculating the difference between tomorrow's price and today's. If the value you're comparing is the derivative with respect to time, instead, then in order to reproduce it you would have to write something like

std::cout << "Theta = " << (europeanOption.NPV() - P)/dayCounter.yearFraction(todaysDate, todaysDate+1) << std::endl;

that is, you'd have to divide by the time between today and tomorrow. When I do this, I get a result very close to the analytic formula.

As for the rho: I think the problem is that you're using the BlackProcess class. This particular process uses the passed risk-free rate as the dividend yield as well, by using the same term-structure handle for both.  Thus, when you set a new value to riskFreeRateQ, you're moving both risk-free rate and dividend yield; and this, of course, causes the numerical rho to be incorrect.  The fix depends on what you actually wanted to do:
- if you wanted a null dividend yield (as it seems, since you're creating a dividendYieldQ quote with a null value) then you have to use the BlackScholesProcess class instead which sets the dividend yield to 0.
-  If, instead, you actually wanted the dividend yield to be the same as the risk-free rate, you'll have to decide again what you actually want. If you want the rho as defined in the usual way (that is, as a change in the risk-free rate with the dividend yield staying fixed), you'll have to use the BlackScholesMertonProcess class and pass the dividend yield explicitly as a different curve. If you want the rho as the Greek for an actual Black process (that is, as a change in both r and q at the same time) then your code is correct, and it's the Greek returned by the analytic engine that is not.

Hope this clarifies things a bit...

Later,
    Luigi




On Fri, Sep 18, 2015 at 10:36 PM DPaulino <[hidden email]> wrote:
Hello,

I'm new to quantlib and have been trying to write a code to calculate a
numerical approximation to the greeks of an one-asset option.

For Delta, Gamma and Vega, what I have this far works great, but both rho
and theta are completely off the mark, even for an European vanilla.

I´ve read both  this topic
<http://quantlib.10058.n7.nabble.com/Vega-rho-and-theta-not-provided-td16447.html>
and  this topic
<http://quantlib.10058.n7.nabble.com/Vega-and-Rho-calculation-for-European-and-American-Options-using-Finite-Difference-Method-td7925.html#a7927>
and as far as I can tell, it should work.

Can anyone give any clue as to what is not working?

The relevant part of the code is:


                Calendar calNACIONAL = Brazil();
                Calendar calBOVESPA = Brazil(Brazil::Exchange);
                Date todaysDate(18, Sep, 2015);
                Date maturity(16, Dec, 2015);
                DayCounter dayCounter = Business252();
                Natural settlementDays = 0;
                Settings::instance().evaluationDate() = todaysDate;

                Option::Type type
                type = Option::Call;

                Real underlying = 4869.00;
                Real strike = 5000.00;
                Spread dividendYield = 0.0;
                Rate riskFreeRate = .1427;
                Volatility volatility = .24679;
                Real dF=0,01
                Real dvol=0,0001
                Real dr=0,0001

               boost::shared_ptr<Exercise> europeanExercise(
                        new EuropeanExercise(maturity));

                // Create the quotes

                boost::shared_ptr<SimpleQuote> underlyingQ(new SimpleQuote(underlying));
                boost::shared_ptr<SimpleQuote> volatilityQ(new SimpleQuote(volatility));
                boost::shared_ptr<SimpleQuote> riskFreeRateQ(new
SimpleQuote(riskFreeRate));
                boost::shared_ptr<SimpleQuote> dividendYieldQ(new
SimpleQuote(dividendYield));


                // bootstrap the yield/dividend/vol curves


                boost::shared_ptr<YieldTermStructure>  flatTermStructure(
                        new FlatForward(settlementDays, calNACIONAL,
                        Handle(riskFreeRateQ), dayCounter));
                Handle<YieldTermStructure> flatDividendTS(
                        boost::shared_ptr<YieldTermStructure>(
                        new FlatForward(settlementDays, calNACIONAL,
                        Handle(dividendYieldQ), dayCounter)));

                boost::shared_ptr<BlackVolTermStructure> flatVolTS(
                        new BlackConstantVol(settlementDays, calBOVESPA,
                           Handle(volatilityQ),dayCounter));
                boost::shared_ptr<StrikedTypePayoff> payoff(
                        new PlainVanillaPayoff(type, strike));
                boost::shared_ptr<BlackProcess> bsmProcess(
                        new BlackProcess(Handle(underlyingQ),
                                                         Handle<YieldTermStructure>(flatTermStructure),
                                                         Handle<BlackVolTermStructure>(flatVolTS)));

                // option
                VanillaOption europeanOption(payoff, europeanExercise);

                Real P;
                Real Pu;
                Real Pd;

                // Numerical Delta
                underlyingQ->setValue(underlying + dF);
                Pu = europeanOption.NPV();
                underlyingQ->setValue(underlying - dF);
                Pd = europeanOption.NPV();
                std::cout << "Delta = " << underlyingQ->value()*(Pu-Pd)/(2*dF)
                << std::endl; underlyingQ->setValue(underlying);

                // Numerical Gamma
                P = europeanOption.NPV();
                underlyingQ->setValue(underlying + dF);
                Pu = europeanOption.NPV();
                underlyingQ->setValue(underlying - dF);
                Pd = europeanOption.NPV();
                std::cout << "Gamma = " << underlyingQ->value()*underlyingQ->value()*(Pu +
                      Pd - 2 * P) / (100*dF*dF) <<
std::endl;underlyingQ->setValue(underlying);

                // Numerical Vega
                volatilityQ->setValue(volatility + dvol);
                Pu = europeanOption.NPV();
                volatilityQ->setValue(volatility - dvol);
                Pd = europeanOption.NPV();
                std::cout << "Vega = " << (Pu - Pd) / (200 * dvol) << std::endl;
                volatilityQ->setValue(volatility);

                //Numerical Rho
                riskFreeRateQ->setValue(riskFreeRate + dr);
                Pu = europeanOption.NPV();
                riskFreeRateQ->setValue(riskFreeRate - dr);
                Pd = europeanOption.NPV();
                std::cout << "Rho = " << (Pu - Pd) / (200 * dr) << std::endl;
                riskFreeRateQ->setValue(riskFreeRate);


                //Numerical Theta
                Settings::instance().evaluationDate() = todaysDate + 1;
                std::cout << "Theta = " << (europeanOption.NPV() - P) << std::endl;
                Settings::instance().evaluationDate() = todaysDate;

                std::cout << std::endl;




--
View this message in context: http://quantlib.10058.n7.nabble.com/Numerical-Greeks-tp16919.html
Sent from the quantlib-users mailing list archive at Nabble.com.

------------------------------------------------------------------------------
_______________________________________________
QuantLib-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/quantlib-users
--

------------------------------------------------------------------------------

_______________________________________________
QuantLib-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/quantlib-users