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