Update version of experimental/mcbasket

View: New views
5 Messages — Rating Filter:   Alert me  

Update version of experimental/mcbasket

by Andrea-60 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

After almost 2 year I would like to post an updated version of mcbasket experimental.
The idea is still the same as the initial version: i.e. have one single engine (here
MCAmericanPathEngine or MCPathBasketEngine) and to only have to write a new option/payoff
(PathMultiAssetOption/PathPayoff)

Here the biggest new feature is the support of American Options.

The key feature is this virtual method of PathPayoff

         virtual void value(const Matrix       & path,
                            Array              & payments,
                            Array              & exercises,
                            std::vector<Array> & states) const = 0;

which has to return all information needed to value a payoff with early exercise (for a single path)

path: is the path of all assets/times
payments: all payments made
exercises: if the option is exercised at time i, all payment up to (and including i) are preserved
and the others cancelled
states: a vector of financial coordinates used in LS

I have attached a diff wrt the most recent svn and an example of an American Lookback.

I can go through all the code in details if people are interested.

I don't think it makes much sense to compare it to the 1st version, since it was very limited in
features and hardly usable at all.

TODO, problems, bugs:

- I had to copy&paste a lot of classes/templates already used in QL (e.g.: EarlyExercisePathPricer,
LongstaffSchwartzPathPricer). My problem is that the existing EarlyExercisePathPricer only seems to
handle an option which pays only once (i.e. at exercise), while I wanted to allow an option that
pays many times and that I can cancel at some point

- allow for non 1-1 mapping between paths and assets (e.g. stoch vol)

- allow for non deterministic interest rates (i.e. replace the discount factors with 1/numeraire)

- find nicer names

[example.cpp]

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

// the only header you need to use QuantLib
#define BOOST_LIB_DIAGNOSTIC
#  include <ql/quantlib.hpp>
#undef BOOST_LIB_DIAGNOSTIC

#include <boost/timer.hpp>
#include <iostream>
#include <iomanip>

using namespace QuantLib;

#if defined(QL_ENABLE_SESSIONS)
namespace QuantLib {

    Integer sessionId() { return 0; }

}
#endif

// The payoff

class AmericanLookback : public AdaptedPathPayoff {
public:
    virtual std::string name() const;
    virtual std::string description() const;
    virtual void operator()(ValuationData & data) const;
    virtual Size basisSystemDimension() const;
    virtual Real lowerBoundContinuationValue() const;
};

std::string AmericanLookback::name() const {
    return "AmericanLookback";
}

std::string AmericanLookback::description() const {
    return name();
}

Size AmericanLookback::basisSystemDimension() const {
    return 2;
}

Real AmericanLookback::lowerBoundContinuationValue() const {
    return 0.0;
}

void AmericanLookback::operator()(ValuationData & data) const {
    Real sum = 0.0;

    const Size numberOfTimes  = data.numberOfTimes();
    const Size numberOfAssets = data.numberOfAssets();

    double runningMaximum = 1.0;
    for (Size i = 0; i < numberOfTimes; ++i) {

        double thisSum = 0.0;
        for (Size j = 0; j < numberOfAssets; ++j)
            thisSum += data.getAssetValue(i, j);
        thisSum /= numberOfAssets;

        runningMaximum = std::max(runningMaximum, thisSum);

        Array financialCoordinates(basisSystemDimension());

        const double payoff = runningMaximum - thisSum;
        financialCoordinates[0]   = runningMaximum / thisSum;
        financialCoordinates[1]   = thisSum;

        double exercise = payoff;
        double payment = 0.0;

        // this is only to be able to price the european version.
        if (i == numberOfTimes - 1)
            std::swap(exercise, payment);

        data.setPayoffValue(i, payment);
        data.setExerciseData(i, exercise, financialCoordinates);
    }
}

// The option

class AmericanLookbackOption : public PathMultiAssetOption {
public:
    AmericanLookbackOption(boost::shared_ptr<PathPayoff> &,
                           std::vector<Date> &,
                           const boost::shared_ptr<PricingEngine>& engine = boost::shared_ptr<PricingEngine>() );

    virtual boost::shared_ptr<PathPayoff> pathPayoff()     const;
    virtual std::vector<Date>             fixingDates()    const;
private:
    boost::shared_ptr<PathPayoff> pathPayoff_;
    std::vector<Date>             fixingDates_;
};

