1 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 3 /* 4 Copyright (C) 2008 Master IMAFA - Polytech'Nice Sophia - Université de Nice Sophia Antipolis 5 6 This file is part of QuantLib, a free-software/open-source library 7 for financial quantitative analysts and developers - http://quantlib.org/ 8 9 QuantLib is free software: you can redistribute it and/or modify it 10 under the terms of the QuantLib license. You should have received a 11 copy of the license along with this program; if not, please email 12 <quantlib-dev@lists.sf.net>. The license is also available online at 13 <http://quantlib.org/license.shtml>. 14 15 This program is distributed in the hope that it will be useful, but WITHOUT 16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 FOR A PARTICULAR PURPOSE. See the license for more details. 18 */ 19 20 /*! \file mceverestengine.hpp 21 \brief Monte Carlo engine for Everest options 22 */ 23 24 #ifndef quantlib_mc_everest_engine_hpp 25 #define quantlib_mc_everest_engine_hpp 26 27 #include <ql/experimental/exoticoptions/everestoption.hpp> 28 #include <ql/pricingengines/mcsimulation.hpp> 29 #include <ql/processes/blackscholesprocess.hpp> 30 #include <ql/processes/stochasticprocessarray.hpp> 31 #include <ql/exercise.hpp> 32 33 namespace QuantLib { 34 35 template <class RNG = PseudoRandom, class S = Statistics> 36 class MCEverestEngine : public EverestOption::engine, 37 public McSimulation<MultiVariate,RNG,S> { 38 public: 39 typedef typename McSimulation<MultiVariate,RNG,S>::path_generator_type 40 path_generator_type; 41 typedef typename McSimulation<MultiVariate,RNG,S>::path_pricer_type 42 path_pricer_type; 43 typedef typename McSimulation<MultiVariate,RNG,S>::stats_type 44 stats_type; 45 MCEverestEngine(const ext::shared_ptr<StochasticProcessArray>&, 46 Size timeSteps, 47 Size timeStepsPerYear, 48 bool brownianBridge, 49 bool antitheticVariate, 50 Size requiredSamples, 51 Real requiredTolerance, 52 Size maxSamples, 53 BigNatural seed); calculate() const54 void calculate() const { 55 56 McSimulation<MultiVariate,RNG,S>::calculate(requiredTolerance_, 57 requiredSamples_, 58 maxSamples_); 59 results_.value = this->mcModel_->sampleAccumulator().mean(); 60 61 if (RNG::allowsErrorEstimate) { 62 results_.errorEstimate = 63 this->mcModel_->sampleAccumulator().errorEstimate(); 64 } 65 66 Real notional = arguments_.notional; 67 DiscountFactor discount = endDiscount(); 68 results_.yield = results_.value/(notional * discount) - 1.0; 69 } 70 private: 71 DiscountFactor endDiscount() const; 72 // McEverest implementation 73 TimeGrid timeGrid() const; pathGenerator() const74 ext::shared_ptr<path_generator_type> pathGenerator() const { 75 76 Size numAssets = processes_->size(); 77 78 TimeGrid grid = timeGrid(); 79 typename RNG::rsg_type gen = 80 RNG::make_sequence_generator(numAssets*(grid.size()-1),seed_); 81 82 return ext::shared_ptr<path_generator_type>( 83 new path_generator_type(processes_, 84 grid, gen, brownianBridge_)); 85 } 86 ext::shared_ptr<path_pricer_type> pathPricer() const; 87 88 // data members 89 ext::shared_ptr<StochasticProcessArray> processes_; 90 Size timeSteps_, timeStepsPerYear_; 91 Size requiredSamples_; 92 Size maxSamples_; 93 Real requiredTolerance_; 94 bool brownianBridge_; 95 BigNatural seed_; 96 }; 97 98 99 //! Monte Carlo Everest-option engine factory 100 template <class RNG = PseudoRandom, class S = Statistics> 101 class MakeMCEverestEngine { 102 public: 103 explicit MakeMCEverestEngine( 104 const ext::shared_ptr<StochasticProcessArray>&); 105 // named parameters 106 MakeMCEverestEngine& withSteps(Size steps); 107 MakeMCEverestEngine& withStepsPerYear(Size steps); 108 MakeMCEverestEngine& withBrownianBridge(bool b = true); 109 MakeMCEverestEngine& withAntitheticVariate(bool b = true); 110 MakeMCEverestEngine& withSamples(Size samples); 111 MakeMCEverestEngine& withAbsoluteTolerance(Real tolerance); 112 MakeMCEverestEngine& withMaxSamples(Size samples); 113 MakeMCEverestEngine& withSeed(BigNatural seed); 114 // conversion to pricing engine 115 operator ext::shared_ptr<PricingEngine>() const; 116 private: 117 ext::shared_ptr<StochasticProcessArray> process_; 118 bool brownianBridge_, antithetic_; 119 Size steps_, stepsPerYear_, samples_, maxSamples_; 120 Real tolerance_; 121 BigNatural seed_; 122 }; 123 124 125 class EverestMultiPathPricer : public PathPricer<MultiPath> { 126 public: 127 explicit EverestMultiPathPricer(Real notional, 128 Rate guarantee, 129 DiscountFactor discount); 130 Real operator()(const MultiPath& multiPath) const; 131 private: 132 Real notional_; 133 Rate guarantee_; 134 DiscountFactor discount_; 135 }; 136 137 138 // template definitions 139 140 template<class RNG, class S> MCEverestEngine(const ext::shared_ptr<StochasticProcessArray> & processes,Size timeSteps,Size timeStepsPerYear,bool brownianBridge,bool antitheticVariate,Size requiredSamples,Real requiredTolerance,Size maxSamples,BigNatural seed)141 inline MCEverestEngine<RNG,S>::MCEverestEngine( 142 const ext::shared_ptr<StochasticProcessArray>& processes, 143 Size timeSteps, 144 Size timeStepsPerYear, 145 bool brownianBridge, 146 bool antitheticVariate, 147 Size requiredSamples, 148 Real requiredTolerance, 149 Size maxSamples, 150 BigNatural seed) 151 : McSimulation<MultiVariate,RNG,S>(antitheticVariate, false), 152 processes_(processes), timeSteps_(timeSteps), 153 timeStepsPerYear_(timeStepsPerYear), 154 requiredSamples_(requiredSamples), maxSamples_(maxSamples), 155 requiredTolerance_(requiredTolerance), 156 brownianBridge_(brownianBridge), seed_(seed) { 157 QL_REQUIRE(timeSteps != Null<Size>() || 158 timeStepsPerYear != Null<Size>(), 159 "no time steps provided"); 160 QL_REQUIRE(timeSteps == Null<Size>() || 161 timeStepsPerYear == Null<Size>(), 162 "both time steps and time steps per year were provided"); 163 QL_REQUIRE(timeSteps != 0, 164 "timeSteps must be positive, " << timeSteps << 165 " not allowed"); 166 QL_REQUIRE(timeStepsPerYear != 0, 167 "timeStepsPerYear must be positive, " << timeStepsPerYear << 168 " not allowed"); 169 registerWith(processes_); 170 } 171 172 template <class RNG, class S> timeGrid() const173 inline TimeGrid MCEverestEngine<RNG,S>::timeGrid() const { 174 Time residualTime = processes_->time( 175 this->arguments_.exercise->lastDate()); 176 if (timeSteps_ != Null<Size>()) { 177 return TimeGrid(residualTime, timeSteps_); 178 } else if (timeStepsPerYear_ != Null<Size>()) { 179 Size steps = static_cast<Size>(timeStepsPerYear_*residualTime); 180 return TimeGrid(residualTime, std::max<Size>(steps, 1)); 181 } else { 182 QL_FAIL("time steps not specified"); 183 } 184 } 185 186 template <class RNG, class S> endDiscount() const187 inline DiscountFactor MCEverestEngine<RNG,S>::endDiscount() const { 188 ext::shared_ptr<GeneralizedBlackScholesProcess> process = 189 ext::dynamic_pointer_cast<GeneralizedBlackScholesProcess>( 190 processes_->process(0)); 191 QL_REQUIRE(process, "Black-Scholes process required"); 192 193 return process->riskFreeRate()->discount( 194 arguments_.exercise->lastDate()); 195 } 196 197 template <class RNG, class S> 198 inline ext::shared_ptr<typename MCEverestEngine<RNG,S>::path_pricer_type> pathPricer() const199 MCEverestEngine<RNG,S>::pathPricer() const { 200 201 return ext::shared_ptr< 202 typename MCEverestEngine<RNG,S>::path_pricer_type>( 203 new EverestMultiPathPricer(arguments_.notional, 204 arguments_.guarantee, 205 endDiscount())); 206 } 207 208 209 template <class RNG, class S> MakeMCEverestEngine(const ext::shared_ptr<StochasticProcessArray> & process)210 inline MakeMCEverestEngine<RNG,S>::MakeMCEverestEngine( 211 const ext::shared_ptr<StochasticProcessArray>& process) 212 : process_(process), brownianBridge_(false), antithetic_(false), 213 steps_(Null<Size>()), stepsPerYear_(Null<Size>()), 214 samples_(Null<Size>()), maxSamples_(Null<Size>()), 215 tolerance_(Null<Real>()), seed_(0) {} 216 217 template <class RNG, class S> 218 inline MakeMCEverestEngine<RNG,S>& withSteps(Size steps)219 MakeMCEverestEngine<RNG,S>::withSteps(Size steps) { 220 steps_ = steps; 221 return *this; 222 } 223 224 template <class RNG, class S> 225 inline MakeMCEverestEngine<RNG,S>& withStepsPerYear(Size steps)226 MakeMCEverestEngine<RNG,S>::withStepsPerYear(Size steps) { 227 stepsPerYear_ = steps; 228 return *this; 229 } 230 231 template <class RNG, class S> 232 inline MakeMCEverestEngine<RNG,S>& withBrownianBridge(bool brownianBridge)233 MakeMCEverestEngine<RNG,S>::withBrownianBridge(bool brownianBridge) { 234 brownianBridge_ = brownianBridge; 235 return *this; 236 } 237 238 template <class RNG, class S> 239 inline MakeMCEverestEngine<RNG,S>& withAntitheticVariate(bool b)240 MakeMCEverestEngine<RNG,S>::withAntitheticVariate(bool b) { 241 antithetic_ = b; 242 return *this; 243 } 244 245 template <class RNG, class S> 246 inline MakeMCEverestEngine<RNG,S>& withSamples(Size samples)247 MakeMCEverestEngine<RNG,S>::withSamples(Size samples) { 248 QL_REQUIRE(tolerance_ == Null<Real>(), 249 "tolerance already set"); 250 samples_ = samples; 251 return *this; 252 } 253 254 template <class RNG, class S> 255 inline MakeMCEverestEngine<RNG,S>& withAbsoluteTolerance(Real tolerance)256 MakeMCEverestEngine<RNG,S>::withAbsoluteTolerance(Real tolerance) { 257 QL_REQUIRE(samples_ == Null<Size>(), 258 "number of samples already set"); 259 QL_REQUIRE(RNG::allowsErrorEstimate, 260 "chosen random generator policy " 261 "does not allow an error estimate"); 262 tolerance_ = tolerance; 263 return *this; 264 } 265 266 template <class RNG, class S> 267 inline MakeMCEverestEngine<RNG,S>& withMaxSamples(Size samples)268 MakeMCEverestEngine<RNG,S>::withMaxSamples(Size samples) { 269 maxSamples_ = samples; 270 return *this; 271 } 272 273 template <class RNG, class S> 274 inline MakeMCEverestEngine<RNG,S>& withSeed(BigNatural seed)275 MakeMCEverestEngine<RNG,S>::withSeed(BigNatural seed) { 276 seed_ = seed; 277 return *this; 278 } 279 280 template <class RNG, class S> 281 inline operator ext::shared_ptr<PricingEngine>() const282 MakeMCEverestEngine<RNG,S>::operator 283 ext::shared_ptr<PricingEngine>() const { 284 QL_REQUIRE(steps_ != Null<Size>() || stepsPerYear_ != Null<Size>(), 285 "number of steps not given"); 286 QL_REQUIRE(steps_ == Null<Size>() || stepsPerYear_ == Null<Size>(), 287 "number of steps overspecified"); 288 return ext::shared_ptr<PricingEngine>(new 289 MCEverestEngine<RNG,S>(process_, 290 steps_, 291 stepsPerYear_, 292 brownianBridge_, 293 antithetic_, 294 samples_, tolerance_, 295 maxSamples_, 296 seed_)); 297 } 298 299 } 300 301 302 #endif 303