/** * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.model.option.parameters; import org.apache.commons.lang.ObjectUtils; import com.opengamma.analytics.financial.instrument.index.IndexPrice; import com.opengamma.analytics.financial.model.interestrate.definition.InflationYearOnYearCapFloorParameters; import com.opengamma.analytics.financial.model.volatility.VolatilityModel; import com.opengamma.analytics.math.interpolation.CombinedInterpolatorExtrapolatorFactory; import com.opengamma.analytics.math.interpolation.GridInterpolator2D; import com.opengamma.analytics.math.interpolation.Interpolator1D; import com.opengamma.analytics.math.interpolation.Interpolator1DFactory; import com.opengamma.analytics.math.interpolation.Interpolator2D; import com.opengamma.analytics.math.surface.InterpolatedDoublesSurface; import com.opengamma.util.ArgumentChecker; import com.opengamma.util.tuple.DoublesPair; /** * Class describing the Black volatility surface used in inflation year on year cap/floor modeling. The inflation year on year rate (\{CPI(T_{i+1})}{CPI(T_{i})})rate is assumed to be normal. */ public class BlackSmileCapInflationYearOnYearParameters implements VolatilityModel<double[]> { /** * The volatility surface. The dimensions are the expiration and the strike. Not null. */ private final InterpolatedDoublesSurface _volatility; /** * The index price for which the volatility is valid. Not null. */ private final IndexPrice _index; /** * Constructor from the parameter surfaces. * @param volatility The Black volatility curve. * @param index The index price for which the volatility is valid. */ public BlackSmileCapInflationYearOnYearParameters(final InterpolatedDoublesSurface volatility, final IndexPrice index) { ArgumentChecker.notNull(volatility, "volatility"); ArgumentChecker.notNull(index, "index"); _volatility = volatility; _index = index; } /** * Constructor from the parameter surfaces. * @param expiryTimes The Black volatility curve. * @param strikes The Black volatility curve. * @param volatility The Black volatility cube. * @param interpolator The interpolator necessary to Black volatility surface from the black volatility cube. * @param index The index price for which the volatility is valid. */ public BlackSmileCapInflationYearOnYearParameters(final double[] expiryTimes, final double[] strikes, final double[][] volatility, final Interpolator2D interpolator, final IndexPrice index) { ArgumentChecker.notNull(volatility, "volatility"); ArgumentChecker.notNull(expiryTimes, "expiryTimes"); ArgumentChecker.notNull(strikes, "strikes"); ArgumentChecker.notNull(index, "index"); ArgumentChecker.isTrue(expiryTimes.length == volatility.length, null); ArgumentChecker.isTrue(strikes.length == volatility[0].length, null); final DoublesPair[] xyData = new DoublesPair[expiryTimes.length * strikes.length]; final double[] volatilityVector = new double[expiryTimes.length * strikes.length]; for (int i = 0; i < expiryTimes.length; i++) { for (int j = 0; j < strikes.length; j++) { xyData[i + j * expiryTimes.length] = DoublesPair.of(expiryTimes[i], strikes[j]); volatilityVector[i + j * expiryTimes.length] = volatility[i][j]; } } _volatility = InterpolatedDoublesSurface.from(xyData, volatilityVector, interpolator); _index = index; } /** * Constructor from the parameter surfaces. * @param parameters The Black volatility curve. * @param interpolator The Black volatility curve. */ public BlackSmileCapInflationYearOnYearParameters(final InflationYearOnYearCapFloorParameters parameters, final Interpolator2D interpolator) { ArgumentChecker.notNull(interpolator, "interpolator"); final double[] expiryTimes = parameters.getExpiryTimes(); final double[] strikes = parameters.getStrikes(); final double[][] volatility = parameters.getVolatility(); final DoublesPair[] xyData = new DoublesPair[expiryTimes.length * strikes.length]; final double[] volatilityVector = new double[expiryTimes.length * strikes.length]; for (int i = 0; i < expiryTimes.length; i++) { for (int j = 0; j < strikes.length; j++) { xyData[i + j * expiryTimes.length] = DoublesPair.of(expiryTimes[i], strikes[j]); volatilityVector[i + j * expiryTimes.length] = volatility[i][j]; } } _volatility = InterpolatedDoublesSurface.from(xyData, volatilityVector, interpolator); _index = parameters.getIndex(); } /** * Constructor from the parameter surfaces and default interpolator. * @param parameters The Black volatility curve. */ public BlackSmileCapInflationYearOnYearParameters(final InflationYearOnYearCapFloorParameters parameters) { final double[] expiryTimes = parameters.getExpiryTimes(); final double[] strikes = parameters.getStrikes(); final double[][] volatility = parameters.getVolatility(); final DoublesPair[] xyData = new DoublesPair[expiryTimes.length * strikes.length]; final double[] volatilityVector = new double[expiryTimes.length * strikes.length]; for (int i = 0; i < expiryTimes.length; i++) { for (int j = 0; j < strikes.length; j++) { xyData[i + j * expiryTimes.length] = DoublesPair.of(expiryTimes[i], strikes[j]); volatilityVector[i + j * expiryTimes.length] = volatility[i][j]; } } final Interpolator1D linearFlat = CombinedInterpolatorExtrapolatorFactory.getInterpolator(Interpolator1DFactory.LINEAR, Interpolator1DFactory.FLAT_EXTRAPOLATOR, Interpolator1DFactory.FLAT_EXTRAPOLATOR); final GridInterpolator2D interpolator = new GridInterpolator2D(linearFlat, linearFlat); _volatility = InterpolatedDoublesSurface.from(xyData, volatilityVector, interpolator); _index = parameters.getIndex(); } /** * Return the volatility for a time to expiration and strike. * @param expiration The time to expiration. * @param strike The strike. * @return The volatility. */ public double getVolatility(final double expiration, final double strike) { return _volatility.getZValue(expiration, strike); } /** * Return the volatility surface. * @return The volatility surface. */ public InterpolatedDoublesSurface getVolatilitySurface() { return _volatility; } @Override /** * Return the volatility for a expiration tenor array. * @param data An array of one doubles with the expiration. * @return The volatility. */ public Double getVolatility(final double[] data) { ArgumentChecker.notNull(data, "data"); ArgumentChecker.isTrue(data.length == 2, "data should have two components (expiration and strike)"); return getVolatility(data[0], data[1]); } /** * Gets the Ibor index for which the volatility is valid. * @return The index. */ public IndexPrice getIndex() { return _index; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + _index.hashCode(); result = prime * result + _volatility.hashCode(); return result; } @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (!(obj instanceof BlackSmileCapInflationYearOnYearParameters)) { return false; } final BlackSmileCapInflationYearOnYearParameters other = (BlackSmileCapInflationYearOnYearParameters) obj; if (!ObjectUtils.equals(_index, other._index)) { return false; } if (!ObjectUtils.equals(_volatility, other._volatility)) { return false; } return true; } }