Package com.opengamma.analytics.financial.model.volatility.smile.fitting.interpolation

Source Code of com.opengamma.analytics.financial.model.volatility.smile.fitting.interpolation.ShiftedLogNormalTailExtrapolationTest

/**
* 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.smile.fitting.interpolation;

import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertTrue;

import org.testng.annotations.Test;

import com.opengamma.analytics.financial.model.finitedifference.applications.PDEUtilityTools;
import com.opengamma.analytics.financial.model.volatility.BlackFormulaRepository;
import com.opengamma.analytics.math.function.Function;
import com.opengamma.analytics.math.minimization.ParameterLimitsTransform;
import com.opengamma.analytics.math.minimization.ParameterLimitsTransform.LimitType;
import com.opengamma.analytics.math.minimization.SingleRangeLimitTransform;
import com.opengamma.analytics.math.surface.FunctionalDoublesSurface;

/**
*
*/
public class ShiftedLogNormalTailExtrapolationTest {
  private static final ShiftedLogNormalTailExtrapolationFitter FITTER = new ShiftedLogNormalTailExtrapolationFitter();
  private static final double FORWARD = 0.04;
  private static final double EXPIRY = 2.5;
  private static final double[][] LEFT_STRIKES = {
      {0.0057, 0.0061 },
      {0.02, 0.025 },
      {0.02, 0.021 },
      {0.015, 0.035 } };
  private static final double[][] RIGHT_STRIKES = {
      {0.041, 0.0415 },
      {0.045, 0.09 },
      {0.055, 0.065 } };
  private static final double[][] LEFT_VOLS = {
      {0.7366, 0.7277 },
      {0.35, 0.3 },
      {0.4, 0.41 },
      {0.31, 0.15 } };
  private static final double[][] RIGHT_VOLS = {
      {0.35, 0.348 },
      {0.4, 0.42 },
      {0.31, 0.37 } };
  private static final double[] LEFT_DD = {0.1, 0.1, 0.2, 0.1 };
  private static final double[] RIGHT_DD = {-0.4, -0.4, -0.3 };
  private static final double[] LEFT_DV_DK;
  private static final double[] RIGHT_DV_DK;
  private static final double[][] LEFT_PRICES;
  private static final double[][] RIGHT_PRICES;

  static {
    final int nl = LEFT_STRIKES.length;
    LEFT_PRICES = new double[nl][2];
    LEFT_DV_DK = new double[nl];
    for (int i = 0; i < nl; i++) {
      LEFT_DV_DK[i] = (LEFT_DD[i] - BlackFormulaRepository.dualDelta(FORWARD, LEFT_STRIKES[i][0], EXPIRY, LEFT_VOLS[i][0], false)) /
          BlackFormulaRepository.vega(FORWARD, LEFT_STRIKES[i][0], EXPIRY, LEFT_VOLS[i][0]);
      for (int j = 0; j < 2; j++) {
        LEFT_PRICES[i][j] = BlackFormulaRepository.price(FORWARD, LEFT_STRIKES[i][j], EXPIRY, LEFT_VOLS[i][j], false);
      }
    }
    final int nr = RIGHT_STRIKES.length;
    RIGHT_PRICES = new double[nl][2];
    RIGHT_DV_DK = new double[nr];
    for (int i = 0; i < nr; i++) {
      RIGHT_DV_DK[i] = (RIGHT_DD[i] - BlackFormulaRepository.dualDelta(FORWARD, RIGHT_STRIKES[i][0], EXPIRY, RIGHT_VOLS[i][0], true)) /
          BlackFormulaRepository.vega(FORWARD, RIGHT_STRIKES[i][0], EXPIRY, RIGHT_VOLS[i][0]);
      for (int j = 0; j < 2; j++) {
        RIGHT_PRICES[i][j] = BlackFormulaRepository.price(FORWARD, RIGHT_STRIKES[i][j], EXPIRY, RIGHT_VOLS[i][j], true);
      }
    }
  }

