Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
Functions
swaptionvolatilityconverter.cpp File Reference
#include "swaptionmarketdata.hpp"
#include "toplevelfixture.hpp"
#include "yieldcurvemarketdata.hpp"
#include <boost/test/unit_test.hpp>
#include <qle/termstructures/swaptionvolatilityconverter.hpp>
#include <qle/termstructures/swaptionvolcube2.hpp>
#include <ql/indexes/swap/euriborswap.hpp>
#include <ql/pricingengines/blackformula.hpp>
#include <boost/assign/list_of.hpp>

Go to the source code of this file.

Functions

 BOOST_AUTO_TEST_CASE (testNormalToLognormal)
 
 BOOST_AUTO_TEST_CASE (testLognormalToNormal)
 
 BOOST_AUTO_TEST_CASE (testNormalToShiftedLognormal)
 
 BOOST_AUTO_TEST_CASE (testShiftedLognormalToShiftedLognormal)
 
 BOOST_AUTO_TEST_CASE (testShiftedLognormalToNormal)
 
 BOOST_AUTO_TEST_CASE (testFailureImplyingVol)
 
 BOOST_AUTO_TEST_CASE (testNormalShiftsIgnored)
 
 BOOST_AUTO_TEST_CASE (testConstructionFromSwapIndex)
 
 BOOST_AUTO_TEST_CASE (testConstructionFromSwapIndexNoDiscount)
 
 BOOST_AUTO_TEST_CASE (testCube)
 

Function Documentation

◆ BOOST_AUTO_TEST_CASE() [1/10]

BOOST_AUTO_TEST_CASE ( testNormalToLognormal  )

Definition at line 90 of file swaptionvolatilityconverter.cpp.

90 {
91 BOOST_TEST_MESSAGE("Testing conversion of swaption vols from normal to lognormal...");
92
93 CommonVars vars;
94
95 // Tolerance used in boost check
96 Real tolerance = 0.00001;
97
98 // Set up the converter (Normal -> Lognormal with no shifts)
99 SwaptionVolatilityConverter converter(vars.referenceDate, vars.atmNormalVolMatrix, vars.yieldCurves.discountEonia,
100 vars.yieldCurves.discountEonia, vars.swapConventions, vars.swapConventions,
101 1 * Years, 30 * Years, ShiftedLognormal);
102
103 // Get back converted volatility structure and test result on pillar points
104 QuantLib::ext::shared_ptr<SwaptionVolatilityStructure> convertedsvs = converter.convert();
105 Volatility targetVol = 0.0;
106 Volatility outVol = 0.0;
107 Real dummyStrike = 0.0;
108 for (Size i = 0; i < vars.atmVols.optionTenors.size(); ++i) {
109 for (Size j = 0; j < vars.atmVols.swapTenors.size(); ++j) {
110 Period optionTenor = vars.atmVols.optionTenors[i];
111 Period swapTenor = vars.atmVols.swapTenors[j];
112 targetVol = vars.atmVols.lnVols[i][j];
113 outVol = convertedsvs->volatility(optionTenor, swapTenor, dummyStrike);
114 BOOST_CHECK_SMALL(outVol - targetVol, tolerance);
115 }
116 }
117}
Class that converts a supplied SwaptionVolatilityStructure to one of another type with possibly diffe...
+ Here is the call graph for this function:

◆ BOOST_AUTO_TEST_CASE() [2/10]

BOOST_AUTO_TEST_CASE ( testLognormalToNormal  )

Definition at line 119 of file swaptionvolatilityconverter.cpp.

