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

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

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

import static org.testng.AssertJUnit.assertEquals;

import org.testng.annotations.Test;

import com.opengamma.analytics.financial.model.option.definition.SmileDeltaParameters;
import com.opengamma.analytics.financial.model.volatility.VolatilityAndBucketedSensitivities;
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.LinearInterpolator1D;
import com.opengamma.analytics.math.interpolation.data.ArrayInterpolator1DDataBundle;
import com.opengamma.util.tuple.Triple;

/**
* Tests related to the construction of term structure of smile data from delta.
* Tests related to the interpolation of volatility.
*/
public class SmileDeltaTermStructureParametersStrikeInterpolationTest {

  private static final double[] TIME_TO_EXPIRY = {0.10, 0.25, 0.50, 1.00, 2.00, 3.00};
  private static final double[] ATM = {0.175, 0.185, 0.18, 0.17, 0.16, 0.17};
  private static final double[] DELTA = new double[] {0.10, 0.25};
  private static final double[][] RISK_REVERSAL = new double[][] { {-0.010, -0.0050}, {-0.011, -0.0060}, {-0.012, -0.0070}, {-0.013, -0.0080}, {-0.014, -0.0090}, {-0.014, -0.0090}};
  private static final double[][] STRANGLE = new double[][] { {0.0300, 0.0100}, {0.0310, 0.0110}, {0.0320, 0.0120}, {0.0330, 0.0130}, {0.0340, 0.0140}, {0.0340, 0.0140}};
  private static final int NB_EXP = TIME_TO_EXPIRY.length;
  private static final SmileDeltaParameters[] VOLATILITY_TERM = new SmileDeltaParameters[NB_EXP];
  static {
    for (int loopexp = 0; loopexp < NB_EXP; loopexp++) {
      VOLATILITY_TERM[loopexp] = new SmileDeltaParameters(TIME_TO_EXPIRY[loopexp], ATM[loopexp], DELTA, RISK_REVERSAL[loopexp], STRANGLE[loopexp]);
    }
  }
  private static final Interpolator1D INTERPOLATOR_STRIKE = CombinedInterpolatorExtrapolatorFactory.getInterpolator(Interpolator1DFactory.LINEAR, Interpolator1DFactory.FLAT_EXTRAPOLATOR,
      Interpolator1DFactory.FLAT_EXTRAPOLATOR);
  private static final Interpolator1D INTERPOLATOR_TIME = CombinedInterpolatorExtrapolatorFactory.getInterpolator(Interpolator1DFactory.TIME_SQUARE, Interpolator1DFactory.FLAT_EXTRAPOLATOR,
      Interpolator1DFactory.FLAT_EXTRAPOLATOR);
  private static final SmileDeltaTermStructureParametersStrikeInterpolation SMILE_TERM = new SmileDeltaTermStructureParametersStrikeInterpolation(VOLATILITY_TERM, INTERPOLATOR_STRIKE);

  private static final double TOLERANCE_VOL = 1.0E-10;

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullVolatility() {
    new SmileDeltaTermStructureParametersStrikeInterpolation(null, INTERPOLATOR_STRIKE);
  }

  @Test
  public void getter() {
    assertEquals("Smile by delta term structure: volatility", VOLATILITY_TERM, SMILE_TERM.getVolatilityTerm());
  }

  @Test
  public void constructor() {
    final SmileDeltaTermStructureParametersStrikeInterpolation smileTerm2 = new SmileDeltaTermStructureParametersStrikeInterpolation(TIME_TO_EXPIRY, DELTA, ATM, RISK_REVERSAL, STRANGLE);
    assertEquals("Smile by delta term structure: constructor", SMILE_TERM, smileTerm2);
  }

  @Test
  public void constructor2() {
    final double[][] vol = new double[NB_EXP][];
    for (int loopexp = 0; loopexp < NB_EXP; loopexp++) {
      vol[loopexp] = VOLATILITY_TERM[loopexp].getVolatility();
    }
    final SmileDeltaTermStructureParametersStrikeInterpolation smileTermVol = new SmileDeltaTermStructureParametersStrikeInterpolation(TIME_TO_EXPIRY, DELTA, vol);
    assertEquals("Smile by delta term structure: constructor", SMILE_TERM, smileTermVol);
  }

