19#include <boost/assign.hpp>
21#include <boost/test/unit_test.hpp>
22#include <boost/test/data/test_case.hpp>
24#include <boost/variant.hpp>
30#include <ql/instruments/makecapfloor.hpp>
31#include <ql/pricingengines/capfloor/bacheliercapfloorengine.hpp>
32#include <ql/pricingengines/capfloor/blackcapfloorengine.hpp>
33#include <ql/time/date.hpp>
34#include <ql/tuple.hpp>
42using namespace boost::unit_test_framework;
45typedef QuantLib::BootstrapHelper<QuantLib::OptionletVolatilityStructure>
helper;
46using boost::assign::list_of;
47using boost::assign::map_list_of;
53using std::setprecision;
64 : referenceDate(5, Feb, 2016), settlementDays(0), calendar(TARGET()), bdc(Following),
65 dayCounter(Actual365Fixed()), accuracy(1.0e-12), tolerance(1.0e-10) {
68 Settings::instance().evaluationDate() = referenceDate;
71 iborIndex = QuantLib::ext::make_shared<Euribor6M>(testYieldCurves.forward6M);
78 Natural settlementDays;
80 BusinessDayConvention bdc;
81 DayCounter dayCounter;
90 QuantLib::ext::shared_ptr<IborIndex> iborIndex;
98 vector<Period> tenors;
99 vector<Real> volatilities;
105ostream&
operator<<(ostream& os,
const AtmVolData& vc) {
106 return os <<
"Atm volatility data with volatility type: " << vc.type <<
", shift: " << vc.displacement;
111vector<AtmVolData> generateAtmVolData() {
114 vector<AtmVolData> data;
124 datum.volatilities = testVols.
nAtmVols;
126 datum.displacement = 0.0;
127 data.push_back(datum);
131 datum.type = ShiftedLognormal;
132 datum.displacement = testVols.
shift_1;
133 data.push_back(datum);
137 datum.type = ShiftedLognormal;
138 datum.displacement = testVols.
shift_2;
139 data.push_back(datum);
145typedef boost::variant<Linear, BackwardFlat, QuantExt::LinearFlat, Cubic, QuantExt::CubicFlat> InterpolationType;
153 samples_.push_back(QuantLib::ext::make_tuple(InterpolationType(Linear()),
true));
155 samples_.push_back(QuantLib::ext::make_tuple(InterpolationType(Cubic()),
true));
156 samples_.push_back(QuantLib::ext::make_tuple(InterpolationType(
QuantExt::CubicFlat()),
true));
157 samples_.push_back(QuantLib::ext::make_tuple(InterpolationType(BackwardFlat()),
true));
158 samples_.push_back(QuantLib::ext::make_tuple(InterpolationType(Linear()),
false));
159 samples_.push_back(QuantLib::ext::make_tuple(InterpolationType(
QuantExt::LinearFlat()),
false));
160 samples_.push_back(QuantLib::ext::make_tuple(InterpolationType(Cubic()),
false));
161 samples_.push_back(QuantLib::ext::make_tuple(InterpolationType(
QuantExt::CubicFlat()),
false));
164 bdata::size_t size()
const {
return samples_.size(); }
166 typedef vector<QuantLib::ext::tuple<InterpolationType, bool> >::const_iterator iterator;
167 iterator begin()
const {
return samples_.begin(); }
170 vector<QuantLib::ext::tuple<InterpolationType, bool> > samples_;
174vector<bool> isMovingValues = list_of(
true)(
false);
177vector<bool> flatFirstPeriodValues = list_of(
true)(
false);
180string to_string(
const InterpolationType& interpolationType) {
182 switch (interpolationType.which()) {
187 result =
"BackwardFlat";
190 result =
"LinearFlat";
196 result =
"CubicFlat";
199 BOOST_FAIL(
"Unexpected interpolation type");
210namespace test_tools {
212template <>
struct print_log_value<
QuantLib::ext::tuple<InterpolationType, bool> > {
213 void operator()(ostream& os,
const QuantLib::ext::tuple<InterpolationType, bool>& tp) {
214 os << to_string(QuantLib::ext::get<0>(tp)) <<
", " << boolalpha << QuantLib::ext::get<1>(tp);
222namespace monomorphic {
224template <>
struct is_dataset<InterpDataset> : boost::mpl::true_ {};
233BOOST_AUTO_TEST_SUITE(PiecewiseAtmOptionletCurveTests)
236 bdata::make(generateAtmVolData()) * InterpDataset() *
bdata::make(isMovingValues) *
237 bdata::make(flatFirstPeriodValues),
238 atmVolData, interpSample, isMoving, flatFirstPeriod) {
240 BOOST_TEST_MESSAGE(
"Testing piecewise optionlet stripping of ATM cap floor curve");
242 InterpolationType interpolationType = QuantLib::ext::get<0>(interpSample);
243 bool interpOnOptionlets = QuantLib::ext::get<1>(interpSample);
245 BOOST_TEST_MESSAGE(
"Test inputs are:");
246 BOOST_TEST_MESSAGE(
" Quote volatility type: " << atmVolData.type);
247 BOOST_TEST_MESSAGE(
" Quote displacement: " << atmVolData.displacement);
248 BOOST_TEST_MESSAGE(
" Interpolation type: " << to_string(interpolationType));
249 BOOST_TEST_MESSAGE(
" Interp on optionlets: " << boolalpha << interpOnOptionlets);
250 BOOST_TEST_MESSAGE(
" Floating reference date: " << boolalpha << isMoving);
251 BOOST_TEST_MESSAGE(
" Flat first period: " << boolalpha << flatFirstPeriod);
254 vector<QuantLib::ext::shared_ptr<CapFloor> > instruments(atmVolData.tenors.size());
255 vector<Real> flatNpvs(atmVolData.tenors.size());
258 vector<QuantLib::ext::shared_ptr<SimpleQuote> > volQuotes(atmVolData.tenors.size());
259 vector<Handle<Quote> > volHandles(atmVolData.tenors.size());
261 BOOST_TEST_MESSAGE(
"The input values at each tenor are:");
262 for (Size i = 0; i < atmVolData.tenors.size(); i++) {
265 Real volatility = atmVolData.volatilities[i];
266 volQuotes[i] = QuantLib::ext::make_shared<SimpleQuote>(volatility);
267 volHandles[i] = Handle<Quote>(volQuotes[i]);
270 instruments[i] = MakeCapFloor(CapFloor::Cap, atmVolData.tenors[i], iborIndex, 0.01);
271 Rate atm = instruments[i]->atmRate(**testYieldCurves.discountEonia);
272 instruments[i] = MakeCapFloor(CapFloor::Cap, atmVolData.tenors[i], iborIndex, atm);
273 if (atmVolData.type == ShiftedLognormal) {
274 instruments[i]->setPricingEngine(QuantLib::ext::make_shared<BlackCapFloorEngine>(
275 testYieldCurves.discountEonia, volatility, dayCounter, atmVolData.displacement));
277 instruments[i]->setPricingEngine(
278 QuantLib::ext::make_shared<BachelierCapFloorEngine>(testYieldCurves.discountEonia, volatility, dayCounter));
280 flatNpvs[i] = instruments[i]->NPV();
282 BOOST_TEST_MESSAGE(
" (Cap/Floor, Tenor, Strike, Volatility, Flat NPV) = (Cap, "
283 << atmVolData.tenors[i] <<
", " << atm <<
", " << fixed << setprecision(13) << volatility
284 <<
", " << flatNpvs[i] <<
")");
290 VolatilityType curveVolatilityType = Normal;
291 Real curveDisplacement = 0.0;
292 QuantLib::ext::shared_ptr<CapFloorTermVolCurve> cftvc;
293 QuantLib::ext::shared_ptr<OptionletVolatilityStructure> ovCurve;
294 switch (interpolationType.which()) {
297 BOOST_TEST_MESSAGE(
"Using Linear interpolation with a moving reference date");
298 cftvc = QuantLib::ext::make_shared<InterpolatedCapFloorTermVolCurve<Linear> >(
299 settlementDays, calendar, bdc, atmVolData.tenors, volHandles, dayCounter, flatFirstPeriod);
300 ovCurve = QuantLib::ext::make_shared<PiecewiseAtmOptionletCurve<Linear> >(
301 settlementDays, cftvc, iborIndex, testYieldCurves.discountEonia, flatFirstPeriod, atmVolData.type,
302 atmVolData.displacement, curveVolatilityType, curveDisplacement, interpOnOptionlets);
304 BOOST_TEST_MESSAGE(
"Using Linear interpolation with a fixed reference date");
305 cftvc = QuantLib::ext::make_shared<InterpolatedCapFloorTermVolCurve<Linear> >(
306 referenceDate, calendar, bdc, atmVolData.tenors, volHandles, dayCounter, flatFirstPeriod);
307 ovCurve = QuantLib::ext::make_shared<PiecewiseAtmOptionletCurve<Linear> >(
308 referenceDate, cftvc, iborIndex, testYieldCurves.discountEonia, flatFirstPeriod, atmVolData.type,
309 atmVolData.displacement, curveVolatilityType, curveDisplacement, interpOnOptionlets);
314 BOOST_TEST_MESSAGE(
"Using BackwardFlat interpolation with a moving reference date");
315 cftvc = QuantLib::ext::make_shared<InterpolatedCapFloorTermVolCurve<BackwardFlat> >(
316 settlementDays, calendar, bdc, atmVolData.tenors, volHandles, dayCounter, flatFirstPeriod);
317 ovCurve = QuantLib::ext::make_shared<PiecewiseAtmOptionletCurve<BackwardFlat> >(
318 settlementDays, cftvc, iborIndex, testYieldCurves.discountEonia, flatFirstPeriod, atmVolData.type,
319 atmVolData.displacement, curveVolatilityType, curveDisplacement, interpOnOptionlets);
321 BOOST_TEST_MESSAGE(
"Using BackwardFlat interpolation with a fixed reference date");
322 cftvc = QuantLib::ext::make_shared<InterpolatedCapFloorTermVolCurve<BackwardFlat> >(
323 referenceDate, calendar, bdc, atmVolData.tenors, volHandles, dayCounter, flatFirstPeriod);
324 ovCurve = QuantLib::ext::make_shared<PiecewiseAtmOptionletCurve<BackwardFlat> >(
325 referenceDate, cftvc, iborIndex, testYieldCurves.discountEonia, flatFirstPeriod, atmVolData.type,
326 atmVolData.displacement, curveVolatilityType, curveDisplacement, interpOnOptionlets);
331 BOOST_TEST_MESSAGE(
"Using LinearFlat interpolation with a moving reference date");
332 cftvc = QuantLib::ext::make_shared<InterpolatedCapFloorTermVolCurve<LinearFlat> >(
333 settlementDays, calendar, bdc, atmVolData.tenors, volHandles, dayCounter, flatFirstPeriod);
334 ovCurve = QuantLib::ext::make_shared<PiecewiseAtmOptionletCurve<LinearFlat> >(
335 settlementDays, cftvc, iborIndex, testYieldCurves.discountEonia, flatFirstPeriod, atmVolData.type,
336 atmVolData.displacement, curveVolatilityType, curveDisplacement, interpOnOptionlets);
338 BOOST_TEST_MESSAGE(
"Using LinearFlat interpolation with a fixed reference date");
339 cftvc = QuantLib::ext::make_shared<InterpolatedCapFloorTermVolCurve<LinearFlat> >(
340 referenceDate, calendar, bdc, atmVolData.tenors, volHandles, dayCounter, flatFirstPeriod);
341 ovCurve = QuantLib::ext::make_shared<PiecewiseAtmOptionletCurve<LinearFlat> >(
342 referenceDate, cftvc, iborIndex, testYieldCurves.discountEonia, flatFirstPeriod, atmVolData.type,
343 atmVolData.displacement, curveVolatilityType, curveDisplacement, interpOnOptionlets);
348 BOOST_TEST_MESSAGE(
"Using Cubic interpolation with a moving reference date");
349 cftvc = QuantLib::ext::make_shared<InterpolatedCapFloorTermVolCurve<Cubic> >(
350 settlementDays, calendar, bdc, atmVolData.tenors, volHandles, dayCounter, flatFirstPeriod);
351 ovCurve = QuantLib::ext::make_shared<PiecewiseAtmOptionletCurve<Cubic> >(
352 settlementDays, cftvc, iborIndex, testYieldCurves.discountEonia, flatFirstPeriod, atmVolData.type,
353 atmVolData.displacement, curveVolatilityType, curveDisplacement, interpOnOptionlets);
355 BOOST_TEST_MESSAGE(
"Using Cubic interpolation with a fixed reference date");
356 cftvc = QuantLib::ext::make_shared<InterpolatedCapFloorTermVolCurve<Cubic> >(
357 referenceDate, calendar, bdc, atmVolData.tenors, volHandles, dayCounter, flatFirstPeriod);
358 ovCurve = QuantLib::ext::make_shared<PiecewiseAtmOptionletCurve<Cubic> >(
359 referenceDate, cftvc, iborIndex, testYieldCurves.discountEonia, flatFirstPeriod, atmVolData.type,
360 atmVolData.displacement, curveVolatilityType, curveDisplacement, interpOnOptionlets);
365 BOOST_TEST_MESSAGE(
"Using CubicFlat interpolation with a moving reference date");
366 cftvc = QuantLib::ext::make_shared<InterpolatedCapFloorTermVolCurve<CubicFlat> >(
367 settlementDays, calendar, bdc, atmVolData.tenors, volHandles, dayCounter, flatFirstPeriod);
368 ovCurve = QuantLib::ext::make_shared<PiecewiseAtmOptionletCurve<CubicFlat> >(
369 settlementDays, cftvc, iborIndex, testYieldCurves.discountEonia, flatFirstPeriod, atmVolData.type,
370 atmVolData.displacement, curveVolatilityType, curveDisplacement, interpOnOptionlets);
372 BOOST_TEST_MESSAGE(
"Using CubicFlat interpolation with a fixed reference date");
373 cftvc = QuantLib::ext::make_shared<InterpolatedCapFloorTermVolCurve<CubicFlat> >(
374 referenceDate, calendar, bdc, atmVolData.tenors, volHandles, dayCounter, flatFirstPeriod);
375 ovCurve = QuantLib::ext::make_shared<PiecewiseAtmOptionletCurve<CubicFlat> >(
376 referenceDate, cftvc, iborIndex, testYieldCurves.discountEonia, flatFirstPeriod, atmVolData.type,
377 atmVolData.displacement, curveVolatilityType, curveDisplacement, interpOnOptionlets);
381 BOOST_FAIL(
"Unexpected interpolation type");
383 Handle<OptionletVolatilityStructure> hovs(ovCurve);
386 BOOST_TEST_MESSAGE(
"The stripped values and differences at each tenor are:");
388 for (Size i = 0; i < atmVolData.tenors.size(); i++) {
391 if (ovCurve->volatilityType() == ShiftedLognormal) {
392 instruments[i]->setPricingEngine(
393 QuantLib::ext::make_shared<BlackCapFloorEngine>(testYieldCurves.discountEonia, hovs));
395 instruments[i]->setPricingEngine(
396 QuantLib::ext::make_shared<BachelierCapFloorEngine>(testYieldCurves.discountEonia, hovs));
398 strippedNpv = instruments[i]->NPV();
400 BOOST_TEST_MESSAGE(
" (Cap/Floor, Tenor, Strike, Volatility, Flat NPV, Stripped NPV, Flat - Stripped) = ("
401 << instruments[i]->type() <<
", " << atmVolData.tenors[i] <<
", "
402 << instruments[i]->capRates()[0] <<
", " << fixed << setprecision(13)
403 << atmVolData.volatilities[i] <<
", " << flatNpvs[i] <<
", " << strippedNpv <<
", "
404 << (flatNpvs[i] - strippedNpv) <<
")");
406 BOOST_CHECK_SMALL(fabs(flatNpvs[i] - strippedNpv), tolerance);
410 BOOST_TEST_MESSAGE(
"Testing that stripping still works after bumping volatility quote");
412 Volatility bumpedVol = volQuotes[idx]->value() * 1.10;
413 volQuotes[idx]->setValue(bumpedVol);
414 strippedNpv = instruments[idx]->NPV();
415 if (atmVolData.type == ShiftedLognormal) {
416 instruments[idx]->setPricingEngine(QuantLib::ext::make_shared<BlackCapFloorEngine>(
417 testYieldCurves.discountEonia, bumpedVol, dayCounter, atmVolData.displacement));
419 instruments[idx]->setPricingEngine(
420 QuantLib::ext::make_shared<BachelierCapFloorEngine>(testYieldCurves.discountEonia, bumpedVol, dayCounter));
422 Real newFlatNpv = instruments[idx]->NPV();
423 BOOST_TEST_MESSAGE(
" (Cap/Floor, Tenor, Strike, Volatility, Flat NPV, Stripped NPV, Flat - Stripped) = ("
424 << instruments[idx]->type() <<
", " << atmVolData.tenors[idx] <<
", "
425 << instruments[idx]->capRates()[0] <<
", " << fixed << setprecision(13) << bumpedVol <<
", "
426 << newFlatNpv <<
", " << strippedNpv <<
", " << (newFlatNpv - strippedNpv) <<
")");
427 BOOST_CHECK_GT(newFlatNpv, flatNpvs[idx]);
428 BOOST_CHECK_SMALL(fabs(newFlatNpv - strippedNpv), tolerance);
430 BOOST_TEST_MESSAGE(
"Test extrapolation settings with out of range date");
431 Date oorDate = ovCurve->maxDate() + 1 * Months;
432 BOOST_CHECK_NO_THROW(ovCurve->volatility(oorDate, 0.01,
true));
433 BOOST_CHECK_THROW(ovCurve->volatility(oorDate, 0.01), Error);
434 ovCurve->enableExtrapolation();
435 BOOST_CHECK_NO_THROW(ovCurve->volatility(oorDate, 0.01));
437 BOOST_TEST_MESSAGE(
"Test term structure stripping still works after changing evaluation date");
438 Date newDate = calendar.advance(referenceDate, 1 * Months);
439 Settings::instance().evaluationDate() = newDate;
441 for (Size i = 0; i < atmVolData.tenors.size(); i++) {
443 Real volatility = volQuotes[i]->value();
450 startDate = iborIndex->fixingCalendar().adjust(referenceDate);
451 startDate = iborIndex->fixingCalendar().advance(startDate, iborIndex->fixingDays() * Days);
454 MakeCapFloor(CapFloor::Cap, atmVolData.tenors[i], iborIndex, 0.01).withEffectiveDate(startDate,
true);
455 Rate atm = instruments[i]->atmRate(**testYieldCurves.discountEonia);
457 MakeCapFloor(CapFloor::Cap, atmVolData.tenors[i], iborIndex, atm).withEffectiveDate(startDate,
true);
459 if (atmVolData.type == ShiftedLognormal) {
460 instruments[i]->setPricingEngine(QuantLib::ext::make_shared<BlackCapFloorEngine>(
461 testYieldCurves.discountEonia, volatility, dayCounter, atmVolData.displacement));
463 instruments[i]->setPricingEngine(
464 QuantLib::ext::make_shared<BachelierCapFloorEngine>(testYieldCurves.discountEonia, volatility, dayCounter));
466 newFlatNpv = instruments[i]->NPV();
469 if (ovCurve->volatilityType() == ShiftedLognormal) {
470 instruments[i]->setPricingEngine(
471 QuantLib::ext::make_shared<BlackCapFloorEngine>(testYieldCurves.discountEonia, hovs));
473 instruments[i]->setPricingEngine(
474 QuantLib::ext::make_shared<BachelierCapFloorEngine>(testYieldCurves.discountEonia, hovs));
476 strippedNpv = instruments[i]->NPV();
478 BOOST_TEST_MESSAGE(
" (Cap/Floor, Tenor, Strike, Volatility, Flat NPV, Stripped NPV, Flat - Stripped) = ("
479 << instruments[i]->type() <<
", " << atmVolData.tenors[i] <<
", "
480 << instruments[i]->capRates()[0] <<
", " << fixed << setprecision(13)
481 << volQuotes[i]->value() <<
", " << newFlatNpv <<
", " << strippedNpv <<
", "
482 << (newFlatNpv - strippedNpv) <<
")");
484 BOOST_CHECK_SMALL(fabs(newFlatNpv - strippedNpv), tolerance);
490 BOOST_TEST_MESSAGE(
"Testing ATM stripping exception behaviour");
494 vector<Period> tenors = testVols.
atmTenors;
495 vector<Real> volatilities = testVols.
nAtmVols;
496 VolatilityType type = Normal;
497 Real displacement = 0.0;
500 vector<QuantLib::ext::shared_ptr<SimpleQuote> > volQuotes(tenors.size());
501 vector<Handle<Quote> > volHandles(tenors.size());
502 for (Size i = 0; i < tenors.size(); i++) {
503 Real volatility = volatilities[i];
504 volQuotes[i] = QuantLib::ext::make_shared<SimpleQuote>(volatility);
505 volHandles[i] = Handle<Quote>(volQuotes[i]);
509 Real globalAccuracy = 1e-10;
510 bool dontThrow =
false;
513 QuantLib::ext::shared_ptr<CapFloorTermVolCurve> cftvc = QuantLib::ext::make_shared<InterpolatedCapFloorTermVolCurve<LinearFlat> >(
514 settlementDays, calendar, bdc, tenors, volHandles, dayCounter,
true);
517 VolatilityType curveVolatilityType = Normal;
518 Real curveDisplacement = 0.0;
519 bool interpOnOptionlets =
true;
520 QuantLib::ext::shared_ptr<OptionletVolatilityStructure> ovCurve =
521 QuantLib::ext::make_shared<PiecewiseAtmOptionletCurve<LinearFlat> >(
522 settlementDays, cftvc, iborIndex, testYieldCurves.discountEonia,
true, type, displacement,
523 curveVolatilityType, curveDisplacement, interpOnOptionlets,
LinearFlat(),
526 accuracy, globalAccuracy, dontThrow));
529 Period oneYear = 1 * Years;
530 Period fiveYears = 5 * Years;
531 Period eightYears = 8 * Years;
532 Volatility oneYearVol;
533 Volatility fiveYearVol;
534 Volatility eightYearVol;
535 BOOST_CHECK_NO_THROW(oneYearVol = ovCurve->volatility(oneYear, 0.01,
true));
536 BOOST_TEST_MESSAGE(
"1Y vol: " << oneYearVol);
537 BOOST_CHECK_NO_THROW(fiveYearVol = ovCurve->volatility(fiveYears, 0.01,
true));
538 BOOST_TEST_MESSAGE(
"5Y vol: " << fiveYearVol);
539 BOOST_CHECK_NO_THROW(eightYearVol = ovCurve->volatility(eightYears, 0.01,
true));
540 BOOST_TEST_MESSAGE(
"8Y vol: " << eightYearVol);
543 volQuotes[2]->setValue(2 * volQuotes[2]->value());
544 BOOST_CHECK_THROW(ovCurve->volatility(fiveYears, 0.01,
true), Error);
548 ovCurve = QuantLib::ext::make_shared<PiecewiseAtmOptionletCurve<LinearFlat> >(
549 settlementDays, cftvc, iborIndex, testYieldCurves.discountEonia,
true, type, displacement, curveVolatilityType,
550 curveDisplacement, interpOnOptionlets,
LinearFlat(),
553 accuracy, globalAccuracy, dontThrow));
558 Volatility testVol = 0.0;
559 BOOST_CHECK_NO_THROW(testVol = ovCurve->volatility(oneYear, 0.01,
true));
560 BOOST_CHECK_SMALL(fabs(testVol - oneYearVol), tolerance);
561 BOOST_TEST_MESSAGE(
"1Y vol after bump using previous: " << testVol);
562 BOOST_CHECK_NO_THROW(testVol = ovCurve->volatility(fiveYears, 0.01,
true));
563 BOOST_CHECK_GT(testVol, fiveYearVol);
564 BOOST_TEST_MESSAGE(
"5Y vol after bump using previous: " << testVol);
567BOOST_AUTO_TEST_SUITE_END()
569BOOST_AUTO_TEST_SUITE_END()
Helper for bootstrapping optionlet volatilities from cap floor volatilities.
structs containing capfloor market data that can be used in tests
Cap floor at-the-money term volatility curve.
Cubic interpolation and flat extrapolation factory and traits.
Linear-interpolation and flat extrapolation factory and traits
std::ostream & operator<<(std::ostream &out, EquityReturnType t)
BOOST_FIXTURE_TEST_CASE(testAtmStrippingExceptions, CommonVars)
BOOST_DATA_TEST_CASE_F(CommonVars, testPiecewiseAtmOptionletStripping, bdata::make(generateAtmVolData()) *InterpDataset() *bdata::make(isMovingValues) *bdata::make(flatFirstPeriodValues), atmVolData, interpSample, isMoving, flatFirstPeriod)
QuantLib::BootstrapHelper< QuantLib::OptionletVolatilityStructure > helper
Create optionlet volatility structure from at-the-money cap floor term volatility curve.
vector< Period > atmTenors
vector< Volatility > slnAtmVols_2
vector< Volatility > nAtmVols
vector< Volatility > slnAtmVols_1
Fixture that can be used at top level.
structs containing yield curve market data that can be used in tests