119 {
120 BOOST_TEST_MESSAGE("Testing conversion of swaption vols from lognormal to normal...");
121
122 CommonVars vars;
123
124 // Tolerance used in boost check
125 Real tolerance = 0.00001;
126
127 // Set up the converter (Lognormal with no shifts -> Normal)
128 SwaptionVolatilityConverter converter(vars.referenceDate, vars.atmLogNormalVolMatrix,
129 vars.yieldCurves.discountEonia, vars.yieldCurves.discountEonia,
130 vars.swapConventions, vars.swapConventions, 1 * Years, 30 * Years, Normal);
131
132 // Get back converted volatility structure and test result on pillar points
133 QuantLib::ext::shared_ptr<SwaptionVolatilityStructure> convertedsvs = converter.convert();
134 Volatility targetVol = 0.0;
135 Volatility outVol = 0.0;
136 Real dummyStrike = 0.0;
137 for (Size i = 0; i < vars.atmVols.optionTenors.size(); ++i) {
138 for (Size j = 0; j < vars.atmVols.swapTenors.size(); ++j) {
139 Period optionTenor = vars.atmVols.optionTenors[i];
140 Period swapTenor = vars.atmVols.swapTenors[j];
141 targetVol = vars.atmVols.nVols[i][j];
142 outVol = convertedsvs->volatility(optionTenor, swapTenor, dummyStrike);
143 BOOST_CHECK_SMALL(outVol - targetVol, tolerance);
144 }
145 }
146}
+ Here is the call graph for this function:

◆ BOOST_AUTO_TEST_CASE() [3/10]

BOOST_AUTO_TEST_CASE ( testNormalToShiftedLognormal  )

Definition at line 148 of file swaptionvolatilityconverter.cpp.

148 {
149 BOOST_TEST_MESSAGE("Testing conversion of swaption vols from normal to shifted lognormal...");
150
151 CommonVars vars;
152
153 // Tolerance used in boost check
154 Real tolerance = 0.00001;
155
156 // Set up the converter (Normal -> Shifted Lognormal with shift set 1)
157 SwaptionVolatilityConverter converter(vars.referenceDate, vars.atmNormalVolMatrix, vars.yieldCurves.discountEonia,
158 vars.yieldCurves.discountEonia, vars.swapConventions, vars.swapConventions,
159 1 * Years, 30 * Years, ShiftedLognormal, vars.atmVols.shifts_1);
160
161 // Get back converted volatility structure and test result on pillar points
162 QuantLib::ext::shared_ptr<SwaptionVolatilityStructure> convertedsvs = converter.convert();
163 Volatility targetVol = 0.0;
164 Volatility outVol = 0.0;
165 Real dummyStrike = 0.0;
166 for (Size i = 0; i < vars.atmVols.optionTenors.size(); ++i) {
167 for (Size j = 0; j < vars.atmVols.swapTenors.size(); ++j) {
168 Period optionTenor = vars.atmVols.optionTenors[i];
169 Period swapTenor = vars.atmVols.swapTenors[j];
170 targetVol = vars.atmVols.slnVols_1[i][j];
171 outVol = convertedsvs->volatility(optionTenor, swapTenor, dummyStrike);
172 BOOST_CHECK_SMALL(outVol - targetVol, tolerance);
173 }
174 }
175}
+ Here is the call graph for this function:

◆ BOOST_AUTO_TEST_CASE() [4/10]

BOOST_AUTO_TEST_CASE ( testShiftedLognormalToShiftedLognormal  )

Definition at line 177 of file swaptionvolatilityconverter.cpp.

177 {
178 BOOST_TEST_MESSAGE("Testing conversion of swaption vols from shifted lognormal to shifted lognormal...");
179
180 CommonVars vars;
181
182 // Tolerance used in boost check
183 Real tolerance = 0.00001;
184
185 // Set up the converter (Normal -> Shifted Lognormal with shift set 1)
186 SwaptionVolatilityConverter converter(vars.referenceDate, vars.atmShiftedLogNormalVolMatrix_1,
187 vars.yieldCurves.discountEonia, vars.yieldCurves.discountEonia,
188 vars.swapConventions, vars.swapConventions, 1 * Years, 30 * Years,
189 ShiftedLognormal, vars.atmVols.shifts_2);
190
191 // Get back converted volatility structure and test result on pillar points
192 QuantLib::ext::shared_ptr<SwaptionVolatilityStructure> convertedsvs = converter.convert();
193 Volatility targetVol = 0.0;
194 Volatility outVol = 0.0;
195 Real dummyStrike = 0.0;
196 for (Size i = 0; i < vars.atmVols.optionTenors.size(); ++i) {
197 for (Size j = 0; j < vars.atmVols.swapTenors.size(); ++j) {
198 Period optionTenor = vars.atmVols.optionTenors[i];
199 Period swapTenor = vars.atmVols.swapTenors[j];
200 targetVol = vars.atmVols.slnVols_2[i][j];
201 outVol = convertedsvs->volatility(optionTenor, swapTenor, dummyStrike);
202 BOOST_CHECK_SMALL(outVol - targetVol, tolerance);
203 }
204 }
205}
+ Here is the call graph for this function:

◆ BOOST_AUTO_TEST_CASE() [5/10]

BOOST_AUTO_TEST_CASE ( testShiftedLognormalToNormal  )

Definition at line 207 of file swaptionvolatilityconverter.cpp.

207 {
208 BOOST_TEST_MESSAGE("Testing conversion of swaption vols from shifted lognormal to normal...");
209
210 CommonVars vars;
211
212 // Tolerance used in boost check
213 Real tolerance = 0.00001;
214
215 // Set up the converter (Shifted Lognormal with shift set 2 -> Normal)
216 SwaptionVolatilityConverter converter(vars.referenceDate, vars.atmShiftedLogNormalVolMatrix_2,
217 vars.yieldCurves.discountEonia, vars.yieldCurves.discountEonia,
218 vars.swapConventions, vars.swapConventions, 1 * Years, 30 * Years, Normal);
219
220 // Get back converted volatility structure and test result on pillar points
221 QuantLib::ext::shared_ptr<SwaptionVolatilityStructure> convertedsvs = converter.convert();
222 Volatility targetVol = 0.0;
223 Volatility outVol = 0.0;
224 Real dummyStrike = 0.0;
225 for (Size i = 0; i < vars.atmVols.optionTenors.size(); ++i) {
226 for (Size j = 0; j < vars.atmVols.swapTenors.size(); ++j) {
227 Period optionTenor = vars.atmVols.optionTenors[i];
228 Period swapTenor = vars.atmVols.swapTenors[j];
229 targetVol = vars.atmVols.nVols[i][j];
230 outVol = convertedsvs->volatility(optionTenor, swapTenor, dummyStrike);
231 BOOST_CHECK_SMALL(outVol - targetVol, tolerance);
232 }
233 }
234}
+ Here is the call graph for this function:

◆ BOOST_AUTO_TEST_CASE() [6/10]

BOOST_AUTO_TEST_CASE ( testFailureImplyingVol  )

Definition at line 236 of file swaptionvolatilityconverter.cpp.

236 {
237 BOOST_TEST_MESSAGE("Testing failure to imply lognormal vol from normal vol...");
238
239 CommonVars vars;
240
241 // Normal volatility matrix where we cannot imply lognormal vol at 3M x 1Y point
242 vector<Period> optionTenors = list_of(Period(3, Months))(Period(1, Years));
243 vector<Period> swapTenors = list_of(Period(1, Years))(Period(5, Years));
244 Matrix normalVols(2, 2);
245 normalVols[0][0] = 0.003340;
246 normalVols[0][1] = 0.004973;
247 normalVols[1][0] = 0.003543;
248 normalVols[1][1] = 0.005270;
249
250 QuantLib::ext::shared_ptr<SwaptionVolatilityStructure> volMatrix = QuantLib::ext::make_shared<SwaptionVolatilityMatrix>(
251 vars.referenceDate, vars.conventions.fixedCalendar, vars.conventions.fixedConvention, optionTenors, swapTenors,
252 normalVols, Actual365Fixed(), true, Normal);
253
254 // Set up the converter (Normal -> Lognormal)
255 SwaptionVolatilityConverter converter(vars.referenceDate, volMatrix, vars.yieldCurves.discountEonia,
256 vars.yieldCurves.discountEonia, vars.swapConventions, vars.swapConventions,
257 1 * Years, 30 * Years, ShiftedLognormal);
258
259 // We expect the conversion to fail
260 BOOST_CHECK_THROW(converter.convert(), QuantLib::Error);
261}
+ Here is the call graph for this function:

◆ BOOST_AUTO_TEST_CASE() [7/10]

BOOST_AUTO_TEST_CASE ( testNormalShiftsIgnored  )

Definition at line 263 of file swaptionvolatilityconverter.cpp.

263 {
264 BOOST_TEST_MESSAGE("Testing shifts supplied to normal converter ignored...");
265
266 CommonVars vars;
267
268 // Tolerance used in boost check
269 Real tolerance = 0.00001;
270
271 // Set up the converter (Lognormal with no shifts -> Normal)
272 // We supply target shifts but they are ignored since target type is Normal
274 vars.referenceDate, vars.atmLogNormalVolMatrix, vars.yieldCurves.discountEonia, vars.yieldCurves.discountEonia,
275 vars.swapConventions, vars.swapConventions, 1 * Years, 30 * Years, Normal, vars.atmVols.shifts_1);
276
277 // Get back converted volatility structure and test result on pillar points
278 QuantLib::ext::shared_ptr<SwaptionVolatilityStructure> convertedsvs = converter.convert();
279 Volatility targetVol = 0.0;
280 Volatility outVol = 0.0;
281 Real dummyStrike = 0.0;
282 for (Size i = 0; i < vars.atmVols.optionTenors.size(); ++i) {
283 for (Size j = 0; j < vars.atmVols.swapTenors.size(); ++j) {
284 Period optionTenor = vars.atmVols.optionTenors[i];
285 Period swapTenor = vars.atmVols.swapTenors[j];
286 targetVol = vars.atmVols.nVols[i][j];
287 outVol = convertedsvs->volatility(optionTenor, swapTenor, dummyStrike);
288 BOOST_CHECK_SMALL(outVol - targetVol, tolerance);
289 }
290 }
291}
+ Here is the call graph for this function:

◆ BOOST_AUTO_TEST_CASE() [8/10]

BOOST_AUTO_TEST_CASE ( testConstructionFromSwapIndex  )

Definition at line 293 of file swaptionvolatilityconverter.cpp.

293 {
294 BOOST_TEST_MESSAGE("Testing construction of SwaptionVolatilityConverter from SwapIndex...");
295
296 CommonVars vars;
297
298 // Tolerance used in boost check
299 Real tolerance = 0.00001;
300
301 // Set up a SwapIndex
302 QuantLib::ext::shared_ptr<SwapIndex> swapIndex =
303 QuantLib::ext::make_shared<EuriborSwapIsdaFixA>(2 * Years, vars.yieldCurves.forward6M, vars.yieldCurves.discountEonia);
304
305 // Set up the converter using swap index (Shifted Lognormal with shift set 2 -> Normal)
306 SwaptionVolatilityConverter converter(vars.referenceDate, vars.atmShiftedLogNormalVolMatrix_2, swapIndex, swapIndex,
307 Normal);
308
309 // Test that the results are still ok
310 QuantLib::ext::shared_ptr<SwaptionVolatilityStructure> convertedsvs = converter.convert();
311 Volatility targetVol = 0.0;
312 Volatility outVol = 0.0;
313 Real dummyStrike = 0.0;
314 for (Size i = 0; i < vars.atmVols.optionTenors.size(); ++i) {
315 for (Size j = 0; j < vars.atmVols.swapTenors.size(); ++j) {
316 Period optionTenor = vars.atmVols.optionTenors[i];
317 Period swapTenor = vars.atmVols.swapTenors[j];
318 targetVol = vars.atmVols.nVols[i][j];
319 outVol = convertedsvs->volatility(optionTenor, swapTenor, dummyStrike);
320 BOOST_CHECK_SMALL(outVol - targetVol, tolerance);
321 }
322 }
323}
+ Here is the call graph for this function:

◆ BOOST_AUTO_TEST_CASE() [9/10]

BOOST_AUTO_TEST_CASE ( testConstructionFromSwapIndexNoDiscount  )

