Skip to content

Commit

Permalink
Add test for SABR smile sections.
Browse files Browse the repository at this point in the history
  • Loading branch information
lballabio committed Aug 13, 2020
1 parent b045a6d commit 77b428d
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 16 deletions.
17 changes: 5 additions & 12 deletions ql/termstructures/volatility/sabrsmilesection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,7 @@ namespace QuantLib {
: SmileSection(timeToExpiry,DayCounter(),
ShiftedLognormal,shift),
forward_(forward), shift_(shift) {

alpha_ = sabrParams[0];
beta_ = sabrParams[1];
nu_ = sabrParams[2];
rho_ = sabrParams[3];

QL_REQUIRE(forward_ + shift_ > 0.0,
"at the money forward rate + shift must be "
"positive: "
<< io::rate(forward_) << " with shift "
<< io::rate(shift_) << " not allowed");
validateSabrParameters(alpha_, beta_, nu_, rho_);
initialise(sabrParams);
}

SabrSmileSection::SabrSmileSection(const Date& d,
Expand All @@ -52,6 +41,10 @@ namespace QuantLib {
const Real shift)
: SmileSection(d, dc,Date(),ShiftedLognormal,shift),
forward_(forward), shift_(shift) {
initialise(sabrParams);
}

void SabrSmileSection::initialise(const std::vector<Real>& sabrParams) {

alpha_ = sabrParams[0];
beta_ = sabrParams[1];
Expand Down
5 changes: 5 additions & 0 deletions ql/termstructures/volatility/sabrsmilesection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,16 @@ namespace QuantLib {
Real minStrike () const { return -shift_; }
Real maxStrike () const { return QL_MAX_REAL; }
Real atmLevel() const { return forward_; }
Real alpha() const { return alpha_; }
Real beta() const { return beta_; }
Real nu() const { return nu_; }
Real rho() const { return rho_; }
protected:
Real varianceImpl(Rate strike) const;
Volatility volatilityImpl(Rate strike) const;
private:
Real alpha_, beta_, nu_, rho_, forward_, shift_;
void initialise(const std::vector<Real>& sabrParameters);
};


Expand Down
117 changes: 113 additions & 4 deletions test-suite/swaptionvolatilitycube.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <ql/termstructures/volatility/swaption/swaptionvolcube2.hpp>
#include <ql/termstructures/volatility/swaption/swaptionvolcube1.hpp>
#include <ql/termstructures/volatility/swaption/spreadedswaptionvol.hpp>
#include <ql/termstructures/volatility/sabrsmilesection.hpp>
#include <ql/utilities/dataformatters.hpp>

using namespace QuantLib;
Expand Down Expand Up @@ -452,6 +453,112 @@ void SwaptionVolatilityCubeTest::testObservability() {
Settings::instance().evaluationDate() = referenceDate;
}

void SwaptionVolatilityCubeTest::testSabrParameters() {
BOOST_TEST_MESSAGE("Testing interpolation of SABR smile sections...");

using namespace swaption_volatility_cube_test;

CommonVars vars;

std::vector<std::vector<Handle<Quote> > >
parametersGuess(vars.cube.tenors.options.size()*vars.cube.tenors.swaps.size());
for (Size i=0; i<vars.cube.tenors.options.size()*vars.cube.tenors.swaps.size(); i++) {
parametersGuess[i] = std::vector<Handle<Quote> >(4);
parametersGuess[i][0] =
Handle<Quote>(ext::shared_ptr<Quote>(new SimpleQuote(0.2)));
parametersGuess[i][1] =
Handle<Quote>(ext::shared_ptr<Quote>(new SimpleQuote(0.5)));
parametersGuess[i][2] =
Handle<Quote>(ext::shared_ptr<Quote>(new SimpleQuote(0.4)));
parametersGuess[i][3] =
Handle<Quote>(ext::shared_ptr<Quote>(new SimpleQuote(0.0)));
}
std::vector<bool> isParameterFixed(4, false);

SwaptionVolCube1 volCube(vars.atmVolMatrix,
vars.cube.tenors.options,
vars.cube.tenors.swaps,
vars.cube.strikeSpreads,
vars.cube.volSpreadsHandle,
vars.swapIndexBase,
vars.shortSwapIndexBase,
vars.vegaWeighedSmileFit,
parametersGuess,
isParameterFixed,
true);

SwaptionVolatilityStructure* volStructure = &volCube;
Real tolerance = 1.0e-4;

//Interpolating between two SmileSection objects

//First section: maturity = 10Y, tenor = 2Y
ext::shared_ptr<SmileSection> smileSection1 = volStructure->smileSection(Period(10,Years), Period(2,Years));

//Second section: maturity = 10Y, tenor = 4Y
ext::shared_ptr<SmileSection> smileSection2 = volStructure->smileSection(Period(10,Years), Period(4,Years));

//Third section in the middle: maturity = 10Y, tenor = 3Y
ext::shared_ptr<SmileSection> smileSection3 = volStructure->smileSection(Period(10,Years), Period(3,Years));

//test alpha interpolation
Real alpha1 = ext::dynamic_pointer_cast<SabrSmileSection>(smileSection1)->alpha();
Real alpha2 = ext::dynamic_pointer_cast<SabrSmileSection>(smileSection2)->alpha();
Real alpha3 = ext::dynamic_pointer_cast<SabrSmileSection>(smileSection3)->alpha();
Real alpha12 = 0.5*(alpha1+alpha2);
if (std::abs(alpha3 - alpha12) > tolerance) {
BOOST_ERROR("\nChecking interpolation of alpha parameters:"
"\nexpected = " << alpha12 <<
"\nobserved = " << alpha3);
}

//test beta interpolation
Real beta1 = ext::dynamic_pointer_cast<SabrSmileSection>(smileSection1)->beta();
Real beta2 = ext::dynamic_pointer_cast<SabrSmileSection>(smileSection2)->beta();
Real beta3 = ext::dynamic_pointer_cast<SabrSmileSection>(smileSection3)->beta();
Real beta12 = 0.5*(beta1+beta2);
if (std::abs(beta3 - beta12) > tolerance) {
BOOST_ERROR("\nChecking interpolation of beta parameters:"
"\nexpected = " << beta12 <<
"\nobserved = " << beta3);
}

//test rho interpolation
Real rho1 = ext::dynamic_pointer_cast<SabrSmileSection>(smileSection1)->rho();
Real rho2 = ext::dynamic_pointer_cast<SabrSmileSection>(smileSection2)->rho();
Real rho3 = ext::dynamic_pointer_cast<SabrSmileSection>(smileSection3)->rho();
Real rho12 = 0.5*(rho1+rho2);
if (std::abs(rho3 - rho12) > tolerance) {
BOOST_ERROR("\nChecking interpolation of rho parameters:"
"\nexpected = " << rho12 <<
"\nobserved = " << rho3);
}

//test nu interpolation
Real nu1 = ext::dynamic_pointer_cast<SabrSmileSection>(smileSection1)->nu();
Real nu2 = ext::dynamic_pointer_cast<SabrSmileSection>(smileSection2)->nu();
Real nu3 = ext::dynamic_pointer_cast<SabrSmileSection>(smileSection3)->nu();
Real nu12 = 0.5*(nu1+nu2);
if (std::abs(nu3 - nu12) > tolerance) {
BOOST_ERROR("\nChecking interpolation of nu parameters:"
"\nexpected = " << nu12 <<
"\nobserved = " << nu3);
}

//test forward interpolation
Real forward1 = smileSection1->atmLevel();
Real forward2 = smileSection2->atmLevel();
Real forward3 = smileSection3->atmLevel();
Real forward12 = 0.5*(forward1+forward2);
if (std::abs(forward3 - forward12) > tolerance) {
BOOST_ERROR("\nChecking interpolation of forward parameters:"
"\nexpected = " << forward12 <<
"\nobserved = " << forward3);
}

}


test_suite* SwaptionVolatilityCubeTest::suite() {
test_suite* suite = BOOST_TEST_SUITE("Swaption Volatility Cube tests");

Expand All @@ -463,11 +570,13 @@ test_suite* SwaptionVolatilityCubeTest::suite() {
// SwaptionVolCubeBySabr reproduces ATM vol with given tolerance
// SwaptionVolCubeBySabr reproduces smile spreads with given tolerance
suite->add(QUANTLIB_TEST_CASE(&SwaptionVolatilityCubeTest::testSabrVols));
suite->add(QUANTLIB_TEST_CASE(
&SwaptionVolatilityCubeTest::testSpreadedCube));
suite->add(QUANTLIB_TEST_CASE(&SwaptionVolatilityCubeTest::testSpreadedCube));
suite->add(QUANTLIB_TEST_CASE(&SwaptionVolatilityCubeTest::testObservability));
suite->add(QUANTLIB_TEST_CASE(&SwaptionVolatilityCubeTest::testSabrParameters));

suite->add(QUANTLIB_TEST_CASE(
&SwaptionVolatilityCubeTest::testObservability));

return suite;
}



1 change: 1 addition & 0 deletions test-suite/swaptionvolatilitycube.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class SwaptionVolatilityCubeTest {
static void testSabrVols();
static void testSpreadedCube();
static void testObservability();
static void testSabrParameters();

static boost::unit_test_framework::test_suite* suite();
};
Expand Down

0 comments on commit 77b428d

Please sign in to comment.