1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2003, 2004 Ferdinando Ametrano
5 Copyright (C) 2005, 2007 StatPro Italia srl
6 Copyright (C) 2006 Warren Chou
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 <http://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#include "lookbackoptions.hpp"
23#include "utilities.hpp"
24#include <ql/time/daycounters/actual360.hpp>
25#include <ql/instruments/lookbackoption.hpp>
26#include <ql/pricingengines/lookback/analyticcontinuousfloatinglookback.hpp>
27#include <ql/pricingengines/lookback/analyticcontinuousfixedlookback.hpp>
28#include <ql/pricingengines/lookback/analyticcontinuouspartialfloatinglookback.hpp>
29#include <ql/pricingengines/lookback/analyticcontinuouspartialfixedlookback.hpp>
30#include <ql/pricingengines/lookback/mclookbackengine.hpp>
31#include <ql/termstructures/yield/flatforward.hpp>
32#include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp>
33#include <ql/utilities/dataformatters.hpp>
34#include <ql/processes/blackscholesprocess.hpp>
35
36using namespace QuantLib;
37using namespace boost::unit_test_framework;
38
39#undef REPORT_FAILURE_FLOATING
40#define REPORT_FAILURE_FLOATING(greekName, minmax, payoff, exercise, \
41 s, q, r, today, v, \
42 expected, calculated, error, tolerance) \
43 BOOST_ERROR( \
44 exerciseTypeToString(exercise) \
45 << payoff->optionType() << " lookback option with " \
46 << payoffTypeToString(payoff) << " payoff:\n" \
47 << " underlying value: " << s << "\n" \
48 << " dividend yield: " << io::rate(q) << "\n" \
49 << " risk-free rate: " << io::rate(r) << "\n" \
50 << " reference date: " << today << "\n" \
51 << " maturity: " << exercise->lastDate() << "\n" \
52 << " volatility: " << io::volatility(v) << "\n\n" \
53 << " expected " << greekName << ": " << expected << "\n" \
54 << " calculated " << greekName << ": " << calculated << "\n"\
55 << " error: " << error << "\n" \
56 << " tolerance: " << tolerance);
57
58#undef REPORT_FAILURE_FIXED
59#define REPORT_FAILURE_FIXED(greekName, minmax, payoff, exercise, \
60 s, q, r, today, v, \
61 expected, calculated, error, tolerance) \
62 BOOST_ERROR( \
63 exerciseTypeToString(exercise) \
64 << payoff->optionType() << " lookback option with " \
65 << payoffTypeToString(payoff) << " payoff:\n" \
66 << " underlying value: " << s << "\n" \
67 << " strike: " << payoff->strike() << "\n" \
68 << " dividend yield: " << io::rate(q) << "\n" \
69 << " risk-free rate: " << io::rate(r) << "\n" \
70 << " reference date: " << today << "\n" \
71 << " maturity: " << exercise->lastDate() << "\n" \
72 << " volatility: " << io::volatility(v) << "\n\n" \
73 << " expected " << greekName << ": " << expected << "\n" \
74 << " calculated " << greekName << ": " << calculated << "\n"\
75 << " error: " << error << "\n" \
76 << " tolerance: " << tolerance);
77
78#undef REPORT_FAILURE_MC
79#define REPORT_FAILURE_MC(lookbackType, optionType, analytical, monteCarlo, tolerance) \
80 BOOST_ERROR( \
81 "Analytical and MC " << lookbackType << " " << optionType << " values differed by more than tolerance" << "\n" \
82 << " Analytical: " << analytical << "\n" \
83 << " Monte Carlo: " << monteCarlo << "\n" \
84 << " tolerance: " << tolerance << "\n" \
85 << " difference: " << std::abs(analytical - monteCarlo));
86
87namespace {
88
89 struct LookbackOptionData {
90 Option::Type type;
91 Real strike;
92 Real minmax;
93 Real s; // spot
94 Rate q; // dividend
95 Rate r; // risk-free rate
96 Time t; // time to maturity
97 Volatility v; // volatility
98
99 //Partial-time lookback options:
100 Real l; // level above/below actual extremum
101 Real t1; // time to start of lookback period
102
103 Real result; // result
104 Real tol; // tolerance
105 };
106
107}
108
109
110void LookbackOptionTest::testAnalyticContinuousFloatingLookback() {
111
112 BOOST_TEST_MESSAGE(
113 "Testing analytic continuous floating-strike lookback options...");
114
115
116 LookbackOptionData values[] = {
117
118 // data from "Option Pricing Formulas", Haug, 1998, pg.61-62
119
120 // type, strike, minmax, s, q, r, t, v, l, t1, result, tol
121 { .type: Option::Call, .strike: 0, .minmax: 100, .s: 120.0, .q: 0.06, .r: 0.10, .t: 0.50, .v: 0.30, .l: 0, .t1: 0, .result: 25.3533, .tol: 1.0e-4},
122
123 // data from "Connecting discrete and continuous path-dependent options",
124 // Broadie, Glasserman & Kou, 1999, pg.70-74
125
126 // type, strike, minmax, s, q, r, t, v, l, t1, result, tol
127 { .type: Option::Call, .strike: 0, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.05, .t: 1.00, .v: 0.30, .l: 0, .t1: 0, .result: 23.7884, .tol: 1.0e-4},
128 { .type: Option::Call, .strike: 0, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.05, .t: 0.20, .v: 0.30, .l: 0, .t1: 0, .result: 10.7190, .tol: 1.0e-4},
129 { .type: Option::Call, .strike: 0, .minmax: 100, .s: 110.0, .q: 0.00, .r: 0.05, .t: 0.20, .v: 0.30, .l: 0, .t1: 0, .result: 14.4597, .tol: 1.0e-4},
130 { .type: Option::Put, .strike: 0, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 0.50, .v: 0.30, .l: 0, .t1: 0, .result: 15.3526, .tol: 1.0e-4},
131 { .type: Option::Put, .strike: 0, .minmax: 110, .s: 100.0, .q: 0.00, .r: 0.10, .t: 0.50, .v: 0.30, .l: 0, .t1: 0, .result: 16.8468, .tol: 1.0e-4},
132 { .type: Option::Put, .strike: 0, .minmax: 120, .s: 100.0, .q: 0.00, .r: 0.10, .t: 0.50, .v: 0.30, .l: 0, .t1: 0, .result: 21.0645, .tol: 1.0e-4},
133 };
134
135 DayCounter dc = Actual360();
136 Date today = Date::todaysDate();
137
138 ext::shared_ptr<SimpleQuote> spot(new SimpleQuote(0.0));
139 ext::shared_ptr<SimpleQuote> qRate(new SimpleQuote(0.0));
140 ext::shared_ptr<YieldTermStructure> qTS = flatRate(today, forward: qRate, dc);
141 ext::shared_ptr<SimpleQuote> rRate(new SimpleQuote(0.0));
142 ext::shared_ptr<YieldTermStructure> rTS = flatRate(today, forward: rRate, dc);
143 ext::shared_ptr<SimpleQuote> vol(new SimpleQuote(0.0));
144 ext::shared_ptr<BlackVolTermStructure> volTS = flatVol(today, volatility: vol, dc);
145
146 for (auto& value : values) {
147 Date exDate = today + timeToDays(t: value.t);
148 ext::shared_ptr<Exercise> exercise(new EuropeanExercise(exDate));
149
150 spot->setValue(value.s);
151 qRate->setValue(value.q);
152 rRate->setValue(value.r);
153 vol->setValue(value.v);
154
155 ext::shared_ptr<FloatingTypePayoff> payoff(new FloatingTypePayoff(value.type));
156
157 ext::shared_ptr<BlackScholesMertonProcess> stochProcess(
158 new BlackScholesMertonProcess(
159 Handle<Quote>(spot),
160 Handle<YieldTermStructure>(qTS),
161 Handle<YieldTermStructure>(rTS),
162 Handle<BlackVolTermStructure>(volTS)));
163
164 ext::shared_ptr<PricingEngine> engine(
165 new AnalyticContinuousFloatingLookbackEngine(stochProcess));
166
167 ContinuousFloatingLookbackOption option(value.minmax, payoff, exercise);
168 option.setPricingEngine(engine);
169
170 Real calculated = option.NPV();
171 Real expected = value.result;
172 Real error = std::fabs(x: calculated-expected);
173 if (error > value.tol) {
174 REPORT_FAILURE_FLOATING("value", values[i].minmax, payoff, exercise, value.s, value.q,
175 value.r, today, value.v, expected, calculated, error,
176 value.tol);
177 }
178 }
179}
180
181
182void LookbackOptionTest::testAnalyticContinuousFixedLookback() {
183
184 BOOST_TEST_MESSAGE(
185 "Testing analytic continuous fixed-strike lookback options...");
186
187 LookbackOptionData values[] = {
188 // data from "Option Pricing Formulas", Haug, 1998, pg.63-64
189 //type, strike, minmax, s, q, r, t, v, l, t1, result, tol
190 { .type: Option::Call, .strike: 95, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 0.50, .v: 0.10, .l: 0, .t1: 0, .result: 13.2687, .tol: 1.0e-4},
191 { .type: Option::Call, .strike: 95, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 0.50, .v: 0.20, .l: 0, .t1: 0, .result: 18.9263, .tol: 1.0e-4},
192 { .type: Option::Call, .strike: 95, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 0.50, .v: 0.30, .l: 0, .t1: 0, .result: 24.9857, .tol: 1.0e-4},
193 { .type: Option::Call, .strike: 100, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 0.50, .v: 0.10, .l: 0, .t1: 0, .result: 8.5126, .tol: 1.0e-4},
194 { .type: Option::Call, .strike: 100, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 0.50, .v: 0.20, .l: 0, .t1: 0, .result: 14.1702, .tol: 1.0e-4},
195 { .type: Option::Call, .strike: 100, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 0.50, .v: 0.30, .l: 0, .t1: 0, .result: 20.2296, .tol: 1.0e-4},
196 { .type: Option::Call, .strike: 105, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 0.50, .v: 0.10, .l: 0, .t1: 0, .result: 4.3908, .tol: 1.0e-4},
197 { .type: Option::Call, .strike: 105, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 0.50, .v: 0.20, .l: 0, .t1: 0, .result: 9.8905, .tol: 1.0e-4},
198 { .type: Option::Call, .strike: 105, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 0.50, .v: 0.30, .l: 0, .t1: 0, .result: 15.8512, .tol: 1.0e-4},
199 { .type: Option::Call, .strike: 95, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 1.00, .v: 0.10, .l: 0, .t1: 0, .result: 18.3241, .tol: 1.0e-4},
200 { .type: Option::Call, .strike: 95, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 1.00, .v: 0.20, .l: 0, .t1: 0, .result: 26.0731, .tol: 1.0e-4},
201 { .type: Option::Call, .strike: 95, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 1.00, .v: 0.30, .l: 0, .t1: 0, .result: 34.7116, .tol: 1.0e-4},
202 { .type: Option::Call, .strike: 100, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 1.00, .v: 0.10, .l: 0, .t1: 0, .result: 13.8000, .tol: 1.0e-4},
203 { .type: Option::Call, .strike: 100, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 1.00, .v: 0.20, .l: 0, .t1: 0, .result: 21.5489, .tol: 1.0e-4},
204 { .type: Option::Call, .strike: 100, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 1.00, .v: 0.30, .l: 0, .t1: 0, .result: 30.1874, .tol: 1.0e-4},
205 { .type: Option::Call, .strike: 105, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 1.00, .v: 0.10, .l: 0, .t1: 0, .result: 9.5445, .tol: 1.0e-4},
206 { .type: Option::Call, .strike: 105, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 1.00, .v: 0.20, .l: 0, .t1: 0, .result: 17.2965, .tol: 1.0e-4},
207 { .type: Option::Call, .strike: 105, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 1.00, .v: 0.30, .l: 0, .t1: 0, .result: 25.9002, .tol: 1.0e-4},
208
209 { .type: Option::Put, .strike: 95, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 0.50, .v: 0.10, .l: 0, .t1: 0, .result: 0.6899, .tol: 1.0e-4},
210 { .type: Option::Put, .strike: 95, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 0.50, .v: 0.20, .l: 0, .t1: 0, .result: 4.4448, .tol: 1.0e-4},
211 { .type: Option::Put, .strike: 95, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 0.50, .v: 0.30, .l: 0, .t1: 0, .result: 8.9213, .tol: 1.0e-4},
212 { .type: Option::Put, .strike: 100, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 0.50, .v: 0.10, .l: 0, .t1: 0, .result: 3.3917, .tol: 1.0e-4},
213 { .type: Option::Put, .strike: 100, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 0.50, .v: 0.20, .l: 0, .t1: 0, .result: 8.3177, .tol: 1.0e-4},
214 { .type: Option::Put, .strike: 100, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 0.50, .v: 0.30, .l: 0, .t1: 0, .result: 13.1579, .tol: 1.0e-4},
215 { .type: Option::Put, .strike: 105, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 0.50, .v: 0.10, .l: 0, .t1: 0, .result: 8.1478, .tol: 1.0e-4},
216 { .type: Option::Put, .strike: 105, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 0.50, .v: 0.20, .l: 0, .t1: 0, .result: 13.0739, .tol: 1.0e-4},
217 { .type: Option::Put, .strike: 105, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 0.50, .v: 0.30, .l: 0, .t1: 0, .result: 17.9140, .tol: 1.0e-4},
218 { .type: Option::Put, .strike: 95, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 1.00, .v: 0.10, .l: 0, .t1: 0, .result: 1.0534, .tol: 1.0e-4},
219 { .type: Option::Put, .strike: 95, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 1.00, .v: 0.20, .l: 0, .t1: 0, .result: 6.2813, .tol: 1.0e-4},
220 { .type: Option::Put, .strike: 95, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 1.00, .v: 0.30, .l: 0, .t1: 0, .result: 12.2376, .tol: 1.0e-4},
221 { .type: Option::Put, .strike: 100, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 1.00, .v: 0.10, .l: 0, .t1: 0, .result: 3.8079, .tol: 1.0e-4},
222 { .type: Option::Put, .strike: 100, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 1.00, .v: 0.20, .l: 0, .t1: 0, .result: 10.1294, .tol: 1.0e-4},
223 { .type: Option::Put, .strike: 100, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 1.00, .v: 0.30, .l: 0, .t1: 0, .result: 16.3889, .tol: 1.0e-4},
224 { .type: Option::Put, .strike: 105, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 1.00, .v: 0.10, .l: 0, .t1: 0, .result: 8.3321, .tol: 1.0e-4},
225 { .type: Option::Put, .strike: 105, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 1.00, .v: 0.20, .l: 0, .t1: 0, .result: 14.6536, .tol: 1.0e-4},
226 { .type: Option::Put, .strike: 105, .minmax: 100, .s: 100.0, .q: 0.00, .r: 0.10, .t: 1.00, .v: 0.30, .l: 0, .t1: 0, .result: 20.9130, .tol: 1.0e-4}
227
228 };
229
230 DayCounter dc = Actual360();
231 Date today = Date::todaysDate();
232
233 ext::shared_ptr<SimpleQuote> spot(new SimpleQuote(0.0));
234 ext::shared_ptr<SimpleQuote> qRate(new SimpleQuote(0.0));
235 ext::shared_ptr<YieldTermStructure> qTS = flatRate(today, forward: qRate, dc);
236 ext::shared_ptr<SimpleQuote> rRate(new SimpleQuote(0.0));
237 ext::shared_ptr<YieldTermStructure> rTS = flatRate(today, forward: rRate, dc);
238 ext::shared_ptr<SimpleQuote> vol(new SimpleQuote(0.0));
239 ext::shared_ptr<BlackVolTermStructure> volTS = flatVol(today, volatility: vol, dc);
240
241 for (auto& value : values) {
242 Date exDate = today + timeToDays(t: value.t);
243 ext::shared_ptr<Exercise> exercise(new EuropeanExercise(exDate));
244
245 spot->setValue(value.s);
246 qRate->setValue(value.q);
247 rRate->setValue(value.r);
248 vol->setValue(value.v);
249
250 ext::shared_ptr<StrikedTypePayoff> payoff(new PlainVanillaPayoff(value.type, value.strike));
251
252 ext::shared_ptr<BlackScholesMertonProcess> stochProcess(
253 new BlackScholesMertonProcess(
254 Handle<Quote>(spot),
255 Handle<YieldTermStructure>(qTS),
256 Handle<YieldTermStructure>(rTS),
257 Handle<BlackVolTermStructure>(volTS)));
258
259 ext::shared_ptr<PricingEngine> engine(
260 new AnalyticContinuousFixedLookbackEngine(stochProcess));
261
262 ContinuousFixedLookbackOption option(value.minmax, payoff, exercise);
263 option.setPricingEngine(engine);
264
265 Real calculated = option.NPV();
266 Real expected = value.result;
267 Real error = std::fabs(x: calculated-expected);
268 if (error > value.tol) {
269 REPORT_FAILURE_FIXED("value", values[i].minmax, payoff, exercise, value.s, value.q,
270 value.r, today, value.v, expected, calculated, error, value.tol);
271 }
272 }
273}
274
275void LookbackOptionTest::testAnalyticContinuousPartialFloatingLookback() {
276
277 BOOST_TEST_MESSAGE(
278 "Testing analytic continuous partial floating-strike lookback options...");
279
280
281 LookbackOptionData values[] = {
282
283 // data from "Option Pricing Formulas, Second Edition", Haug, 2006, pg.146
284
285 //type, strike, minmax, s, q, r, t, v, l, t1, result, tol
286 { .type: Option::Call, .strike: 0, .minmax: 90, .s: 90, .q: 0, .r: 0.06, .t: 1, .v: 0.1, .l: 1, .t1: 0.25, .result: 8.6524, .tol: 1.0e-4},
287 { .type: Option::Call, .strike: 0, .minmax: 90, .s: 90, .q: 0, .r: 0.06, .t: 1, .v: 0.1, .l: 1, .t1: 0.5, .result: 9.2128, .tol: 1.0e-4},
288 { .type: Option::Call, .strike: 0, .minmax: 90, .s: 90, .q: 0, .r: 0.06, .t: 1, .v: 0.1, .l: 1, .t1: 0.75, .result: 9.5567, .tol: 1.0e-4},
289
290 { .type: Option::Call, .strike: 0, .minmax: 110, .s: 110, .q: 0, .r: 0.06, .t: 1, .v: 0.1, .l: 1, .t1: 0.25, .result: 10.5751, .tol: 1.0e-4},
291 { .type: Option::Call, .strike: 0, .minmax: 110, .s: 110, .q: 0, .r: 0.06, .t: 1, .v: 0.1, .l: 1, .t1: 0.5, .result: 11.2601, .tol: 1.0e-4},
292 { .type: Option::Call, .strike: 0, .minmax: 110, .s: 110, .q: 0, .r: 0.06, .t: 1, .v: 0.1, .l: 1, .t1: 0.75, .result: 11.6804, .tol: 1.0e-4},
293
294 { .type: Option::Call, .strike: 0, .minmax: 90, .s: 90, .q: 0, .r: 0.06, .t: 1, .v: 0.2, .l: 1, .t1: 0.25, .result: 13.3402, .tol: 1.0e-4},
295 { .type: Option::Call, .strike: 0, .minmax: 90, .s: 90, .q: 0, .r: 0.06, .t: 1, .v: 0.2, .l: 1, .t1: 0.5, .result: 14.5121, .tol: 1.0e-4},
296 { .type: Option::Call, .strike: 0, .minmax: 90, .s: 90, .q: 0, .r: 0.06, .t: 1, .v: 0.2, .l: 1, .t1: 0.75, .result: 15.314, .tol: 1.0e-4},
297
298 { .type: Option::Call, .strike: 0, .minmax: 110, .s: 110, .q: 0, .r: 0.06, .t: 1, .v: 0.2, .l: 1, .t1: 0.25, .result: 16.3047, .tol: 1.0e-4},
299 { .type: Option::Call, .strike: 0, .minmax: 110, .s: 110, .q: 0, .r: 0.06, .t: 1, .v: 0.2, .l: 1, .t1: 0.5, .result: 17.737, .tol: 1.0e-4},
300 { .type: Option::Call, .strike: 0, .minmax: 110, .s: 110, .q: 0, .r: 0.06, .t: 1, .v: 0.2, .l: 1, .t1: 0.75, .result: 18.7171, .tol: 1.0e-4},
301
302 { .type: Option::Call, .strike: 0, .minmax: 90, .s: 90, .q: 0, .r: 0.06, .t: 1, .v: 0.3, .l: 1, .t1: 0.25, .result: 17.9831, .tol: 1.0e-4},
303 { .type: Option::Call, .strike: 0, .minmax: 90, .s: 90, .q: 0, .r: 0.06, .t: 1, .v: 0.3, .l: 1, .t1: 0.5, .result: 19.6618, .tol: 1.0e-4},
304 { .type: Option::Call, .strike: 0, .minmax: 90, .s: 90, .q: 0, .r: 0.06, .t: 1, .v: 0.3, .l: 1, .t1: 0.75, .result: 20.8493, .tol: 1.0e-4},
305
306 { .type: Option::Call, .strike: 0, .minmax: 110, .s: 110, .q: 0, .r: 0.06, .t: 1, .v: 0.3, .l: 1, .t1: 0.25, .result: 21.9793, .tol: 1.0e-4},
307 { .type: Option::Call, .strike: 0, .minmax: 110, .s: 110, .q: 0, .r: 0.06, .t: 1, .v: 0.3, .l: 1, .t1: 0.5, .result: 24.0311, .tol: 1.0e-4},
308 { .type: Option::Call, .strike: 0, .minmax: 110, .s: 110, .q: 0, .r: 0.06, .t: 1, .v: 0.3, .l: 1, .t1: 0.75, .result: 25.4825, .tol: 1.0e-4},
309
310 { .type: Option::Put, .strike: 0, .minmax: 90, .s: 90, .q: 0, .r: 0.06, .t: 1, .v: 0.1, .l: 1, .t1: 0.25, .result: 2.7189, .tol: 1.0e-4},
311 { .type: Option::Put, .strike: 0, .minmax: 90, .s: 90, .q: 0, .r: 0.06, .t: 1, .v: 0.1, .l: 1, .t1: 0.5, .result: 3.4639, .tol: 1.0e-4},
312 { .type: Option::Put, .strike: 0, .minmax: 90, .s: 90, .q: 0, .r: 0.06, .t: 1, .v: 0.1, .l: 1, .t1: 0.75, .result: 4.1912, .tol: 1.0e-4},
313
314 { .type: Option::Put, .strike: 0, .minmax: 110, .s: 110, .q: 0, .r: 0.06, .t: 1, .v: 0.1, .l: 1, .t1: 0.25, .result: 3.3231, .tol: 1.0e-4},
315 { .type: Option::Put, .strike: 0, .minmax: 110, .s: 110, .q: 0, .r: 0.06, .t: 1, .v: 0.1, .l: 1, .t1: 0.5, .result: 4.2336, .tol: 1.0e-4},
316 { .type: Option::Put, .strike: 0, .minmax: 110, .s: 110, .q: 0, .r: 0.06, .t: 1, .v: 0.1, .l: 1, .t1: 0.75, .result: 5.1226, .tol: 1.0e-4},
317
318 { .type: Option::Put, .strike: 0, .minmax: 90, .s: 90, .q: 0, .r: 0.06, .t: 1, .v: 0.2, .l: 1, .t1: 0.25, .result: 7.9153, .tol: 1.0e-4},
319 { .type: Option::Put, .strike: 0, .minmax: 90, .s: 90, .q: 0, .r: 0.06, .t: 1, .v: 0.2, .l: 1, .t1: 0.5, .result: 9.5825, .tol: 1.0e-4},
320 { .type: Option::Put, .strike: 0, .minmax: 90, .s: 90, .q: 0, .r: 0.06, .t: 1, .v: 0.2, .l: 1, .t1: 0.75, .result: 11.0362, .tol: 1.0e-4},
321
322 { .type: Option::Put, .strike: 0, .minmax: 110, .s: 110, .q: 0, .r: 0.06, .t: 1, .v: 0.2, .l: 1, .t1: 0.25, .result: 9.6743, .tol: 1.0e-4},
323 { .type: Option::Put, .strike: 0, .minmax: 110, .s: 110, .q: 0, .r: 0.06, .t: 1, .v: 0.2, .l: 1, .t1: 0.5, .result: 11.7119, .tol: 1.0e-4},
324 { .type: Option::Put, .strike: 0, .minmax: 110, .s: 110, .q: 0, .r: 0.06, .t: 1, .v: 0.2, .l: 1, .t1: 0.75, .result: 13.4887, .tol: 1.0e-4},
325
326 { .type: Option::Put, .strike: 0, .minmax: 90, .s: 90, .q: 0, .r: 0.06, .t: 1, .v: 0.3, .l: 1, .t1: 0.25, .result: 13.4719, .tol: 1.0e-4},
327 { .type: Option::Put, .strike: 0, .minmax: 90, .s: 90, .q: 0, .r: 0.06, .t: 1, .v: 0.3, .l: 1, .t1: 0.5, .result: 16.1495, .tol: 1.0e-4},
328 { .type: Option::Put, .strike: 0, .minmax: 90, .s: 90, .q: 0, .r: 0.06, .t: 1, .v: 0.3, .l: 1, .t1: 0.75, .result: 18.4071, .tol: 1.0e-4},
329
330 { .type: Option::Put, .strike: 0, .minmax: 110, .s: 110, .q: 0, .r: 0.06, .t: 1, .v: 0.3, .l: 1, .t1: 0.25, .result: 16.4657, .tol: 1.0e-4},
331 { .type: Option::Put, .strike: 0, .minmax: 110, .s: 110, .q: 0, .r: 0.06, .t: 1, .v: 0.3, .l: 1, .t1: 0.5, .result: 19.7383, .tol: 1.0e-4},
332 { .type: Option::Put, .strike: 0, .minmax: 110, .s: 110, .q: 0, .r: 0.06, .t: 1, .v: 0.3, .l: 1, .t1: 0.75, .result: 22.4976, .tol: 1.0e-4}
333 };
334
335 DayCounter dc = Actual360();
336 Date today = Date::todaysDate();
337
338 ext::shared_ptr<SimpleQuote> spot(new SimpleQuote(0.0));
339 ext::shared_ptr<SimpleQuote> qRate(new SimpleQuote(0.0));
340 ext::shared_ptr<YieldTermStructure> qTS = flatRate(today, forward: qRate, dc);
341 ext::shared_ptr<SimpleQuote> rRate(new SimpleQuote(0.0));
342 ext::shared_ptr<YieldTermStructure> rTS = flatRate(today, forward: rRate, dc);
343 ext::shared_ptr<SimpleQuote> vol(new SimpleQuote(0.0));
344 ext::shared_ptr<BlackVolTermStructure> volTS = flatVol(today, volatility: vol, dc);
345
346 for (auto& value : values) {
347 Date exDate = today + timeToDays(t: value.t);
348 ext::shared_ptr<Exercise> exercise(new EuropeanExercise(exDate));
349
350 spot->setValue(value.s);
351 qRate->setValue(value.q);
352 rRate->setValue(value.r);
353 vol->setValue(value.v);
354
355 ext::shared_ptr<FloatingTypePayoff> payoff(new FloatingTypePayoff(value.type));
356
357 ext::shared_ptr<BlackScholesMertonProcess> stochProcess(
358 new BlackScholesMertonProcess(
359 Handle<Quote>(spot),
360 Handle<YieldTermStructure>(qTS),
361 Handle<YieldTermStructure>(rTS),
362 Handle<BlackVolTermStructure>(volTS)));
363
364 ext::shared_ptr<PricingEngine> engine(
365 new AnalyticContinuousPartialFloatingLookbackEngine(stochProcess));
366
367 Date lookbackEnd = today + timeToDays(t: value.t1);
368 ContinuousPartialFloatingLookbackOption option(value.minmax, value.l, lookbackEnd, payoff,
369 exercise);
370 option.setPricingEngine(engine);
371
372 Real calculated = option.NPV();
373 Real expected = value.result;
374 Real error = std::fabs(x: calculated-expected);
375 if (error > value.tol) {
376 REPORT_FAILURE_FLOATING("value", values[i].minmax, payoff, exercise, value.s, value.q,
377 value.r, today, value.v, expected, calculated, error,
378 value.tol);
379 }
380 }
381}
382
383void LookbackOptionTest::testAnalyticContinuousPartialFixedLookback() {
384
385 BOOST_TEST_MESSAGE(
386 "Testing analytic continuous fixed-strike lookback options...");
387
388 LookbackOptionData values[] = {
389 // data from "Option Pricing Formulas, Second Edition", Haug, 2006, pg.148
390 //type, strike, minmax, s, q, r, t, v, l, t1, result, tol
391 { .type: Option::Call, .strike: 90, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.1, .l: 0, .t1: 0.25, .result: 20.2845, .tol: 1.0e-4},
392 { .type: Option::Call, .strike: 90, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.1, .l: 0, .t1: 0.5, .result: 19.6239, .tol: 1.0e-4},
393 { .type: Option::Call, .strike: 90, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.1, .l: 0, .t1: 0.75, .result: 18.6244, .tol: 1.0e-4},
394
395 { .type: Option::Call, .strike: 110, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.1, .l: 0, .t1: 0.25, .result: 4.0432, .tol: 1.0e-4},
396 { .type: Option::Call, .strike: 110, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.1, .l: 0, .t1: 0.5, .result: 3.958, .tol: 1.0e-4},
397 { .type: Option::Call, .strike: 110, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.1, .l: 0, .t1: 0.75, .result: 3.7015, .tol: 1.0e-4},
398
399 { .type: Option::Call, .strike: 90, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.2, .l: 0, .t1: 0.25, .result: 27.5385, .tol: 1.0e-4},
400 { .type: Option::Call, .strike: 90, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.2, .l: 0, .t1: 0.5, .result: 25.8126, .tol: 1.0e-4},
401 { .type: Option::Call, .strike: 90, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.2, .l: 0, .t1: 0.75, .result: 23.4957, .tol: 1.0e-4},
402
403 { .type: Option::Call, .strike: 110, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.2, .l: 0, .t1: 0.25, .result: 11.4895, .tol: 1.0e-4},
404 { .type: Option::Call, .strike: 110, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.2, .l: 0, .t1: 0.5, .result: 10.8995, .tol: 1.0e-4},
405 { .type: Option::Call, .strike: 110, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.2, .l: 0, .t1: 0.75, .result: 9.8244, .tol: 1.0e-4},
406
407 { .type: Option::Call, .strike: 90, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.3, .l: 0, .t1: 0.25, .result: 35.4578, .tol: 1.0e-4},
408 { .type: Option::Call, .strike: 90, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.3, .l: 0, .t1: 0.5, .result: 32.7172, .tol: 1.0e-4},
409 { .type: Option::Call, .strike: 90, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.3, .l: 0, .t1: 0.75, .result: 29.1473, .tol: 1.0e-4},
410
411 { .type: Option::Call, .strike: 110, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.3, .l: 0, .t1: 0.25, .result: 19.725, .tol: 1.0e-4},
412 { .type: Option::Call, .strike: 110, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.3, .l: 0, .t1: 0.5, .result: 18.4025, .tol: 1.0e-4},
413 { .type: Option::Call, .strike: 110, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.3, .l: 0, .t1: 0.75, .result: 16.2976, .tol: 1.0e-4},
414
415 { .type: Option::Put, .strike: 90, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.1, .l: 0, .t1: 0.25, .result: 0.4973, .tol: 1.0e-4},
416 { .type: Option::Put, .strike: 90, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.1, .l: 0, .t1: 0.5, .result: 0.4632, .tol: 1.0e-4},
417 { .type: Option::Put, .strike: 90, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.1, .l: 0, .t1: 0.75, .result: 0.3863, .tol: 1.0e-4},
418
419 { .type: Option::Put, .strike: 110, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.1, .l: 0, .t1: 0.25, .result: 12.6978, .tol: 1.0e-4},
420 { .type: Option::Put, .strike: 110, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.1, .l: 0, .t1: 0.5, .result: 10.9492, .tol: 1.0e-4},
421 { .type: Option::Put, .strike: 110, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.1, .l: 0, .t1: 0.75, .result: 9.1555, .tol: 1.0e-4},
422
423 { .type: Option::Put, .strike: 90, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.2, .l: 0, .t1: 0.25, .result: 4.5863, .tol: 1.0e-4},
424 { .type: Option::Put, .strike: 90, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.2, .l: 0, .t1: 0.5, .result: 4.1925, .tol: 1.0e-4},
425 { .type: Option::Put, .strike: 90, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.2, .l: 0, .t1: 0.75, .result: 3.5831, .tol: 1.0e-4},
426
427 { .type: Option::Put, .strike: 110, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.2, .l: 0, .t1: 0.25, .result: 19.0255, .tol: 1.0e-4},
428 { .type: Option::Put, .strike: 110, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.2, .l: 0, .t1: 0.5, .result: 16.9433, .tol: 1.0e-4},
429 { .type: Option::Put, .strike: 110, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.2, .l: 0, .t1: 0.75, .result: 14.6505, .tol: 1.0e-4},
430
431 { .type: Option::Put, .strike: 90, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.3, .l: 0, .t1: 0.25, .result: 9.9348, .tol: 1.0e-4},
432 { .type: Option::Put, .strike: 90, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.3, .l: 0, .t1: 0.5, .result: 9.1111, .tol: 1.0e-4},
433 { .type: Option::Put, .strike: 90, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.3, .l: 0, .t1: 0.75, .result: 7.9267, .tol: 1.0e-4},
434
435 { .type: Option::Put, .strike: 110, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.3, .l: 0, .t1: 0.25, .result: 25.2112, .tol: 1.0e-4},
436 { .type: Option::Put, .strike: 110, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.3, .l: 0, .t1: 0.5, .result: 22.8217, .tol: 1.0e-4},
437 { .type: Option::Put, .strike: 110, .minmax: 0, .s: 100, .q: 0, .r: 0.06, .t: 1, .v: 0.3, .l: 0, .t1: 0.75, .result: 20.0566, .tol: 1.0e-4}
438 };
439
440 DayCounter dc = Actual360();
441 Date today = Date::todaysDate();
442
443 ext::shared_ptr<SimpleQuote> spot(new SimpleQuote(0.0));
444 ext::shared_ptr<SimpleQuote> qRate(new SimpleQuote(0.0));
445 ext::shared_ptr<YieldTermStructure> qTS = flatRate(today, forward: qRate, dc);
446 ext::shared_ptr<SimpleQuote> rRate(new SimpleQuote(0.0));
447 ext::shared_ptr<YieldTermStructure> rTS = flatRate(today, forward: rRate, dc);
448 ext::shared_ptr<SimpleQuote> vol(new SimpleQuote(0.0));
449 ext::shared_ptr<BlackVolTermStructure> volTS = flatVol(today, volatility: vol, dc);
450
451 for (auto& value : values) {
452 Date exDate = today + timeToDays(t: value.t);
453 ext::shared_ptr<Exercise> exercise(new EuropeanExercise(exDate));
454
455 spot->setValue(value.s);
456 qRate->setValue(value.q);
457 rRate->setValue(value.r);
458 vol->setValue(value.v);
459
460 ext::shared_ptr<StrikedTypePayoff> payoff(new PlainVanillaPayoff(value.type, value.strike));
461
462 ext::shared_ptr<BlackScholesMertonProcess> stochProcess(
463 new BlackScholesMertonProcess(
464 Handle<Quote>(spot),
465 Handle<YieldTermStructure>(qTS),
466 Handle<YieldTermStructure>(rTS),
467 Handle<BlackVolTermStructure>(volTS)));
468
469 ext::shared_ptr<PricingEngine> engine(
470 new AnalyticContinuousPartialFixedLookbackEngine(stochProcess));
471
472 Date lookbackStart = today + timeToDays(t: value.t1);
473 ContinuousPartialFixedLookbackOption option(lookbackStart,
474 payoff,
475 exercise);
476 option.setPricingEngine(engine);
477
478 Real calculated = option.NPV();
479 Real expected = value.result;
480 Real error = std::fabs(x: calculated-expected);
481 if (error > value.tol) {
482 REPORT_FAILURE_FIXED("value", values[i].minmax, payoff, exercise, value.s, value.q,
483 value.r, today, value.v, expected, calculated, error, value.tol);
484 }
485 }
486}
487
488void LookbackOptionTest::testMonteCarloLookback() {
489 BOOST_TEST_MESSAGE("Testing Monte Carlo engines for lookback options...");
490
491 Real tolerance = 0.1;
492
493 DayCounter dc = Actual360();
494 Date today = Date::todaysDate();
495
496 Real strike = 90;
497 Real t = 1;
498 Real t1= 0.25;
499
500 Date exDate = today + timeToDays(t);
501 ext::shared_ptr<Exercise> exercise(new EuropeanExercise(exDate));
502
503 ext::shared_ptr<SimpleQuote> spot(new SimpleQuote(0.0));
504 ext::shared_ptr<SimpleQuote> qRate(new SimpleQuote(0.0));
505 ext::shared_ptr<YieldTermStructure> qTS = flatRate(today, forward: qRate, dc);
506 ext::shared_ptr<SimpleQuote> rRate(new SimpleQuote(0.0));
507 ext::shared_ptr<YieldTermStructure> rTS = flatRate(today, forward: rRate, dc);
508 ext::shared_ptr<SimpleQuote> vol(new SimpleQuote(0.0));
509 ext::shared_ptr<BlackVolTermStructure> volTS = flatVol(today, volatility: vol, dc);
510
511 spot ->setValue(100);
512 qRate->setValue(0);
513 rRate->setValue(0.06);
514 vol ->setValue(0.1);
515
516 ext::shared_ptr<BlackScholesMertonProcess> stochProcess(
517 new BlackScholesMertonProcess(
518 Handle<Quote>(spot),
519 Handle<YieldTermStructure>(qTS),
520 Handle<YieldTermStructure>(rTS),
521 Handle<BlackVolTermStructure>(volTS)));
522
523 Option::Type types[] = { Option::Call, Option::Put };
524
525 for (auto type : types) {
526 ext::shared_ptr<StrikedTypePayoff> payoff(new PlainVanillaPayoff(type, strike));
527
528 /**
529 * Partial Fixed
530 * **/
531
532 Date lookbackStart = today + timeToDays(t: t1);
533 ContinuousPartialFixedLookbackOption partialFixedLookback(lookbackStart,
534 payoff,
535 exercise);
536 ext::shared_ptr<PricingEngine> engine(
537 new AnalyticContinuousPartialFixedLookbackEngine(stochProcess));
538 partialFixedLookback.setPricingEngine(engine);
539
540 Real analytical = partialFixedLookback.NPV();
541
542 ext::shared_ptr<PricingEngine> mcpartialfixedengine =
543 MakeMCLookbackEngine<ContinuousPartialFixedLookbackOption, PseudoRandom>
544 (stochProcess)
545 .withSteps(steps: 2000)
546 .withAntitheticVariate()
547 .withSeed(seed: 1)
548 .withAbsoluteTolerance(tolerance);
549
550 partialFixedLookback.setPricingEngine(mcpartialfixedengine);
551 Real monteCarlo = partialFixedLookback.NPV();
552
553 Real diff = std::abs(x: analytical - monteCarlo);
554
555 if (diff > tolerance){
556 REPORT_FAILURE_MC("Partial Fixed", type, analytical, monteCarlo, tolerance);
557 }
558
559 /**
560 * Fixed
561 * **/
562
563 Real minMax = 100;
564
565 ContinuousFixedLookbackOption fixedLookback(minMax,
566 payoff,
567 exercise);
568 ext::shared_ptr<PricingEngine> analyticalfixedengine(
569 new AnalyticContinuousFixedLookbackEngine(stochProcess));
570 fixedLookback.setPricingEngine(analyticalfixedengine);
571
572 analytical = fixedLookback.NPV();
573
574 ext::shared_ptr<PricingEngine> mcfixedengine =
575 MakeMCLookbackEngine<ContinuousFixedLookbackOption, PseudoRandom>
576 (stochProcess)
577 .withSteps(steps: 2000)
578 .withAntitheticVariate()
579 .withSeed(seed: 1)
580 .withAbsoluteTolerance(tolerance);
581
582 fixedLookback.setPricingEngine(mcfixedengine);
583 monteCarlo = fixedLookback.NPV();
584
585 diff = std::abs(x: analytical - monteCarlo);
586
587 if (diff > tolerance){
588 REPORT_FAILURE_MC("Fixed", type, analytical, monteCarlo, tolerance);
589 }
590
591 /**
592 * Partial Floating
593 * **/
594
595 Real lambda = 1;
596 Date lookbackEnd = today + timeToDays(t: t1);
597
598 ext::shared_ptr<FloatingTypePayoff> floatingPayoff(new FloatingTypePayoff(type));
599
600 ContinuousPartialFloatingLookbackOption partialFloating(minMax,
601 lambda,
602 lookbackEnd,
603 floatingPayoff,
604 exercise);
605 ext::shared_ptr<PricingEngine> analyticalpartialFloatingengine(
606 new AnalyticContinuousPartialFloatingLookbackEngine(stochProcess));
607 partialFloating.setPricingEngine(analyticalpartialFloatingengine);
608
609 analytical = partialFloating.NPV();
610
611 ext::shared_ptr<PricingEngine> mcpartialfloatingengine =
612 MakeMCLookbackEngine<ContinuousPartialFloatingLookbackOption, PseudoRandom>
613 (stochProcess)
614 .withSteps(steps: 2000)
615 .withAntitheticVariate()
616 .withSeed(seed: 1)
617 .withAbsoluteTolerance(tolerance);
618
619 partialFloating.setPricingEngine(mcpartialfloatingengine);
620 monteCarlo = partialFloating.NPV();
621
622 diff = std::abs(x: analytical - monteCarlo);
623
624 if (diff > tolerance){
625 REPORT_FAILURE_MC("Partial Floating", type, analytical, monteCarlo, tolerance);
626 }
627
628 /**
629 * Floating
630 * **/
631
632 ContinuousFloatingLookbackOption floating(minMax,
633 floatingPayoff,
634 exercise);
635 ext::shared_ptr<PricingEngine> analyticalFloatingengine(
636 new AnalyticContinuousFloatingLookbackEngine(stochProcess));
637 floating.setPricingEngine(analyticalFloatingengine);
638
639 analytical = floating.NPV();
640
641 ext::shared_ptr<PricingEngine> mcfloatingengine =
642 MakeMCLookbackEngine<ContinuousFloatingLookbackOption, PseudoRandom>
643 (stochProcess)
644 .withSteps(steps: 2000)
645 .withAntitheticVariate()
646 .withSeed(seed: 1)
647 .withAbsoluteTolerance(tolerance);
648
649 floating.setPricingEngine(mcfloatingengine);
650 monteCarlo = floating.NPV();
651
652 diff = std::abs(x: analytical - monteCarlo);
653
654 if (diff > tolerance){
655 REPORT_FAILURE_MC("Floating", type, analytical, monteCarlo, tolerance);
656 }
657 }
658}
659
660
661test_suite* LookbackOptionTest::suite(SpeedLevel speed) {
662 auto* suite = BOOST_TEST_SUITE("Lookback option tests");
663
664 suite->add(QUANTLIB_TEST_CASE(&LookbackOptionTest::testAnalyticContinuousFloatingLookback));
665 suite->add(QUANTLIB_TEST_CASE(&LookbackOptionTest::testAnalyticContinuousFixedLookback));
666 suite->add(QUANTLIB_TEST_CASE(&LookbackOptionTest::testAnalyticContinuousPartialFloatingLookback));
667 suite->add(QUANTLIB_TEST_CASE(&LookbackOptionTest::testAnalyticContinuousPartialFixedLookback));
668
669 if (speed == Slow) {
670 suite->add(QUANTLIB_TEST_CASE(&LookbackOptionTest::testMonteCarloLookback));
671 }
672
673 return suite;
674}
675
676

source code of quantlib/test-suite/lookbackoptions.cpp