local volatility surface

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

local volatility surface

Kim Kuen Tang
Hi guys,

the Black-Scholes implied volatlity sigma=sigma(t,K,T) , starting at t,
is the number which, when put in the Black-Scholes formula for a
european option with strike K and maturity T quoted at t, reproduces the
fair price on the market. The existence of such a surface indicates that
the Black-Scholes assumption that assets have a constant volatility
should be relaxed. The simplest extension is to assume that assets still
follow a one-dimensional ito diffusion process but with a local
volatility function that depends on the forward and the time. A local
volatility surface class
ql/termstructures/volatility/equityfx/localvolsurface.hpp already exists
in QuantLib. This class takes an implied vol surface as an input and use
the dupire equation to calculate the local volatility. A drawback of
this equation is that it uses the first and second derivatives of the
european option price. The produced local volatility surface is not able
to match the european options. I suggest to replace the dupire equation
with an algorithm to calibrate the  local volatility by fitting the
prices of a set of vanilla european options.

Several steps need to be done for this purpose.

(i) A localvol class needs to be implemented that just takes as an input
a matrix, vector of dates and srtikes that do the interpolation.  See
attached file.
(ii) A dupire process needs to be implemented that just takes the local
vol class and returns the drift and diffusion according to time and
forward. See attached file again.
(iii) A pricing engine for european options needs to be implemented that
calculates the market value according a given dupire process. This
pricing engine will be used as part of the calibration procedure. This
part is almost finished using finite element.
(iv) A pricing engine for european options based on monte carlo
simulation needs to be implemented. This pricing engine will then be
used to validate that the other pricing engine is really working. (
Writing test cases)
(v) A minization procedure to choose the correct surface among a family
of surfaces.
(vi) Exporting the implemented classes to QuantLibXL and building excel
sheets to provide examples.

Step (iii) is almost finished. In my calculation procedure i wite codes
like

vvec=(M+.5*t* (L+r*M ) ).applyTo(uvec);
//modifying L
uvec=(M-.5*t* (L+r*M ) ).solveFor(vvec);

Here M is the mass matrix and L the stiffness matrix and are from type
TridiagonalOperator. Such writing is of course really bad because this
will result in eight times allocating and deallocating a
TridiagonalOperator. A speedup with the help of template expression
using Boost.proto should avoid the creation of temporary
TridiagonalOperator. This needs to be implemented.

I hope that i can get help for step (iv) and (vi). If someone is
interested just drop me an email.

With kind regards,
Kim Tang

/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2009 Kim Kuen Tang

 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/license.shtml>.

 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 "dupireprocess.hpp"

namespace QuantLib {

    DupireProcess::DupireProcess(
             const Handle<Quote>& x0,
             const Handle<YieldTermStructure>& dividendTS,
             const Handle<YieldTermStructure>& riskFreeTS,
             const Handle<LocalVol>& localvol,
             const boost::shared_ptr<discretization>& disc)
    : StochasticProcess1D(disc), x0_(x0), riskFreeRate_(riskFreeTS),
      dividendYield_(dividendTS), localvol_(localvol)
    {
        registerWith(x0_);
        registerWith(riskFreeRate_);
        registerWith(dividendYield_);
    }

    Real DupireProcess::x0() const {
        return x0_->value();
    }

    Real DupireProcess::drift(Time t, Real x) const {

        // we could be more anticipatory if we know the right dt
        // for which the drift will be used
        Time t1 = t + 0.0001;
        return (riskFreeRate_->forwardRate(t,t1,Continuous,NoFrequency,true)
             - dividendYield_->forwardRate(t,t1,Continuous,NoFrequency,true) ) *x;
             
    }

    Real DupireProcess::diffusion(Time t, Real x) const {
        return localvol_->localVol(t, x, true)*x;
    }

    Real DupireProcess::apply(Real x0, Real dx) const {
        return x0 * std::exp(dx);
    }

    Time DupireProcess::time(const Date& d) const {
        return riskFreeRate_->dayCounter().yearFraction(
                                           riskFreeRate_->referenceDate(), d);
    }

    void DupireProcess::update() {
        StochasticProcess1D::update();
    }

    const Handle<Quote>&
    DupireProcess::stateVariable() const {
        return x0_;
    }

    const Handle<YieldTermStructure>&
    DupireProcess::dividendYield() const {
        return dividendYield_;
    }

    const Handle<YieldTermStructure>&
    DupireProcess::riskFreeRate() const {
        return riskFreeRate_;
    }

    const Handle<LocalVol>&
    DupireProcess::localVolatility() const
        {
                return localvol_;
    }

}

/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2009 Kim Kuen Tang

 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/license.shtml>.

 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.
*/

# ifndef QUANTLIB_DUPIREPROCESS_HPP_KKT_250609
# define QUANTLIB_DUPIREPROCESS_HPP_KKT_250609

