Package com.opengamma.analytics.financial.model.volatility.surface

Source Code of com.opengamma.analytics.financial.model.volatility.surface.SmileDeltaTermStructureParameters

/**
* Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.model.volatility.surface;

import java.util.Arrays;

import org.apache.commons.lang.NotImplementedException;
import org.apache.commons.lang.ObjectUtils;

import com.opengamma.analytics.financial.model.option.definition.SmileDeltaParameters;
import com.opengamma.analytics.financial.model.volatility.SmileAndBucketedSensitivities;
import com.opengamma.analytics.financial.model.volatility.VolatilityAndBucketedSensitivities;
import com.opengamma.analytics.financial.model.volatility.VolatilityAndBucketedSensitivitiesModel;
import com.opengamma.analytics.financial.model.volatility.curve.BlackForexTermStructureParameters;
import com.opengamma.analytics.math.curve.InterpolatedDoublesCurve;
import com.opengamma.analytics.math.interpolation.CombinedInterpolatorExtrapolatorFactory;
import com.opengamma.analytics.math.interpolation.Interpolator1D;
import com.opengamma.analytics.math.interpolation.Interpolator1DFactory;
import com.opengamma.analytics.math.interpolation.data.ArrayInterpolator1DDataBundle;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.tuple.Triple;

/**
* Class describing the a term structure of smiles from ATM, risk reversal and strangle as used in Forex market.
* The delta used is the delta with respect to forward.
*/
public class SmileDeltaTermStructureParameters implements VolatilityAndBucketedSensitivitiesModel<Triple<Double, Double, Double>> {

  /**
   * The time to expiration in the term structure.
   */
  private final double[] _timeToExpiration;
  /**
   * The smile description at the different time to expiration. All item should have the same deltas.
   */
  private final SmileDeltaParameters[] _volatilityTerm;
  /**
   * The interpolator/extrapolator used in the expiry dimension.
   */
  private final Interpolator1D _timeInterpolator;

  /**
   * The default interpolator: time square (total variance) with flat extrapolation.
   */
  private static final Interpolator1D DEFAULT_INTERPOLATOR_EXPIRY = CombinedInterpolatorExtrapolatorFactory.getInterpolator(Interpolator1DFactory.TIME_SQUARE, Interpolator1DFactory.FLAT_EXTRAPOLATOR,
      Interpolator1DFactory.FLAT_EXTRAPOLATOR);

  /**
   * Constructor from volatility term structure.
   * @param volatilityTerm The volatility description at the different expiration.
   */
  public SmileDeltaTermStructureParameters(final SmileDeltaParameters[] volatilityTerm) {
    this(volatilityTerm, DEFAULT_INTERPOLATOR_EXPIRY);
  }

  /**
   * Constructor from volatility term structure.
   * @param volatilityTerm The volatility description at the different expiration.
   * @param interpolator The time interpolator
   */
  public SmileDeltaTermStructureParameters(final SmileDeltaParameters[] volatilityTerm, final Interpolator1D interpolator) {
    ArgumentChecker.notNull(volatilityTerm, "Volatility term structure");
    ArgumentChecker.notNull(interpolator, "interpolator");
    _volatilityTerm = volatilityTerm;
    final int nbExp = volatilityTerm.length;
    _timeToExpiration = new double[nbExp];
    for (int loopexp = 0; loopexp < nbExp; loopexp++) {
      _timeToExpiration[loopexp] = _volatilityTerm[loopexp].getTimeToExpiry();
    }
    _timeInterpolator = interpolator;
  }

  /**
   * Constructor from market data.
   * @param timeToExpiration The time to expiration of each volatility smile, not null
   * @param delta The delta at which the volatilities are given. Must be positive and sorted in ascending order. The put will have as delta the opposite of the numbers.
   * Common to all time to expiration. Not null
   * @param volatility The volatilities at each delta, not null
   */
  public SmileDeltaTermStructureParameters(final double[] timeToExpiration, final double[] delta, final double[][] volatility) {
    ArgumentChecker.notNull(timeToExpiration, "time to expiry");
    ArgumentChecker.notNull(delta, "delta");
    ArgumentChecker.notNull(volatility, "volatility");
    final int nbExp = timeToExpiration.length;
    ArgumentChecker.isTrue(volatility.length == nbExp, "Volatility array length {} should be equal to the number of expiries {}", volatility.length, nbExp);
    ArgumentChecker.isTrue(volatility[0].length == 2 * delta.length + 1, "Volatility array {} should be equal to (2 * number of deltas) + 1, have {}", volatility[0].length, 2 * delta.length + 1);
    _timeToExpiration = timeToExpiration;
    _volatilityTerm = new SmileDeltaParameters[nbExp];
    for (int loopexp = 0; loopexp < nbExp; loopexp++) {
      _volatilityTerm[loopexp] = new SmileDeltaParameters(timeToExpiration[loopexp], delta, volatility[loopexp]);
    }
    _timeInterpolator = DEFAULT_INTERPOLATOR_EXPIRY;
    ArgumentChecker.isTrue(_volatilityTerm[0].getVolatility().length > 1, "Need more than one volatility value to perform interpolation");
  }

