/src/quantlib/ql/pricingengines/lookback/mclookbackengine.cpp
Line | Count | Source |
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 | | <https://www.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 | | #include <ql/pricingengines/lookback/mclookbackengine.hpp> |
21 | | #include <algorithm> |
22 | | |
23 | | namespace QuantLib { |
24 | | |
25 | | class LookbackFixedPathPricer : public PathPricer<Path> { |
26 | | public: |
27 | | LookbackFixedPathPricer(Option::Type type, |
28 | | Real strike, |
29 | | DiscountFactor discount); |
30 | | Real operator()(const Path& path) const override; |
31 | | |
32 | | private: |
33 | | PlainVanillaPayoff payoff_; |
34 | | DiscountFactor discount_; |
35 | | }; |
36 | | |
37 | | class LookbackPartialFixedPathPricer : public PathPricer<Path> { |
38 | | public: |
39 | | LookbackPartialFixedPathPricer(Time lookbackStart, |
40 | | Option::Type type, |
41 | | Real strike, |
42 | | DiscountFactor discount); |
43 | | Real operator()(const Path& path) const override; |
44 | | |
45 | | private: |
46 | | Time lookbackStart_; |
47 | | PlainVanillaPayoff payoff_; |
48 | | DiscountFactor discount_; |
49 | | }; |
50 | | |
51 | | class LookbackFloatingPathPricer : public PathPricer<Path> { |
52 | | public: |
53 | | LookbackFloatingPathPricer(Option::Type type, |
54 | | DiscountFactor discount); |
55 | | Real operator()(const Path& path) const override; |
56 | | |
57 | | private: |
58 | | FloatingTypePayoff payoff_; |
59 | | DiscountFactor discount_; |
60 | | }; |
61 | | |
62 | | class LookbackPartialFloatingPathPricer : public PathPricer<Path> { |
63 | | public: |
64 | | LookbackPartialFloatingPathPricer(Time lookbackEnd, |
65 | | Option::Type type, |
66 | | DiscountFactor discount); |
67 | | Real operator()(const Path& path) const override; |
68 | | |
69 | | private: |
70 | | Time lookbackEnd_; |
71 | | FloatingTypePayoff payoff_; |
72 | | DiscountFactor discount_; |
73 | | }; |
74 | | |
75 | | namespace detail { |
76 | | |
77 | | ext::shared_ptr<PathPricer<Path> > |
78 | | mc_lookback_path_pricer( |
79 | | const ContinuousFixedLookbackOption::arguments& args, |
80 | | const GeneralizedBlackScholesProcess& process, |
81 | 0 | DiscountFactor discount) { |
82 | 0 | ext::shared_ptr<PlainVanillaPayoff> payoff = |
83 | 0 | ext::dynamic_pointer_cast<PlainVanillaPayoff>(args.payoff); |
84 | 0 | QL_REQUIRE(payoff, "non-plain payoff given"); |
85 | | |
86 | 0 | return ext::shared_ptr<PathPricer<Path> >( |
87 | 0 | new LookbackFixedPathPricer(payoff->optionType(), |
88 | 0 | payoff->strike(), |
89 | 0 | discount)); |
90 | 0 | } |
91 | | |
92 | | ext::shared_ptr<PathPricer<Path> > |
93 | | mc_lookback_path_pricer( |
94 | | const ContinuousPartialFixedLookbackOption::arguments& args, |
95 | | const GeneralizedBlackScholesProcess& process, |
96 | 0 | DiscountFactor discount) { |
97 | 0 | ext::shared_ptr<PlainVanillaPayoff> payoff = |
98 | 0 | ext::dynamic_pointer_cast<PlainVanillaPayoff>(args.payoff); |
99 | 0 | QL_REQUIRE(payoff, "non-plain payoff given"); |
100 | | |
101 | 0 | Time lookbackStart = process.time(args.lookbackPeriodStart); |
102 | |
|
103 | 0 | return ext::shared_ptr<PathPricer<Path> >( |
104 | 0 | new LookbackPartialFixedPathPricer(lookbackStart, |
105 | 0 | payoff->optionType(), |
106 | 0 | payoff->strike(), |
107 | 0 | discount)); |
108 | 0 | } |
109 | | |
110 | | ext::shared_ptr<PathPricer<Path> > |
111 | | mc_lookback_path_pricer( |
112 | | const ContinuousFloatingLookbackOption::arguments& args, |
113 | | const GeneralizedBlackScholesProcess& process, |
114 | 0 | DiscountFactor discount) { |
115 | 0 | ext::shared_ptr<FloatingTypePayoff> payoff = |
116 | 0 | ext::dynamic_pointer_cast<FloatingTypePayoff>(args.payoff); |
117 | 0 | QL_REQUIRE(payoff, "non-floating payoff given"); |
118 | | |
119 | 0 | return ext::shared_ptr<PathPricer<Path> >( |
120 | 0 | new LookbackFloatingPathPricer(payoff->optionType(), |
121 | 0 | discount)); |
122 | 0 | } |
123 | | |
124 | | ext::shared_ptr<PathPricer<Path> > |
125 | | mc_lookback_path_pricer( |
126 | | const ContinuousPartialFloatingLookbackOption::arguments& args, |
127 | | const GeneralizedBlackScholesProcess& process, |
128 | 0 | DiscountFactor discount) { |
129 | 0 | ext::shared_ptr<FloatingTypePayoff> payoff = |
130 | 0 | ext::dynamic_pointer_cast<FloatingTypePayoff>(args.payoff); |
131 | 0 | QL_REQUIRE(payoff, "non-floating payoff given"); |
132 | | |
133 | 0 | Time lookbackEnd = process.time(args.lookbackPeriodEnd); |
134 | |
|
135 | 0 | return ext::shared_ptr<PathPricer<Path> >( |
136 | 0 | new LookbackPartialFloatingPathPricer(lookbackEnd, |
137 | 0 | payoff->optionType(), |
138 | 0 | discount)); |
139 | 0 | } |
140 | | |
141 | | } |
142 | | |
143 | | |
144 | | LookbackFixedPathPricer::LookbackFixedPathPricer( |
145 | | Option::Type type, |
146 | | Real strike, |
147 | | DiscountFactor discount) |
148 | 0 | : payoff_(type, strike), discount_(discount) { |
149 | 0 | QL_REQUIRE(strike>=0.0, |
150 | 0 | "strike less than zero not allowed"); |
151 | 0 | } |
152 | | |
153 | 0 | Real LookbackFixedPathPricer::operator()(const Path& path) const { |
154 | 0 | QL_REQUIRE(!path.empty(), "the path cannot be empty"); |
155 | | |
156 | 0 | Real underlying; |
157 | 0 | switch (payoff_.optionType()) { |
158 | 0 | case Option::Put: |
159 | 0 | underlying = *std::min_element(path.begin()+1, path.end()); |
160 | 0 | break; |
161 | 0 | case Option::Call: |
162 | 0 | underlying = *std::max_element(path.begin()+1, path.end()); |
163 | 0 | break; |
164 | 0 | default: |
165 | 0 | QL_FAIL("unknown option type"); |
166 | 0 | } |
167 | | |
168 | 0 | return payoff_(underlying) * discount_; |
169 | 0 | } |
170 | | |
171 | | |
172 | | LookbackPartialFixedPathPricer::LookbackPartialFixedPathPricer( |
173 | | Time lookbackStart, |
174 | | Option::Type type, |
175 | | Real strike, |
176 | | const DiscountFactor discount) |
177 | 0 | : lookbackStart_(lookbackStart), payoff_(type, strike), discount_(discount) { |
178 | 0 | QL_REQUIRE(strike>=0.0, |
179 | 0 | "strike less than zero not allowed"); |
180 | 0 | } |
181 | | |
182 | 0 | Real LookbackPartialFixedPathPricer::operator()(const Path& path) const { |
183 | 0 | QL_REQUIRE(!path.empty(), "the path cannot be empty"); |
184 | | |
185 | 0 | const TimeGrid& timeGrid = path.timeGrid(); |
186 | 0 | Size startIndex = timeGrid.closestIndex(lookbackStart_); |
187 | 0 | Real underlying; |
188 | 0 | switch (payoff_.optionType()) { |
189 | 0 | case Option::Put: |
190 | 0 | underlying = *std::min_element(path.begin()+startIndex+1, path.end()); |
191 | 0 | break; |
192 | 0 | case Option::Call: |
193 | 0 | underlying = *std::max_element(path.begin()+startIndex+1, path.end()); |
194 | 0 | break; |
195 | 0 | default: |
196 | 0 | QL_FAIL("unknown option type"); |
197 | 0 | } |
198 | | |
199 | 0 | return payoff_(underlying) * discount_; |
200 | 0 | } |
201 | | |
202 | | |
203 | | LookbackFloatingPathPricer::LookbackFloatingPathPricer( |
204 | | Option::Type type, |
205 | | const DiscountFactor discount) |
206 | 0 | : payoff_(type), discount_(discount) {} |
207 | | |
208 | 0 | Real LookbackFloatingPathPricer::operator()(const Path& path) const { |
209 | 0 | QL_REQUIRE(!path.empty(), "the path cannot be empty"); |
210 | | |
211 | 0 | Real terminalPrice = path.back(); |
212 | 0 | Real strike; |
213 | 0 | switch (payoff_.optionType()) { |
214 | 0 | case Option::Call: |
215 | 0 | strike = *std::min_element(path.begin()+1, path.end()); |
216 | 0 | break; |
217 | 0 | case Option::Put: |
218 | 0 | strike = *std::max_element(path.begin()+1, path.end()); |
219 | 0 | break; |
220 | 0 | default: |
221 | 0 | QL_FAIL("unknown option type"); |
222 | 0 | } |
223 | | |
224 | 0 | return payoff_(terminalPrice, strike) * discount_; |
225 | 0 | } |
226 | | |
227 | | |
228 | | LookbackPartialFloatingPathPricer::LookbackPartialFloatingPathPricer( |
229 | | Time lookbackEnd, |
230 | | Option::Type type, |
231 | | DiscountFactor discount) |
232 | 0 | : lookbackEnd_(lookbackEnd), payoff_(type), discount_(discount) {} |
233 | | |
234 | 0 | Real LookbackPartialFloatingPathPricer::operator()(const Path& path) const { |
235 | 0 | QL_REQUIRE(!path.empty(), "the path cannot be empty"); |
236 | | |
237 | 0 | const TimeGrid& timeGrid = path.timeGrid(); |
238 | 0 | Size endIndex = timeGrid.closestIndex(lookbackEnd_); |
239 | 0 | Real terminalPrice = path.back(); |
240 | 0 | Real strike; |
241 | |
|
242 | 0 | switch (payoff_.optionType()) { |
243 | 0 | case Option::Call: |
244 | 0 | strike = *std::min_element(path.begin()+1, path.begin()+endIndex+1); |
245 | 0 | break; |
246 | 0 | case Option::Put: |
247 | 0 | strike = *std::max_element(path.begin()+1, path.begin()+endIndex+1); |
248 | 0 | break; |
249 | 0 | default: |
250 | 0 | QL_FAIL("unknown option type"); |
251 | 0 | } |
252 | | |
253 | 0 | return payoff_(terminalPrice, strike) * discount_; |
254 | 0 | } |
255 | | |
256 | | } |