  @Test
  public void leftTailVolTest() {
    final int nl = LEFT_STRIKES.length;
    for (int i = 0; i < nl; i++) {
      double[] res = FITTER.fitTwoVolatilities(FORWARD, LEFT_STRIKES[i], LEFT_VOLS[i], EXPIRY);
      assertEquals(2, res.length);
      for (int j = 0; j < 2; j++) {
        double vol = ShiftedLogNormalTailExtrapolation.impliedVolatility(FORWARD, LEFT_STRIKES[i][j], EXPIRY, res[0], res[1]);
        assertEquals(LEFT_VOLS[i][j], vol, 1e-9);
      }
      for (int j = 0; j < 5; j++) {
        double k = FORWARD * (j / 10.);
        double vol0 = ShiftedLogNormalTailExtrapolation.impliedVolatility(FORWARD, k, EXPIRY, res[0], res[1]);
        assertTrue(vol0 > 0.0 && !Double.isInfinite(vol0) && !Double.isNaN(vol0));
      }
    }
  }

  @Test
  public void leftTailPriceTest() {
    final int nl = LEFT_STRIKES.length;
    for (int i = 0; i < nl; i++) {
      double[] res = FITTER.fitTwoPrices(FORWARD, LEFT_STRIKES[i], LEFT_PRICES[i], EXPIRY, false);
      assertEquals(2, res.length);
      for (int j = 0; j < 2; j++) {
        double price = ShiftedLogNormalTailExtrapolation.price(FORWARD, LEFT_STRIKES[i][j], EXPIRY, false, res[0], res[1]);
        assertEquals(LEFT_PRICES[i][j], price, 1e-9);
      }
      double pOld = ShiftedLogNormalTailExtrapolation.price(FORWARD, 0.0, EXPIRY, false, res[0], res[1]);
      assertEquals(0.0, pOld, 0.0);
      for (int j = 1; j < 5; j++) {
        double k = FORWARD * (j / 10.);
        double price = ShiftedLogNormalTailExtrapolation.price(FORWARD, k, EXPIRY, false, res[0], res[1]);
        assertTrue(price > pOld);
        pOld = price;
      }
    }
  }

  @Test
  public void leftTailPriceGradTest() {
    final boolean isCall = false;
    final int n = LEFT_STRIKES.length;
    for (int i = 0; i < n; i++) {
      double[] res = FITTER.fitPriceAndGrad(FORWARD, LEFT_STRIKES[i][0], LEFT_PRICES[i][0], LEFT_DD[i], EXPIRY, isCall);
      assertEquals(2, res.length);
      double price = ShiftedLogNormalTailExtrapolation.price(FORWARD, LEFT_STRIKES[i][0], EXPIRY, isCall, res[0], res[1]);
      assertEquals(LEFT_PRICES[i][0], price, 1e-9);
      double dd = ShiftedLogNormalTailExtrapolation.dualDelta(FORWARD, LEFT_STRIKES[i][0], EXPIRY, isCall, res[0], res[1]);
      assertEquals(LEFT_DD[i], dd, 1e-9);
    }
  }

  @Test
  public void leftTailVolGradTest() {
    final int n = LEFT_STRIKES.length;
    for (int i = 0; i < n; i++) {
      double[] res = FITTER.fitVolatilityAndGrad(FORWARD, LEFT_STRIKES[i][0], LEFT_VOLS[i][0], LEFT_DV_DK[i], EXPIRY);
      assertEquals(2, res.length);
      double vol = ShiftedLogNormalTailExtrapolation.impliedVolatility(FORWARD, LEFT_STRIKES[i][0], EXPIRY, res[0], res[1]);
      assertEquals(LEFT_VOLS[i][0], vol, 1e-8);
      double dd = ShiftedLogNormalTailExtrapolation.dVdK(FORWARD, LEFT_STRIKES[i][0], EXPIRY, res[0], res[1], vol);
      assertEquals(LEFT_DV_DK[i], dd, 1e-6);
    }
  }
 