  /**
   * Constructor from market data. The default interpolator is used for the time dimension.
   * @param timeToExpiration The time to expiration of each volatility smile.
   * @param delta The delta at which the volatilities are given. Common to all time to expiration.
   * @param atm The ATM volatilities for each time to expiration. The length should be equal to the length of timeToExpiration.
   * @param riskReversal The risk reversal figures.
   * @param strangle The strangle figures.
   */
  public SmileDeltaTermStructureParameters(final double[] timeToExpiration, final double[] delta, final double[] atm, final double[][] riskReversal, final double[][] strangle) {
    this(timeToExpiration, delta, atm, riskReversal, strangle, DEFAULT_INTERPOLATOR_EXPIRY);
  }

  /**
   * Constructor from market data.
   * @param timeToExpiration The time to expiration of each volatility smile, not null
   * @param delta The delta at which the volatilities are given. Common to all time to expiration. Not null
   * @param atm The ATM volatilities for each time to expiration. The length should be equal to the length of timeToExpiration. Not null
   * @param riskReversal The risk reversal figures, not null.
   * @param strangle The strangle figures, not null.
   * @param timeInterpolator The interpolator to be used in the time dimension, not null.
   */
  public SmileDeltaTermStructureParameters(final double[] timeToExpiration, final double[] delta, final double[] atm, final double[][] riskReversal, final double[][] strangle,
      final Interpolator1D timeInterpolator) {
    ArgumentChecker.notNull(timeToExpiration, "time to expiry");
    ArgumentChecker.notNull(delta, "delta");
    ArgumentChecker.notNull(atm, "ATM");
    ArgumentChecker.notNull(riskReversal, "risk reversal");
    ArgumentChecker.notNull(strangle, "strangle");
    ArgumentChecker.notNull(timeInterpolator, "time interpolator");
    final int nbExp = timeToExpiration.length;
    ArgumentChecker.isTrue(atm.length == nbExp, "ATM length should be coherent with time to expiration length");
    ArgumentChecker.isTrue(riskReversal.length == nbExp, "Risk reversal length should be coherent with time to expiration length");
    ArgumentChecker.isTrue(strangle.length == nbExp, "Risk reversal length should be coherent with time to expiration length");
    ArgumentChecker.isTrue(riskReversal[0].length == delta.length, "Risk reversal size should be coherent with time to delta length");
    ArgumentChecker.isTrue(strangle[0].length == delta.length, "Risk reversal size should be coherent with time to delta length");
    _timeToExpiration = timeToExpiration;
    _volatilityTerm = new SmileDeltaParameters[nbExp];
    for (int loopexp = 0; loopexp < nbExp; loopexp++) {
      _volatilityTerm[loopexp] = new SmileDeltaParameters(timeToExpiration[loopexp], atm[loopexp], delta, riskReversal[loopexp], strangle[loopexp]);
    }
    _timeInterpolator = timeInterpolator;
    ArgumentChecker.isTrue(_volatilityTerm[0].getVolatility().length > 1, "Need more than one volatility value to perform interpolation");
  }

  public SmileDeltaTermStructureParameters copy() {
    return new SmileDeltaTermStructureParameters(getVolatilityTerm(), getTimeInterpolator());
  }

  /**
   * Get smile at a given time. The smile is described by the volatilities at a given delta. The smile is obtained from the data by the given interpolator.
   * @param time The time to expiration.
   * @return The smile.
   */
  public SmileDeltaParameters getSmileForTime(final double time) {
    final int nbVol = _volatilityTerm[0].getVolatility().length;
    final int nbTime = _timeToExpiration.length;
    ArgumentChecker.isTrue(nbTime > 1, "Need more than one time value to perform interpolation");
    final double[] volatilityT = new double[nbVol];
    for (int loopvol = 0; loopvol < nbVol; loopvol++) {
      final double[] volDelta = new double[nbTime];
      for (int looptime = 0; looptime < nbTime; looptime++) {
        volDelta[looptime] = _volatilityTerm[looptime].getVolatility()[loopvol];
      }
      final ArrayInterpolator1DDataBundle interpData = new ArrayInterpolator1DDataBundle(_timeToExpiration, volDelta, true);
      volatilityT[loopvol] = _timeInterpolator.interpolate(interpData, time);
    }
    final SmileDeltaParameters smile = new SmileDeltaParameters(time, _volatilityTerm[0].getDelta(), volatilityT);
    return smile;
  }

