/**
* 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.smile.fitting;
import org.apache.commons.lang.Validate;
import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.EuropeanVanillaOption;
import com.opengamma.analytics.financial.model.volatility.smile.function.SABRFormulaData;
import com.opengamma.analytics.financial.model.volatility.smile.function.VolatilityFunctionProvider;
import com.opengamma.analytics.math.function.Function1D;
import com.opengamma.analytics.math.rootfinding.BracketRoot;
import com.opengamma.analytics.math.rootfinding.RealSingleRootFinder;
import com.opengamma.analytics.math.rootfinding.RidderSingleRootFinder;
/**
*
*/
public class SABRATMVolatilityCalculator {
private final VolatilityFunctionProvider<SABRFormulaData> _sabrFormula;
private final BracketRoot _bracketer = new BracketRoot();
private final RealSingleRootFinder _rootFinder = new RidderSingleRootFinder();
public SABRATMVolatilityCalculator(final VolatilityFunctionProvider<SABRFormulaData> formula) {
Validate.notNull(formula, "formula");
_sabrFormula = formula;
}
/**
* Finds the alpha that gives the required ATM volatility
* @param data SABR parameters - the alpha value is ignored
* @param option The option
* @param forward the forward
* @param atmVol The ATM volatility
* @return the value of alpha
*/
public double calculate(final SABRFormulaData data, final EuropeanVanillaOption option, final double forward, final double atmVol) {
Validate.notNull(data, "data");
Validate.notNull(option, "option");
Validate.isTrue(atmVol > 0, "ATM vol must be > 0");
final Function1D<Double, Double> f = new Function1D<Double, Double>() {
@SuppressWarnings("synthetic-access")
@Override
public Double evaluate(final Double alpha) {
final SABRFormulaData newData = new SABRFormulaData(alpha, data.getBeta(), data.getRho(), data.getNu());
return _sabrFormula.getVolatilityFunction(option, forward).evaluate(newData) - atmVol;
}
};
final double alphaTry = atmVol * Math.pow(forward, 1 - data.getBeta());
final double[] range = _bracketer.getBracketedPoints(f, alphaTry / 2.0, 2 * alphaTry);
return _rootFinder.getRoot(f, range[0], range[1]);
}
}