  @Test
  /**
   * Tests the volatility at a point of the grid.
   */
  public void volatilityAtPoint() {
    final double forward = 1.40;
    final double timeToExpiration = 0.50;
    final double[] strikes = SMILE_TERM.getVolatilityTerm()[2].getStrike(forward);
    final double volComputed = SMILE_TERM.getVolatility(timeToExpiration, strikes[1], forward);
    final double volExpected = SMILE_TERM.getVolatilityTerm()[2].getVolatility()[1];
    assertEquals("Smile by delta term structure: volatility at a point", volExpected, volComputed, TOLERANCE_VOL);
  }

  @Test
  /**
   * Tests the interpolation in the strike dimension at a time of the grid.
   */
  public void volatilityStrikeInterpolation() {
    final double forward = 1.40;
    final double timeToExpiration = 0.50;
    final double strike = 1.50;
    final double[] strikes = SMILE_TERM.getVolatilityTerm()[2].getStrike(forward);
    final double[] vol = SMILE_TERM.getVolatilityTerm()[2].getVolatility();
    final ArrayInterpolator1DDataBundle volatilityInterpolation = new ArrayInterpolator1DDataBundle(strikes, vol);
    final LinearInterpolator1D interpolator = new LinearInterpolator1D();
    final double volExpected = interpolator.interpolate(volatilityInterpolation, strike);
    final double volComputed = SMILE_TERM.getVolatility(timeToExpiration, strike, forward);
    assertEquals("Smile by delta term structure: volatility interpolation on strike", volExpected, volComputed, TOLERANCE_VOL);
  }

  @Test
  /**
   * Tests the extrapolation below the first expiration.
   */
  public void volatilityBelowFirstExpiry() {
    final double forward = 1.40;
    final double timeToExpiration = 0.05;
    final double strike = 1.45;
    final SmileDeltaParameters smile = new SmileDeltaParameters(timeToExpiration, ATM[0], DELTA, RISK_REVERSAL[0], STRANGLE[0]);
    final double[] strikes = smile.getStrike(forward);
    final double[] vol = smile.getVolatility();
    final ArrayInterpolator1DDataBundle volatilityInterpolation = new ArrayInterpolator1DDataBundle(strikes, vol);
    final double volExpected = INTERPOLATOR_STRIKE.interpolate(volatilityInterpolation, strike);
    final double volComputed = SMILE_TERM.getVolatility(timeToExpiration, strike, forward);
    assertEquals("Smile by delta term structure: volatility interpolation on strike", volExpected, volComputed, TOLERANCE_VOL);
  }

  @Test
  /**
   * Tests the extrapolation above the last expiration.
   */
  public void volatilityAboveLastExpiry() {
    final double forward = 1.40;
    final double timeToExpiration = 5.00;
    final double strike = 1.45;
    final SmileDeltaParameters smile = new SmileDeltaParameters(timeToExpiration, ATM[NB_EXP - 1], DELTA, RISK_REVERSAL[NB_EXP - 1], STRANGLE[NB_EXP - 1]);
    final double[] strikes = smile.getStrike(forward);
    final double[] vol = smile.getVolatility();
    final ArrayInterpolator1DDataBundle volatilityInterpolation = new ArrayInterpolator1DDataBundle(strikes, vol);
    final double volExpected = INTERPOLATOR_STRIKE.interpolate(volatilityInterpolation, strike);
    final double volComputed = SMILE_TERM.getVolatility(timeToExpiration, strike, forward);
    assertEquals("Smile by delta term structure: volatility interpolation on strike", volExpected, volComputed, TOLERANCE_VOL);
  }

