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