Coverage Report

Created: 2026-06-08 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}