1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2006, 2008 Ferdinando Ametrano
5 Copyright (C) 2006 François du Vignaud
6 Copyright (C) 2007 Cristina Duminuco
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 "swaptionvolatilitymatrix.hpp"
23#include "swaptionvolstructuresutilities.hpp"
24#include "utilities.hpp"
25#include <ql/utilities/dataformatters.hpp>
26#include <ql/indexes/swap/euriborswap.hpp>
27#include <ql/instruments/makeswaption.hpp>
28#include <ql/pricingengines/swaption/blackswaptionengine.hpp>
29#include <ql/termstructures/yield/flatforward.hpp>
30#include <ql/math/comparison.hpp>
31#include <string>
32
33using namespace QuantLib;
34using namespace boost::unit_test_framework;
35
36namespace swaption_volatility_matrix_test {
37
38 struct CommonVars {
39 // global data
40 Date referenceDate;
41 SwaptionMarketConventions conventions;
42 AtmVolatility atm;
43 RelinkableHandle<YieldTermStructure> termStructure;
44 RelinkableHandle<SwaptionVolatilityStructure> atmVolMatrix;
45 Real tolerance;
46
47 // setup
48 CommonVars() {
49 conventions.setConventions();
50 atm.setMarketData();
51 Settings::instance().evaluationDate() =
52 conventions.calendar.adjust(Date::todaysDate());
53 atmVolMatrix = RelinkableHandle<SwaptionVolatilityStructure>(
54 ext::shared_ptr<SwaptionVolatilityStructure>(new
55 SwaptionVolatilityMatrix(conventions.calendar,
56 conventions.optionBdc,
57 atm.tenors.options,
58 atm.tenors.swaps,
59 atm.volsHandle,
60 conventions.dayCounter)));
61 termStructure.linkTo(
62 h: ext::shared_ptr<YieldTermStructure>(new
63 FlatForward(0, conventions.calendar,
64 0.05, Actual365Fixed())));
65 }
66
67 // utilities
68 void makeObservabilityTest(
69 const std::string& description,
70 const ext::shared_ptr<SwaptionVolatilityStructure>& vol,
71 bool mktDataFloating,
72 bool referenceDateFloating) {
73 Rate dummyStrike = .02;
74 Date referenceDate = Settings::instance().evaluationDate();
75 Volatility initialVol = vol->volatility(
76 optionDate: referenceDate + atm.tenors.options[0],
77 swapTenor: atm.tenors.swaps[0], strike: dummyStrike, extrapolate: false);
78 // testing evaluation date change ...
79 Settings::instance().evaluationDate() =
80 referenceDate - Period(1, Years);
81 Volatility newVol = vol->volatility(
82 optionDate: referenceDate + atm.tenors.options[0],
83 swapTenor: atm.tenors.swaps[0], strike: dummyStrike, extrapolate: false);
84 Settings::instance().evaluationDate() = referenceDate;
85 if (referenceDateFloating && (initialVol == newVol))
86 BOOST_ERROR(description <<
87 " the volatility should change when the reference date is changed !");
88 if (!referenceDateFloating && (initialVol != newVol))
89 BOOST_ERROR(description <<
90 " the volatility should not change when the reference date is changed !");
91
92 // test market data change...
93 if (mktDataFloating){
94 Volatility initialVolatility = atm.volsHandle[0][0]->value();
95 ext::dynamic_pointer_cast<SimpleQuote>(
96 r: atm.volsHandle[0][0].currentLink())->setValue(10);
97 newVol = vol->volatility(
98 optionDate: referenceDate + atm.tenors.options[0],
99 swapTenor: atm.tenors.swaps[0], strike: dummyStrike, extrapolate: false);
100 ext::dynamic_pointer_cast<SimpleQuote>(
101 r: atm.volsHandle[0][0].currentLink())
102 ->setValue(initialVolatility);
103 if (initialVol == newVol)
104 BOOST_ERROR(description << " the volatility should change when"
105 " the market data is changed !");
106 }
107 }
108
109 void makeCoherenceTest(
110 const std::string& description,
111 const ext::shared_ptr<SwaptionVolatilityDiscrete>& vol) {
112
113 for (Size i=0; i<atm.tenors.options.size(); ++i) {
114 Date optionDate =
115 vol->optionDateFromTenor(p: atm.tenors.options[i]);
116 if (optionDate!=vol->optionDates()[i])
117 BOOST_FAIL(
118 "optionDateFromTenor failure for " <<
119 description << ":"
120 "\n option tenor: " << atm.tenors.options[i] <<
121 "\nactual option date : " << optionDate <<
122 "\n exp. option date : " << vol->optionDates()[i]);
123 Time optionTime = vol->timeFromReference(d: optionDate);
124 if (!close(x: optionTime,y: vol->optionTimes()[i]))
125 BOOST_FAIL(
126 "timeFromReference failure for " <<
127 description << ":"
128 "\n option tenor: " << atm.tenors.options[i] <<
129 "\n option date : " << optionDate <<
130 "\nactual option time : " << optionTime <<
131 "\n exp. option time : " << vol->optionTimes()[i]);
132 }
133
134 ext::shared_ptr<BlackSwaptionEngine> engine(new
135 BlackSwaptionEngine(termStructure,
136 Handle<SwaptionVolatilityStructure>(vol)));
137
138 for (Size j=0; j<atm.tenors.swaps.size(); j++) {
139 Time swapLength = vol->swapLength(swapTenor: atm.tenors.swaps[j]);
140 if (!close(x: swapLength,y: years(atm.tenors.swaps[j])))
141 BOOST_FAIL("convertSwapTenor failure for " <<
142 description << ":"
143 "\n swap tenor : " << atm.tenors.swaps[j] <<
144 "\n actual swap length: " << swapLength <<
145 "\n exp. swap length: " << years(atm.tenors.swaps[j]));
146
147 ext::shared_ptr<SwapIndex> swapIndex(new
148 EuriborSwapIsdaFixA(atm.tenors.swaps[j], termStructure));
149
150 for (Size i=0; i<atm.tenors.options.size(); ++i) {
151 Real error, tolerance = 1.0e-16;
152 Volatility actVol, expVol = atm.vols[i][j];
153
154 actVol = vol->volatility(optionTenor: atm.tenors.options[i],
155 swapTenor: atm.tenors.swaps[j], strike: 0.05, extrapolate: true);
156 error = std::abs(x: expVol-actVol);
157 if (error>tolerance)
158 BOOST_FAIL(
159 "recovery of atm vols failed for " <<
160 description << ":"
161 "\noption tenor = " << atm.tenors.options[i] <<
162 "\n swap length = " << atm.tenors.swaps[j] <<
163 "\nexpected vol = " << io::volatility(expVol) <<
164 "\n actual vol = " << io::volatility(actVol) <<
165 "\n error = " << io::volatility(error) <<
166 "\n tolerance = " << tolerance);
167
168 Date optionDate =
169 vol->optionDateFromTenor(p: atm.tenors.options[i]);
170 actVol = vol->volatility(optionDate,
171 swapTenor: atm.tenors.swaps[j], strike: 0.05, extrapolate: true);
172 error = std::abs(x: expVol-actVol);
173 if (error>tolerance)
174 BOOST_FAIL(
175 "recovery of atm vols failed for " <<
176 description << ":"
177 "\noption tenor: " << atm.tenors.options[i] <<
178 "\noption date : " << optionDate <<
179 "\n swap tenor: " << atm.tenors.swaps[j] <<
180 "\n exp. vol: " << io::volatility(expVol) <<
181 "\n actual vol: " << io::volatility(actVol) <<
182 "\n error: " << io::volatility(error) <<
183 "\n tolerance: " << tolerance);
184
185 Time optionTime = vol->timeFromReference(d: optionDate);
186 actVol = vol->volatility(optionTime, swapLength,
187 strike: 0.05, extrapolate: true);
188 error = std::abs(x: expVol-actVol);
189 if (error>tolerance)
190 BOOST_FAIL(
191 "recovery of atm vols failed for " <<
192 description << ":"
193 "\noption tenor: " << atm.tenors.options[i] <<
194 "\noption time : " << optionTime <<
195 "\n swap tenor: " << atm.tenors.swaps[j] <<
196 "\n swap length: " << swapLength <<
197 "\n exp. vol: " << io::volatility(expVol) <<
198 "\n actual vol: " << io::volatility(actVol) <<
199 "\n error: " << io::volatility(error) <<
200 "\n tolerance: " << tolerance);
201
202 // ATM swaption
203 Swaption swaption =
204 MakeSwaption(swapIndex, atm.tenors.options[i])
205 .withPricingEngine(engine);
206
207 Date exerciseDate = swaption.exercise()->dates().front();
208 if (exerciseDate!=vol->optionDates()[i])
209 BOOST_FAIL(
210 "\noptionDateFromTenor mismatch for " <<
211 description << ":"
212 "\n option tenor: " << atm.tenors.options[i] <<
213 "\nactual option date: " << exerciseDate <<
214 "\n exp. option date: " << vol->optionDates()[i]);
215
216 Date start = swaption.underlyingSwap()->startDate();
217 Date end = swaption.underlyingSwap()->maturityDate();
218 Time swapLength2 = vol->swapLength(start, end);
219 if (!close(x: swapLength2,y: swapLength))
220 BOOST_FAIL("\nswapLength failure for " <<
221 description << ":"
222 "\n exp. swap length: " << swapLength <<
223 "\n actual swap length: " << swapLength2 <<
224 "\n swap tenor : " << atm.tenors.swaps[j] <<
225 "\n swap index tenor : " << swapIndex->tenor() <<
226 "\n option date: " << exerciseDate <<
227 "\n start date: " << start <<
228 "\n maturity date: " << end
229 );
230
231 Real npv = swaption.NPV();
232 actVol = swaption.impliedVolatility(price: npv, discountCurve: termStructure,
233 guess: expVol*0.98, accuracy: 1e-6,
234 maxEvaluations: 100, minVol: 10.0e-7, maxVol: 4.0,
235 type: ShiftedLognormal, displacement: 0.0);
236 error = std::abs(x: expVol-actVol);
237 Real tolerance2 = 0.000001;
238 if (error>tolerance2)
239 BOOST_FAIL(
240 "recovery of atm vols through BlackSwaptionEngine failed for " <<
241 description << ":"
242 "\noption tenor: " << atm.tenors.options[i] <<
243 "\noption time : " << optionTime <<
244 "\n swap tenor: " << atm.tenors.swaps[j] <<
245 "\n swap length: " << swapLength <<
246 "\n exp. vol: " << io::volatility(expVol) <<
247 "\n actual vol: " << io::volatility(actVol) <<
248 "\n error: " << io::volatility(error) <<
249 "\n tolerance: " << tolerance2);
250 }
251 }
252 }
253 };
254
255}
256
257
258void SwaptionVolatilityMatrixTest::testSwaptionVolMatrixObservability() {
259
260 BOOST_TEST_MESSAGE("Testing swaption volatility matrix observability...");
261
262 using namespace swaption_volatility_matrix_test;
263
264 CommonVars vars;
265
266 ext::shared_ptr<SwaptionVolatilityMatrix> vol;
267 std::string description;
268
269 //floating reference date, floating market data
270 description = "floating reference date, floating market data";
271 vol = ext::make_shared<SwaptionVolatilityMatrix>(args&: vars.conventions.calendar,
272 args&: vars.conventions.optionBdc,
273 args&: vars.atm.tenors.options,
274 args&: vars.atm.tenors.swaps,
275 args&: vars.atm.volsHandle,
276 args&: vars.conventions.dayCounter);
277 vars.makeObservabilityTest(description, vol, mktDataFloating: true, referenceDateFloating: true);
278
279 //fixed reference date, floating market data
280 description = "fixed reference date, floating market data";
281 vol = ext::make_shared<SwaptionVolatilityMatrix>(args&: Settings::instance().evaluationDate(),
282 args&: vars.conventions.calendar,
283 args&: vars.conventions.optionBdc,
284 args&: vars.atm.tenors.options,
285 args&: vars.atm.tenors.swaps,
286 args&: vars.atm.volsHandle,
287 args&: vars.conventions.dayCounter);
288 vars.makeObservabilityTest(description, vol, mktDataFloating: true, referenceDateFloating: false);
289
290 // floating reference date, fixed market data
291 description = "floating reference date, fixed market data";
292 vol = ext::make_shared<SwaptionVolatilityMatrix>(args&: vars.conventions.calendar,
293 args&: vars.conventions.optionBdc,
294 args&: vars.atm.tenors.options,
295 args&: vars.atm.tenors.swaps,
296 args&: vars.atm.volsHandle,
297 args&: vars.conventions.dayCounter);
298 vars.makeObservabilityTest(description, vol, mktDataFloating: false, referenceDateFloating: true);
299
300 // fixed reference date, fixed market data
301 description = "fixed reference date, fixed market data";
302 vol = ext::make_shared<SwaptionVolatilityMatrix>(args&: Settings::instance().evaluationDate(),
303 args&: vars.conventions.calendar,
304 args&: vars.conventions.optionBdc,
305 args&: vars.atm.tenors.options,
306 args&: vars.atm.tenors.swaps,
307 args&: vars.atm.volsHandle,
308 args&: vars.conventions.dayCounter);
309 vars.makeObservabilityTest(description, vol, mktDataFloating: false, referenceDateFloating: false);
310
311 // fixed reference date and fixed market data, option dates
312 //SwaptionVolatilityMatrix(const Date& referenceDate,
313 // const std::vector<Date>& exerciseDates,
314 // const std::vector<Period>& swapTenors,
315 // const Matrix& volatilities,
316 // const DayCounter& dayCounter);
317}
318
319
320void SwaptionVolatilityMatrixTest::testSwaptionVolMatrixCoherence() {
321
322 BOOST_TEST_MESSAGE("Testing swaption volatility matrix...");
323
324 using namespace swaption_volatility_matrix_test;
325
326 CommonVars vars;
327
328 ext::shared_ptr<SwaptionVolatilityMatrix> vol;
329 std::string description;
330
331 //floating reference date, floating market data
332 description = "floating reference date, floating market data";
333 vol = ext::make_shared<SwaptionVolatilityMatrix>(args&: vars.conventions.calendar,
334 args&: vars.conventions.optionBdc,
335 args&: vars.atm.tenors.options,
336 args&: vars.atm.tenors.swaps,
337 args&: vars.atm.volsHandle,
338 args&: vars.conventions.dayCounter);
339 vars.makeCoherenceTest(description, vol);
340
341 //fixed reference date, floating market data
342 description = "fixed reference date, floating market data";
343 vol = ext::make_shared<SwaptionVolatilityMatrix>(args&: Settings::instance().evaluationDate(),
344 args&: vars.conventions.calendar,
345 args&: vars.conventions.optionBdc,
346 args&: vars.atm.tenors.options,
347 args&: vars.atm.tenors.swaps,
348 args&: vars.atm.volsHandle,
349 args&: vars.conventions.dayCounter);
350 vars.makeCoherenceTest(description, vol);
351
352 // floating reference date, fixed market data
353 description = "floating reference date, fixed market data";
354 vol = ext::make_shared<SwaptionVolatilityMatrix>(args&: vars.conventions.calendar,
355 args&: vars.conventions.optionBdc,
356 args&: vars.atm.tenors.options,
357 args&: vars.atm.tenors.swaps,
358 args&: vars.atm.volsHandle,
359 args&: vars.conventions.dayCounter);
360 vars.makeCoherenceTest(description, vol);
361
362 // fixed reference date, fixed market data
363 description = "fixed reference date, fixed market data";
364 vol = ext::make_shared<SwaptionVolatilityMatrix>(args&: Settings::instance().evaluationDate(),
365 args&: vars.conventions.calendar,
366 args&: vars.conventions.optionBdc,
367 args&: vars.atm.tenors.options,
368 args&: vars.atm.tenors.swaps,
369 args&: vars.atm.volsHandle,
370 args&: vars.conventions.dayCounter);
371 vars.makeCoherenceTest(description, vol);
372}
373
374test_suite* SwaptionVolatilityMatrixTest::suite() {
375 auto* suite = BOOST_TEST_SUITE("Swaption Volatility Matrix tests");
376
377 suite->add(QUANTLIB_TEST_CASE(
378 &SwaptionVolatilityMatrixTest::testSwaptionVolMatrixCoherence));
379
380 suite->add(QUANTLIB_TEST_CASE(
381 &SwaptionVolatilityMatrixTest::testSwaptionVolMatrixObservability));
382
383 return suite;
384}
385

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

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