  @Test
  public void leftTailVolGradZeroTest() {
    final int n = LEFT_STRIKES.length;
    final double volGrad00 = 0.0;
    for (int i = 0; i < n; i++) {
      double[] res = FITTER.fitVolatilityAndGrad(FORWARD, LEFT_STRIKES[i][0], LEFT_VOLS[i][0], volGrad00, EXPIRY);
      assertEquals(2, res.length);
      double vol = ShiftedLogNormalTailExtrapolation.impliedVolatility(FORWARD, LEFT_STRIKES[i][0], EXPIRY, res[0], res[1]);
      assertEquals(LEFT_VOLS[i][0], vol, 1e-8);
    }
  }
 
  @Test
  public void leftTailVolMaxGradTest() {
    int i = 2;
    final double strike = LEFT_STRIKES[i][0];
    final double volInput = LEFT_VOLS[i][0];

    final boolean isCall = strike >= FORWARD;
    final double blackDD = BlackFormulaRepository.dualDelta(FORWARD, strike, EXPIRY, volInput, isCall);
    final double blackVega = BlackFormulaRepository.vega(FORWARD, strike, EXPIRY, volInput);

    final double maxGrad = (isCall ? -blackDD : 1 - blackDD) / blackVega;

    double[] res = FITTER.fitVolatilityAndGrad(FORWARD, strike, volInput, maxGrad-1e-8, EXPIRY);
    double volOutput = ShiftedLogNormalTailExtrapolation.impliedVolatility(FORWARD, LEFT_STRIKES[i][0], EXPIRY, res[0], res[1]);
    assertEquals(volInput, volOutput, 1e-8);
  }
 
  @Test(enabled = false)
  public void leftTailVolGradComparison() {
    final int i = 2;
    double[] shiftedParams = FITTER.fitVolatilityAndGrad(FORWARD, LEFT_STRIKES[i][0], LEFT_VOLS[i][0], LEFT_DV_DK[i], EXPIRY);
    double[] shiftedParamsZero = FITTER.fitVolatilityAndGrad(FORWARD, LEFT_STRIKES[i][0], LEFT_VOLS[i][0], 0.0, EXPIRY);
   
    final int nSteps = 200;
    final double kMax = LEFT_STRIKES[i][0];
    final double sizeSteps = kMax / nSteps;
    double k = sizeSteps;
   
    System.out.println("Strike" + "," + "DualDelta" + "," + "Flat");
    for (int j = 0; j < nSteps; j++) {
     
      double vol = ShiftedLogNormalTailExtrapolation.impliedVolatility(FORWARD, k, EXPIRY, shiftedParams[0], shiftedParams[1]);
      double volZero = ShiftedLogNormalTailExtrapolation.impliedVolatility(FORWARD, k, EXPIRY, shiftedParamsZero[0], shiftedParamsZero[1]);
      System.out.println(k + "," + vol + "," + volZero);
      k += sizeSteps;
    }
  }
 
 
 
  @Test
  public void rightTailVolTest() {
    final int nl = RIGHT_STRIKES.length;
    for (int i = 0; i < nl; i++) {
      double[] res = FITTER.fitTwoVolatilities(FORWARD, RIGHT_STRIKES[i], RIGHT_VOLS[i], EXPIRY);
      assertEquals(2, res.length);
      for (int j = 0; j < 2; j++) {
        double vol = ShiftedLogNormalTailExtrapolation.impliedVolatility(FORWARD, RIGHT_STRIKES[i][j], EXPIRY, res[0], res[1]);
        assertEquals(RIGHT_VOLS[i][j], vol, 1e-9);
      }
      for (int j = 1; j < 6; j++) {
        double k = 2 * FORWARD * j;
        double vol0 = ShiftedLogNormalTailExtrapolation.impliedVolatility(FORWARD, k, EXPIRY, res[0], res[1]);
        assertTrue(vol0 > 0.0 && !Double.isInfinite(vol0) && !Double.isNaN(vol0));
      }
    }
  }

