/** * Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.model.volatility; import java.util.LinkedHashMap; 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.SABRHaganVolatilityFunction; import com.opengamma.analytics.financial.model.volatility.smile.function.VolatilityFunctionProvider; import com.opengamma.analytics.math.curve.Curve; import com.opengamma.analytics.math.function.Function1D; /** * */ public class SABRTermStructureParameters implements VolatilityModel1D { private static final String ALPHA = "alpha"; private static final String BETA = "beta"; private static final String NU = "nu"; private static final String RHO = "rho"; private static final VolatilityFunctionProvider<SABRFormulaData> DEFUALT_SABR = new SABRHaganVolatilityFunction(); private final Curve<Double, Double> _alpha; private final Curve<Double, Double> _beta; private final Curve<Double, Double> _nu; private final Curve<Double, Double> _rho; private final VolatilityFunctionProvider<SABRFormulaData> _sabrFunction; public SABRTermStructureParameters(final LinkedHashMap<String, Curve<Double, Double>> curveBundle) { Validate.notNull(curveBundle, "null curve bundle"); Curve<Double, Double> alpha = curveBundle.get(ALPHA); Curve<Double, Double> beta = curveBundle.get(BETA); Curve<Double, Double> nu = curveBundle.get(NU); Curve<Double, Double> rho = curveBundle.get(RHO); validate(alpha, beta, rho, nu); _alpha = alpha; _beta = beta; _nu = nu; _rho = rho; _sabrFunction = DEFUALT_SABR; } public SABRTermStructureParameters(final Curve<Double, Double> alpha, final Curve<Double, Double> beta, final Curve<Double, Double> rho, final Curve<Double, Double> nu) { this(alpha, beta, rho, nu, DEFUALT_SABR); } public SABRTermStructureParameters(final Curve<Double, Double> alpha, final Curve<Double, Double> beta, final Curve<Double, Double> rho, final Curve<Double, Double> nu, VolatilityFunctionProvider<SABRFormulaData> sabrFunction) { validate(alpha, beta, rho, nu); Validate.notNull(sabrFunction, "null sabrFunction"); _alpha = alpha; _beta = beta; _nu = nu; _rho = rho; _sabrFunction = sabrFunction; } private static void validate(final Curve<Double, Double> alpha, final Curve<Double, Double> beta, final Curve<Double, Double> rho, final Curve<Double, Double> nu) { Validate.notNull(alpha, "null aplha"); Validate.notNull(beta, "null beta"); Validate.notNull(nu, "null nu"); Validate.notNull(rho, "null rho"); } public double getAlpha(final double timeToExpiry) { return _alpha.getYValue(timeToExpiry); } public double getBeta(final double timeToExpiry) { return _beta.getYValue(timeToExpiry); } public double getRho(final double timeToExpiry) { return _rho.getYValue(timeToExpiry); } public double getNu(final double timeToExpiry) { return _nu.getYValue(timeToExpiry); } /** * get the Black volatility for a given forward/strike/time-to-expiry * @param fwdKT Array of values of forward, strike and time-to-expiry <b>in that order</b> * @return The (Black) volatility */ @Override public Double getVolatility(double[] fwdKT) { Validate.notNull(fwdKT, "null fwdKT"); Validate.isTrue(fwdKT.length == 3, "length must be 3"); return getVolatility(fwdKT[0], fwdKT[1], fwdKT[2]); } /** * get the Black volatility for a given forward/strike/time-to-expiry * @param fwd The Forward * @param strike The Strike * @param timeToExpiry The time-to-expiry * @return The (Black) volatility */ @Override public double getVolatility(final double fwd, final double strike, final double timeToExpiry) { final SABRFormulaData data = new SABRFormulaData(getAlpha(timeToExpiry), getBeta(timeToExpiry), getRho(timeToExpiry), getNu(timeToExpiry)); final EuropeanVanillaOption option = new EuropeanVanillaOption(strike, timeToExpiry, true); final Function1D<SABRFormulaData, Double> func = _sabrFunction.getVolatilityFunction(option, fwd); double vol = func.evaluate(data); //The SABR Hagan formula can produce negative vols return Math.max(0, vol); } @Override public double getVolatility(SimpleOptionData option) { return getVolatility(option.getForward(), option.getStrike(), option.getTimeToExpiry()); } }