/src/quantlib/ql/pricingengines/vanilla/mceuropeanengine.hpp
Line | Count | Source |
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 | | <https://www.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 override; |
66 | | }; |
67 | | |
68 | | //! Monte Carlo European engine factory |
69 | | template <class RNG = PseudoRandom, class S = Statistics> |
70 | | class MakeMCEuropeanEngine { |
71 | | public: |
72 | | MakeMCEuropeanEngine(ext::shared_ptr<GeneralizedBlackScholesProcess>); |
73 | | // named parameters |
74 | | MakeMCEuropeanEngine& withSteps(Size steps); |
75 | | MakeMCEuropeanEngine& withStepsPerYear(Size steps); |
76 | | MakeMCEuropeanEngine& withBrownianBridge(bool b = true); |
77 | | MakeMCEuropeanEngine& withSamples(Size samples); |
78 | | MakeMCEuropeanEngine& withAbsoluteTolerance(Real tolerance); |
79 | | MakeMCEuropeanEngine& withMaxSamples(Size samples); |
80 | | MakeMCEuropeanEngine& withSeed(BigNatural seed); |
81 | | MakeMCEuropeanEngine& withAntitheticVariate(bool b = true); |
82 | | // conversion to pricing engine |
83 | | operator ext::shared_ptr<PricingEngine>() const; |
84 | | private: |
85 | | ext::shared_ptr<GeneralizedBlackScholesProcess> process_; |
86 | | bool antithetic_ = false; |
87 | | Size steps_, stepsPerYear_, samples_, maxSamples_; |
88 | | Real tolerance_; |
89 | | bool brownianBridge_ = false; |
90 | | BigNatural seed_ = 0; |
91 | | }; |
92 | | |
93 | | class EuropeanPathPricer : public PathPricer<Path> { |
94 | | public: |
95 | | EuropeanPathPricer(Option::Type type, |
96 | | Real strike, |
97 | | DiscountFactor discount); |
98 | | Real operator()(const Path& path) const override; |
99 | | |
100 | | private: |
101 | | PlainVanillaPayoff payoff_; |
102 | | DiscountFactor discount_; |
103 | | }; |
104 | | |
105 | | |
106 | | // inline definitions |
107 | | |
108 | | template <class RNG, class S> |
109 | | inline |
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> |
135 | | 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> |
157 | | inline MakeMCEuropeanEngine<RNG, S>::MakeMCEuropeanEngine( |
158 | | ext::shared_ptr<GeneralizedBlackScholesProcess> process) |
159 | | : process_(std::move(process)), steps_(Null<Size>()), stepsPerYear_(Null<Size>()), |
160 | | samples_(Null<Size>()), maxSamples_(Null<Size>()), tolerance_(Null<Real>()) {} |
161 | | |
162 | | template <class RNG, class S> |
163 | | inline MakeMCEuropeanEngine<RNG,S>& |
164 | | MakeMCEuropeanEngine<RNG,S>::withSteps(Size steps) { |
165 | | steps_ = steps; |
166 | | return *this; |
167 | | } |
168 | | |
169 | | template <class RNG, class S> |
170 | | inline MakeMCEuropeanEngine<RNG,S>& |
171 | | MakeMCEuropeanEngine<RNG,S>::withStepsPerYear(Size steps) { |
172 | | stepsPerYear_ = steps; |
173 | | return *this; |
174 | | } |
175 | | |
176 | | template <class RNG, class S> |
177 | | inline MakeMCEuropeanEngine<RNG,S>& |
178 | | MakeMCEuropeanEngine<RNG,S>::withSamples(Size samples) { |
179 | | QL_REQUIRE(tolerance_ == Null<Real>(), |
180 | | "tolerance already set"); |
181 | | samples_ = samples; |
182 | | return *this; |
183 | | } |
184 | | |
185 | | template <class RNG, class S> |
186 | | inline MakeMCEuropeanEngine<RNG,S>& |
187 | | MakeMCEuropeanEngine<RNG,S>::withAbsoluteTolerance(Real tolerance) { |
188 | | QL_REQUIRE(samples_ == Null<Size>(), |
189 | | "number of samples already set"); |
190 | | QL_REQUIRE(RNG::allowsErrorEstimate, |
191 | | "chosen random generator policy " |
192 | | "does not allow an error estimate"); |
193 | | tolerance_ = tolerance; |
194 | | return *this; |
195 | | } |
196 | | |
197 | | template <class RNG, class S> |
198 | | inline MakeMCEuropeanEngine<RNG,S>& |
199 | | MakeMCEuropeanEngine<RNG,S>::withMaxSamples(Size samples) { |
200 | | maxSamples_ = samples; |
201 | | return *this; |
202 | | } |
203 | | |
204 | | template <class RNG, class S> |
205 | | inline MakeMCEuropeanEngine<RNG,S>& |
206 | | MakeMCEuropeanEngine<RNG,S>::withSeed(BigNatural seed) { |
207 | | seed_ = seed; |
208 | | return *this; |
209 | | } |
210 | | |
211 | | template <class RNG, class S> |
212 | | inline MakeMCEuropeanEngine<RNG,S>& |
213 | | MakeMCEuropeanEngine<RNG,S>::withBrownianBridge(bool brownianBridge) { |
214 | | brownianBridge_ = brownianBridge; |
215 | | return *this; |
216 | | } |
217 | | |
218 | | template <class RNG, class S> |
219 | | inline MakeMCEuropeanEngine<RNG,S>& |
220 | | MakeMCEuropeanEngine<RNG,S>::withAntitheticVariate(bool b) { |
221 | | antithetic_ = b; |
222 | | return *this; |
223 | | } |
224 | | |
225 | | template <class RNG, class S> |
226 | | inline |
227 | | MakeMCEuropeanEngine<RNG,S>::operator ext::shared_ptr<PricingEngine>() |
228 | | const { |
229 | | QL_REQUIRE(steps_ != Null<Size>() || stepsPerYear_ != Null<Size>(), |
230 | | "number of steps not given"); |
231 | | QL_REQUIRE(steps_ == Null<Size>() || stepsPerYear_ == Null<Size>(), |
232 | | "number of steps overspecified"); |
233 | | return ext::shared_ptr<PricingEngine>(new |
234 | | MCEuropeanEngine<RNG,S>(process_, |
235 | | steps_, |
236 | | stepsPerYear_, |
237 | | brownianBridge_, |
238 | | antithetic_, |
239 | | samples_, tolerance_, |
240 | | maxSamples_, |
241 | | seed_)); |
242 | | } |
243 | | |
244 | | |
245 | | |
246 | | inline EuropeanPathPricer::EuropeanPathPricer(Option::Type type, |
247 | | Real strike, |
248 | | DiscountFactor discount) |
249 | | : payoff_(type, strike), discount_(discount) { |
250 | | QL_REQUIRE(strike>=0.0, |
251 | | "strike less than zero not allowed"); |
252 | | } |
253 | | |
254 | 0 | inline Real EuropeanPathPricer::operator()(const Path& path) const { |
255 | 0 | QL_REQUIRE(!path.empty(), "the path cannot be empty"); |
256 | 0 | return payoff_(path.back()) * discount_; |
257 | 0 | } |
258 | | |
259 | | } |
260 | | |
261 | | |
262 | | #endif |