  @Test
  /**
   * Tests the interpolation in the time and strike dimensions.
   */
  public void volatilityTimeInterpolation() {
    final double forward = 1.40;
    final double timeToExpiration = 0.75;
    final double strike = 1.50;
    final double[] vol050 = SMILE_TERM.getVolatilityTerm()[2].getVolatility();
    final double[] vol100 = SMILE_TERM.getVolatilityTerm()[3].getVolatility();
    final double[] vol = new double[vol050.length];
    for (int loopvol = 0; loopvol < vol050.length; loopvol++) {
      vol[loopvol] = Math.sqrt(((vol050[loopvol] * vol050[loopvol] * TIME_TO_EXPIRY[2] + vol100[loopvol] * vol100[loopvol] * TIME_TO_EXPIRY[3]) / 2.0) / timeToExpiration);
    }
    final SmileDeltaParameters smile = new SmileDeltaParameters(timeToExpiration, DELTA, vol);
    final double[] strikes = smile.getStrike(forward);
    final ArrayInterpolator1DDataBundle volatilityInterpolation = new ArrayInterpolator1DDataBundle(strikes, vol);
    final LinearInterpolator1D interpolator = new LinearInterpolator1D();
    final double volExpected = interpolator.interpolate(volatilityInterpolation, strike);
    final double volComputed = SMILE_TERM.getVolatility(timeToExpiration, strike, forward);
    assertEquals("Smile by delta term structure: volatility interpolation on strike", volExpected, volComputed, TOLERANCE_VOL);
    final double volTriple = SMILE_TERM.getVolatility(new Triple<>(timeToExpiration, strike, forward));
    assertEquals("Smile by delta term structure: volatility interpolation on strike", volComputed, volTriple, TOLERANCE_VOL);
    final SmileDeltaTermStructureParametersStrikeInterpolation smileTerm2 = new SmileDeltaTermStructureParametersStrikeInterpolation(TIME_TO_EXPIRY, DELTA, ATM, RISK_REVERSAL, STRANGLE,
        INTERPOLATOR_STRIKE, INTERPOLATOR_TIME);
    final double volComputed2 = smileTerm2.getVolatility(timeToExpiration, strike, forward);
    assertEquals("Smile by delta term structure: volatility interpolation on strike", volComputed, volComputed2, TOLERANCE_VOL);
  }

  @Test
  /**
   * Tests the interpolation and its derivative with respect to the data by comparison to finite difference.
   */
  public void volatilityAjoint() {
    final double forward = 1.40;
    final double[] timeToExpiration = new double[] {0.75, 1.00, 2.50};
    final double[] strike = new double[] {1.50, 1.70, 2.20};
    final double[] tolerance = new double[] {3.0E-2, 1.0E-1, 1.0E-5};
    final int nbTest = strike.length;
    final double shift = 0.00001;
    for (int looptest = 0; looptest < nbTest; looptest++) {
      final double vol = SMILE_TERM.getVolatility(timeToExpiration[looptest], strike[looptest], forward);
      final double[][] bucketTest = new double[TIME_TO_EXPIRY.length][2 * DELTA.length + 1];
      final VolatilityAndBucketedSensitivities volComputed = SMILE_TERM.getVolatilityAndSensitivities(timeToExpiration[looptest], strike[looptest], forward);
      final double[][] bucketSensi = volComputed.getBucketedSensitivities();
      assertEquals("Smile by delta term structure: volatility adjoint", vol, volComputed.getVolatility(), 1.0E-10);
      final SmileDeltaParameters[] volData = new SmileDeltaParameters[TIME_TO_EXPIRY.length];
      final double[] volBumped = new double[2 * DELTA.length + 1];
      for (int loopexp = 0; loopexp < TIME_TO_EXPIRY.length; loopexp++) {
        for (int loopsmile = 0; loopsmile < 2 * DELTA.length + 1; loopsmile++) {
          System.arraycopy(SMILE_TERM.getVolatilityTerm(), 0, volData, 0, TIME_TO_EXPIRY.length);
          System.arraycopy(SMILE_TERM.getVolatilityTerm()[loopexp].getVolatility(), 0, volBumped, 0, 2 * DELTA.length + 1);
          volBumped[loopsmile] += shift;
          volData[loopexp] = new SmileDeltaParameters(TIME_TO_EXPIRY[loopexp], DELTA, volBumped);
          final SmileDeltaTermStructureParametersStrikeInterpolation smileTermBumped = new SmileDeltaTermStructureParametersStrikeInterpolation(volData, INTERPOLATOR_STRIKE);
          bucketTest[loopexp][loopsmile] = (smileTermBumped.getVolatility(timeToExpiration[looptest], strike[looptest], forward) - volComputed.getVolatility()) / shift;
          // FIXME: the strike sensitivity to volatility is missing. To be corrected when [PLAT-1396] is fixed.
          assertEquals("Smile by delta term structure: (test: " + looptest + ") volatility bucket sensitivity " + loopexp + " - " + loopsmile, bucketTest[loopexp][loopsmile],
              bucketSensi[loopexp][loopsmile], tolerance[looptest]);
        }
      }
    }
  }