  @Test
  public void rightTailPriceTest() {
    final int nl = RIGHT_STRIKES.length;
    for (int i = 0; i < nl; i++) {
      double[] res = FITTER.fitTwoPrices(FORWARD, RIGHT_STRIKES[i], RIGHT_PRICES[i], EXPIRY, true);
      assertEquals(2, res.length);
      for (int j = 0; j < 2; j++) {
        double price = ShiftedLogNormalTailExtrapolation.price(FORWARD, RIGHT_STRIKES[i][j], EXPIRY, true, res[0], res[1]);
        assertEquals(RIGHT_PRICES[i][j], price, 1e-9);
      }
      double pOld = ShiftedLogNormalTailExtrapolation.price(FORWARD, 2.0 * FORWARD, EXPIRY, true, res[0], res[1]);
      for (int j = 2; j < 6; j++) {
        double k = 2 * FORWARD * j;
        double price = ShiftedLogNormalTailExtrapolation.price(FORWARD, k, EXPIRY, true, res[0], res[1]);
        assertTrue(price < pOld);
        pOld = price;
      }
    }
  }

  @Test
  public void rightTailPriceGradTest() {
    final boolean isCall = true;
    final int nr = RIGHT_STRIKES.length;
    for (int i = 0; i < nr; i++) {
      double[] res = FITTER.fitPriceAndGrad(FORWARD, RIGHT_STRIKES[i][0], RIGHT_PRICES[i][0], RIGHT_DD[i], EXPIRY, isCall);
      assertEquals(2, res.length);
      double price = ShiftedLogNormalTailExtrapolation.price(FORWARD, RIGHT_STRIKES[i][0], EXPIRY, isCall, res[0], res[1]);
      assertEquals(RIGHT_PRICES[i][0], price, 1e-9);
      double dd = ShiftedLogNormalTailExtrapolation.dualDelta(FORWARD, RIGHT_STRIKES[i][0], EXPIRY, isCall, res[0], res[1]);
      assertEquals(RIGHT_DD[i], dd, 1e-7);
    }
  }

  @Test
  public void rightTailVolGradTest() {
    final int n = RIGHT_STRIKES.length;
    for (int i = 0; i < n; i++) {
      double[] res = FITTER.fitVolatilityAndGrad(FORWARD, RIGHT_STRIKES[i][0], RIGHT_VOLS[i][0], RIGHT_DV_DK[i], EXPIRY);
      assertEquals(2, res.length);
      double vol = ShiftedLogNormalTailExtrapolation.impliedVolatility(FORWARD, RIGHT_STRIKES[i][0], EXPIRY, res[0], res[1]);
      assertEquals(RIGHT_VOLS[i][0], vol, 1e-7);
      double dd = ShiftedLogNormalTailExtrapolation.dVdK(FORWARD, RIGHT_STRIKES[i][0], EXPIRY, res[0], res[1], vol);
      assertEquals(RIGHT_DV_DK[i], dd, 1e-6);
    }
  }

  @Test
  public void rightTailVolGradZeroTest() {
    final int n = RIGHT_STRIKES.length;
    for (int i = 0; i < n; i++) {
      double[] res = FITTER.fitVolatilityAndGrad(FORWARD, RIGHT_STRIKES[i][0], RIGHT_VOLS[i][0], 0.0, EXPIRY);
      assertEquals(2, res.length);
      double vol = ShiftedLogNormalTailExtrapolation.impliedVolatility(FORWARD, RIGHT_STRIKES[i][0], EXPIRY, res[0], res[1]);
      assertEquals(RIGHT_VOLS[i][0], vol, 1e-7);
    }
  }
 
  @Test
      (enabled = false)
      public void leftTailVolPrint() {
    final int nl = LEFT_STRIKES.length;
    for (int i = 0; i < nl; i++) {
      //  double[] res = FITTER.fitTwoVolatilities(FORWARD, LEFT_STRIKES[i], LEFT_VOLS[i], EXPIARY);
      double[] res = FITTER.fitVolatilityAndGrad(FORWARD, LEFT_STRIKES[i][0], LEFT_VOLS[i][0], LEFT_DV_DK[i], EXPIRY);
      assertEquals(2, res.length);
      System.out.println("fit:\t" + res[0] + "\t" + res[1]);
      for (int j = 0; j < 101; j++) {
        double d = -5.0 + 4.8 * j / 100.;
        double k = FORWARD * Math.exp(d * Math.sqrt(EXPIRY));
        double vol = ShiftedLogNormalTailExtrapolation.impliedVolatility(FORWARD, k, EXPIRY, res[0], res[1]);
        System.out.println(k + "\t" + vol);
      }
      System.out.print("\n");
    }
  }