AmericanLookbackOption::AmericanLookbackOption(boost::shared_ptr<PathPayoff>              & pathPayoff,
                                               std::vector<Date>                          & fixingDates,
                                               const boost::shared_ptr<PricingEngine>     & engine) :
    PathMultiAssetOption(engine),
    pathPayoff_(pathPayoff),
    fixingDates_(fixingDates)
{
}

boost::shared_ptr<PathPayoff> AmericanLookbackOption::pathPayoff()  const {
    return pathPayoff_;
}

std::vector<Date>             AmericanLookbackOption::fixingDates() const {
    return fixingDates_;
}

int main(int, char* []) {

    QL_TRACE_ENABLE;

    try {

        boost::timer timer;
        std::cout << std::endl;

        // our options
        Calendar calendar = TARGET();
        Real underlying = 1.0;
        Spread dividendYield = 0.00;
        Rate riskFreeRate = 0.05;
        Volatility volatility = 0.20;

        Date todaysDate(15, May, 1998);
        Date settlementDate(17, May, 1998);
        Settings::instance().evaluationDate() = todaysDate;

        DayCounter dayCounter = Actual365Fixed();

        std::cout << "Underlying price = "        << underlying << 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;

        std::string method;

        std::cout << std::endl ;

        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, calendar, volatility, dayCounter)));

        boost::shared_ptr<StochasticProcess1D> stochasticProcess(
                 new BlackScholesMertonProcess(underlyingH, flatDividendTS,
                                               flatTermStructure, flatVolTS));
        std::vector<boost::shared_ptr<StochasticProcess1D> > arrayOfProcesses;
        arrayOfProcesses.push_back(stochasticProcess);

        Matrix corr(1, 1);
        corr[0][0] = 1;
        boost::shared_ptr<StochasticProcessArray> mdProcess(new StochasticProcessArray(arrayOfProcesses, corr));

        // options

        boost::shared_ptr<PathPayoff> lookbackPayoff(new AmericanLookback());
        std::vector<Date> fixings;

        Date firstFixing(17, May, 2000);
        fixings.push_back(firstFixing);
        Period annual(Annual);
        for (Size i = 0; i < 5; ++i)
            fixings.push_back(fixings.back() + annual);

        AmericanLookbackOption lookbackOption(lookbackPayoff, fixings);

        // Monte Carlo Method

        Size timeSteps = 10;

        method = "MC (Sobol)";
        Size nSamples = 1 << 17;
        Size calibSamples = 1 << 17;

        boost::shared_ptr<PricingEngine> mcengine;

        mcengine = MakeMCPathBasketEngine<LowDiscrepancy>(mdProcess).withSteps(timeSteps).withSamples(nSamples);
        lookbackOption.setPricingEngine(mcengine);
        std::cout << method << " E " << nSamples << " iterations: " << lookbackOption.NPV() << std::endl;

        mcengine = MakeMCAmericanPathEngine<LowDiscrepancy>(mdProcess).withSteps(timeSteps).withSamples(nSamples).withCalibrationSamples(calibSamples);
        lookbackOption.setPricingEngine(mcengine);
        std::cout << method << " A " << nSamples << " iterations: " << lookbackOption.NPV() << std::endl;

        return 0;

    } catch (Error& err) {
        std::cout << "QuantLib::Error: " << err.what() << std::endl;
        return 1;
    } catch (std::exception& e) {
        std::cout << "std::exception: " << e.what() << std::endl;
        return 2;
    } catch (...) {
        std::cout << "unknown error" << std::endl;
        return 3;
    }
}



------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
QuantLib-dev mailing list
QuantLib-dev@...
https://lists.sourceforge.net/lists/listinfo/quantlib-dev

ql.diff.gz (12K) Download Attachment

Re: Update version of experimental/mcbasket

by Klaus Spanderen-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Andrea

do you see a change to replace the original version of the classes

 EarlyExercisePathPricer and LongstaffSchwartzPathPricer

in ql/methods/montecarlo by your version?

best regards
 Klaus

------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
QuantLib-dev mailing list
QuantLib-dev@...
https://lists.sourceforge.net/lists/listinfo/quantlib-dev

