[go: up one dir, main page]

1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2009 Dimitri Reiswich
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#include "compoundoption.hpp"
21#include "utilities.hpp"
22#include <ql/instruments/compoundoption.hpp>
23#include <ql/pricingengines/exotic/analyticcompoundoptionengine.hpp>
24#include <ql/instruments/europeanoption.hpp>
25#include <ql/pricingengines/vanilla/analyticeuropeanengine.hpp>
26#include <ql/time/calendars/target.hpp>
27#include <ql/time/calendars/nullcalendar.hpp>
28#include <ql/time/daycounters/actual360.hpp>
29#include <ql/quotes/simplequote.hpp>
30#include <ql/termstructures/yield/flatforward.hpp>
31#include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp>
32#include <ql/utilities/dataformatters.hpp>
33
34using namespace QuantLib;
35using namespace boost::unit_test_framework;
36
37#undef REPORT_FAILURE
38#define REPORT_FAILURE(greekName, payoffM, payoffD, exerciseM, \
39 exerciseD, s, q, r, today, \
40 v, expected, calculated, error, tolerance) \
41 BOOST_FAIL(\
42 "\nmother option type: " << payoffM->optionType() << \
43 "\ndaughter option type: " << payoffD->optionType() << \
44 "\nspot value: " << s << \
45 "\nstrike mother: " << payoffM->strike() << \
46 "\nstrike daughter: " << payoffD->strike() << \
47 "\ndividend yield: " << io::rate(q) << \
48 "\nrisk-free rate: " << io::rate(r) << \
49 "\nreference date: " << today << \
50 "\nmaturity mother: " << exerciseM->lastDate() << \
51 "\nmaturity daughter: " << exerciseD->lastDate() << \
52 "\nvolatility: " << io::volatility(v) << \
53 "\n expected " << greekName << ": " << expected << \
54 "\ncalculated " << greekName << ": " << calculated << \
55 "\nerror: " << error << \
56 "\ntolerance: " << tolerance);
57
58namespace compound_option_test {
59
60 struct CompoundOptionData {
61 Option::Type typeMother;
62 Option::Type typeDaughter;
63 Real strikeMother;
64 Real strikeDaughter;
65 Real s; // spot
66 Rate q; // dividend
67 Rate r; // risk-free rate
68 Time tMother; // time to maturity
69 Time tDaughter;// time to maturity
70 Volatility v; // volatility
71 Real npv; // expected result
72 Real tol; // tolerance
73 Real delta;
74 Real gamma;
75 Real vega;
76 Real theta;
77 };
78
79}
80
81
82void CompoundOptionTest::testPutCallParity(){
83
84 BOOST_TEST_MESSAGE("Testing compound-option put-call parity...");
85
86 using namespace compound_option_test;
87
88 // Test Put Call Parity for compound options.
89 // Formula taken from: "Foreign Exchange Risk", Wystup, Risk 2002
90 // Page 81, Equation 9.5
91
92
93 CompoundOptionData values[] = {
94 // type Mother, typeDaughter, strike Mother, strike Daughter, spot, q, r, t Mother, t Daughter, vol
95 { .typeMother: Option::Put, .typeDaughter: Option::Call, .strikeMother: 50.0, .strikeDaughter: 520.0 , .s: 500.0, .q: 0.03, .r: 0.08, .tMother: 0.25, .tDaughter: 0.5, .v: 0.35},
96 { .typeMother: Option::Call, .typeDaughter: Option::Call, .strikeMother: 50.0, .strikeDaughter: 520.0 , .s: 500.0, .q: 0.03, .r: 0.08, .tMother: 0.25, .tDaughter: 0.5, .v: 0.35},
97 { .typeMother: Option::Call, .typeDaughter: Option::Put, .strikeMother: 50.0, .strikeDaughter: 520.0 , .s: 500.0, .q: 0.03, .r: 0.08, .tMother: 0.25, .tDaughter: 0.5, .v: 0.35},
98 { .typeMother: Option::Call, .typeDaughter: Option::Call, .strikeMother: 0.05, .strikeDaughter: 1.14 , .s: 1.20, .q: 0.0, .r: 0.01, .tMother: 0.5, .tDaughter: 2.0, .v: 0.11},
99 { .typeMother: Option::Call, .typeDaughter: Option::Put , .strikeMother: 0.05, .strikeDaughter: 1.14 , .s: 1.20, .q: 0.0, .r: 0.01, .tMother: 0.5, .tDaughter: 2.0, .v: 0.11},
100 { .typeMother: Option::Call, .typeDaughter: Option::Call, .strikeMother: 10.0, .strikeDaughter: 122.0 , .s: 120.0, .q: 0.06, .r: 0.02, .tMother: 0.1, .tDaughter: 0.7, .v: 0.22},
101 { .typeMother: Option::Call, .typeDaughter: Option::Put, .strikeMother: 10.0, .strikeDaughter: 122.0 , .s: 120.0, .q: 0.06, .r: 0.02, .tMother: 0.1, .tDaughter: 0.7, .v: 0.22},
102 { .typeMother: Option::Call, .typeDaughter: Option::Call, .strikeMother: 0.4, .strikeDaughter: 8.2 , .s: 8.0, .q: 0.05, .r: 0.00, .tMother: 2.0, .tDaughter: 3.0, .v: 0.08},
103 { .typeMother: Option::Call, .typeDaughter: Option::Put, .strikeMother: 0.4, .strikeDaughter: 8.2 , .s: 8.0, .q: 0.05, .r: 0.00, .tMother: 2.0, .tDaughter: 3.0, .v: 0.08},
104 { .typeMother: Option::Call, .typeDaughter: Option::Call, .strikeMother: 0.02, .strikeDaughter: 1.6 , .s: 1.6, .q: 0.013, .r: 0.022, .tMother: 0.45, .tDaughter: 0.5, .v: 0.17},
105 { .typeMother: Option::Call, .typeDaughter: Option::Put, .strikeMother: 0.02, .strikeDaughter: 1.6 , .s: 1.6, .q: 0.013, .r: 0.022, .tMother: 0.45, .tDaughter: 0.5, .v: 0.17},
106 };
107
108 Calendar calendar = TARGET();
109
110 DayCounter dc = Actual360();
111 Date todaysDate = Settings::instance().evaluationDate();
112
113 ext::shared_ptr<SimpleQuote> spot(new SimpleQuote(0.0));
114 ext::shared_ptr<SimpleQuote> rRate(new SimpleQuote(0.0));
115 ext::shared_ptr<SimpleQuote> qRate(new SimpleQuote(0.0));
116 ext::shared_ptr<SimpleQuote> vol(new SimpleQuote(0.0));
117
118 ext::shared_ptr<YieldTermStructure> rTS(
119 new FlatForward(0, NullCalendar(), Handle<Quote>(rRate), dc));
120
121 ext::shared_ptr<YieldTermStructure> qTS(
122 new FlatForward(0, NullCalendar(), Handle<Quote>(qRate), dc));
123
124 ext::shared_ptr<BlackVolTermStructure> volTS(
125 new BlackConstantVol(todaysDate, NullCalendar(),
126 Handle<Quote>(vol), dc));
127
128 for (auto& value : values) {
129
130 ext::shared_ptr<StrikedTypePayoff> payoffMotherCall(
131 new PlainVanillaPayoff(Option::Call, value.strikeMother));
132
133 ext::shared_ptr<StrikedTypePayoff> payoffMotherPut(
134 new PlainVanillaPayoff(Option::Put, value.strikeMother));
135
136 ext::shared_ptr<StrikedTypePayoff> payoffDaughter(
137 new PlainVanillaPayoff(value.typeDaughter, value.strikeDaughter));
138
139 Date matDateMom = todaysDate + timeToDays(t: value.tMother);
140 Date matDateDaughter = todaysDate + timeToDays(t: value.tDaughter);
141
142 ext::shared_ptr<Exercise> exerciseCompound(
143 new EuropeanExercise(matDateMom));
144 ext::shared_ptr<Exercise> exerciseDaughter(
145 new EuropeanExercise(matDateDaughter));
146
147 spot->setValue(value.s);
148 qRate->setValue(value.q);
149 rRate->setValue(value.r);
150 vol->setValue(value.v);
151
152 CompoundOption compoundOptionCall(payoffMotherCall,exerciseCompound,
153 payoffDaughter, exerciseDaughter);
154
155 CompoundOption compoundOptionPut(payoffMotherPut,exerciseCompound,
156 payoffDaughter, exerciseDaughter);
157
158 VanillaOption vanillaOption(EuropeanOption(payoffDaughter,
159 exerciseDaughter));
160
161 ext::shared_ptr<BlackScholesMertonProcess> stochProcess(
162 new BlackScholesMertonProcess(
163 Handle<Quote>(spot),
164 Handle<YieldTermStructure>(qTS),
165 Handle<YieldTermStructure>(rTS),
166 Handle<BlackVolTermStructure>(volTS)));
167
168
169 ext::shared_ptr<PricingEngine> engineCompound(
170 new AnalyticCompoundOptionEngine(stochProcess));
171
172 ext::shared_ptr<PricingEngine> engineEuropean(
173 new AnalyticEuropeanEngine(stochProcess));
174
175 compoundOptionCall.setPricingEngine(engineCompound);
176 compoundOptionPut.setPricingEngine(engineCompound);
177 vanillaOption.setPricingEngine(engineEuropean);
178
179 Real discFact=rTS->discount(d: matDateMom);
180 Real discStrike = value.strikeMother * discFact;
181
182 Real calculated =
183 compoundOptionCall.NPV() + discStrike - compoundOptionPut.NPV()
184 - vanillaOption.NPV();
185
186 Real expected=0.0;
187 Real error=std::abs(x: calculated-expected);
188 Real tolerance=1.0e-8;
189
190 if(error>tolerance){
191 REPORT_FAILURE("put call parity", payoffMotherCall, payoffDaughter, exerciseCompound,
192 exerciseDaughter, value.s, value.q, value.r, todaysDate, value.v,
193 value.delta, calculated, error, tolerance);
194 }
195 }
196}
197
198void CompoundOptionTest::testValues(){
199
200 BOOST_TEST_MESSAGE("Testing compound-option values and greeks...");
201
202 using namespace compound_option_test;
203
204 CompoundOptionData values[] = {
205 // type Mother, typeDaughter, strike Mother, strike Daughter, spot, q, r, t Mother, t Daughter, vol, value, tol, delta, gamma, vega, theta
206 // Tolerance is taken to be pretty high with 1.0e-3, since the price/theta is very sensitive with respect to
207 // the implementation of the bivariate normal - which differs in the various implementations.
208 // Option Value Taken from Haug 2007, Greeks from www.sitmo.com
209 { .typeMother: Option::Put, .typeDaughter: Option::Call, .strikeMother: 50.0, .strikeDaughter: 520.0 , .s: 500.0, .q: 0.03, .r: 0.08, .tMother: 0.25, .tDaughter: 0.5, .v: 0.35, .npv: 21.1965, .tol: 1.0e-3, .delta: -0.1966,.gamma: 0.0007, .vega: -32.1241, .theta: -3.3837},
210 //*********************************************************
211 // Option Values and Greeks taken from www.sitmo.com
212 { .typeMother: Option::Call, .typeDaughter: Option::Call, .strikeMother: 50.0, .strikeDaughter: 520.0 , .s: 500.0, .q: 0.03, .r: 0.08, .tMother: 0.25, .tDaughter: 0.5, .v: 0.35, .npv: 17.5945, .tol: 1.0e-3, .delta: 0.3219,.gamma: 0.0038, .vega: 106.5185, .theta: -65.1614},
213 { .typeMother: Option::Call, .typeDaughter: Option::Put, .strikeMother: 50.0, .strikeDaughter: 520.0 , .s: 500.0, .q: 0.03, .r: 0.08, .tMother: 0.25, .tDaughter: 0.5, .v: 0.35, .npv: 18.7128, .tol: 1.0e-3, .delta: -0.2906,.gamma: 0.0036, .vega: 103.3856, .theta: -46.6982},
214 { .typeMother: Option::Put, .typeDaughter: Option::Put, .strikeMother: 50.0, .strikeDaughter: 520.0 , .s: 500.0, .q: 0.03, .r: 0.08, .tMother: 0.25, .tDaughter: 0.5, .v: 0.35, .npv: 15.2601, .tol: 1.0e-3, .delta: 0.1760,.gamma: 0.0005, .vega: -35.2570, .theta: -10.1126},
215 // type Mother, typeDaughter, strike Mother, strike Daughter, spot, q, r, t Mother, t Daughter, vol, value, tol, delta, gamma, vega, theta
216 { .typeMother: Option::Call, .typeDaughter: Option::Call, .strikeMother: 0.05, .strikeDaughter: 1.14 , .s: 1.20, .q: 0.0, .r: 0.01, .tMother: 0.5, .tDaughter: 2.0, .v: 0.11, .npv: 0.0729, .tol: 1.0e-3, .delta: 0.6614,.gamma: 2.5762, .vega: 0.5812, .theta: -0.0297},
217 { .typeMother: Option::Call, .typeDaughter: Option::Put , .strikeMother: 0.05, .strikeDaughter: 1.14 , .s: 1.20, .q: 0.0, .r: 0.01, .tMother: 0.5, .tDaughter: 2.0, .v: 0.11, .npv: 0.0074, .tol: 1.0e-3, .delta: -0.1334,.gamma: 1.9681, .vega: 0.2933, .theta: -0.0155},
218 { .typeMother: Option::Put ,.typeDaughter: Option::Call, .strikeMother: 0.05, .strikeDaughter: 1.14 , .s: 1.20, .q: 0.0, .r: 0.01, .tMother: 0.5, .tDaughter: 2.0, .v: 0.11, .npv: 0.0021, .tol: 1.0e-3, .delta: -0.0426,.gamma: 0.7252, .vega: -0.0052, .theta: -0.0058},
219 { .typeMother: Option::Put, .typeDaughter: Option::Put , .strikeMother: 0.05, .strikeDaughter: 1.14 , .s: 1.20, .q: 0.0, .r: 0.01, .tMother: 0.5, .tDaughter: 2.0, .v: 0.11, .npv: 0.0192, .tol: 1.0e-3, .delta: 0.1626,.gamma: 0.1171, .vega: -0.2931, .theta: -0.0028},
220 // type Mother, typeDaughter, strike Mother, strike Daughter, spot, q, r, t Mother, t Daughter, vol, value, tol, delta, gamma, vega, theta
221 { .typeMother: Option::Call, .typeDaughter: Option::Call, .strikeMother: 10.0, .strikeDaughter: 122.0 , .s: 120.0, .q: 0.06, .r: 0.02, .tMother: 0.1, .tDaughter: 0.7, .v: 0.22, .npv: 0.4419, .tol: 1.0e-3, .delta: 0.1049,.gamma: 0.0195, .vega: 11.3368, .theta: -6.2871},
222 { .typeMother: Option::Call, .typeDaughter: Option::Put, .strikeMother: 10.0, .strikeDaughter: 122.0 , .s: 120.0, .q: 0.06, .r: 0.02, .tMother: 0.1, .tDaughter: 0.7, .v: 0.22, .npv: 2.6112, .tol: 1.0e-3, .delta: -0.3618,.gamma: 0.0337, .vega: 28.4843, .theta: -13.4124},
223 { .typeMother: Option::Put, .typeDaughter: Option::Call, .strikeMother: 10.0, .strikeDaughter: 122.0 , .s: 120.0, .q: 0.06, .r: 0.02, .tMother: 0.1, .tDaughter: 0.7, .v: 0.22, .npv: 4.1616, .tol: 1.0e-3, .delta: -0.3174,.gamma: 0.0024, .vega: -26.6403, .theta: -2.2720},
224 { .typeMother: Option::Put, .typeDaughter: Option::Put, .strikeMother: 10.0, .strikeDaughter: 122.0 , .s: 120.0, .q: 0.06, .r: 0.02, .tMother: 0.1, .tDaughter: 0.7, .v: 0.22, .npv: 1.0914, .tol: 1.0e-3, .delta: 0.1748,.gamma: 0.0165, .vega: -9.4928, .theta: -4.8995},
225 //*********************************************************
226 //*********************************************************
227 // Option Values and Greeks taken from mathfinance VBA implementation
228 // type Mother, typeDaughter, strike Mother, strike Daughter, spot, q, r, t Mother, t Daughter, vol, value, tol, delta, gamma, vega, theta
229 { .typeMother: Option::Call, .typeDaughter: Option::Call, .strikeMother: 0.4, .strikeDaughter: 8.2 , .s: 8.0, .q: 0.05, .r: 0.00, .tMother: 2.0, .tDaughter: 3.0, .v: 0.08, .npv: 0.0099, .tol: 1.0e-3, .delta: 0.0285,.gamma: 0.0688, .vega: 0.7764, .theta: -0.0027},
230 { .typeMother: Option::Call, .typeDaughter: Option::Put, .strikeMother: 0.4, .strikeDaughter: 8.2 , .s: 8.0, .q: 0.05, .r: 0.00, .tMother: 2.0, .tDaughter: 3.0, .v: 0.08, .npv: 0.9826, .tol: 1.0e-3, .delta: -0.7224,.gamma: 0.2158, .vega: 2.7279, .theta: -0.3332},
231 { .typeMother: Option::Put, .typeDaughter: Option::Call, .strikeMother: 0.4, .strikeDaughter: 8.2 , .s: 8.0, .q: 0.05, .r: 0.00, .tMother: 2.0, .tDaughter: 3.0, .v: 0.08, .npv: 0.3585, .tol: 1.0e-3, .delta: -0.0720,.gamma: -0.0835, .vega: -1.5633, .theta: -0.0117},
232 { .typeMother: Option::Put, .typeDaughter: Option::Put, .strikeMother: 0.4, .strikeDaughter: 8.2 , .s: 8.0, .q: 0.05, .r: 0.00, .tMother: 2.0, .tDaughter: 3.0, .v: 0.08, .npv: 0.0168, .tol: 1.0e-3, .delta: 0.0378, .gamma: 0.0635, .vega: 0.3882, .theta: 0.0021},
233 // type Mother, typeDaughter, strike Mother, strike Daughter, spot, q, r, t Mother, t Daughter, vol, value, tol, delta, gamma, vega, theta
234 { .typeMother: Option::Call, .typeDaughter: Option::Call, .strikeMother: 0.02, .strikeDaughter: 1.6 , .s: 1.6, .q: 0.013, .r: 0.022, .tMother: 0.45, .tDaughter: 0.5, .v: 0.17, .npv: 0.0680, .tol: 1.0e-3, .delta: 0.4937,.gamma: 2.1271, .vega: 0.4418, .theta: -0.0843},
235 { .typeMother: Option::Call, .typeDaughter: Option::Put, .strikeMother: 0.02, .strikeDaughter: 1.6 , .s: 1.6, .q: 0.013, .r: 0.022, .tMother: 0.45, .tDaughter: 0.5, .v: 0.17, .npv: 0.0605, .tol: 1.0e-3, .delta: -0.4169,.gamma: 2.0836, .vega: 0.4330, .theta: -0.0697},
236 { .typeMother: Option::Put, .typeDaughter: Option::Call, .strikeMother: 0.02, .strikeDaughter: 1.6 , .s: 1.6, .q: 0.013, .r: 0.022, .tMother: 0.45, .tDaughter: 0.5, .v: 0.17, .npv: 0.0081, .tol: 1.0e-3, .delta: -0.0417,.gamma: 0.0761, .vega: -0.0045, .theta: -0.0020},
237 { .typeMother: Option::Put, .typeDaughter: Option::Put, .strikeMother: 0.02, .strikeDaughter: 1.6 , .s: 1.6, .q: 0.013, .r: 0.022, .tMother: 0.45, .tDaughter: 0.5, .v: 0.17, .npv: 0.0078, .tol: 1.0e-3, .delta: 0.0413,.gamma: 0.0326, .vega: -0.0133, .theta: -0.0016}
238 };
239
240 Calendar calendar = TARGET();
241
242 DayCounter dc = Actual360();
243 Date todaysDate = Settings::instance().evaluationDate();
244
245 ext::shared_ptr<SimpleQuote> spot(new SimpleQuote(0.0));
246 ext::shared_ptr<SimpleQuote> rRate(new SimpleQuote(0.0));
247 ext::shared_ptr<SimpleQuote> qRate(new SimpleQuote(0.0));
248 ext::shared_ptr<SimpleQuote> vol(new SimpleQuote(0.0));
249
250 ext::shared_ptr<YieldTermStructure> rTS(
251 new FlatForward(0, NullCalendar(), Handle<Quote>(rRate), dc));
252
253 ext::shared_ptr<YieldTermStructure> qTS(
254 new FlatForward(0, NullCalendar(), Handle<Quote>(qRate), dc));
255
256 ext::shared_ptr<BlackVolTermStructure> volTS(
257 new BlackConstantVol(todaysDate, NullCalendar(),
258 Handle<Quote>(vol), dc));
259
260 for (auto& value : values) {
261
262 ext::shared_ptr<StrikedTypePayoff> payoffMother(
263 new PlainVanillaPayoff(value.typeMother, value.strikeMother));
264
265 ext::shared_ptr<StrikedTypePayoff> payoffDaughter(
266 new PlainVanillaPayoff(value.typeDaughter, value.strikeDaughter));
267
268 Date matDateMom = todaysDate + timeToDays(t: value.tMother);
269 Date matDateDaughter = todaysDate + timeToDays(t: value.tDaughter);
270
271 ext::shared_ptr<Exercise> exerciseMother(
272 new EuropeanExercise(matDateMom));
273 ext::shared_ptr<Exercise> exerciseDaughter(
274 new EuropeanExercise(matDateDaughter));
275
276 spot->setValue(value.s);
277 qRate->setValue(value.q);
278 rRate->setValue(value.r);
279 vol->setValue(value.v);
280
281 CompoundOption compoundOption(payoffMother,exerciseMother,
282 payoffDaughter, exerciseDaughter);
283
284 ext::shared_ptr<BlackScholesMertonProcess> stochProcess(
285 new BlackScholesMertonProcess(
286 Handle<Quote>(spot),
287 Handle<YieldTermStructure>(qTS),
288 Handle<YieldTermStructure>(rTS),
289 Handle<BlackVolTermStructure>(volTS)));
290
291 ext::shared_ptr<PricingEngine> engineCompound(
292 new AnalyticCompoundOptionEngine(stochProcess));
293
294 compoundOption.setPricingEngine(engineCompound);
295
296 Real calculated = compoundOption.NPV();
297 Real error = std::fabs(x: calculated - value.npv); //-values[i].npv
298 Real tolerance = value.tol;
299
300 if (error>tolerance) {
301 REPORT_FAILURE("value", payoffMother, payoffDaughter, exerciseMother, exerciseDaughter,
302 value.s, value.q, value.r, todaysDate, value.v, value.npv, calculated,
303 error, tolerance);
304 }
305
306 calculated = compoundOption.delta();
307 error = std::fabs(x: calculated - value.delta);
308 tolerance = value.tol;
309
310 if (error>tolerance) {
311 REPORT_FAILURE("delta", payoffMother, payoffDaughter, exerciseMother, exerciseDaughter,
312 value.s, value.q, value.r, todaysDate, value.v, value.delta, calculated,
313 error, tolerance);
314 }
315
316 calculated = compoundOption.gamma();
317 error = std::fabs(x: calculated - value.gamma);
318 tolerance = value.tol;
319
320 if (error>tolerance) {
321 REPORT_FAILURE("gamma", payoffMother, payoffDaughter, exerciseMother, exerciseDaughter,
322 value.s, value.q, value.r, todaysDate, value.v, value.gamma, calculated,
323 error, tolerance);
324 }
325
326 calculated = compoundOption.vega();
327 error = std::fabs(x: calculated - value.vega);
328 tolerance = value.tol;
329
330 if (error>tolerance) {
331 REPORT_FAILURE("vega", payoffMother, payoffDaughter, exerciseMother, exerciseDaughter,
332 value.s, value.q, value.r, todaysDate, value.v, value.vega, calculated,
333 error, tolerance);
334 }
335
336 calculated = compoundOption.theta();
337 error = std::fabs(x: calculated - value.theta);
338 tolerance = value.tol;
339
340 if (error>tolerance) {
341 REPORT_FAILURE("theta", payoffMother, payoffDaughter, exerciseMother, exerciseDaughter,
342 value.s, value.q, value.r, todaysDate, value.v, value.theta, calculated,
343 error, tolerance);
344 }
345 }
346}
347
348
349test_suite* CompoundOptionTest::suite() {
350 auto* suite = BOOST_TEST_SUITE("Compound option tests");
351
352 suite->add(QUANTLIB_TEST_CASE(&CompoundOptionTest::testValues));
353 suite->add(QUANTLIB_TEST_CASE(&CompoundOptionTest::testPutCallParity));
354
355 return suite;
356}
357
358
359

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