  @Test
      (enabled = false)
      public void rightTailVolPrint() {
    System.out.println("ShiftedLogNormalTailExtrapolationTest");
    final int n = RIGHT_STRIKES.length;
    for (int i = 0; i < n; i++) {
      double[] res = FITTER.fitTwoVolatilities(FORWARD, RIGHT_STRIKES[i], RIGHT_VOLS[i], EXPIRY);
      assertEquals(2, res.length);
      System.out.println("fit:\t" + res[0] + "\t" + res[1]);
      for (int j = 0; j < 101; j++) {
        double d = 1.0 + 4.5 * j / 100.;
        double k = FORWARD * Math.exp(d * Math.sqrt(EXPIRY));
        double vol = ShiftedLogNormalTailExtrapolation.impliedVolatility(FORWARD, k, EXPIRY, res[0], res[1]);
        System.out.println(k + "\t" + vol);
      }
      System.out.print("\n");
    }
  }

  @Test(enabled = false)
  public void printSeachSurfaceTest() {
    System.out.println("ShiftedLogNormalTailExtrapolationTest");
    Function<Double, Double> func = new Function<Double, Double>() {

      @Override
      public Double evaluate(Double... x) {
        double mu = x[0];
        double sigma = x[1];
        double vol1 = ShiftedLogNormalTailExtrapolation.impliedVolatility(FORWARD, LEFT_STRIKES[1][0], EXPIRY, mu, sigma) - LEFT_VOLS[1][0];
        double vol2 = ShiftedLogNormalTailExtrapolation.impliedVolatility(FORWARD, LEFT_STRIKES[1][1], EXPIRY, mu, sigma) - LEFT_VOLS[1][1];
        return vol1 * vol1 + vol2 * vol2;
      }
    };
    FunctionalDoublesSurface surf = FunctionalDoublesSurface.from(func);
    PDEUtilityTools.printSurface("debug", surf, -0.7, -0.0, 0.01, 0.4, 200, 200);
  }

  @Test(enabled = false)
  public void debugTest() {
    double eps = 1e-300;
    double f = 1.0;
    double t = 2. / 52.;
    //    double price = 0.0005;
    //    double dd = -0.04;
    double k = 1.24;

    //    double mu = 0.1;
    //    double theta = 0.4;

    //    double p = ShiftedLogNormalTailExtrapolation.price(f, k, t, true, mu, theta);
    //    double dd = ShiftedLogNormalTailExtrapolation.dualDelta(f, k, t, true, mu, theta);
    //    System.out.println(p + "\t" + dd);

    for (int i = 0; i < 100; i++) {
      double mu = 0.172 + 0.0005 * i / 100.;
      for (int j = 0; j < 100; j++) {
        double theta = 0.125 + 0.001 * j / 100.;
        double p = Math.max(eps, ShiftedLogNormalTailExtrapolation.price(f, k, t, true, mu, theta));
        double dd = Math.min(-eps, ShiftedLogNormalTailExtrapolation.dualDelta(f, k, t, true, mu, theta));
        System.out.println(mu + "\t" + theta + "\t" + p + "\t" + dd);
      }
    }

    //    ShiftedLogNormalTailExtrapolationFitter fitter = new ShiftedLogNormalTailExtrapolationFitter();
    //    double[] res = fitter.fitPriceAndGrad(f, k, price, dd, t, true);
    //    System.out.println(res[0] + "\t" + res[1]);
  }

  @Test
      (enabled = false)
      public void debugTest2() {
    final ParameterLimitsTransform trans = new SingleRangeLimitTransform(0.0, LimitType.GREATER_THAN);
    ShiftedLogNormalTailExtrapolationFitter fitter = new ShiftedLogNormalTailExtrapolationFitter();
    double f = 1.0;
    double t = 2. / 52.;
    double k = 1.1;

    double mu = 0.133333;
    double theta = 0.16;
    double p = ShiftedLogNormalTailExtrapolation.price(f, k, t, true, mu, theta);
    double dd = ShiftedLogNormalTailExtrapolation.dualDelta(f, k, t, true, mu, theta);
    System.out.println("price and DD " + p + "\t" + dd);
    System.out.println("trans " + trans.inverseTransform(-2.2521684610628063));

    double[] res = fitter.fitPriceAndGrad(f, k, p, dd, t, true);
    assertEquals("mu ", mu, res[0], 1e-8);
    assertEquals("theta", theta, res[1], 1e-8);
  }

