com.opengamma.analytics.financial.model.volatility.surface.SmileDeltaTermStructureParameters.java Source code

Java tutorial

Introduction

Here is the source code for com.opengamma.analytics.financial.model.volatility.surface.SmileDeltaTermStructureParameters.java

Source

/**
 * 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;
    }

}