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/exercise.hpp>
28#include <ql/experimental/exoticoptions/everestoption.hpp>
29#include <ql/pricingengines/mcsimulation.hpp>
30#include <ql/processes/blackscholesprocess.hpp>
31#include <ql/processes/stochasticprocessarray.hpp>
32#include <utility>
33
34namespace QuantLib {
35
36 template <class RNG = PseudoRandom, class S = Statistics>
37 class MCEverestEngine : public EverestOption::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 MCEverestEngine(ext::shared_ptr<StochasticProcessArray>,
47 Size timeSteps,
48 Size timeStepsPerYear,
49 bool brownianBridge,
50 bool antitheticVariate,
51 Size requiredSamples,
52 Real requiredTolerance,
53 Size maxSamples,
54 BigNatural seed);
55 void calculate() const override {
56
57 McSimulation<MultiVariate,RNG,S>::calculate(requiredTolerance_,
58 requiredSamples_,
59 maxSamples_);
60 results_.value = this->mcModel_->sampleAccumulator().mean();
61
62 if (RNG::allowsErrorEstimate) {
63 results_.errorEstimate =
64 this->mcModel_->sampleAccumulator().errorEstimate();
65 }
66
67 Real notional = arguments_.notional;
68 DiscountFactor discount = endDiscount();
69 results_.yield = results_.value/(notional * discount) - 1.0;
70 }
71
72 private:
73 DiscountFactor endDiscount() const;
74 // McEverest implementation
75 TimeGrid timeGrid() const override;
76 ext::shared_ptr<path_generator_type> pathGenerator() const override {
77
78 Size numAssets = processes_->size();
79
80 TimeGrid grid = timeGrid();
81 typename RNG::rsg_type gen =
82 RNG::make_sequence_generator(numAssets*(grid.size()-1),seed_);
83
84 return ext::shared_ptr<path_generator_type>(
85 new path_generator_type(processes_,
86 grid, gen, brownianBridge_));
87 }
88 ext::shared_ptr<path_pricer_type> pathPricer() const override;
89
90 // data members
91 ext::shared_ptr<StochasticProcessArray> processes_;
92 Size timeSteps_, timeStepsPerYear_;
93 Size requiredSamples_;
94 Size maxSamples_;
95 Real requiredTolerance_;
96 bool brownianBridge_;
97 BigNatural seed_;
98 };
99
100
101 //! Monte Carlo Everest-option engine factory
102 template <class RNG = PseudoRandom, class S = Statistics>
103 class MakeMCEverestEngine {
104 public:
105 explicit MakeMCEverestEngine(ext::shared_ptr<StochasticProcessArray>);
106 // named parameters
107 MakeMCEverestEngine& withSteps(Size steps);
108 MakeMCEverestEngine& withStepsPerYear(Size steps);
109 MakeMCEverestEngine& withBrownianBridge(bool b = true);
110 MakeMCEverestEngine& withAntitheticVariate(bool b = true);
111 MakeMCEverestEngine& withSamples(Size samples);
112 MakeMCEverestEngine& withAbsoluteTolerance(Real tolerance);
113 MakeMCEverestEngine& withMaxSamples(Size samples);
114 MakeMCEverestEngine& withSeed(BigNatural seed);
115 // conversion to pricing engine
116 operator ext::shared_ptr<PricingEngine>() const;
117 private:
118 ext::shared_ptr<StochasticProcessArray> process_;
119 bool brownianBridge_ = false, antithetic_ = false;
120 Size steps_, stepsPerYear_, samples_, maxSamples_;
121 Real tolerance_;
122 BigNatural seed_ = 0;
123 };
124
125
126 class EverestMultiPathPricer : public PathPricer<MultiPath> {
127 public:
128 explicit EverestMultiPathPricer(Real notional,
129 Rate guarantee,
130 DiscountFactor discount);
131 Real operator()(const MultiPath& multiPath) const override;
132
133 private:
134 Real notional_;
135 Rate guarantee_;
136 DiscountFactor discount_;
137 };
138
139
140 // template definitions
141
142 template <class RNG, class S>
143 inline MCEverestEngine<RNG, S>::MCEverestEngine(
144 ext::shared_ptr<StochasticProcessArray> processes,
145 Size timeSteps,
146 Size timeStepsPerYear,
147 bool brownianBridge,
148 bool antitheticVariate,
149 Size requiredSamples,
150 Real requiredTolerance,
151 Size maxSamples,
152 BigNatural seed)
153 : McSimulation<MultiVariate, RNG, S>(antitheticVariate, false),
154 processes_(std::move(processes)), timeSteps_(timeSteps), timeStepsPerYear_(timeStepsPerYear),
155 requiredSamples_(requiredSamples), maxSamples_(maxSamples),
156 requiredTolerance_(requiredTolerance), 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(h: processes_);
170 }
171
172 template <class RNG, class S>
173 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>(a: steps, b: 1));
181 } else {
182 QL_FAIL("time steps not specified");
183 }
184 }
185
186 template <class RNG, class S>
187 inline DiscountFactor MCEverestEngine<RNG,S>::endDiscount() const {
188 ext::shared_ptr<GeneralizedBlackScholesProcess> process =
189 ext::dynamic_pointer_cast<GeneralizedBlackScholesProcess>(
190 r: processes_->process(i: 0));
191 QL_REQUIRE(process, "Black-Scholes process required");
192
193 return process->riskFreeRate()->discount(
194 d: arguments_.exercise->lastDate());
195 }
196
197 template <class RNG, class S>
198 inline ext::shared_ptr<typename MCEverestEngine<RNG,S>::path_pricer_type>
199 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>
210 inline MakeMCEverestEngine<RNG, S>::MakeMCEverestEngine(
211 ext::shared_ptr<StochasticProcessArray> process)
212 : process_(std::move(process)), steps_(Null<Size>()), stepsPerYear_(Null<Size>()),
213 samples_(Null<Size>()), maxSamples_(Null<Size>()), tolerance_(Null<Real>()) {}
214
215 template <class RNG, class S>
216 inline MakeMCEverestEngine<RNG,S>&
217 MakeMCEverestEngine<RNG,S>::withSteps(Size steps) {
218 steps_ = steps;
219 return *this;
220 }
221
222 template <class RNG, class S>
223 inline MakeMCEverestEngine<RNG,S>&
224 MakeMCEverestEngine<RNG,S>::withStepsPerYear(Size steps) {
225 stepsPerYear_ = steps;
226 return *this;
227 }
228
229 template <class RNG, class S>
230 inline MakeMCEverestEngine<RNG,S>&
231 MakeMCEverestEngine<RNG,S>::withBrownianBridge(bool brownianBridge) {
232 brownianBridge_ = brownianBridge;
233 return *this;
234 }
235
236 template <class RNG, class S>
237 inline MakeMCEverestEngine<RNG,S>&
238 MakeMCEverestEngine<RNG,S>::withAntitheticVariate(bool b) {
239 antithetic_ = b;
240 return *this;
241 }
242
243 template <class RNG, class S>
244 inline MakeMCEverestEngine<RNG,S>&
245 MakeMCEverestEngine<RNG,S>::withSamples(Size samples) {
246 QL_REQUIRE(tolerance_ == Null<Real>(),
247 "tolerance already set");
248 samples_ = samples;
249 return *this;
250 }
251
252 template <class RNG, class S>
253 inline MakeMCEverestEngine<RNG,S>&
254 MakeMCEverestEngine<RNG,S>::withAbsoluteTolerance(Real tolerance) {
255 QL_REQUIRE(samples_ == Null<Size>(),
256 "number of samples already set");
257 QL_REQUIRE(RNG::allowsErrorEstimate,
258 "chosen random generator policy "
259 "does not allow an error estimate");
260 tolerance_ = tolerance;
261 return *this;
262 }
263
264 template <class RNG, class S>
265 inline MakeMCEverestEngine<RNG,S>&
266 MakeMCEverestEngine<RNG,S>::withMaxSamples(Size samples) {
267 maxSamples_ = samples;
268 return *this;
269 }
270
271 template <class RNG, class S>
272 inline MakeMCEverestEngine<RNG,S>&
273 MakeMCEverestEngine<RNG,S>::withSeed(BigNatural seed) {
274 seed_ = seed;
275 return *this;
276 }
277
278 template <class RNG, class S>
279 inline
280 MakeMCEverestEngine<RNG,S>::operator
281 ext::shared_ptr<PricingEngine>() const {
282 QL_REQUIRE(steps_ != Null<Size>() || stepsPerYear_ != Null<Size>(),
283 "number of steps not given");
284 QL_REQUIRE(steps_ == Null<Size>() || stepsPerYear_ == Null<Size>(),
285 "number of steps overspecified");
286 return ext::shared_ptr<PricingEngine>(new
287 MCEverestEngine<RNG,S>(process_,
288 steps_,
289 stepsPerYear_,
290 brownianBridge_,
291 antithetic_,
292 samples_, tolerance_,
293 maxSamples_,
294 seed_));
295 }
296
297}
298
299
300#endif
301

source code of quantlib/ql/experimental/exoticoptions/mceverestengine.hpp