/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* Copyright (C) 2005 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 mceuropeanhestonengine.hpp \brief Monte Carlo Heston-model engine for European options */ #ifndef quantlib_mc_european_heston_engine_hpp #define quantlib_mc_european_heston_engine_hpp #include #include namespace QuantLib { //! Monte Carlo Heston-model engine for European options /*! \ingroup vanillaengines \test the correctness of the returned value is tested by reproducing results available in web/literature */ template class MCEuropeanHestonEngine : public MCVanillaEngine { public: typedef typename MCVanillaEngine::path_pricer_type path_pricer_type; MCEuropeanHestonEngine(Size timeSteps, Size timeStepsPerYear, bool antitheticVariate, Size requiredSamples, Real requiredTolerance, Size maxSamples, BigNatural seed); protected: boost::shared_ptr pathPricer() const; }; //! Monte Carlo Heston European engine factory template class MakeMCEuropeanHestonEngine { public: MakeMCEuropeanHestonEngine(); // named parameters MakeMCEuropeanHestonEngine& withSteps(Size steps); MakeMCEuropeanHestonEngine& withStepsPerYear(Size steps); MakeMCEuropeanHestonEngine& withSamples(Size samples); MakeMCEuropeanHestonEngine& withTolerance(Real tolerance); MakeMCEuropeanHestonEngine& withMaxSamples(Size samples); MakeMCEuropeanHestonEngine& withSeed(BigNatural seed); MakeMCEuropeanHestonEngine& withAntitheticVariate(bool b = true); // conversion to pricing engine operator boost::shared_ptr() const; private: bool antithetic_; Size steps_, stepsPerYear_, samples_, maxSamples_; Real tolerance_; BigNatural seed_; }; class EuropeanHestonPathPricer : public PathPricer { public: EuropeanHestonPathPricer(Option::Type type, Real strike, DiscountFactor discount); Real operator()(const MultiPath& Multipath) const; private: PlainVanillaPayoff payoff_; DiscountFactor discount_; }; // template definitions template MCEuropeanHestonEngine::MCEuropeanHestonEngine( Size timeSteps, Size timeStepsPerYear, bool antitheticVariate, Size requiredSamples, Real requiredTolerance, Size maxSamples, BigNatural seed) : MCVanillaEngine(timeSteps, timeStepsPerYear, false, antitheticVariate, false, requiredSamples, requiredTolerance, maxSamples, seed) {} template boost::shared_ptr< QL_TYPENAME MCEuropeanHestonEngine::path_pricer_type> MCEuropeanHestonEngine::pathPricer() const { boost::shared_ptr payoff( boost::dynamic_pointer_cast( this->arguments_.payoff)); QL_REQUIRE(payoff, "non-plain payoff given"); boost::shared_ptr process = boost::dynamic_pointer_cast( this->arguments_.stochasticProcess); QL_REQUIRE(process, "Heston process required"); return boost::shared_ptr< QL_TYPENAME MCEuropeanHestonEngine::path_pricer_type>( new EuropeanHestonPathPricer( payoff->optionType(), payoff->strike(), process->riskFreeRate()->discount( this->timeGrid().back()))); } template inline MakeMCEuropeanHestonEngine::MakeMCEuropeanHestonEngine() : antithetic_(false), steps_(Null()), stepsPerYear_(Null()), samples_(Null()), maxSamples_(Null()), tolerance_(Null()), seed_(0) {} template inline MakeMCEuropeanHestonEngine& MakeMCEuropeanHestonEngine::withSteps(Size steps) { QL_REQUIRE(stepsPerYear_ == Null(), "number of steps per year already set"); steps_ = steps; return *this; } template inline MakeMCEuropeanHestonEngine& MakeMCEuropeanHestonEngine::withStepsPerYear(Size steps) { QL_REQUIRE(steps_ == Null(), "number of steps already set"); stepsPerYear_ = steps; return *this; } template inline MakeMCEuropeanHestonEngine& MakeMCEuropeanHestonEngine::withSamples(Size samples) { QL_REQUIRE(tolerance_ == Null(), "tolerance already set"); samples_ = samples; return *this; } template inline MakeMCEuropeanHestonEngine& MakeMCEuropeanHestonEngine::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 MakeMCEuropeanHestonEngine& MakeMCEuropeanHestonEngine::withMaxSamples(Size samples) { maxSamples_ = samples; return *this; } template inline MakeMCEuropeanHestonEngine& MakeMCEuropeanHestonEngine::withSeed(BigNatural seed) { seed_ = seed; return *this; } template inline MakeMCEuropeanHestonEngine& MakeMCEuropeanHestonEngine::withAntitheticVariate(bool b) { antithetic_ = b; return *this; } template inline MakeMCEuropeanHestonEngine:: operator boost::shared_ptr() const { QL_REQUIRE(steps_ != Null() || stepsPerYear_ != Null(), "number of steps not given"); return boost::shared_ptr( new MCEuropeanHestonEngine(steps_, stepsPerYear_, antithetic_, samples_, tolerance_, maxSamples_, seed_)); } inline EuropeanHestonPathPricer::EuropeanHestonPathPricer( Option::Type type, Real strike, DiscountFactor discount) : payoff_(type, strike), discount_(discount) { QL_REQUIRE(strike>=0.0, "strike less than zero not allowed"); } inline Real EuropeanHestonPathPricer::operator()( const MultiPath& multiPath) const { const Path& path = multiPath[0]; const Size n = multiPath.pathSize(); QL_REQUIRE(n>0, "the path cannot be empty"); return payoff_(path.back()) * discount_; } } #endif