Definition at line 325 of file swaptionvolatilityconverter.cpp.

325 {
326 BOOST_TEST_MESSAGE("Testing construction from SwapIndex with no exogenous discount curve...");
327
328 CommonVars vars;
329
330 // Set up a SwapIndex
331 QuantLib::ext::shared_ptr<SwapIndex> swapIndex =
332 QuantLib::ext::make_shared<EuriborSwapIsdaFixA>(2 * Years, vars.yieldCurves.forward6M);
333
334 // Set up the converter using swap index (Shifted Lognormal with shift set 2 -> Normal)
335 SwaptionVolatilityConverter converter(vars.referenceDate, vars.atmShiftedLogNormalVolMatrix_2, swapIndex, swapIndex,
336 Normal);
337
338 // Test that calling convert() still works
339 BOOST_CHECK_NO_THROW(converter.convert());
340}
+ Here is the call graph for this function:

◆ BOOST_AUTO_TEST_CASE() [10/10]

BOOST_AUTO_TEST_CASE ( testCube  )

Definition at line 342 of file swaptionvolatilityconverter.cpp.

342 {
343 BOOST_TEST_MESSAGE("Testing lognormal to normal conversion for cube...");
344
345 CommonVars vars;
346
347 // Set up Swap Indices
348 QuantLib::ext::shared_ptr<SwapIndex> shortSwapIndex =
349 QuantLib::ext::make_shared<EuriborSwapIsdaFixA>(1 * Years, vars.yieldCurves.forward3M, vars.yieldCurves.discountEonia);
350 QuantLib::ext::shared_ptr<SwapIndex> swapIndex =
351 QuantLib::ext::make_shared<EuriborSwapIsdaFixA>(30 * Years, vars.yieldCurves.forward6M, vars.yieldCurves.discountEonia);
352
353 // Set up a lognormal cube
354 QuantLib::ext::shared_ptr<SwaptionVolatilityCube> cube = QuantLib::ext::make_shared<QuantExt::SwaptionVolCube2>(
355 Handle<SwaptionVolatilityStructure>(vars.atmLogNormalVolMatrix), vars.atmVols.optionTenors,
356 vars.atmVols.swapTenors, vars.atmVols.strikeSpreads, vars.atmVols.lnVolSpreads, swapIndex, shortSwapIndex,
357 false, true);
358
359 // Convert the cube to normal
360 SwaptionVolatilityConverter converter(vars.referenceDate, cube, swapIndex, shortSwapIndex, Normal);
361 QuantLib::ext::shared_ptr<SwaptionVolatilityStructure> convertedsvs = converter.convert();
362
363 // Price swaptions in the lognormal and normal cube and compare their premiums
364 for (Size i = 0; i < vars.atmVols.optionTenors.size(); ++i) {
365 for (Size j = 0; j < vars.atmVols.swapTenors.size(); ++j) {
366 for (Size k = 0; k < vars.atmVols.strikeSpreads.size(); ++k) {
367 Period optionTenor = vars.atmVols.optionTenors[i];
368 Period swapTenor = vars.atmVols.swapTenors[j];
369 Real atmStrike = cube->atmStrike(optionTenor, swapTenor);
370 Real strikeSpread = vars.atmVols.strikeSpreads[k];
371 Real strike = atmStrike + strikeSpread;
372 if (strike > 0.0) {
373 Real inVol = cube->volatility(optionTenor, swapTenor, atmStrike + strikeSpread);
374 Real outVol = convertedsvs->volatility(optionTenor, swapTenor, atmStrike + strikeSpread);
375 Option::Type type = strikeSpread < 0.0 ? Option::Put : Option::Call;
376 Real tte = cube->optionTimes()[i];
377 Real inPrem = blackFormula(type, strike, atmStrike, inVol * std::sqrt(tte));
378 Real outPrem = bachelierBlackFormula(type, strike, atmStrike, outVol * std::sqrt(tte));
379 BOOST_CHECK_CLOSE(inPrem, outPrem, 0.01);
380 }
381 }
382 }
383 }
384}
+ Here is the call graph for this function: