1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
|
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
Copyright (C) 2014 Peter Caspers
This file is part of QuantLib, a free-software/open-source library
for financial quantitative analysts and developers - http://quantlib.org/
QuantLib is free software: you can redistribute it and/or modify it
under the terms of the QuantLib license. You should have received a
copy of the license along with this program; if not, please email
<quantlib-dev@lists.sf.net>. The license is also available online at
<https://www.quantlib.org/license.shtml>.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the license for more details.
*/
#include "toplevelfixture.hpp"
#include "utilities.hpp"
#include <ql/termstructures/volatility/sabrsmilesection.hpp>
#include <ql/experimental/volatility/noarbsabrsmilesection.hpp>
using namespace QuantLib;
using namespace boost::unit_test_framework;
BOOST_FIXTURE_TEST_SUITE(QuantLibTests, TopLevelFixture)
BOOST_AUTO_TEST_SUITE(NoArbSabrTests)
void checkD0(const Real sigmaI, const Real beta, const Real rho, const Real nu,
const Real tau, const unsigned int absorptions) {
Real forward = 0.03; // does not matter in the end
Real alpha = sigmaI / std::pow(forward, beta - 1.0);
QuantLib::detail::D0Interpolator d(forward, tau, alpha, beta, nu, rho);
if (std::fabs(d() * QuantLib::detail::NoArbSabrModel::nsim - (Real)absorptions) > 0.1)
BOOST_ERROR("failed to reproduce number of absorptions at sigmaI="
<< sigmaI << ", beta=" << beta << ", rho=" << rho << ", nu="
<< nu << " tau=" << tau << ": D0Interpolator says "
<< d() * QuantLib::detail::NoArbSabrModel::nsim
<< " while the reference value is " << absorptions);
}
BOOST_AUTO_TEST_CASE(testAbsorptionMatrix) {
BOOST_TEST_MESSAGE("Testing no-arbitrage Sabr absorption matrix...");
// check some points explicitly against the external file's contents
// sigmaI, beta, rho, nu, tau, absorptions
checkD0(1,0.01,0.75,0.1,0.25,60342); // upper left corner
checkD0(0.8,0.01,0.75,0.1,0.25,12148);
checkD0(0.05,0.01,0.75,0.1,0.25,0);
checkD0(1,0.01,0.75,0.1,10.0,1890509);
checkD0(0.8,0.01,0.75,0.1,10.0,1740233);
checkD0(0.05,0.01,0.75,0.1,10.0,0);
checkD0(1,0.01,0.75,0.1,30.0,2174176);
checkD0(0.8,0.01,0.75,0.1,30.0,2090672);
checkD0(0.05,0.01,0.75,0.1,30.0,31);
checkD0(0.35,0.10,-0.75,0.1,0.25,0);
checkD0(0.35,0.10,-0.75,0.1,14.75,1087841);
checkD0(0.35,0.10,-0.75,0.1,30.0,1406569);
checkD0(0.24,0.90,0.50,0.8,1.25,27);
checkD0(0.24,0.90,0.50,0.8,25.75,167541);
checkD0(0.05,0.90,-0.75,0.8,2.0,17);
checkD0(0.05,0.90,-0.75,0.8,30.0,42100); // lower right corner
}
BOOST_AUTO_TEST_CASE(testConsistencyWithHagan) {
BOOST_TEST_MESSAGE("Testing consistency of noarb-sabr with Hagan et al (2002)");
// parameters taken from Doust's paper, figure 3
Real tau = 1.0;
Real beta = 0.5;
Real alpha = 0.026;
Real rho = -0.1;
Real nu = 0.4;
Real f = 0.0488;
SabrSmileSection sabr(tau, f, {alpha, beta, nu, rho});
NoArbSabrSmileSection noarbsabr(tau, f, {alpha, beta, nu, rho});
Real absProb=noarbsabr.model()->absorptionProbability();
if( absProb > 1E-10 || absProb < 0.0 )
BOOST_ERROR("absorption probability should be close to zero, but is " << absProb);
Real strike = 0.0001;
while (strike < 0.15) {
// test vanilla prices
Real sabrPrice = sabr.optionPrice(strike);
Real noarbsabrPrice = noarbsabr.optionPrice(strike);
if (std::fabs(sabrPrice - noarbsabrPrice) > 1e-5)
BOOST_ERROR("incosistent Hagan price ("
<< sabrPrice << ") and noarb-sabr price ("
<< noarbsabrPrice << ") at strike " << strike);
// test digitals
Real sabrDigital = sabr.digitalOptionPrice(strike);
Real noarbsabrDigital = noarbsabr.digitalOptionPrice(strike);
if (std::fabs(sabrDigital - noarbsabrDigital) > 1e-3)
BOOST_ERROR("incosistent Hagan digital ("
<< sabrDigital << ") and noarb-sabr digital ("
<< noarbsabrDigital << ") at strike " << strike);
// test density
Real sabrDensity = sabr.density(strike);
Real noarbsabrDensity = noarbsabr.density(strike);
if (std::fabs(sabrDensity - noarbsabrDensity) > 1e-0)
BOOST_ERROR("incosistent Hagan density ("
<< sabrDensity << ") and noarb-sabr density ("
<< noarbsabrDensity << ") at strike " << strike);
strike += 0.0001;
}
}
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE_END()
|