Login  Register

Re: AnaliticHestonEngine -- SV or SVJ

Posted by nabbleuser2008 on Sep 22, 2008; 12:04pm
URL: http://quantlib.414.s1.nabble.com/AnaliticHestonEngine-SV-or-SVJ-tp6640p6650.html

Dear Klaus,
 Thank you very much for all your help.

  Took me a little while to compare the prices from all the methods, including the one with adjusted maturity.  May be for the reasons you're mentioning below, I'm not getting a perfect fit with any of the models, even though some or most model prices are very good.


 Thanks again for all your help and advice.

 Cheers,

C



<quote author="Klaus Spanderen-2">
Hi

sorry for the late answer.


On Monday 01 September 2008 17:57:02 nabbleuser2008 wrote:
> I also wanted to try what you're saying below, but I was not
> able to understand how to do what you were saying

I've attached a version of the LongstaffSchwartzPathPricer, which calculates
the average life time 'til exercise of an option instead of the price. (There
are better ways to do this but this was easy to implement). Just replace the
original file by the attached one and ran e.g. eamples like
MCLongstaffSchwartzEngineTest::testAmericanOption. The npv is the average
life time. Now (hopefully;-) the implied vols of calls and puts quoted in
terms of the average life time will be closer together than the implied vols
quoted in terms of the option maturity. Calibrate on "synth" european options
with maturity = avg. life time of the american options.

> I've used the FDDividendAmericanEngine to calculate the implied
> volatilities ( Even though I noticed the comment in the source file that
> impliedVolatility may not be accurate. I still used it as I couldn't find a
> better alternative in the QL librarary for my needs, as I'm interested in
> americans with discrete dividend payments.)
>

Be aware that the Heston model is using a dividend yield and that the
volatilities for a discrete dividend Black-Scholes models and dividend yield
BS-model aren't the same. See e.g.

 Bos, R. et al. (2003) Dealing with discrete dividends, Risk Magazine, 16, pp.
109–112.

to transfer volatility surfaces between both dividend models. The Heston
calibration helper assumes a dividend yield BS volatility. May be for the
time being you are better off using the FDAmericanEngine and a dividend
yield.

cheers
 Klaus

--
Klaus Spanderen
Ludwig Erhard Str. 12
48734 Reken (Germany)
EMail: klaus@NOSPAMspanderen.de (remove NOSPAM from the address)

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

/*
 Copyright (C) 2006 Klaus Spanderen

 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
 <quantlib-dev@lists.sf.net>. 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 longstaffschwartzpathpricer.hpp
    \brief Longstaff-Schwarz path pricer for early exercise options
*/

#ifndef quantlib_longstaff_schwartz_path_pricer_hpp
#define quantlib_longstaff_schwartz_path_pricer_hpp

#include <ql/termstructures/yieldtermstructure.hpp>
#include <ql/math/functional.hpp>
#include <ql/math/linearleastsquaresregression.hpp>
#include <ql/methods/montecarlo/pathpricer.hpp>
#include <ql/methods/montecarlo/earlyexercisepathpricer.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>

namespace QuantLib {

    //! Longstaff-Schwarz path pricer for early exercise options
    /*! References:

        Francis Longstaff, Eduardo Schwartz, 2001. Valuing American Options
        by Simulation: A Simple Least-Squares Approach, The Review of
        Financial Studies, Volume 14, No. 1, 113-147

        \ingroup mcarlo

        \test the correctness of the returned value is tested by
              reproducing results available in web/literature
    */
    template <class PathType>
    class LongstaffSchwartzPathPricer : public PathPricer<PathType> {
      public:
        typedef typename EarlyExerciseTraits<PathType>::StateType StateType;

        LongstaffSchwartzPathPricer(
            const TimeGrid& times,
            const boost::shared_ptr<EarlyExercisePathPricer<PathType> >& ,
            const boost::shared_ptr<YieldTermStructure>& termStructure);

        Real operator()(const PathType& path) const;
        virtual void calibrate();