Re: Update version of experimental/mcbasket

by Andrea-60 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On 10/10/09 20:53, Klaus Spanderen wrote:
> Hi Andrea
>
> do you see a change to replace the original version of the classes
>
>   EarlyExercisePathPricer and LongstaffSchwartzPathPricer
>
> in ql/methods/montecarlo by your version?

Ideally yes.
The reasons I did not use the EarlyExercisePathPricer are:

1) it only provides a method to get the exercise payment (i.e. operator()) and the state, while I
would like to get the value of payments that are made until the option is cancelled

2) I first added this 3rd virtual method. but then I realized that what the
LongstaffSchwartzPathPricer caches is not optimal. it caches the paths, while I found much better to
cache a triplet of vectors (exercise payments, payments, states) so that I process a single path
only once.
For a trivial case (i.e. the american call option) it is the same, but if each payment or state is
path dependent, then if I only cache the path, I have to reprocess the whole path each time I need a
new "time".

3) so I decided that it was better for the LongstaffSchwartzPathPricer to have access to the payoff
directly and store the relevant information for each path (and not the path itself)

I have not seen how the current implementation of EarlyExercisePathPricer &
LongstaffSchwartzPathPricer are used in a complex path dependent case, so maybe there is a more
"standard" way of doing it.

Then I added to LongstaffSchwartzPathPricer 2 extra things (which are easily ported to the main version)

1) it currently skips all paths that give a non positive exercise value. this because it assumes the
continuation value will always be positive, and there is no point to accept a negative exercise.
it might not be the case always and it is hard to dynamically detect this lower bound (0.0). so the
payoff has a function to return the lower bound of the continuation value or -INF if absent

2) it checks if the 2 trivial exercise strategies (exercise for all paths or never) are better than
the LS algorithm. if this is the case, then we override the decision with 2 special vectors of
coefficients (empty => never, too big => always).
I noticed that if the states are chosen badly, the LS algorithm can be trivially wrong.
This might be bad for sensitivities since the whole "function" has a discontinuity.
And it prints the result of this check using QL_TRACE

Andrea


------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
QuantLib-dev mailing list
QuantLib-dev@...
https://lists.sourceforge.net/lists/listinfo/quantlib-dev

Re: Update version of experimental/mcbasket

by Andrea-60 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On 11/10/09 19:46, Andrea wrote:

> 1) it currently skips all paths that give a non positive exercise value. this because it assumes the
> continuation value will always be positive, and there is no point to accept a negative exercise.
> it might not be the case always and it is hard to dynamically detect this lower bound (0.0). so the
> payoff has a function to return the lower bound of the continuation value or -INF if absent

It is actually possible to dynamically detect what an out of the money option is.
Since we go backward, we just remember what the lowest payoff is, and never exercise if the early
termination value is less or equal to that value.

In this updated version of the mcbasket experimental patch, I've implemented it.
In my (simple) tests it worked properly.


------------------------------------------------------------------------------
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-dev mailing list
QuantLib-dev@...
https://lists.sourceforge.net/lists/listinfo/quantlib-dev

mcbasket.diff.gz (13K) Download Attachment

Re: Update version of experimental/mcbasket

by Klaus Spanderen-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi

can you do me a favour and send me your ql/experimental/mcbasket directory as
a tar-ball? (the diff doesn't work out on my machine here.).

thanks

Klaus

On Monday 09 November 2009 14:34:24 Andrea wrote:

> On 11/10/09 19:46, Andrea wrote:
> > 1) it currently skips all paths that give a non positive exercise value.
> > this because it assumes the continuation value will always be positive,
> > and there is no point to accept a negative exercise. it might not be the
> > case always and it is hard to dynamically detect this lower bound (0.0).
> > so the payoff has a function to return the lower bound of the
> > continuation value or -INF if absent
>
> It is actually possible to dynamically detect what an out of the money
> option is. Since we go backward, we just remember what the lowest payoff
> is, and never exercise if the early termination value is less or equal to
> that value.
>
> In this updated version of the mcbasket experimental patch, I've
> implemented it. In my (simple) tests it worked properly.



------------------------------------------------------------------------------
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-dev mailing list
QuantLib-dev@...
https://lists.sourceforge.net/lists/listinfo/quantlib-dev