# include <ql/stochasticprocess.hpp>
# include <ql/processes/eulerdiscretization.hpp>
# include <ql/termstructures/yieldtermstructure.hpp>
# include <ql/quote.hpp>
# include "localvol.hpp"

namespace QuantLib {

    //! dupire process
    /*! This class describes the stochastic process governed by
        \f[
            dS(t) /S = (r(t)-q(t) ) dt + \sigma(t,S) dW_t
        \f]

        \ingroup processes
    */
        class DupireProcess : public StochasticProcess1D {
      public:
        DupireProcess(
            const Handle<Quote>& x0,
            const Handle<YieldTermStructure>& dividendTS,
            const Handle<YieldTermStructure>& riskFreeTS,
            const Handle<LocalVol>& localvol,
            const boost::shared_ptr<discretization>& d =
                  boost::shared_ptr<discretization>(new EulerDiscretization));
        //! \name StochasticProcess1D interface
        //@{
        Real x0() const;
        /*! \todo revise extrapolation */
        Real drift(Time t, Real x) const;
        /*! \todo revise extrapolation */
        Real diffusion(Time t, Real x) const;
        Real apply(Real x0, Real dx) const;
        //@}
        Time time(const Date&) const;
        //! \name Observer interface
        //@{
        void update();
        //@}
        //! \name Inspectors
        //@{
        const Handle<Quote>& stateVariable() const;
        const Handle<YieldTermStructure>& dividendYield() const;
        const Handle<YieldTermStructure>& riskFreeRate() const;
        const Handle<LocalVol>& localVolatility() const;
        //@}
      private:
        Handle<Quote> x0_;
        Handle<YieldTermStructure> riskFreeRate_, dividendYield_;
        Handle<LocalVol> localvol_;
    };
} //QuantLib
# endif
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2009 Kim Kuen Tang

 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/license.shtml>.

 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 "localvol.hpp"
# include <ql/termstructures/volatility/equityfx/blackvoltermstructure.hpp>
# include <ql/termstructures/yieldtermstructure.hpp>
# include <ql/quotes/simplequote.hpp>
# include <ql/math/interpolations/bilinearinterpolation.hpp>

namespace QuantLib {

        Real LocalVol::maxVol() const
        {
                return *std::max_element(volMatrix_.begin(), volMatrix_.end());
        }

    const Date& LocalVol::referenceDate() const {
        return this->referenceDate_;
    }

    DayCounter LocalVol::dayCounter() const {
                return dayCounter_;
    }

    Date LocalVol::maxDate() const {
        return maxDate_;
    }

    Real LocalVol::minStrike() const {
        return strikes_.back();
    }

    Real LocalVol::maxStrike() const {
        return strikes_.front();
    }

    LocalVol::LocalVol(const Date& referenceDate,
                 const Calendar& cal,
                 const std::vector<Date>& dates,
                 const std::vector<Real>& strikes,
                 const Matrix& volMatrix,
                 const DayCounter& dayCounter,
                 Extrapolation lowerEx,
                 Extrapolation upperEx )
    : LocalVolTermStructure(referenceDate,cal,Following,dayCounter),
                referenceDate_(referenceDate),
                dayCounter_(dayCounter), maxDate_(dates.back()), strikes_(strikes),
                lowerExtrapolation_(lowerEx), upperExtrapolation_(upperEx),volMatrix_(volMatrix)
        {

        QL_REQUIRE(dates.size()==volMatrix.columns(),
                   "mismatch between date vector and vol matrix colums");
        QL_REQUIRE(strikes_.size()==volMatrix.rows(),
                   "mismatch between money-strike vector and vol matrix rows");

        QL_REQUIRE(dates[0]>=referenceDate,
                   "cannot have dates[0] <= referenceDate");

                times_.resize(dates.size());
                std::vector<Time>::iterator t=times_.begin();
                for(std::vector<Date>::const_iterator it=dates.begin(), end=dates.end();
                        it!=end;++it, ++t)
                        *t=timeFromReference(*it);
               
                for(std::vector<Time>::const_iterator it=times_.begin()+1, end=times_.end();
                        it!=end;++it)
                QL_REQUIRE(it[0]-it[-1] > 0.0, "dates are not sorted");


        // default: bilinear interpolation
        setInterpolation<Bilinear>();
    }

    void LocalVol::accept(AcyclicVisitor& v) {
        Visitor<LocalVol>* v1 =
            dynamic_cast<Visitor<LocalVol>*>(&v);
        if (v1 != 0)
            v1->visit(*this);
        else
            LocalVolTermStructure::accept(v);
    }

    Volatility LocalVol::localVolImpl(Time t, Real underlyingLevel) const
        {
                return varianceSurface_(t,underlyingLevel,true);
    }

}


# ifndef LOCALVOL_HPP_KTT_260709
# define LOCALVOL_HPP_KTT_260709

/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2009 Kim Kuen Tang

 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/license.shtml>.

 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.
*/

