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 mcpagodaengine.hpp 21 \brief Monte Carlo engine for pagoda options 22 */ 23 24 #ifndef quantlib_mc_pagoda_engine_hpp 25 #define quantlib_mc_pagoda_engine_hpp 26 27 #include <ql/experimental/exoticoptions/pagodaoption.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 //! Pricing engine for pagoda options using Monte Carlo simulation 36 template <class RNG = PseudoRandom, class S = Statistics> 37 class MCPagodaEngine : public PagodaOption::engine, 38 public McSimulation<MultiVariate,RNG,S> { 39 public: 40 typedef typename McSimulation<MultiVariate,RNG,S>::path_generator_type 41 path_generator_type; 42 typedef typename McSimulation<MultiVariate,RNG,S>::path_pricer_type 43 path_pricer_type; 44 typedef typename McSimulation<MultiVariate,RNG,S>::stats_type 45 stats_type; 46 // constructor 47 MCPagodaEngine(const ext::shared_ptr<StochasticProcessArray>&, 48 bool brownianBridge, 49 bool antitheticVariate, 50 Size requiredSamples, 51 Real requiredTolerance, 52 Size maxSamples, 53 BigNatural seed); calculate() const54 void calculate() const { 55 McSimulation<MultiVariate,RNG,S>::calculate(requiredTolerance_, 56 requiredSamples_, 57 maxSamples_); 58 results_.value = this->mcModel_->sampleAccumulator().mean(); 59 if (RNG::allowsErrorEstimate) 60 results_.errorEstimate = 61 this->mcModel_->sampleAccumulator().errorEstimate(); 62 } 63 private: 64 // McSimulation implementation 65 TimeGrid timeGrid() const; pathGenerator() const66 ext::shared_ptr<path_generator_type> pathGenerator() const { 67 68 Size numAssets = processes_->size(); 69 70 TimeGrid grid = timeGrid(); 71 typename RNG::rsg_type gen = 72 RNG::make_sequence_generator(numAssets*(grid.size()-1),seed_); 73 74 return ext::shared_ptr<path_generator_type>( 75 new path_generator_type(processes_, 76 grid, gen, brownianBridge_)); 77 } 78 ext::shared_ptr<path_pricer_type> pathPricer() const; 79 80 // data members 81 ext::shared_ptr<StochasticProcessArray> processes_; 82 Size requiredSamples_; 83 Size maxSamples_; 84 Real requiredTolerance_; 85 bool brownianBridge_; 86 BigNatural seed_; 87 }; 88 89 90 //! Monte Carlo pagoda-option engine factory 91 template <class RNG = PseudoRandom, class S = Statistics> 92 class MakeMCPagodaEngine { 93 public: 94 explicit MakeMCPagodaEngine( 95 const ext::shared_ptr<StochasticProcessArray>&); 96 // named parameters 97 MakeMCPagodaEngine& withBrownianBridge(bool b = true); 98 MakeMCPagodaEngine& withAntitheticVariate(bool b = true); 99 MakeMCPagodaEngine& withSamples(Size samples); 100 MakeMCPagodaEngine& withAbsoluteTolerance(Real tolerance); 101 MakeMCPagodaEngine& withMaxSamples(Size samples); 102 MakeMCPagodaEngine& withSeed(BigNatural seed); 103 // conversion to pricing engine 104 operator ext::shared_ptr<PricingEngine>() const; 105 private: 106 ext::shared_ptr<StochasticProcessArray> process_; 107 bool brownianBridge_, antithetic_; 108 Size samples_, maxSamples_; 109 Real tolerance_; 110 BigNatural seed_; 111 }; 112 113 114 class PagodaMultiPathPricer : public PathPricer<MultiPath> { 115 public: 116 PagodaMultiPathPricer(Real roof, Real fraction, 117 DiscountFactor discount); 118 Real operator()(const MultiPath& multiPath) const; 119 private: 120 DiscountFactor discount_; 121 Real roof_, fraction_; 122 }; 123 124 125 // template definitions 126 127 template<class RNG, class S> MCPagodaEngine(const ext::shared_ptr<StochasticProcessArray> & processes,bool brownianBridge,bool antitheticVariate,Size requiredSamples,Real requiredTolerance,Size maxSamples,BigNatural seed)128 inline MCPagodaEngine<RNG,S>::MCPagodaEngine( 129 const ext::shared_ptr<StochasticProcessArray>& processes, 130 bool brownianBridge, 131 bool antitheticVariate, 132 Size requiredSamples, 133 Real requiredTolerance, 134 Size maxSamples, 135 BigNatural seed) 136 : McSimulation<MultiVariate,RNG,S>(antitheticVariate, false), 137 processes_(processes), requiredSamples_(requiredSamples), 138 maxSamples_(maxSamples), requiredTolerance_(requiredTolerance), 139 brownianBridge_(brownianBridge), seed_(seed) { 140 registerWith(processes_); 141 } 142 143 template <class RNG, class S> timeGrid() const144 inline TimeGrid MCPagodaEngine<RNG,S>::timeGrid() const { 145 146 std::vector<Time> fixingTimes; 147 for (Size i=0; i<arguments_.fixingDates.size(); i++) { 148 Time t = processes_->time(arguments_.fixingDates[i]); 149 QL_REQUIRE(t >= 0.0, "seasoned options are not handled"); 150 if (i > 0) { 151 QL_REQUIRE(t > fixingTimes.back(), "fixing dates not sorted"); 152 } 153 fixingTimes.push_back(t); 154 } 155 156 return TimeGrid(fixingTimes.begin(), fixingTimes.end()); 157 } 158 159 160 template <class RNG, class S> 161 inline 162 ext::shared_ptr<typename MCPagodaEngine<RNG,S>::path_pricer_type> pathPricer() const163 MCPagodaEngine<RNG,S>::pathPricer() const { 164 165 ext::shared_ptr<GeneralizedBlackScholesProcess> process = 166 ext::dynamic_pointer_cast<GeneralizedBlackScholesProcess>( 167 processes_->process(0)); 168 QL_REQUIRE(process, "Black-Scholes process required"); 169 170 return ext::shared_ptr< 171 typename MCPagodaEngine<RNG,S>::path_pricer_type>( 172 new PagodaMultiPathPricer(arguments_.roof, arguments_.fraction, 173 process->riskFreeRate()->discount( 174 arguments_.exercise->lastDate()))); 175 } 176 177 178 template <class RNG, class S> MakeMCPagodaEngine(const ext::shared_ptr<StochasticProcessArray> & process)179 inline MakeMCPagodaEngine<RNG,S>::MakeMCPagodaEngine( 180 const ext::shared_ptr<StochasticProcessArray>& process) 181 : process_(process), brownianBridge_(false), antithetic_(false), 182 samples_(Null<Size>()), maxSamples_(Null<Size>()), 183 tolerance_(Null<Real>()), seed_(0) {} 184 185 template <class RNG, class S> 186 inline MakeMCPagodaEngine<RNG,S>& withBrownianBridge(bool brownianBridge)187 MakeMCPagodaEngine<RNG,S>::withBrownianBridge(bool brownianBridge) { 188 brownianBridge_ = brownianBridge; 189 return *this; 190 } 191 192 template <class RNG, class S> 193 inline MakeMCPagodaEngine<RNG,S>& withAntitheticVariate(bool b)194 MakeMCPagodaEngine<RNG,S>::withAntitheticVariate(bool b) { 195 antithetic_ = b; 196 return *this; 197 } 198 199 template <class RNG, class S> 200 inline MakeMCPagodaEngine<RNG,S>& withSamples(Size samples)201 MakeMCPagodaEngine<RNG,S>::withSamples(Size samples) { 202 QL_REQUIRE(tolerance_ == Null<Real>(), 203 "tolerance already set"); 204 samples_ = samples; 205 return *this; 206 } 207 208 template <class RNG, class S> 209 inline MakeMCPagodaEngine<RNG,S>& withAbsoluteTolerance(Real tolerance)210 MakeMCPagodaEngine<RNG,S>::withAbsoluteTolerance(Real tolerance) { 211 QL_REQUIRE(samples_ == Null<Size>(), 212 "number of samples already set"); 213 QL_REQUIRE(RNG::allowsErrorEstimate, 214 "chosen random generator policy " 215 "does not allow an error estimate"); 216 tolerance_ = tolerance; 217 return *this; 218 } 219 220 template <class RNG, class S> 221 inline MakeMCPagodaEngine<RNG,S>& withMaxSamples(Size samples)222 MakeMCPagodaEngine<RNG,S>::withMaxSamples(Size samples) { 223 maxSamples_ = samples; 224 return *this; 225 } 226 227 template <class RNG, class S> 228 inline MakeMCPagodaEngine<RNG,S>& withSeed(BigNatural seed)229 MakeMCPagodaEngine<RNG,S>::withSeed(BigNatural seed) { 230 seed_ = seed; 231 return *this; 232 } 233 234 template <class RNG, class S> 235 inline operator ext::shared_ptr<PricingEngine>() const236 MakeMCPagodaEngine<RNG,S>::operator 237 ext::shared_ptr<PricingEngine>() const { 238 return ext::shared_ptr<PricingEngine>(new 239 MCPagodaEngine<RNG,S>(process_, 240 brownianBridge_, 241 antithetic_, 242 samples_, tolerance_, 243 maxSamples_, 244 seed_)); 245 } 246 247 } 248 249 250 251 #endif 252