/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* Copyright (C) 2003 Ferdinando Ametrano Copyright (C) 2000, 2001, 2002, 2003 RiskMap 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 mceuropeanengine.hpp \brief Monte Carlo European option engine */ #ifndef quantlib_montecarlo_european_engine_hpp #define quantlib_montecarlo_european_engine_hpp #include #include #include #include namespace QuantLib { //! European option pricing engine using Monte Carlo simulation /*! \ingroup vanillaengines \test the correctness of the returned value is tested by checking it against analytic results. */ template class MCEuropeanEngine : public MCVanillaEngine { public: typedef typename MCVanillaEngine::path_generator_type path_generator_type; typedef typename MCVanillaEngine::path_pricer_type path_pricer_type; typedef typename MCVanillaEngine::stats_type stats_type; // constructor MCEuropeanEngine(Size timeSteps, Size timeStepsPerYear, bool brownianBridge, bool antitheticVariate, bool controlVariate, Size requiredSamples, Real requiredTolerance, Size maxSamples, BigNatural seed); protected: boost::shared_ptr pathPricer() const; }; //! Monte Carlo European engine factory template class MakeMCEuropeanEngine { public: MakeMCEuropeanEngine(); // named parameters MakeMCEuropeanEngine& withSteps(Size steps); MakeMCEuropeanEngine& withStepsPerYear(Size steps); MakeMCEuropeanEngine& withBrownianBridge(bool b = true); MakeMCEuropeanEngine& withSamples(Size samples); MakeMCEuropeanEngine& withTolerance(Real tolerance); MakeMCEuropeanEngine& withMaxSamples(Size samples); MakeMCEuropeanEngine& withSeed(BigNatural seed); MakeMCEuropeanEngine& withAntitheticVariate(bool b = true); MakeMCEuropeanEngine& withControlVariate(bool b = true); // conversion to pricing engine operator boost::shared_ptr() const; private: bool antithetic_, controlVariate_; Size steps_, stepsPerYear_, samples_, maxSamples_; Real tolerance_; bool brownianBridge_; BigNatural seed_; }; class EuropeanPathPricer : public PathPricer { public: EuropeanPathPricer(Option::Type type, Real strike, DiscountFactor discount); Real operator()(const Path& path) const; private: PlainVanillaPayoff payoff_; DiscountFactor discount_; }; // inline definitions template inline MCEuropeanEngine::MCEuropeanEngine(Size timeSteps, Size timeStepsPerYear, bool brownianBridge, bool antitheticVariate, bool controlVariate, Size requiredSamples, Real requiredTolerance, Size maxSamples, BigNatural seed) : MCVanillaEngine(timeSteps, timeStepsPerYear, brownianBridge, antitheticVariate, controlVariate, requiredSamples, requiredTolerance, maxSamples, seed) {} template inline boost::shared_ptr::path_pricer_type> MCEuropeanEngine::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, "Black-Scholes process required"); return boost::shared_ptr< QL_TYPENAME MCEuropeanEngine::path_pricer_type>( new EuropeanPathPricer( payoff->optionType(), payoff->strike(), process->riskFreeRate()->discount(this->timeGrid().back()))); } template inline MakeMCEuropeanEngine::MakeMCEuropeanEngine() : antithetic_(false), controlVariate_(false), steps_(Null()), stepsPerYear_(Null()), samples_(Null()), maxSamples_(Null()), tolerance_(Null()), brownianBridge_(false), seed_(0) {} template inline MakeMCEuropeanEngine& MakeMCEuropeanEngine::withSteps(Size steps) { steps_ = steps; return *this; } template inline MakeMCEuropeanEngine& MakeMCEuropeanEngine::withStepsPerYear(Size steps) { stepsPerYear_ = steps; return *this; } template inline MakeMCEuropeanEngine& MakeMCEuropeanEngine::withSamples(Size samples) { QL_REQUIRE(tolerance_ == Null(), "tolerance already set"); samples_ = samples; return *this; } template inline MakeMCEuropeanEngine& MakeMCEuropeanEngine::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 MakeMCEuropeanEngine& MakeMCEuropeanEngine::withMaxSamples(Size samples) { maxSamples_ = samples; return *this; } template inline MakeMCEuropeanEngine& MakeMCEuropeanEngine::withSeed(BigNatural seed) { seed_ = seed; return *this; } template inline MakeMCEuropeanEngine& MakeMCEuropeanEngine::withBrownianBridge(bool brownianBridge) { brownianBridge_ = brownianBridge; return *this; } template inline MakeMCEuropeanEngine& MakeMCEuropeanEngine::withAntitheticVariate(bool b) { antithetic_ = b; return *this; } template inline MakeMCEuropeanEngine& MakeMCEuropeanEngine::withControlVariate(bool b) { controlVariate_ = b; return *this; } template inline MakeMCEuropeanEngine::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 MCEuropeanEngine(steps_, stepsPerYear_, brownianBridge_, antithetic_, controlVariate_, samples_, tolerance_, maxSamples_, seed_)); } inline EuropeanPathPricer::EuropeanPathPricer(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 EuropeanPathPricer::operator()(const Path& path) const { QL_REQUIRE(path.length() > 0, "the path cannot be empty"); return payoff_(path.back()) * discount_; } } #endif