      protected:
        bool  calibrationPhase_;
        const boost::shared_ptr<EarlyExercisePathPricer<PathType> >
            pathPricer_;

        boost::scoped_array<Array> coeff_;
        boost::scoped_array<DiscountFactor> dF_;

        mutable std::vector<PathType> paths_;
        const   std::vector<boost::function1<Real, StateType> > v_;
        const TimeGrid times_;
    };

    template <class PathType> inline
    LongstaffSchwartzPathPricer<PathType>::LongstaffSchwartzPathPricer(
        const TimeGrid& times,
        const boost::shared_ptr<EarlyExercisePathPricer<PathType> >&
            pathPricer,
        const boost::shared_ptr<YieldTermStructure>& termStructure)
    : calibrationPhase_(true),
      pathPricer_(pathPricer),
      coeff_     (new Array[times.size()-1]),
      dF_        (new DiscountFactor[times.size()-1]),
      v_         (pathPricer_->basisSystem()),
      times_     (times) {

        for (Size i=0; i<times.size()-1; ++i) {
            dF_[i] =   termStructure->discount(times[i+1])
                     / termStructure->discount(times[i]);
        }
    }

    template <class PathType> inline
    Real LongstaffSchwartzPathPricer<PathType>::operator()(
        const PathType& path) const {
        if (calibrationPhase_) {
            // store paths for the calibration
            paths_.push_back(path);
            // result doesn't matter
            return 0.0;
        }

        const Size len = EarlyExerciseTraits<PathType>::pathLength(path);
        Real price = times_[len-1];
       
        for (Size i=len-2; i>0; --i) {
            const Real exercise = (*pathPricer_)(path, i);
            if (exercise > 0.0) {
                const StateType regValue = pathPricer_->state(path, i);

                Real continuationValue = 0.0;
                for (Size l=0; l<v_.size(); ++l) {
                    continuationValue += coeff_[i][l] * v_[l](regValue);
                }

                if (continuationValue < exercise) {
                    price = times_[i];
                }
            }
        }

        return price;
    }

    template <class PathType> inline
    void LongstaffSchwartzPathPricer<PathType>::calibrate() {
        const Size n = paths_.size();
        Array prices(n), exercise(n);
        const Size len = EarlyExerciseTraits<PathType>::pathLength(paths_[0]);

        std::transform(paths_.begin(), paths_.end(), prices.begin(),
                       boost::bind(&EarlyExercisePathPricer<PathType>
                                     ::operator(),
                                   pathPricer_.get(), _1, len-1));

        for (Size i=len-2; i>0; --i) {
            std::vector<Real>      y;
            std::vector<StateType> x;

            //roll back step
            for (Size j=0; j<n; ++j) {
                exercise[j]=(*pathPricer_)(paths_[j], i);

                if (exercise[j]>0.0) {
                    x.push_back(pathPricer_->state(paths_[j], i));
                    y.push_back(dF_[i]*prices[j]);
                }
            }

            if (v_.size() <=  x.size()) {
                coeff_[i]
                    = LinearLeastSquaresRegression<StateType>(x, y, v_).a();
            }
            else {
            // if number of itm paths is smaller then the number of
            // calibration functions -> no early exercise
                coeff_[i] = Array(v_.size(), 0.0);
            }

            for (Size j=0, k=0; j<n; ++j) {
                prices[j]*=dF_[i];
                if (exercise[j]>0.0) {
                    Real continuationValue = 0.0;
                    for (Size l=0; l<v_.size(); ++l) {
                        continuationValue += coeff_[i][l] * v_[l](x[k]);
                    }
                    if (continuationValue < exercise[j]) {
                        prices[j] = exercise[j];
                    }
                    ++k;
                }
            }
        }

        // remove calibration paths
        paths_.clear();
        // entering the calculation phase
        calibrationPhase_ = false;
    }
}


#endif

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
QuantLib-users mailing list
QuantLib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/quantlib-users

</quote>