  @Test(enabled = false)
  /**
   * Code to graph the strikes for the given deltas at different expirations. In normal tests, should be (enabled=false).
   */
  public void deltaSmile() {
    final double forward = 1.40;
    final double expiryMax = 2.0;
    final int nbExp = 50;
    final int nbVol = 2 * DELTA.length + 1;
    final double[][] strikes = new double[nbExp][nbVol];
    final double[] expiries = new double[nbExp];
    final double[] variancePeriodT = new double[nbVol];
    final double[] volatilityT = new double[nbVol];
    final double[] variancePeriod0 = new double[nbVol];
    final double[] variancePeriod1 = new double[nbVol];
    for (int loopexp = 0; loopexp < nbExp; loopexp++) {
      expiries[loopexp] = loopexp * expiryMax / nbExp;
      final ArrayInterpolator1DDataBundle interpData = new ArrayInterpolator1DDataBundle(TIME_TO_EXPIRY, new double[NB_EXP]);
      final int indexLower = interpData.getLowerBoundIndex(expiries[loopexp]);
      if (expiries[loopexp] < 1.0E-10) {
        for (int loopvol = 0; loopvol < nbVol; loopvol++) {
          volatilityT[loopvol] = SMILE_TERM.getVolatilityTerm()[indexLower].getVolatility()[loopvol];
        }
      } else {
        final double weight0 = (TIME_TO_EXPIRY[indexLower + 1] - expiries[loopexp]) / (TIME_TO_EXPIRY[indexLower + 1] - TIME_TO_EXPIRY[indexLower]);
        // Implementation note: Linear interpolation on variance over the period (s^2*t).
        for (int loopvol = 0; loopvol < nbVol; loopvol++) {
          variancePeriod0[loopvol] = SMILE_TERM.getVolatilityTerm()[indexLower].getVolatility()[loopvol] * SMILE_TERM.getVolatilityTerm()[indexLower].getVolatility()[loopvol]
              * TIME_TO_EXPIRY[indexLower];
          variancePeriod1[loopvol] = SMILE_TERM.getVolatilityTerm()[indexLower + 1].getVolatility()[loopvol] * SMILE_TERM.getVolatilityTerm()[indexLower + 1].getVolatility()[loopvol]
              * TIME_TO_EXPIRY[indexLower + 1];
          variancePeriodT[loopvol] = weight0 * variancePeriod0[loopvol] + (1 - weight0) * variancePeriod1[loopvol];
          volatilityT[loopvol] = Math.sqrt(variancePeriodT[loopvol] / expiries[loopexp]);
        }
      }
      final SmileDeltaParameters smile = new SmileDeltaParameters(expiries[loopexp], DELTA, volatilityT);
      strikes[loopexp] = smile.getStrike(forward);
    }
  }

  @Test(enabled = false)
  /**
   * Analysis the code performance. In normal tests, should be (enabled=false).
   */
  public void performance() {
    long startTime, endTime;
    final int nbTest = 100000;

    final double forward = 1.40;
    final double timeToExpiration = 0.50;
    final double strike = 1.50;

    @SuppressWarnings("unused")
    double volComputed;

    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      volComputed = SMILE_TERM.getVolatility(timeToExpiration, strike, forward);
    }
    endTime = System.currentTimeMillis();
    System.out.println(nbTest + " Smile Delta volatility: " + (endTime - startTime) + " ms");
    // Performance note: price: 18-Jun-12: On Mac Pro 3.2 GHz Quad-Core Intel Xeon: 225 ms for 100000 volatilities.
  }

}
TOP

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

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.