SABRATMVolatilityCalibrationFunction { public SABRDataBundle calibrate(final OptionDefinition option, final SABRDataBundle data) { Validate.notNull(option, "option"); Validate.notNull(data, "data"); final double beta = data.getBeta(); final double t = option.getTimeToExpiry(data.getDate()); final double rho = data.getRho(); final double ksi = data.getVolOfVol(); final double sigmaATM = data.getVolatility(t, option.getStrike()); final double b = data.getCostOfCarry(); final double f = data.getSpot() * Math.exp(b * t); final double beta1 = 1 - beta; final double f1 = Math.pow(f, beta1); final double a0 = -sigmaATM * f1; final double a1 = 1 + (2 - 3 * rho * rho) * ksi * ksi * t / 24; final double a2 = rho * beta * ksi * t / 4 / f1; final double a3 = beta1 * beta1 * t / 24 / f1 / f1; Double[] roots; if (CompareUtils.closeEquals(a3, 0, 1e-16)) { roots = QUADRATIC_FINDER.getRoots(new RealPolynomialFunction1D(new double[] {a0, a1, a2})); } else { roots = ROOT_FINDER.getRoots(new RealPolynomialFunction1D(new double[] {a0, a1, a2, a3})); } Arrays.sort(roots); if (roots[0] > 0) { return data.withAlpha(roots[0]); } for (final Double r : roots) { if (r > 0) { return data.withAlpha(r); } } throw new MathException("Could not find positive real root"); }  SABRDataBundle calibrate(final OptionDefinition option, final SABRDataBundle data);  }
@Test(expectedExceptions = IllegalArgumentException.class) public void testNullOption() { FUNCTION.calibrate(null, DATA); }
@Test(expectedExceptions = IllegalArgumentException.class) public void testNullData() { FUNCTION.calibrate(OPTION, null); }
@Test public void testZeroVolOfVol() { final double beta = 0.5; final SABRDataBundle data = DATA.withVolOfVol(0).withBeta(beta); final double f1 = Math.pow(F, 1 - beta); final double a0 = -ATM_SIGMA * f1; final double a1 = 1; final double a2 = 0; final double a3 = (1 - beta) * (1 - beta) * T / 24 / f1 / f1; final Double[] roots = CUBIC_ROOT_FINDER.getRoots(new RealPolynomialFunction1D(new double[] {a0, a1, a2, a3})); assertEquals(roots[0], FUNCTION.calibrate(OPTION, data).getAlpha(), 1e-9); }
@Test public void testBetaEqualsOne() { final double a0 = -ATM_SIGMA; final double a1 = 1 + (2 - 3 * RHO * RHO) * KSI * KSI * T / 24; final double a2 = RHO * KSI * T / 4; final Double[] roots = QUADRATIC_ROOT_FINDER.getRoots(new RealPolynomialFunction1D(new double[] {a0, a1, a2})); assertEquals(FUNCTION.calibrate(OPTION, DATA).getAlpha(), roots[1], 1e-9); }