/** * Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.model.option.definition; import org.apache.commons.lang.ObjectUtils; import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.EuropeanVanillaOption; import com.opengamma.analytics.financial.model.volatility.VolatilityModel; 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.function.Function1D; import com.opengamma.analytics.math.surface.InterpolatedDoublesSurface; import com.opengamma.financial.convention.daycount.DayCount; import com.opengamma.financial.convention.daycount.DayCounts; import com.opengamma.util.ArgumentChecker; import com.opengamma.util.tuple.DoublesPair; /** * Class describing the SABR parameter surfaces used in interest rate modeling. */ public class SABRInterestRateParameters implements VolatilityModel<double[]> { /** * The alpha (volatility level) surface. The first dimension is the expiration and the second the tenor. */ private final InterpolatedDoublesSurface _alphaSurface; /** * The beta (elasticity) surface. The first dimension is the expiration and the second the tenor. */ private final InterpolatedDoublesSurface _betaSurface; /** * The rho (correlation) surface. The first dimension is the expiration and the second the tenor. */ private final InterpolatedDoublesSurface _rhoSurface; /** * The nu (volatility of volatility) surface. The first dimension is the expiration and the second the tenor. */ private final InterpolatedDoublesSurface _nuSurface; /** * The function containing the SABR volatility formula. Default is HaganVolatilityFunction. */ private final VolatilityFunctionProvider<SABRFormulaData> _sabrFunction; /** * The standard day count for which the parameter surfaces are valid. */ /** @deprecated [PLAT-6236] Should be removed from here as it is available at the provider level. **/ @Deprecated private final DayCount _dayCount; /** Default day count used while deprecating the _dayCount field **/ private static final DayCount DAY_COUNT_DEFAULT = DayCounts.ACT_360; /** * Constructor from the parameter surfaces. The default SABR volatility formula is HaganVolatilityFunction. * @param alpha The alpha parameters. The first dimension is the expiration and the second the tenor. * @param beta The beta parameters. * @param rho The rho parameters. * @param nu The nu parameters. */ public SABRInterestRateParameters(final InterpolatedDoublesSurface alpha, final InterpolatedDoublesSurface beta, final InterpolatedDoublesSurface rho, final InterpolatedDoublesSurface nu) { this(alpha, beta, rho, nu, new SABRHaganVolatilityFunction()); } /** * Constructor from the parameter surfaces. The default SABR volatility formula is HaganVolatilityFunction. * @param alpha The alpha parameters. The first dimension is the expiration and the second the tenor. * @param beta The beta parameters. * @param rho The rho parameters. * @param nu The nu parameters. * @param sabrFormula The SABR formula provider. */ public SABRInterestRateParameters(final InterpolatedDoublesSurface alpha, final InterpolatedDoublesSurface beta, final InterpolatedDoublesSurface rho, final InterpolatedDoublesSurface nu, final VolatilityFunctionProvider<SABRFormulaData> sabrFormula) { ArgumentChecker.notNull(alpha, "alpha surface"); ArgumentChecker.notNull(beta, "beta surface"); ArgumentChecker.notNull(rho, "rho surface"); ArgumentChecker.notNull(nu, "nu surface"); ArgumentChecker.notNull(sabrFormula, "SABR formula"); _alphaSurface = alpha; _betaSurface = beta; _rhoSurface = rho; _nuSurface = nu; _dayCount = DAY_COUNT_DEFAULT; _sabrFunction = sabrFormula; } /** * Constructor from the parameter surfaces. The default SABR volatility formula is HaganVolatilityFunction. * @param alpha The alpha parameters. The first dimension is the expiration and the second the tenor. * @param beta The beta parameters. * @param rho The rho parameters. * @param nu The nu parameters. * @param dayCount The standard day count for which the parameter surfaces are valid. * @deprecated Used the constructor without day count. */ @Deprecated public SABRInterestRateParameters(final InterpolatedDoublesSurface alpha, final InterpolatedDoublesSurface beta, final InterpolatedDoublesSurface rho, final InterpolatedDoublesSurface nu, final DayCount dayCount) { this(alpha, beta, rho, nu, dayCount, new SABRHaganVolatilityFunction()); } /** * Constructor from the parameter surfaces. The default SABR volatility formula is HaganVolatilityFunction. * @param alpha The alpha parameters. The first dimension is the expiration and the second the tenor. * @param beta The beta parameters. * @param rho The rho parameters. * @param nu The nu parameters. * @param dayCount The standard day count for which the parameter surfaces are valid. * @param sabrFormula The SABR formula provider. * @deprecated Used the constructor without day count. */ @Deprecated public SABRInterestRateParameters(final InterpolatedDoublesSurface alpha, final InterpolatedDoublesSurface beta, final InterpolatedDoublesSurface rho, final InterpolatedDoublesSurface nu, final DayCount dayCount, final VolatilityFunctionProvider<SABRFormulaData> sabrFormula) { ArgumentChecker.notNull(alpha, "alpha surface"); ArgumentChecker.notNull(beta, "beta surface"); ArgumentChecker.notNull(rho, "rho surface"); ArgumentChecker.notNull(nu, "nu surface"); ArgumentChecker.notNull(dayCount, "dayCount"); ArgumentChecker.notNull(sabrFormula, "SABR formula"); _alphaSurface = alpha; _betaSurface = beta; _rhoSurface = rho; _nuSurface = nu; _dayCount = dayCount; _sabrFunction = sabrFormula; } /** * Return the alpha parameter for a pair of time to expiry and instrument maturity. * @param expiryMaturity The expiry/maturity pair. * @return The alpha parameter. */ public double getAlpha(final DoublesPair expiryMaturity) { return _alphaSurface.getZValue(expiryMaturity); } /** * Return the beta parameter for a pair of time to expiry and instrument maturity. * @param expiryMaturity The expiry/maturity pair. * @return The beta parameter. */ public double getBeta(final DoublesPair expiryMaturity) { return _betaSurface.getZValue(expiryMaturity); } /** * Return the rho parameter for a pair of time to expiry and instrument maturity. * @param expiryMaturity The expiry/maturity pair. * @return The rho parameter. */ public double getRho(final DoublesPair expiryMaturity) { return _rhoSurface.getZValue(expiryMaturity); } /** * Return the nu parameter for a pair of time to expiry and instrument maturity. * @param expiryMaturity The expiry/maturity pair. * @return The nu parameter. */ public double getNu(final DoublesPair expiryMaturity) { return _nuSurface.getZValue(expiryMaturity); } /** * Gets the standard day count for which the parameter surfaces are valid. * @return The day count. * @deprecated Should be removed from the data structure but available at the provider level. */ @Deprecated public DayCount getDayCount() { return _dayCount; } /** * Gets the SABR function. * @return The SABR function */ public VolatilityFunctionProvider<SABRFormulaData> getSabrFunction() { return _sabrFunction; } /** * Gets the alpha surface. * @return The alpha surface. */ public InterpolatedDoublesSurface getAlphaSurface() { return _alphaSurface; } /** * Gets the beta surface. * @return The beta surface. */ public InterpolatedDoublesSurface getBetaSurface() { return _betaSurface; } /** * Gets the rho surface. * @return The rho surface. */ public InterpolatedDoublesSurface getRhoSurface() { return _rhoSurface; } /** * Gets the nu surface. * @return The nu surface. */ public InterpolatedDoublesSurface getNuSurface() { return _nuSurface; } /** * Return the volatility for a expiry, a maturity, a strike and a forward rate. * @param expiryTime Time to expiry. * @param maturity Tenor. * @param strike The strike. * @param forward The forward. * @return The volatility. */ public double getVolatility(final double expiryTime, final double maturity, final double strike, final double forward) { final DoublesPair expiryMaturity = DoublesPair.of(expiryTime, maturity); final SABRFormulaData data = new SABRFormulaData(getAlpha(expiryMaturity), getBeta(expiryMaturity), getRho(expiryMaturity), getNu(expiryMaturity)); final EuropeanVanillaOption option = new EuropeanVanillaOption(strike, expiryTime, true); final Function1D<SABRFormulaData, Double> funcSabrLongPayer = _sabrFunction.getVolatilityFunction(option, forward); return funcSabrLongPayer.evaluate(data); } @Override /** * Return the volatility for a expiry/maturity/strike/forward array. * @param data An array of four doubles with [0] the expiry, [1] the maturity, [2] the strike, [3] the forward. * @return The volatility. */ public Double getVolatility(final double[] data) { ArgumentChecker.notNull(data, "data"); ArgumentChecker.isTrue(data.length == 4, "data should have four components (expiry time, maturity, strike and forward"); return getVolatility(data[0], data[1], data[2], data[3]); } /** * Return the Black implied volatility in the SABR model and its derivatives when the SABR function is Hagan function. * @param expiryTime Time to expiry. * @param maturity Tenor. * @param strike The strike. * @param forward The forward. * @return The volatility and its derivative. An array with [0] the volatility, [1] Derivative w.r.t the forward, [2] the derivative w.r.t the strike, * [3] the derivative w.r.t. to alpha, [4] the derivative w.r.t. to beta, [5] the derivative w.r.t. to rho, [6] the derivative w.r.t. to nu. */ public double[] getVolatilityAdjoint(final double expiryTime, final double maturity, final double strike, final double forward) { ArgumentChecker.isTrue(_sabrFunction instanceof SABRHaganVolatilityFunction, "Adjoint volatility available only for Hagan formula"); final SABRHaganVolatilityFunction sabrHaganFunction = (SABRHaganVolatilityFunction) _sabrFunction; final DoublesPair expiryMaturity = DoublesPair.of(expiryTime, maturity); final SABRFormulaData data = new SABRFormulaData(getAlpha(expiryMaturity), getBeta(expiryMaturity), getRho(expiryMaturity), getNu(expiryMaturity)); final EuropeanVanillaOption option = new EuropeanVanillaOption(strike, expiryTime, true); final double[] result = sabrHaganFunction.getVolatilityAdjoint(option, forward, data); return result; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + _alphaSurface.hashCode(); result = prime * result + _betaSurface.hashCode(); result = prime * result + _nuSurface.hashCode(); result = prime * result + _rhoSurface.hashCode(); result = prime * result + _sabrFunction.hashCode(); return result; } @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final SABRInterestRateParameters other = (SABRInterestRateParameters) obj; if (!ObjectUtils.equals(_alphaSurface, other._alphaSurface)) { return false; } if (!ObjectUtils.equals(_betaSurface, other._betaSurface)) { return false; } if (!ObjectUtils.equals(_rhoSurface, other._rhoSurface)) { return false; } if (!ObjectUtils.equals(_nuSurface, other._nuSurface)) { return false; } return ObjectUtils.equals(_sabrFunction, other._sabrFunction); } }