/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.model.volatility.surface; import java.util.Arrays; import org.apache.commons.lang.Validate; import com.opengamma.analytics.financial.model.option.definition.OptionDefinition; import com.opengamma.analytics.financial.model.option.definition.SABRDataBundle; import com.opengamma.analytics.math.MathException; import com.opengamma.analytics.math.function.RealPolynomialFunction1D; import com.opengamma.analytics.math.rootfinding.CubicRealRootFinder; import com.opengamma.analytics.math.rootfinding.Polynomial1DRootFinder; import com.opengamma.analytics.math.rootfinding.QuadraticRealRootFinder; import com.opengamma.util.CompareUtils; /** * */ public class SABRATMVolatilityCalibrationFunction { private static final Polynomial1DRootFinder<Double> QUADRATIC_FINDER = new QuadraticRealRootFinder(); private static final Polynomial1DRootFinder<Double> ROOT_FINDER = new CubicRealRootFinder(); 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"); } }