/* -*- 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 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 #include #include #include #include #include #include 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 LongstaffSchwartzPathPricer : public PathPricer { public: typedef typename EarlyExerciseTraits::StateType StateType; LongstaffSchwartzPathPricer( const TimeGrid& times, const boost::shared_ptr >& , const boost::shared_ptr& termStructure); Real operator()(const PathType& path) const; virtual void calibrate(); protected: bool calibrationPhase_; const boost::shared_ptr > pathPricer_; boost::scoped_array coeff_; boost::scoped_array dF_; mutable std::vector paths_; const std::vector > v_; }; template inline LongstaffSchwartzPathPricer::LongstaffSchwartzPathPricer( const TimeGrid& times, const boost::shared_ptr >& pathPricer, const boost::shared_ptr& termStructure) : calibrationPhase_(true), pathPricer_(pathPricer), coeff_ (new Array[times.size()-1]), dF_ (new DiscountFactor[times.size()-1]), v_ (pathPricer_->basisSystem()) { for (Size i=0; idiscount(times[i+1]) / termStructure->discount(times[i]); } } template inline Real LongstaffSchwartzPathPricer::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::pathLength(path); Real price = (*pathPricer_)(path, len-1); for (Size i=len-2; i>0; --i) { price*=dF_[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 inline void LongstaffSchwartzPathPricer::calibrate() { const Size n = paths_.size(); Array prices(n), exercise(n); const Size len = EarlyExerciseTraits::pathLength(paths_[0]); std::transform(paths_.begin(), paths_.end(), prices.begin(), boost::bind(&EarlyExercisePathPricer ::operator(), pathPricer_.get(), _1, len-1)); for (Size i=len-2; i>0; --i) { std::vector y; std::vector x; //roll back step for (Size j=0; j0.0) { x.push_back(pathPricer_->state(paths_[j], i)); y.push_back(dF_[i]*prices[j]); } } if (v_.size() <= x.size()) { coeff_[i] = LinearLeastSquaresRegression(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; j0.0) { Real continuationValue = 0.0; for (Size l=0; l