/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* Copyright (C) 2006 Klaus Spanderen Copyright (C) 2007 StatPro Italia srl 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 mcamericanengine.hpp \brief American Monte Carlo engine */ #ifndef quantlib_mc_american_engine_hpp #define quantlib_mc_american_engine_hpp #include #include #include #include #include #include #include namespace QuantLib { //! American Monte Carlo engine /*! References: \ingroup vanillaengines \test the correctness of the returned value is tested by reproducing results available in web/literature */ template class MCAmericanEngine : public MCLongstaffSchwartzEngine{ public: MCAmericanEngine(Size timeSteps, Size timeStepsPerYear, bool antitheticVariate, bool controlVariate, Size requiredSamples, Real requiredTolerance, Size maxSamples, BigNatural seed, Size polynomOrder, LsmBasisSystem::PolynomType polynomType, Size nCalibrationSamples = Null()); protected: boost::shared_ptr > lsmPathPricer() const; Real controlVariateValue() const; boost::shared_ptr controlPricingEngine() const; boost::shared_ptr > controlPathPricer() const; private: const Size polynomOrder_; const LsmBasisSystem::PolynomType polynomType_; }; class AmericanPathPricer : public EarlyExercisePathPricer { public: AmericanPathPricer(const boost::shared_ptr& payoff, Size polynomOrder, LsmBasisSystem::PolynomType polynomType); Real state(const Path& path, Size t) const; Real operator()(const Path& path, Size t) const; std::vector > basisSystem() const; protected: Real payoff(Real state) const; Real scalingValue_; const boost::shared_ptr payoff_; std::vector > v_; }; //! Monte Carlo American engine factory template class MakeMCAmericanEngine { public: MakeMCAmericanEngine(); // named parameters MakeMCAmericanEngine& withSteps(Size steps); MakeMCAmericanEngine& withStepsPerYear(Size steps); MakeMCAmericanEngine& withSamples(Size samples); MakeMCAmericanEngine& withTolerance(Real tolerance); MakeMCAmericanEngine& withMaxSamples(Size samples); MakeMCAmericanEngine& withSeed(BigNatural seed); MakeMCAmericanEngine& withAntitheticVariate(bool b = true); MakeMCAmericanEngine& withControlVariate(bool b = true); MakeMCAmericanEngine& withPolynomOrder(Size polynomOrer); MakeMCAmericanEngine& withBasisSystem(LsmBasisSystem::PolynomType); MakeMCAmericanEngine& withCalibrationSamples(Size calibrationSamples); // conversion to pricing engine operator boost::shared_ptr() const; private: bool antithetic_, controlVariate_; Size steps_, stepsPerYear_; Size samples_, maxSamples_, calibrationSamples_; Real tolerance_; BigNatural seed_; Size polynomOrder_; LsmBasisSystem::PolynomType polynomType_; }; template inline MCAmericanEngine::MCAmericanEngine( Size timeSteps, Size timeStepsPerYear, bool antitheticVariate, bool controlVariate, Size requiredSamples, Real requiredTolerance, Size maxSamples,BigNatural seed, Size polynomOrder, LsmBasisSystem::PolynomType polynomType, Size nCalibrationSamples) : MCLongstaffSchwartzEngine( timeSteps, timeStepsPerYear, false, antitheticVariate, controlVariate, requiredSamples, requiredTolerance, maxSamples, seed, nCalibrationSamples), polynomOrder_(polynomOrder), polynomType_(polynomType) { } template inline boost::shared_ptr > MCAmericanEngine::lsmPathPricer() const { boost::shared_ptr process = boost::dynamic_pointer_cast( this->arguments_.stochasticProcess); QL_REQUIRE(process, "generialzed Black-Scholes proces s required"); boost::shared_ptr exercise = boost::dynamic_pointer_cast( this->arguments_.exercise); QL_REQUIRE(exercise, "wrong exercise given"); QL_REQUIRE(!exercise->payoffAtExpiry(), "payoff at expiry not handled"); boost::shared_ptr earlyExercisePathPricer( new AmericanPathPricer(this->arguments_.payoff, polynomOrder_, polynomType_)); return boost::shared_ptr > ( new LongstaffSchwartzPathPricer( this->timeGrid(), earlyExercisePathPricer, process->riskFreeRate().currentLink())); } template inline boost::shared_ptr > MCAmericanEngine::controlPathPricer() const { boost::shared_ptr payoff = boost::dynamic_pointer_cast( this->arguments_.payoff); QL_REQUIRE(payoff, "StrikedTypePayoff needed for control variate"); boost::shared_ptr process = boost::dynamic_pointer_cast( this->arguments_.stochasticProcess); QL_REQUIRE(process, "generalized Black-Scholes process required"); return boost::shared_ptr >( new EuropeanPathPricer( payoff->optionType(), payoff->strike(), process->riskFreeRate()->discount(this->timeGrid().back())) ); } template inline boost::shared_ptr MCAmericanEngine::controlPricingEngine() const { return boost::shared_ptr(new AnalyticEuropeanEngine()); } template inline Real MCAmericanEngine::controlVariateValue() const { boost::shared_ptr controlPE = this->controlPricingEngine(); QL_REQUIRE(controlPE, "engine does not provide " "control variation pricing engine"); VanillaOption::arguments* controlArguments = dynamic_cast(controlPE->getArguments()); *controlArguments = this->arguments_; controlArguments->exercise = boost::shared_ptr( new EuropeanExercise(this->arguments_.exercise->lastDate())); controlPE->calculate(); const VanillaOption::results* controlResults = dynamic_cast( controlPE->getResults()); return controlResults->value; } template inline MakeMCAmericanEngine::MakeMCAmericanEngine() : antithetic_(false), controlVariate_(false), steps_(Null()), stepsPerYear_(Null()), samples_(Null()), maxSamples_(Null()), calibrationSamples_(2048), tolerance_(Null()), seed_(0), polynomOrder_(2), polynomType_ (LsmBasisSystem::Monomial) {} template inline MakeMCAmericanEngine& MakeMCAmericanEngine::withPolynomOrder(Size polynomOrder) { polynomOrder_ = polynomOrder; return *this; } template inline MakeMCAmericanEngine& MakeMCAmericanEngine::withBasisSystem( LsmBasisSystem::PolynomType polynomType) { polynomType_ = polynomType; return *this; } template inline MakeMCAmericanEngine& MakeMCAmericanEngine::withSteps(Size steps) { steps_ = steps; return *this; } template inline MakeMCAmericanEngine& MakeMCAmericanEngine::withStepsPerYear(Size steps) { stepsPerYear_ = steps; return *this; } template inline MakeMCAmericanEngine& MakeMCAmericanEngine::withSamples(Size samples) { QL_REQUIRE(tolerance_ == Null(), "tolerance already set"); samples_ = samples; return *this; } template inline MakeMCAmericanEngine& MakeMCAmericanEngine::withTolerance(Real tolerance) { QL_REQUIRE(samples_ == Null(), "number of samples already set"); QL_REQUIRE(RNG::allowsErrorEstimate, "chosen random generator policy " "does not allow an error estimate"); tolerance_ = tolerance; return *this; } template inline MakeMCAmericanEngine& MakeMCAmericanEngine::withMaxSamples(Size samples) { maxSamples_ = samples; return *this; } template inline MakeMCAmericanEngine& MakeMCAmericanEngine::withCalibrationSamples(Size samples) { calibrationSamples_ = samples; return *this; } template inline MakeMCAmericanEngine& MakeMCAmericanEngine::withSeed(BigNatural seed) { seed_ = seed; return *this; } template inline MakeMCAmericanEngine& MakeMCAmericanEngine::withAntitheticVariate(bool b) { antithetic_ = b; return *this; } template inline MakeMCAmericanEngine& MakeMCAmericanEngine::withControlVariate(bool b) { controlVariate_ = b; return *this; } template inline MakeMCAmericanEngine::operator boost::shared_ptr() const { QL_REQUIRE(steps_ != Null() || stepsPerYear_ != Null(), "number of steps not given"); QL_REQUIRE(steps_ == Null() || stepsPerYear_ == Null(), "number of steps overspecified"); return boost::shared_ptr(new MCAmericanEngine(steps_, stepsPerYear_, antithetic_, controlVariate_, samples_, tolerance_, maxSamples_, seed_, polynomOrder_, polynomType_, calibrationSamples_)); } } #endif