1 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 3 /* 4 Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl 5 Copyright (C) 2003 Ferdinando Ametrano 6 Copyright (C) 2007, 2008 StatPro Italia srl 7 8 This file is part of QuantLib, a free-software/open-source library 9 for financial quantitative analysts and developers - http://quantlib.org/ 10 11 QuantLib is free software: you can redistribute it and/or modify it 12 under the terms of the QuantLib license. You should have received a 13 copy of the license along with this program; if not, please email 14 <quantlib-dev@lists.sf.net>. The license is also available online at 15 <http://quantlib.org/license.shtml>. 16 17 This program is distributed in the hope that it will be useful, but WITHOUT 18 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 19 FOR A PARTICULAR PURPOSE. See the license for more details. 20 */ 21 22 /*! \file mceuropeanengine.hpp 23 \brief Monte Carlo European option engine 24 */ 25 26 #ifndef quantlib_montecarlo_european_engine_hpp 27 #define quantlib_montecarlo_european_engine_hpp 28 29 #include <ql/pricingengines/vanilla/mcvanillaengine.hpp> 30 #include <ql/processes/blackscholesprocess.hpp> 31 #include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp> 32 #include <ql/termstructures/volatility/equityfx/blackvariancecurve.hpp> 33 34 namespace QuantLib { 35 36 //! European option pricing engine using Monte Carlo simulation 37 /*! \ingroup vanillaengines 38 39 \test the correctness of the returned value is tested by 40 checking it against analytic results. 41 */ 42 template <class RNG = PseudoRandom, class S = Statistics> 43 class MCEuropeanEngine : public MCVanillaEngine<SingleVariate,RNG,S> { 44 public: 45 typedef 46 typename MCVanillaEngine<SingleVariate,RNG,S>::path_generator_type 47 path_generator_type; 48 typedef 49 typename MCVanillaEngine<SingleVariate,RNG,S>::path_pricer_type 50 path_pricer_type; 51 typedef typename MCVanillaEngine<SingleVariate,RNG,S>::stats_type 52 stats_type; 53 // constructor 54 MCEuropeanEngine( 55 const ext::shared_ptr<GeneralizedBlackScholesProcess>& process, 56 Size timeSteps, 57 Size timeStepsPerYear, 58 bool brownianBridge, 59 bool antitheticVariate, 60 Size requiredSamples, 61 Real requiredTolerance, 62 Size maxSamples, 63 BigNatural seed); 64 protected: 65 ext::shared_ptr<path_pricer_type> pathPricer() const; 66 }; 67 68 //! Monte Carlo European engine factory 69 template <class RNG = PseudoRandom, class S = Statistics> 70 class MakeMCEuropeanEngine { 71 public: 72 MakeMCEuropeanEngine( 73 const ext::shared_ptr<GeneralizedBlackScholesProcess>&); 74 // named parameters 75 MakeMCEuropeanEngine& withSteps(Size steps); 76 MakeMCEuropeanEngine& withStepsPerYear(Size steps); 77 MakeMCEuropeanEngine& withBrownianBridge(bool b = true); 78 MakeMCEuropeanEngine& withSamples(Size samples); 79 MakeMCEuropeanEngine& withAbsoluteTolerance(Real tolerance); 80 MakeMCEuropeanEngine& withMaxSamples(Size samples); 81 MakeMCEuropeanEngine& withSeed(BigNatural seed); 82 MakeMCEuropeanEngine& withAntitheticVariate(bool b = true); 83 // conversion to pricing engine 84 operator ext::shared_ptr<PricingEngine>() const; 85 private: 86 ext::shared_ptr<GeneralizedBlackScholesProcess> process_; 87 bool antithetic_; 88 Size steps_, stepsPerYear_, samples_, maxSamples_; 89 Real tolerance_; 90 bool brownianBridge_; 91 BigNatural seed_; 92 }; 93 94 class EuropeanPathPricer : public PathPricer<Path> { 95 public: 96 EuropeanPathPricer(Option::Type type, 97 Real strike, 98 DiscountFactor discount); 99 Real operator()(const Path& path) const; 100 private: 101 PlainVanillaPayoff payoff_; 102 DiscountFactor discount_; 103 }; 104 105 106 // inline definitions 107 108 template <class RNG, class S> 109 inline MCEuropeanEngine(const ext::shared_ptr<GeneralizedBlackScholesProcess> & process,Size timeSteps,Size timeStepsPerYear,bool brownianBridge,bool antitheticVariate,Size requiredSamples,Real requiredTolerance,Size maxSamples,BigNatural seed)110 MCEuropeanEngine<RNG,S>::MCEuropeanEngine( 111 const ext::shared_ptr<GeneralizedBlackScholesProcess>& process, 112 Size timeSteps, 113 Size timeStepsPerYear, 114 bool brownianBridge, 115 bool antitheticVariate, 116 Size requiredSamples, 117 Real requiredTolerance, 118 Size maxSamples, 119 BigNatural seed) 120 : MCVanillaEngine<SingleVariate,RNG,S>(process, 121 timeSteps, 122 timeStepsPerYear, 123 brownianBridge, 124 antitheticVariate, 125 false, 126 requiredSamples, 127 requiredTolerance, 128 maxSamples, 129 seed) {} 130 131 132 template <class RNG, class S> 133 inline 134 ext::shared_ptr<typename MCEuropeanEngine<RNG,S>::path_pricer_type> pathPricer() const135 MCEuropeanEngine<RNG,S>::pathPricer() const { 136 137 ext::shared_ptr<PlainVanillaPayoff> payoff = 138 ext::dynamic_pointer_cast<PlainVanillaPayoff>( 139 this->arguments_.payoff); 140 QL_REQUIRE(payoff, "non-plain payoff given"); 141 142 ext::shared_ptr<GeneralizedBlackScholesProcess> process = 143 ext::dynamic_pointer_cast<GeneralizedBlackScholesProcess>( 144 this->process_); 145 QL_REQUIRE(process, "Black-Scholes process required"); 146 147 return ext::shared_ptr< 148 typename MCEuropeanEngine<RNG,S>::path_pricer_type>( 149 new EuropeanPathPricer( 150 payoff->optionType(), 151 payoff->strike(), 152 process->riskFreeRate()->discount(this->timeGrid().back()))); 153 } 154 155 156 template <class RNG, class S> MakeMCEuropeanEngine(const ext::shared_ptr<GeneralizedBlackScholesProcess> & process)157 inline MakeMCEuropeanEngine<RNG,S>::MakeMCEuropeanEngine( 158 const ext::shared_ptr<GeneralizedBlackScholesProcess>& process) 159 : process_(process), antithetic_(false), 160 steps_(Null<Size>()), stepsPerYear_(Null<Size>()), 161 samples_(Null<Size>()), maxSamples_(Null<Size>()), 162 tolerance_(Null<Real>()), brownianBridge_(false), seed_(0) {} 163 164 template <class RNG, class S> 165 inline MakeMCEuropeanEngine<RNG,S>& withSteps(Size steps)166 MakeMCEuropeanEngine<RNG,S>::withSteps(Size steps) { 167 steps_ = steps; 168 return *this; 169 } 170 171 template <class RNG, class S> 172 inline MakeMCEuropeanEngine<RNG,S>& withStepsPerYear(Size steps)173 MakeMCEuropeanEngine<RNG,S>::withStepsPerYear(Size steps) { 174 stepsPerYear_ = steps; 175 return *this; 176 } 177 178 template <class RNG, class S> 179 inline MakeMCEuropeanEngine<RNG,S>& withSamples(Size samples)180 MakeMCEuropeanEngine<RNG,S>::withSamples(Size samples) { 181 QL_REQUIRE(tolerance_ == Null<Real>(), 182 "tolerance already set"); 183 samples_ = samples; 184 return *this; 185 } 186 187 template <class RNG, class S> 188 inline MakeMCEuropeanEngine<RNG,S>& withAbsoluteTolerance(Real tolerance)189 MakeMCEuropeanEngine<RNG,S>::withAbsoluteTolerance(Real tolerance) { 190 QL_REQUIRE(samples_ == Null<Size>(), 191 "number of samples already set"); 192 QL_REQUIRE(RNG::allowsErrorEstimate, 193 "chosen random generator policy " 194 "does not allow an error estimate"); 195 tolerance_ = tolerance; 196 return *this; 197 } 198 199 template <class RNG, class S> 200 inline MakeMCEuropeanEngine<RNG,S>& withMaxSamples(Size samples)201 MakeMCEuropeanEngine<RNG,S>::withMaxSamples(Size samples) { 202 maxSamples_ = samples; 203 return *this; 204 } 205 206 template <class RNG, class S> 207 inline MakeMCEuropeanEngine<RNG,S>& withSeed(BigNatural seed)208 MakeMCEuropeanEngine<RNG,S>::withSeed(BigNatural seed) { 209 seed_ = seed; 210 return *this; 211 } 212 213 template <class RNG, class S> 214 inline MakeMCEuropeanEngine<RNG,S>& withBrownianBridge(bool brownianBridge)215 MakeMCEuropeanEngine<RNG,S>::withBrownianBridge(bool brownianBridge) { 216 brownianBridge_ = brownianBridge; 217 return *this; 218 } 219 220 template <class RNG, class S> 221 inline MakeMCEuropeanEngine<RNG,S>& withAntitheticVariate(bool b)222 MakeMCEuropeanEngine<RNG,S>::withAntitheticVariate(bool b) { 223 antithetic_ = b; 224 return *this; 225 } 226 227 template <class RNG, class S> 228 inline operator ext::shared_ptr<PricingEngine>() const229 MakeMCEuropeanEngine<RNG,S>::operator ext::shared_ptr<PricingEngine>() 230 const { 231 QL_REQUIRE(steps_ != Null<Size>() || stepsPerYear_ != Null<Size>(), 232 "number of steps not given"); 233 QL_REQUIRE(steps_ == Null<Size>() || stepsPerYear_ == Null<Size>(), 234 "number of steps overspecified"); 235 return ext::shared_ptr<PricingEngine>(new 236 MCEuropeanEngine<RNG,S>(process_, 237 steps_, 238 stepsPerYear_, 239 brownianBridge_, 240 antithetic_, 241 samples_, tolerance_, 242 maxSamples_, 243 seed_)); 244 } 245 246 247 EuropeanPathPricer(Option::Type type,Real strike,DiscountFactor discount)248 inline EuropeanPathPricer::EuropeanPathPricer(Option::Type type, 249 Real strike, 250 DiscountFactor discount) 251 : payoff_(type, strike), discount_(discount) { 252 QL_REQUIRE(strike>=0.0, 253 "strike less than zero not allowed"); 254 } 255 operator ()(const Path & path) const256 inline Real EuropeanPathPricer::operator()(const Path& path) const { 257 QL_REQUIRE(path.length() > 0, "the path cannot be empty"); 258 return payoff_(path.back()) * discount_; 259 } 260 261 } 262 263 264 #endif 265