  /**
   * Get the smile at a given time and the sensitivities with respect to the volatilities.
   * @param time The time to expiration.
   * @param volatilityAtTimeSensitivity The sensitivity to the volatilities of the smile at the given time.
   * After the methods, it contains the volatility sensitivity to the data points.
   * @return The smile
   */
  public SmileAndBucketedSensitivities getSmileAndSensitivitiesForTime(final double time, final double[] volatilityAtTimeSensitivity) {
    final int nbVol = _volatilityTerm[0].getVolatility().length;
    ArgumentChecker.isTrue(volatilityAtTimeSensitivity.length == nbVol, "Sensitivity with incorrect size");
    ArgumentChecker.isTrue(nbVol > 1, "Need more than one volatility value to perform interpolation");
    final int nbTime = _timeToExpiration.length;
    ArgumentChecker.isTrue(nbTime > 1, "Need more than one time value to perform interpolation");
    final double[] volatilityT = new double[nbVol];
    final double[][] volatilitySensitivity = new double[nbTime][nbVol];
    for (int loopvol = 0; loopvol < nbVol; loopvol++) {
      final double[] volDelta = new double[nbTime];
      for (int looptime = 0; looptime < nbTime; looptime++) {
        volDelta[looptime] = _volatilityTerm[looptime].getVolatility()[loopvol];
      }
      final ArrayInterpolator1DDataBundle interpData = new ArrayInterpolator1DDataBundle(_timeToExpiration, volDelta, true);
      final double[] volatilitySensitivityVol = _timeInterpolator.getNodeSensitivitiesForValue(interpData, time);
      for (int looptime = 0; looptime < nbTime; looptime++) {
        volatilitySensitivity[looptime][loopvol] = volatilitySensitivityVol[looptime] * volatilityAtTimeSensitivity[loopvol];
      }
      volatilityT[loopvol] = _timeInterpolator.interpolate(interpData, time);
    }
    final SmileDeltaParameters smile = new SmileDeltaParameters(time, _volatilityTerm[0].getDelta(), volatilityT);
    return new SmileAndBucketedSensitivities(smile, volatilitySensitivity);
  }

  /**
   * Gets the times to expiration.
   * @return The times.
   */
  public double[] getTimeToExpiration() {
    return _timeToExpiration;
  }

  /**
   * Gets the number of expirations.
   * @return The number of expirations.
   */
  public int getNumberExpiration() {
    return _timeToExpiration.length;
  }

  /**
   * Gets the time interpolator
   * @return The time interpolator
   */
  public Interpolator1D getTimeInterpolator() {
    return _timeInterpolator;
  }

  /**
   * Gets the volatility smiles from delta.
   * @return The volatility smiles.
   */
  public SmileDeltaParameters[] getVolatilityTerm() {
    return _volatilityTerm;
  }

  /**
   * Gets the number of strikes (common to all dates).
   * @return The number of strikes.
   */
  public int getNumberStrike() {
    return _volatilityTerm[0].getVolatility().length;
  }

  /**
   * Gets delta (common to all time to expiration).
   * @return The delta.
   */
  public double[] getDelta() {
    return _volatilityTerm[0].getDelta();
  }

  /**
   * Gets put delta absolute value for all strikes. The ATM is 0.50 delta and the x call are transformed in 1-x put.
   * @return The delta.
   */
  public double[] getDeltaFull() {
    final int nbDelta = _volatilityTerm[0].getDelta().length;
    final double[] result = new double[2 * nbDelta + 1];
    for (int loopdelta = 0; loopdelta < nbDelta; loopdelta++) {
      result[loopdelta] = _volatilityTerm[0].getDelta()[loopdelta];
      result[nbDelta + 1 + loopdelta] = 1.0 - _volatilityTerm[0].getDelta()[nbDelta - 1 - loopdelta];
    }
    result[nbDelta] = 0.50;
    return result;
  }

  /**
   * Get the volatility from a triple.
   * @param tsf The Time, Strike, Forward triple, not null
   * @return The volatility.
   */
  @Override
  public Double getVolatility(final Triple<Double, Double, Double> tsf) {
    throw new NotImplementedException();
  }

  @Override
  public VolatilityAndBucketedSensitivities getVolatilityAndSensitivities(final Triple<Double, Double, Double> tsf) {
    throw new NotImplementedException();
  }

  public BlackForexTermStructureParameters toTermStructureOnlyData(final Interpolator1D interpolator) {
    ArgumentChecker.notNull(interpolator, "interpolator");
    final int n = _timeToExpiration.length;
    final double[] timesToExpiry = new double[n];
    System.arraycopy(_timeToExpiration, 0, timesToExpiry, 0, n);
    final double[] vols = new double[n];
    final int atmIndex = (_volatilityTerm[0].getVolatility().length - 1) / 2;
    for (int i = 0; i < n; i++) {
      vols[i] = _volatilityTerm[i].getVolatility()[atmIndex];
    }
    return new BlackForexTermStructureParameters(InterpolatedDoublesCurve.fromSorted(timesToExpiry, vols, interpolator));
  }

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + Arrays.hashCode(_timeToExpiration);
    result = prime * result + Arrays.hashCode(_volatilityTerm);
    result = prime * result + _timeInterpolator.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 SmileDeltaTermStructureParameters other = (SmileDeltaTermStructureParameters) obj;
    if (!Arrays.equals(_timeToExpiration, other._timeToExpiration)) {
      return false;
    }
    if (!Arrays.equals(_volatilityTerm, other._volatilityTerm)) {
      return false;
    }
    if (!ObjectUtils.equals(_timeInterpolator, other._timeInterpolator)) {
      return false;
    }
    return true;
  }

}
TOP

Related Classes of com.opengamma.analytics.financial.model.volatility.surface.SmileDeltaTermStructureParameters

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.