/*! \file localvol.hpp
    \brief Local volatility surface
*/

# include <ql/termstructures/volatility/equityfx/localvoltermstructure.hpp>
# include <ql/math/matrix.hpp>
# include <ql/math/interpolations/interpolation2d.hpp>


namespace QuantLib {


    class LocalVol : public LocalVolTermStructure {
      public:
                  enum Extrapolation { ConstantExtrapolation,
                             InterpolatorDefaultExtrapolation };
        LocalVol(const Date& referenceDate,
                 const Calendar& cal,
                 const std::vector<Date>& dates,
                 const std::vector<Real>& strikes,
                 const Matrix& volMatrix,
                 const DayCounter& dayCounter,
                 Extrapolation lowerExtrapolation =
                    InterpolatorDefaultExtrapolation,
                 Extrapolation upperExtrapolation =
                    InterpolatorDefaultExtrapolation);

        //! \name TermStructure interface
        //@{
        const Date& referenceDate() const;
        DayCounter dayCounter() const;
        Date maxDate() const;
        //@}
        //! \name VolatilityTermStructure interface
        //@{
        Real minStrike() const;
        Real maxStrike() const;
                Real maxVol() const;
               
                template <class Interpolator>
        void setInterpolation(const Interpolator& i = Interpolator()) {
            varianceSurface_ =
                i.interpolate(times_.begin(), times_.end(),
                              strikes_.begin(), strikes_.end(),
                              volMatrix_);
            notifyObservers();
        }
        //@}
        //! \name Visitability
        //@{
        virtual void accept(AcyclicVisitor&);
        //@}
      protected:
        Volatility localVolImpl(Time, Real) const;
      private:
        DayCounter dayCounter_;
        Date maxDate_;
                Date referenceDate_;
        std::vector<Real> strikes_;
        std::vector<Time> times_;
        Matrix volMatrix_;
        Interpolation2D varianceSurface_;
        Extrapolation lowerExtrapolation_, upperExtrapolation_;
    };

}

#endif
------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
QuantLib-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/quantlib-users
Reply | Threaded
Open this post in threaded view
|

Re: local volatility surface

Klaus Spanderen-2
Hi Kim

On Tuesday 04 August 2009 22:15:23 Kim Kuen Tang wrote:
> (iii) A pricing engine for european options needs to be implemented that
> calculates the market value according a given dupire process. This
> pricing engine will be used as part of the calibration procedure. This
> part is almost finished using finite element.

The performance of the finite difference pricing engine might (will) be too
slow for calibration purposes if you are using the backwards equation to
price option by option. The forward equation of the problem (s. Fokker-Planck
equation) allows you to price all calibration options at once and will give
you a real performance boost.

cheers
 Klaus


------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
QuantLib-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/quantlib-users
Reply | Threaded
Open this post in threaded view
|

Re: local volatility surface

Kim Kuen Tang


Klaus Spanderen schrieb:

Hi Klaus,

> The performance of the finite difference pricing engine might (will) be too
> slow for calibration purposes if you are using the backwards equation to
> price option by option. The forward equation of the problem (s. Fokker-Planck
> equation) allows you to price all calibration options at once and will give
> you a real performance boost.
>
>  
thanks for the advice.
Using Fokker-Planck equation saves a lot of work for evaluating the cost
function and the gradient of the cost function.
I will integrate this in the calibration procedure. In the meantime a
clever target function needs to be chosen to ensure stability of the
calibration.
For example small change of the input implied volatility surface
shouldnt have big impact on the local volatility surface. And it
shouldnt produce values near to zero or negative.

Do you have some advice?

Best regards,
Kim Tang
> cheers
>  Klaus
>
>
>  


------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
QuantLib-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/quantlib-users
Reply | Threaded
Open this post in threaded view
|

Re: local volatility surface

Andrew Kolesnikov

Kim Tang scribed:

> Using Fokker-Planck equation saves a lot of work for evaluating the cost
> function and the gradient of the cost function.
> I will integrate this in the calibration procedure. In the meantime a
> clever target function needs to be chosen to ensure stability of the
> calibration.
 
Hi, Kim.
In fact, what you want to do was already done in the article "The equity option volatility smile: an implicit finite-difference approach", B. G. Andersen and Rupert Brotherton-Ratcliffe, so try to find it.
Regarding your topic i have some questions:
- what is essential of volMatrix in your LocalVol class? I guess, that it should be local vol matrix, moreover varianceSurface_ should be replaced by localVolSurface_;
- what do you mean by 5th step, cause maybe it's a topic i'm really interested in? When you have some market data (ie option vols/variances) you should choose good extrapolation technique for the tails, cause
you need wide range (strikes) of local vols during implementation of MC or PDE, and this data have big impact on the LV calibration. I use simple bicubic interpolation, which is enough for LV calculation, but good extrapolation is still mystery for me.

PS i'm not really familiar with MC framework, but you could implement your engine via PDE in QL