/* -*- 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 . The license is also available online at . 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 mclongstaffschwartzengine.hpp \brief Longstaff Schwartz Monte Carlo engine for early exercise options */ #ifndef quantlib_mc_longstaff_schwartz_engine_hpp #define quantlib_mc_longstaff_schwartz_engine_hpp #include #include namespace QuantLib { //! Longstaff-Schwarz Monte Carlo engine 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 \test the correctness of the returned value is tested by reproducing results available in web/literature */ template class MC, class RNG, class S = Statistics> class MCLongstaffSchwartzEngine : public GenericEngine, public McSimulation { public: typedef typename MC::path_type path_type; typedef typename McSimulation::stats_type stats_type; typedef typename McSimulation::path_pricer_type path_pricer_type; typedef typename McSimulation::path_generator_type path_generator_type; MCLongstaffSchwartzEngine( Size timeSteps, Size timeStepsPerYear, bool brownianBridge, bool antitheticVariate, bool controlVariate, Size requiredSamples, Real requiredTolerance, Size maxSamples, BigNatural seed, Size nCalibrationSamples = Null()); void calculate() const; protected: virtual boost::shared_ptr > lsmPathPricer() const = 0; TimeGrid timeGrid() const; boost::shared_ptr pathPricer() const; boost::shared_ptr pathGenerator() const; const Size timeSteps_; const Size timeStepsPerYear_; const bool brownianBridge_; const Size requiredSamples_; const Real requiredTolerance_; const Size maxSamples_; const Size seed_; const Size nCalibrationSamples_; mutable boost::shared_ptr > pathPricer_; }; template class MC, class RNG, class S> inline MCLongstaffSchwartzEngine::MCLongstaffSchwartzEngine( Size timeSteps, Size timeStepsPerYear, bool brownianBridge, bool antitheticVariate, bool controlVariate, Size requiredSamples, Real requiredTolerance, Size maxSamples, BigNatural seed, Size nCalibrationSamples) : McSimulation (antitheticVariate, controlVariate), timeSteps_ (timeSteps), timeStepsPerYear_ (timeStepsPerYear), brownianBridge_ (brownianBridge), requiredSamples_ (requiredSamples), requiredTolerance_ (requiredTolerance), maxSamples_ (maxSamples), seed_ (seed), nCalibrationSamples_( (nCalibrationSamples == Null()) ? 2048 : nCalibrationSamples) { } template class MC, class RNG, class S> inline boost::shared_ptr::path_pricer_type> MCLongstaffSchwartzEngine::pathPricer() const { QL_REQUIRE(pathPricer_, "path pricer unknown"); return pathPricer_; } template class MC, class RNG, class S> inline void MCLongstaffSchwartzEngine::calculate() const { pathPricer_ = this->lsmPathPricer(); this->mcModel_ = boost::shared_ptr >( new MonteCarloModel (pathGenerator(), pathPricer_, stats_type(), this->antitheticVariate_)); this->mcModel_->addSamples(nCalibrationSamples_); this->pathPricer_->calibrate(); McSimulation::calculate(requiredTolerance_, requiredSamples_, maxSamples_); this->results_.value = this->mcModel_->sampleAccumulator().mean(); if (RNG::allowsErrorEstimate) { this->results_.errorEstimate = this->mcModel_->sampleAccumulator().errorEstimate(); } } template class MC, class RNG, class S> inline TimeGrid MCLongstaffSchwartzEngine::timeGrid() const { Date lastExerciseDate = this->arguments_.exercise->lastDate(); Time t = this->arguments_.stochasticProcess->time(lastExerciseDate); if (this->timeSteps_ != Null()) { return TimeGrid(t, this->timeSteps_); } else if (this->timeStepsPerYear_ != Null()) { Size steps = static_cast(this->timeStepsPerYear_*t); return TimeGrid(t, std::max(steps, 1)); } else { QL_FAIL("time steps not specified"); } } template class MC, class RNG, class S> inline boost::shared_ptr::path_generator_type> MCLongstaffSchwartzEngine::pathGenerator() const { Size dimensions = this->arguments_.stochasticProcess->factors(); TimeGrid grid = this->timeGrid(); typename RNG::rsg_type generator = RNG::make_sequence_generator(dimensions*(grid.size()-1),seed_); return boost::shared_ptr( new path_generator_type(this->arguments_.stochasticProcess, grid, generator, brownianBridge_)); } } #endif