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