/** * 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 java.util.Arrays; import com.opengamma.analytics.financial.model.volatility.BlackFormulaRepository; import com.opengamma.util.ArgumentChecker; /** * Class describing the data required to describe a delta dependent smile from ATM, risk reversal and strangle as used in Forex market. * The delta used is the delta with respect to forward. */ public class SmileDeltaParameters { /** * The time to expiry associated to the data. */ private final double _timeToExpiry; /** * Delta of the different data points. Must be positive and sorted in ascending order. The put will have as delta the opposite of the numbers. */ private final double[] _delta; /** * The volatilities associated to the strikes, */ private final double[] _volatility; /** * Constructor from volatility * @param timeToExpiration The time to expiration associated to the data. * @param delta Delta of the different data points. Must be positive and sorted in ascending order. The put will have as delta the opposite of the numbers. * @param volatility The volatilities. */ public SmileDeltaParameters(final double timeToExpiration, final double[] delta, final double[] volatility) { ArgumentChecker.notNull(delta, "Delta"); ArgumentChecker.notNull(volatility, "Volatility"); ArgumentChecker.isTrue(2 * delta.length + 1 == volatility.length, "Length of delta {} should be coherent with volatility length {}", 2 * delta.length + 1, volatility.length); _timeToExpiry = timeToExpiration; _delta = delta; _volatility = volatility; } /** * Constructor from market data ATM, RR, Strangle. * @param timeToExpiry The time to expiration associated to the data. * @param atm The ATM volatility. * @param delta Delta of the different data points. Must be positive and sorted in ascending order. The put will have as delta the opposite of the numbers. * @param riskReversal The risk reversal volatility figures, in the same order as the delta. * @param strangle The strangle volatility figures, in the same order as the delta. */ public SmileDeltaParameters(final double timeToExpiry, final double atm, final double[] delta, final double[] riskReversal, final double[] strangle) { ArgumentChecker.notNull(delta, "Delta"); ArgumentChecker.notNull(riskReversal, "Risk Reversal"); ArgumentChecker.notNull(strangle, "Strangle"); ArgumentChecker.isTrue(delta.length == riskReversal.length, "Length of delta {} should be equal to length of risk reversal {}", delta.length, riskReversal.length); ArgumentChecker.isTrue(delta.length == strangle.length, "Length of delta {} should be equal to length of strangle {} ", delta.length, strangle.length); //TODO: check that delta is sorted (ascending). //REVIEW 6-7-2011 emcleod better to do a parallel sort of delta, risk reversal and strangle and have another constructor // with an isSorted parameter that will not attempt the sort this._timeToExpiry = timeToExpiry; this._delta = delta; final int nbDelta = delta.length; _volatility = new double[2 * nbDelta + 1]; _volatility[nbDelta] = atm; for (int loopdelta = 0; loopdelta < nbDelta; loopdelta++) { _volatility[loopdelta] = strangle[loopdelta] + atm - riskReversal[loopdelta] / 2.0; // Put _volatility[2 * nbDelta - loopdelta] = strangle[loopdelta] + atm + riskReversal[loopdelta] / 2.0; // Call } } /** * Computes the strikes in ascending order. Put with lower delta (in absolute value) first, ATM and call with larger delta first * @param forward The forward. * @return The strikes. */ public double[] getStrike(final double forward) { final int nbDelta = _delta.length; final double[] strike = new double[2 * nbDelta + 1]; strike[nbDelta] = forward * Math.exp(_volatility[nbDelta] * _volatility[nbDelta] * _timeToExpiry / 2.0); for (int loopdelta = 0; loopdelta < nbDelta; loopdelta++) { strike[loopdelta] = BlackFormulaRepository.impliedStrike(-_delta[loopdelta], false, forward, _timeToExpiry, _volatility[loopdelta]); // Put strike[2 * nbDelta - loopdelta] = BlackFormulaRepository.impliedStrike(_delta[loopdelta], true, forward, _timeToExpiry, _volatility[2 * nbDelta - loopdelta]); // Call } return strike; } /** * Gets the time to expiry associated to the data. * @return The time to expiry. */ public double getTimeToExpiry() { return _timeToExpiry; } /** * Gets the delta of the different data points. Must be positive and sorted in ascending order. The put will have as delta the opposite of the numbers. * @return The delta. */ public double[] getDelta() { return _delta; } /** * Gets the volatilities associated to the strikes, * @return The volatilities, */ public double[] getVolatility() { return _volatility; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + Arrays.hashCode(_delta); long temp; temp = Double.doubleToLongBits(_timeToExpiry); result = prime * result + (int) (temp ^ (temp >>> 32)); result = prime * result + Arrays.hashCode(_volatility); 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 SmileDeltaParameters other = (SmileDeltaParameters) obj; if (!Arrays.equals(_delta, other._delta)) { return false; } if (Double.doubleToLongBits(_timeToExpiry) != Double.doubleToLongBits(other._timeToExpiry)) { return false; } if (!Arrays.equals(_volatility, other._volatility)) { return false; } return true; } }