  @Test
  public void roundTripTest() {
    ShiftedLogNormalTailExtrapolationFitter fitter = new ShiftedLogNormalTailExtrapolationFitter();
    double f = 1.0;
    double t = 2. / 52.;
    for (int i = 0; i < 10; i++) {
      double mu = 0.0 + 0.2 * i / 9.;
      for (int j = 0; j < 10; j++) {
        double theta = 0.1 + 0.3 * j / 10.;
        for (int k = 0; k < 10; k++) {
          double strike = 1.1 + 0.1 * k;
          double p = ShiftedLogNormalTailExtrapolation.price(f, strike, t, true, mu, theta);
          double dd = ShiftedLogNormalTailExtrapolation.dualDelta(f, strike, t, true, mu, theta);
          //  System.out.println(" ShiftedLogNormalTailExtrapolationTest " + mu + "\t" + theta + "\t" + strike + "\t" + p + "\t" + dd);
          double[] res = fitter.fitPriceAndGrad(f, strike, p, dd, t, true);
          assertEquals("mu (k = " + strike + ", mu = " + mu + ", theta = " + theta + ")", mu, res[0], 1e-7);
          assertEquals("theta (k = " + strike + ", mu = " + mu + ", theta = " + theta + ")", theta, res[1], 1e-7);
        }
      }
    }
  }

  @Test(enabled = false)
  public void failingTest() {
    double f = 1332.6440427977093;
    double k = 500.0;
    double t = 0.06557377049180328;
    double vol = 1.173565;
    double volGrad = -0.002302809210959822 / 1.1;
    ShiftedLogNormalTailExtrapolationFitter fitter = new ShiftedLogNormalTailExtrapolationFitter();

    double[] res = fitter.fitVolatilityAndGrad(f, k, vol, volGrad, t);
    System.out.println(res[0] + "\t" + res[1]);
  }

  @Test
      (enabled = false)
      public void printSeachSurfaceTest2() {
    final double f = 1332.6440427977093;
    final double k = 500.0;
    final double t = 0.06557377049180328;
    final double vol = 1.173565;
    final double volGrad = -0.002302809210959822 / 1.0;
    final double p = BlackFormulaRepository.price(f, k, t, vol, false);
    final double dd = BlackFormulaRepository.dualDelta(f, k, t, vol, false) + BlackFormulaRepository.vega(f, k, t, vol) * volGrad;

    System.out.println("ShiftedLogNormalTailExtrapolationTest");
    Function<Double, Double> func = new Function<Double, Double>() {

      @Override
      public Double evaluate(Double... x) {
        double mu = x[0];
        double sigma = x[1];
        //  double sigma = 0.8 * mu + s;
        double p1 = Math.log(ShiftedLogNormalTailExtrapolation.price(f, k, t, false, mu, sigma) / p);
        double p2 = Math.log(ShiftedLogNormalTailExtrapolation.dualDelta(f, k, t, false, mu, sigma) / dd);
        double temp = p1 * p1 + p2 * p2;
        return Double.isInfinite(temp) ? 1e6 : temp;
      }
    };
    FunctionalDoublesSurface surf = FunctionalDoublesSurface.from(func);
    PDEUtilityTools.printSurface("debug", surf, 250, 300, 70, 90.0, 200, 200);

    double mu = 0.1;
    double sigma = 0.1;

    double r1 = ShiftedLogNormalTailExtrapolation.impliedVolatility(f, k, t, mu, sigma);
    double r2 = ShiftedLogNormalTailExtrapolation.dVdK(f, k, t, mu, sigma);
    System.out.println(r1 + "\t" + r2);
  }

}
TOP

Related Classes of com.opengamma.analytics.financial.model.volatility.smile.fitting.interpolation.ShiftedLogNormalTailExtrapolationTest

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.