@Test public void testVolatilityAdjointLargeRhoZLessThan1() { double eps = 1e-4; double tol = 1e-5; SabrFormulaData data = DATA.withRho(1.0 - 1e-9); testVolatilityAdjoint(F, CALL_ITM, data, eps, tol); }
@Test public void testVolatilityAdjointLargeRhoZGreaterThan1() { double eps = 1e-11; double tol = 1e-4; SabrFormulaData data = DATA.withRho(1.0 - 1e-9).withAlpha(0.15 * ALPHA); testVolatilityAdjoint(F, CALL_ITM, data, eps, tol); }
/** Test the rho = 1 edge case */ @Test public void testVolatilityAdjointRho1() { double eps = 1e-4; double tol = 1e-5; SabrFormulaData data = DATA.withRho(1.0); testVolatilityAdjoint(F, CALL_ATM, data, eps, tol); testVolatilityAdjoint(F, CALL_ITM, data, eps, tol); testVolatilityAdjoint(F, CALL_OTM, data, eps, tol); }
@SuppressWarnings("null") private double fdSensitivity( EuropeanVanillaOption optionData, double forward, SabrFormulaData sabrData, SabrParameter param, double delta) { Function<SabrFormulaData, Double> funcC = null; Function<SabrFormulaData, Double> funcB = null; Function<SabrFormulaData, Double> funcA = null; SabrFormulaData dataC = null; SabrFormulaData dataB = sabrData; SabrFormulaData dataA = null; Function<SabrFormulaData, Double> func = getVolatilityFunction(optionData, forward); FiniteDifferenceType fdType = null; switch (param) { case Strike: double strike = optionData.getStrike(); if (strike >= delta) { fdType = FiniteDifferenceType.CENTRAL; funcA = getVolatilityFunction(withStrike(optionData, strike - delta), forward); funcC = getVolatilityFunction(withStrike(optionData, strike + delta), forward); } else { fdType = FiniteDifferenceType.FORWARD; funcA = func; funcB = getVolatilityFunction(withStrike(optionData, strike + delta), forward); funcC = getVolatilityFunction(withStrike(optionData, strike + 2 * delta), forward); } dataC = sabrData; dataB = sabrData; dataA = sabrData; break; case Forward: if (forward > delta) { fdType = FiniteDifferenceType.CENTRAL; funcA = getVolatilityFunction(optionData, forward - delta); funcC = getVolatilityFunction(optionData, forward + delta); } else { fdType = FiniteDifferenceType.FORWARD; funcA = func; funcB = getVolatilityFunction(optionData, forward + delta); funcC = getVolatilityFunction(optionData, forward + 2 * delta); } dataC = sabrData; dataB = sabrData; dataA = sabrData; break; case Alpha: double a = sabrData.getAlpha(); if (a >= delta) { fdType = FiniteDifferenceType.CENTRAL; dataA = sabrData.withAlpha(a - delta); dataC = sabrData.withAlpha(a + delta); } else { fdType = FiniteDifferenceType.FORWARD; dataA = sabrData; dataB = sabrData.withAlpha(a + delta); dataC = sabrData.withAlpha(a + 2 * delta); } funcC = func; funcB = func; funcA = func; break; case Beta: double b = sabrData.getBeta(); if (b >= delta) { fdType = FiniteDifferenceType.CENTRAL; dataA = sabrData.withBeta(b - delta); dataC = sabrData.withBeta(b + delta); } else { fdType = FiniteDifferenceType.FORWARD; dataA = sabrData; dataB = sabrData.withBeta(b + delta); dataC = sabrData.withBeta(b + 2 * delta); } funcC = func; funcB = func; funcA = func; break; case Nu: double n = sabrData.getNu(); if (n >= delta) { fdType = FiniteDifferenceType.CENTRAL; dataA = sabrData.withNu(n - delta); dataC = sabrData.withNu(n + delta); } else { fdType = FiniteDifferenceType.FORWARD; dataA = sabrData; dataB = sabrData.withNu(n + delta); dataC = sabrData.withNu(n + 2 * delta); } funcC = func; funcB = func; funcA = func; break; case Rho: double r = sabrData.getRho(); if ((r + 1) < delta) { fdType = FiniteDifferenceType.FORWARD; dataA = sabrData; dataB = sabrData.withRho(r + delta); dataC = sabrData.withRho(r + 2 * delta); } else if ((1 - r) < delta) { fdType = FiniteDifferenceType.BACKWARD; dataA = sabrData.withRho(r - 2 * delta); dataB = sabrData.withRho(r - delta); dataC = sabrData; } else { fdType = FiniteDifferenceType.CENTRAL; dataC = sabrData.withRho(r + delta); dataA = sabrData.withRho(r - delta); } funcC = func; funcB = func; funcA = func; break; default: throw new MathException("enum not found"); } if (fdType != null) { switch (fdType) { case FORWARD: return (-1.5 * funcA.apply(dataA) + 2.0 * funcB.apply(dataB) - 0.5 * funcC.apply(dataC)) / delta; case BACKWARD: return (0.5 * funcA.apply(dataA) - 2.0 * funcB.apply(dataB) + 1.5 * funcC.apply(dataC)) / delta; case CENTRAL: return (funcC.apply(dataC) - funcA.apply(dataA)) / 2.0 / delta; default: throw new MathException("enum not found"); } } throw new MathException("enum not found"); }