1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2020 Lew Wei Hao
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 mclookbackengine.hpp
21 \brief Monte Carlo lookback fixed engines
22*/
23
24#ifndef quantlib_mc_lookback_engines_hpp
25#define quantlib_mc_lookback_engines_hpp
26
27#include <ql/exercise.hpp>
28#include <ql/instruments/lookbackoption.hpp>
29#include <ql/pricingengines/mcsimulation.hpp>
30#include <ql/processes/blackscholesprocess.hpp>
31#include <utility>
32
33namespace QuantLib {
34
35 //! Monte Carlo lookback-option engine
36 template <class I, class RNG = PseudoRandom, class S = Statistics>
37 class MCLookbackEngine : public I::engine,
38 public McSimulation<SingleVariate,RNG,S> {
39 public:
40 typedef typename McSimulation<SingleVariate,RNG,S>::path_generator_type
41 path_generator_type;
42 typedef typename McSimulation<SingleVariate,RNG,S>::path_pricer_type
43 path_pricer_type;
44 // constructor
45 MCLookbackEngine(ext::shared_ptr<GeneralizedBlackScholesProcess> process,
46 Size timeSteps,
47 Size timeStepsPerYear,
48 bool brownianBridge,
49 bool antithetic,
50 Size requiredSamples,
51 Real requiredTolerance,
52 Size maxSamples,
53 BigNatural seed);
54 void calculate() const override {
55 Real spot = process_->x0();
56 QL_REQUIRE(spot > 0.0, "negative or null underlying given");
57 McSimulation<SingleVariate,RNG,S>::calculate(requiredTolerance_,
58 requiredSamples_,
59 maxSamples_);
60 this->results_.value = this->mcModel_->sampleAccumulator().mean();
61 if (RNG::allowsErrorEstimate)
62 this->results_.errorEstimate =
63 this->mcModel_->sampleAccumulator().errorEstimate();
64 }
65
66 protected:
67 // McSimulation implementation
68 TimeGrid timeGrid() const override;
69 ext::shared_ptr<path_generator_type> pathGenerator() const override {
70 TimeGrid grid = timeGrid();
71 typename RNG::rsg_type gen =
72 RNG::make_sequence_generator(grid.size()-1,seed_);
73 return ext::shared_ptr<path_generator_type>(
74 new path_generator_type(process_,
75 grid, gen, brownianBridge_));
76 }
77 ext::shared_ptr<path_pricer_type> pathPricer() const override;
78 // data members
79 ext::shared_ptr<GeneralizedBlackScholesProcess> process_;
80 Size timeSteps_, timeStepsPerYear_;
81 Size requiredSamples_, maxSamples_;
82 Real requiredTolerance_;
83 bool antithetic_;
84 bool brownianBridge_;
85 BigNatural seed_;
86 };
87
88
89 //! Monte Carlo lookback-option engine factory
90 template <class I, class RNG = PseudoRandom, class S = Statistics>
91 class MakeMCLookbackEngine {
92 public:
93 explicit MakeMCLookbackEngine(ext::shared_ptr<GeneralizedBlackScholesProcess>);
94 // named parameters
95 MakeMCLookbackEngine& withSteps(Size steps);
96 MakeMCLookbackEngine& withStepsPerYear(Size steps);
97 MakeMCLookbackEngine& withBrownianBridge(bool b = true);
98 MakeMCLookbackEngine& withAntitheticVariate(bool b = true);
99 MakeMCLookbackEngine& withSamples(Size samples);
100 MakeMCLookbackEngine& withAbsoluteTolerance(Real tolerance);
101 MakeMCLookbackEngine& withMaxSamples(Size samples);
102 MakeMCLookbackEngine& withSeed(BigNatural seed);
103 // conversion to pricing engine
104 operator ext::shared_ptr<PricingEngine>() const;
105 private:
106 ext::shared_ptr<GeneralizedBlackScholesProcess> process_;
107 bool brownianBridge_ = false, antithetic_ = false;
108 Size steps_, stepsPerYear_, samples_, maxSamples_;
109 Real tolerance_;
110 BigNatural seed_ = 0;
111 };
112
113
114 // template definitions
115
116 template <class I, class RNG, class S>
117 inline MCLookbackEngine<I, RNG, S>::MCLookbackEngine(
118 ext::shared_ptr<GeneralizedBlackScholesProcess> process,
119 Size timeSteps,
120 Size timeStepsPerYear,
121 bool brownianBridge,
122 bool antitheticVariate,
123 Size requiredSamples,
124 Real requiredTolerance,
125 Size maxSamples,
126 BigNatural seed)
127 : McSimulation<SingleVariate, RNG, S>(antitheticVariate, false), process_(std::move(process)),
128 timeSteps_(timeSteps), timeStepsPerYear_(timeStepsPerYear), requiredSamples_(requiredSamples),
129 maxSamples_(maxSamples), requiredTolerance_(requiredTolerance),
130 brownianBridge_(brownianBridge), seed_(seed) {
131 QL_REQUIRE(timeSteps != Null<Size>() ||
132 timeStepsPerYear != Null<Size>(),
133 "no time steps provided");
134 QL_REQUIRE(timeSteps == Null<Size>() ||
135 timeStepsPerYear == Null<Size>(),
136 "both time steps and time steps per year were provided");
137 QL_REQUIRE(timeSteps != 0,
138 "timeSteps must be positive, " << timeSteps <<
139 " not allowed");
140 QL_REQUIRE(timeStepsPerYear != 0,
141 "timeStepsPerYear must be positive, " << timeStepsPerYear <<
142 " not allowed");
143 this->registerWith(process_);
144 }
145
146
147 template <class I, class RNG, class S>
148 inline TimeGrid MCLookbackEngine<I,RNG,S>::timeGrid() const {
149
150 Time residualTime = process_->time(this->arguments_.exercise->lastDate());
151 if (timeSteps_ != Null<Size>()) {
152 return TimeGrid(residualTime, timeSteps_);
153 } else if (timeStepsPerYear_ != Null<Size>()) {
154 Size steps = static_cast<Size>(timeStepsPerYear_*residualTime);
155 return TimeGrid(residualTime, std::max<Size>(a: steps, b: 1));
156 } else {
157 QL_FAIL("time steps not specified");
158 }
159 }
160
161
162 namespace detail {
163
164 // these functions are specialized for each of the instruments.
165
166 ext::shared_ptr<PathPricer<Path> >
167 mc_lookback_path_pricer(
168 const ContinuousFixedLookbackOption::arguments& args,
169 const GeneralizedBlackScholesProcess& process,
170 DiscountFactor discount);
171
172 ext::shared_ptr<PathPricer<Path> >
173 mc_lookback_path_pricer(
174 const ContinuousPartialFixedLookbackOption::arguments& args,
175 const GeneralizedBlackScholesProcess& process,
176 DiscountFactor discount);
177
178 ext::shared_ptr<PathPricer<Path> >
179 mc_lookback_path_pricer(
180 const ContinuousFloatingLookbackOption::arguments& args,
181 const GeneralizedBlackScholesProcess& process,
182 DiscountFactor discount);
183
184 ext::shared_ptr<PathPricer<Path> >
185 mc_lookback_path_pricer(
186 const ContinuousPartialFloatingLookbackOption::arguments& args,
187 const GeneralizedBlackScholesProcess& process,
188 DiscountFactor discount);
189
190 }
191
192
193 template <class I, class RNG, class S>
194 inline ext::shared_ptr<typename MCLookbackEngine<I,RNG,S>::path_pricer_type>
195 MCLookbackEngine<I,RNG,S>::pathPricer() const {
196 TimeGrid grid = this->timeGrid();
197 DiscountFactor discount = this->process_->riskFreeRate()->discount(t: grid.back());
198
199 return detail::mc_lookback_path_pricer(this->arguments_,
200 *(this->process_),
201 discount);
202 }
203
204
205 template <class I, class RNG, class S>
206 inline MakeMCLookbackEngine<I, RNG, S>::MakeMCLookbackEngine(
207 ext::shared_ptr<GeneralizedBlackScholesProcess> process)
208 : process_(std::move(process)), steps_(Null<Size>()), stepsPerYear_(Null<Size>()),
209 samples_(Null<Size>()), maxSamples_(Null<Size>()), tolerance_(Null<Real>()) {}
210
211 template <class I, class RNG, class S>
212 inline MakeMCLookbackEngine<I,RNG,S>&
213 MakeMCLookbackEngine<I,RNG,S>::withSteps(Size steps) {
214 steps_ = steps;
215 return *this;
216 }
217
218 template <class I, class RNG, class S>
219 inline MakeMCLookbackEngine<I,RNG,S>&
220 MakeMCLookbackEngine<I,RNG,S>::withStepsPerYear(Size steps) {
221 stepsPerYear_ = steps;
222 return *this;
223 }
224
225 template <class I, class RNG, class S>
226 inline MakeMCLookbackEngine<I,RNG,S>&
227 MakeMCLookbackEngine<I,RNG,S>::withBrownianBridge(bool brownianBridge) {
228 brownianBridge_ = brownianBridge;
229 return *this;
230 }
231
232 template <class I, class RNG, class S>
233 inline MakeMCLookbackEngine<I,RNG,S>&
234 MakeMCLookbackEngine<I,RNG,S>::withAntitheticVariate(bool b) {
235 antithetic_ = b;
236 return *this;
237 }
238
239 template <class I, class RNG, class S>
240 inline MakeMCLookbackEngine<I,RNG,S>&
241 MakeMCLookbackEngine<I,RNG,S>::withSamples(Size samples) {
242 QL_REQUIRE(tolerance_ == Null<Real>(),
243 "tolerance already set");
244 samples_ = samples;
245 return *this;
246 }
247
248 template <class I, class RNG, class S>
249 inline MakeMCLookbackEngine<I,RNG,S>&
250 MakeMCLookbackEngine<I,RNG,S>::withAbsoluteTolerance(Real tolerance) {
251 QL_REQUIRE(samples_ == Null<Size>(),
252 "number of samples already set");
253 QL_REQUIRE(RNG::allowsErrorEstimate,
254 "chosen random generator policy "
255 "does not allow an error estimate");
256 tolerance_ = tolerance;
257 return *this;
258 }
259
260 template <class I, class RNG, class S>
261 inline MakeMCLookbackEngine<I,RNG,S>&
262 MakeMCLookbackEngine<I,RNG,S>::withMaxSamples(Size samples) {
263 maxSamples_ = samples;
264 return *this;
265 }
266
267 template <class I, class RNG, class S>
268 inline MakeMCLookbackEngine<I,RNG,S>&
269 MakeMCLookbackEngine<I,RNG,S>::withSeed(BigNatural seed) {
270 seed_ = seed;
271 return *this;
272 }
273
274 template <class I, class RNG, class S>
275 inline MakeMCLookbackEngine<I,RNG,S>::operator ext::shared_ptr<PricingEngine>() const {
276 QL_REQUIRE(steps_ != Null<Size>() || stepsPerYear_ != Null<Size>(),
277 "number of steps not given");
278 QL_REQUIRE(steps_ == Null<Size>() || stepsPerYear_ == Null<Size>(),
279 "number of steps overspecified");
280
281 return ext::shared_ptr<PricingEngine>(
282 new MCLookbackEngine<I,RNG,S>(process_,
283 steps_,
284 stepsPerYear_,
285 brownianBridge_,
286 antithetic_,
287 samples_,
288 tolerance_,
289 maxSamples_,
290 seed_));
291 }
292
293}
294
295#endif
296

source code of quantlib/ql/pricingengines/lookback/mclookbackengine.hpp