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

Source Code of com.opengamma.analytics.financial.model.volatility.local.ForexLocalVolatilityTest

/**
* 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.local;

import java.io.PrintStream;
import java.util.Arrays;

import org.testng.annotations.Test;

import com.opengamma.analytics.financial.model.finitedifference.applications.PDEUtilityTools;
import com.opengamma.analytics.financial.model.interestrate.curve.ForwardCurve;
import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.EuropeanVanillaOption;
import com.opengamma.analytics.financial.model.volatility.BlackFormulaRepository;
import com.opengamma.analytics.financial.model.volatility.smile.fitting.sabr.ForexSmileDeltaSurfaceDataBundle;
import com.opengamma.analytics.financial.model.volatility.smile.fitting.sabr.SmileSurfaceDataBundle;
import com.opengamma.analytics.financial.model.volatility.smile.function.SABRFormulaData;
import com.opengamma.analytics.financial.model.volatility.smile.function.SABRHaganVolatilityFunction;
import com.opengamma.analytics.financial.model.volatility.surface.BlackVolatilitySurface;
import com.opengamma.analytics.financial.model.volatility.surface.BlackVolatilitySurfaceMoneyness;
import com.opengamma.analytics.financial.model.volatility.surface.VolatilitySurfaceInterpolator;
import com.opengamma.analytics.math.function.Function;
import com.opengamma.analytics.math.function.Function1D;
import com.opengamma.analytics.math.interpolation.CombinedInterpolatorExtrapolator;
import com.opengamma.analytics.math.interpolation.DoubleQuadraticInterpolator1D;
import com.opengamma.analytics.math.interpolation.LinearExtrapolator1D;
import com.opengamma.analytics.math.rootfinding.BisectionSingleRootFinder;
import com.opengamma.analytics.math.rootfinding.BracketRoot;
import com.opengamma.analytics.math.surface.FunctionalDoublesSurface;
import com.opengamma.analytics.math.surface.Surface;

/**
*
*/
public class ForexLocalVolatilityTest {

  private static final DoubleQuadraticInterpolator1D INTERPOLATOR_1D = new DoubleQuadraticInterpolator1D();
  private static final CombinedInterpolatorExtrapolator EXTRAPOLATOR_1D = new CombinedInterpolatorExtrapolator(INTERPOLATOR_1D, new LinearExtrapolator1D(INTERPOLATOR_1D));

  //Instrument used for Vega/Greeks Reports
  private static final double EXAMPLE_EXPIRY = 0.5;
  private static final double EXAMPLE_STRIKE = 1.4;

  private static final double[] DELTAS = new double[] {0.15, 0.25 };
  // private static final double[] FORWARDS = new double[] {1.3400578756875536, 1.340097783513583, 1.3401632874217568, 1.3402609422950176, 1.3407805380931572, 1.341476699363105,
  //    1.3421440211105033, 1.3428419833962038, 1.3528497010863676, 1.35183878530766 };
  private static final double[] FORWARDS;
  //  private static final double SPOT = 1.34;
  //  private static double DRIFT = 0.05;

  @SuppressWarnings("unused")
  private static final String[] TENORS = new String[] {"1W", "2W", "3W", "1M", "3M", "6M", "9M", "1Y", "5Y", "10Y" };
  private static final double[] EXPIRIES = new double[] {7. / 365, 14 / 365., 21 / 365., 1 / 12., 3 / 12., 0.5, 0.75, 1, 5, 10 };
  private static final double[] ATM = new double[] {0.17045, 0.1688, 0.167425, 0.1697, 0.1641, 0.1642, 0.1641, 0.1642, 0.138, 0.12515 };
  private static final double[][] RR = new double[][] { {-0.0168, -0.02935, -0.039125, -0.047325, -0.058325, -0.06055, -0.0621, -0.063, -0.032775, -0.023925 },
      {-0.012025, -0.02015, -0.026, -0.0314, -0.0377, -0.03905, -0.0396, -0.0402, -0.02085, -0.015175 } };
  private static final double[][] BUTT = new double[][] { {0.00665, 0.00725, 0.00835, 0.009075, 0.013175, 0.01505, 0.01565, 0.0163, 0.009275, 0.007075, },
      {0.002725, 0.00335, 0.0038, 0.004, 0.0056, 0.0061, 0.00615, 0.00635, 0.00385, 0.002575 } };
  //  private static final double[] ATM;
  //  private static final double[][] RR;
  //  private static final double[][] BUTT;
  //  private static final double[][] STRIKES;
  //  private static final double[][] VOLS;
  private static final int N = EXPIRIES.length;

  private static final SmileSurfaceDataBundle MARKET_DATA;
  private static final VolatilitySurfaceInterpolator SURFACE_FITTER = new VolatilitySurfaceInterpolator(/*new SmileInterpolatorSpline()*/);
  private static final LocalVolatilityPDEGreekCalculator CAL;

  private static final DupireLocalVolatilityCalculator DUPIRE = new DupireLocalVolatilityCalculator();

  static {
    FORWARDS = new double[N];
    Arrays.fill(FORWARDS, 10.0);

    //    ATM = new double[N];
    //    Arrays.fill(ATM, 0.11);
    //    RR = new double[2][N];
    //    BUTT = new double[2][N];
    //
    //    STRIKES = new double[N][];
    //    VOLS = new double[N][];
    //    for (int i = 0; i < N; i++) {
    //      //  FORWARDS[i] = SPOT * Math.exp(DRIFT * EXPIRIES[i]);
    //      final SmileDeltaParameter cal = new SmileDeltaParameter(EXPIRIES[i], ATM[i], DELTAS,
    //          new double[] {RR[0][i], RR[1][i] }, new double[] {BUTT[0][i], BUTT[1][i] });
    //      STRIKES[i] = cal.getStrike(FORWARDS[i]);
    //      VOLS[i] = cal.getVolatility();
    //    }

    MARKET_DATA = new ForexSmileDeltaSurfaceDataBundle(FORWARDS, EXPIRIES, DELTAS, ATM, RR, BUTT, true, EXTRAPOLATOR_1D);
    //MARKET_DATA = new StandardSmileSurfaceDataBundle(FORWARDS, EXPIRIES, STRIKES, VOLS, true, EXTRAPOLATOR_1D);
    CAL = new LocalVolatilityPDEGreekCalculator(MARKET_DATA.getForwardCurve(), EXPIRIES, MARKET_DATA.getStrikes(), MARKET_DATA.getVolatilities(), true);
  }

  //For each expiry, print the expiry and the strikes and implied volatilities
  @Test
      (enabled = false)
      public void printMarketData() {
    final double[][] strikes = MARKET_DATA.getStrikes();
    final double[][] vols = MARKET_DATA.getVolatilities();

    for (int i = 0; i < N; i++) {
      System.out.println(EXPIRIES[i]);
    }
    System.out.print("\n");
    for (int i = 0; i < N; i++) {
      final int m = strikes[i].length;
      for (int j = 0; j < m; j++) {
        System.out.print(strikes[i][j] + "\t");
      }
      System.out.print("\n");
    }
    System.out.print("\n");
    for (int i = 0; i < N; i++) {
      final int m = strikes[i].length;
      for (int j = 0; j < m; j++) {
        System.out.print(vols[i][j] + "\t");
      }
      System.out.print("\n");
    }
  }

  //Fit the market data at each time slice and print the smiles and a functions of both strike and delta
  @Test
      (enabled = false)
      public void fitMarketData() {
    final double lambda = 0.05;
    final Function1D<Double, Double>[] smiles = SURFACE_FITTER.getIndependentSmileFits(MARKET_DATA);

    //  double debug = smiles[4].evaluate(2.2);

    System.out.println("Fitted smiles by strike");
    System.out.print("\t");
    for (int j = 0; j < 100; j++) {
      final double m = 0.3 + j * 2.7 / 99.;
      System.out.print(m + "\t");
    }
    System.out.print("\n");
    for (int i = 0; i < N; i++) {
      final double f = FORWARDS[i];
      System.out.print(EXPIRIES[i] + "\t");
      for (int j = 0; j < 100; j++) {
        final double m = 0.3 + j * 2.7 / 99.;
        final double k = m * f;
        final double vol = smiles[i].evaluate(k);
        System.out.print(vol + "\t");
      }
      System.out.print("\n");
    }
    System.out.print("\n");

    //    System.out.println("Fitted smiles by proxy delta");
    //    System.out.print("\t");
    //    for (int j = 0; j < 100; j++) {
    //      final double d = -2.5 + j * 5.0 / 99.;
    //      System.out.print(d + "\t");
    //    }
    //    System.out.print("\n");
    //    for (int i = 0; i < N; i++) {
    //      double f = FORWARDS[i];
    //      double rootT = Math.sqrt(EXPIRIES[i] + lambda);
    //      System.out.print(EXPIRIES[i] + "\t");
    //      for (int j = 0; j < 100; j++) {
    //        final double d = -2.5 + j * 5.0 / 99.;
    //        double k = Math.exp(d * rootT) * f;
    //        final double vol = smiles[i].evaluate(k);
    //        System.out.print(vol + "\t");
    //      }
    //      System.out.print("\n");
    //    }
    //    System.out.print("\n");

    //    System.out.println("Fitted smiles by delta");
    //    System.out.print("\t");
    //    for (int j = 0; j < 100; j++) {
    //      final double d = 0.001 + j * 0.998 / 99.;
    //      System.out.print(d + "\t");
    //    }
    //    System.out.print("\n");
    //    for (int i = 0; i < N; i++) {
    //      System.out.print(EXPIRIES[i] + "\t");
    //      for (int j = 0; j < 100; j++) {
    //        final double d = 0.05 + j * 0.9 / 99.;
    //        final Function1D<Double, Double> func = getStrikeForDeltaFunction(FORWARDS[i], EXPIRIES[i], true, smiles[i]);
    //        final double vol = smiles[i].evaluate(func.evaluate(d));
    //        System.out.print(vol + "\t");
    //      }
    //      System.out.print("\n");
    //    }

  }

  /**
   * Print the fitted implied vol surface and the derived implied vol
   */
  @Test
      (enabled = false)
      public void printSurface() {
    final BlackVolatilitySurfaceMoneyness surface = SURFACE_FITTER.getVolatilitySurface(MARKET_DATA);
    PDEUtilityTools.printSurface("vol surface", surface.getSurface(), 0, 7. / 365, 0.95, 1.05, 200, 100);
    //    Surface<Double, Double, Double> dens = DUPIRE.getDensity(surface);
    //    PDEUtilityTools.printSurface("density surface", dens, 0.01, 1.0, 0.75, 1.25, 200, 100);
    //    Surface<Double, Double, Double> theta = DUPIRE.getTheta(surface);
    //  PDEUtilityTools.printSurface("theta surface", theta, 0, 10, 0.1, 3.0, 200, 100);
    LocalVolatilitySurfaceMoneyness lv = DUPIRE.getLocalVolatility(surface);
    PDEUtilityTools.printSurface("LV surface", lv.getSurface(), 0, 7 / 365., 0.95, 1.05, 200, 100);
    //    final LocalVolatilitySurfaceMoneyness lv2 = DUPIRE.getLocalVolatility(surface);
    //
    //    PDEUtilityTools.printSurface("LV surface2", lv2.getSurface(), 0, 10, 0.3, 3.0, 200, 100);

  }

  @Test(enabled = false)
  public void densityCheck() {

    final double sigma = 0.25;

    final Function<Double, Double> densityFunc = new Function<Double, Double>() {
      @Override
      public Double evaluate(final Double... x) {
        final double t = x[0];
        final double f = x[1];
        return BlackFormulaRepository.dualGamma(1.0, f, t, sigma);
      }
    };

    final FunctionalDoublesSurface density = FunctionalDoublesSurface.from(densityFunc);
    PDEUtilityTools.printSurface("density surface", density, 0.01, 10, 0.0, 4.0, 200, 100);

  }

  @Test(enabled = false)
  public void densityCheck2() {

    final double alpha = 0.2;
    final double beta = 0.7;
    final double rho = -0.4;
    final double nu = 0.3;
    final SABRFormulaData data = new SABRFormulaData(alpha, beta, rho, nu);
    final SABRHaganVolatilityFunction sabr = new SABRHaganVolatilityFunction();

    final Function<Double, Double> densityFunc = new Function<Double, Double>() {
      @Override
      public Double evaluate(final Double... x) {
        final double t = x[0];
        final double k = x[1];
        final double[] d1 = new double[5];
        final double[][] d2 = new double[2][2];
        final double vol = sabr.getVolatilityAdjoint2(new EuropeanVanillaOption(k, t, false), 1.0, data, d1, d2);
        final double dSigmadK = d1[1];
        final double d2SigmadK2 = d2[1][1];
        final double dg = BlackFormulaRepository.dualGamma(1.0, k, t, vol);
        final double vanna = BlackFormulaRepository.dualVanna(1.0, k, t, vol);
        final double vega = BlackFormulaRepository.vega(1.0, k, t, vol);
        final double vomma = BlackFormulaRepository.vomma(1.0, k, t, vol);
        final double dens = dg + 2 * vanna * dSigmadK + vomma * dSigmadK * dSigmadK + vega * d2SigmadK2;

        return dens;
      }
    };

    final FunctionalDoublesSurface density = FunctionalDoublesSurface.from(densityFunc);
    PDEUtilityTools.printSurface("density surface", density, 0.01, 10, 0.01, 5.0, 200, 100);

  }

  /**
   * Print the fitted implied vol surface and the derived implied vol as a function of moneyness m = log(k/f)/(1+lambda*sqrt(t))
   */
  @Test
      (enabled = false)
      public void printDeltaProxySurface() {
    final double xMin = -0.5;
    final double xMax = 0.5;
    final BlackVolatilitySurfaceMoneyness surface = SURFACE_FITTER.getVolatilitySurface(MARKET_DATA);
    final Surface<Double, Double, Double> moneynessSurface = toDeltaProxySurface(surface);
    PDEUtilityTools.printSurface("moneyness surface", moneynessSurface, 0, 10, xMin, xMax, 200, 100);

    //    final LocalVolatilitySurfaceMoneyness lv = DUPIRE.getLocalVolatility(surface);
    //    final Surface<Double, Double, Double> lvMoneynessSurface = toDeltaProxySurface(lv);
    //    PDEUtilityTools.printSurface("LV moneyness surface", lvMoneynessSurface, 0.0, 10, xMin, xMax, 200, 100);
  }

  @Test
      (enabled = false)
      public void printPrices() {
    final PrintStream ps = System.out;
    CAL.prices(ps, EXAMPLE_EXPIRY, new double[] {0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8 });
  }

  @Test
      (enabled = false)
      public void runPDESolver() {
    final long startTime = System.nanoTime();
    final PrintStream ps = System.out;
    CAL.runPDESolver(ps);
    final long endTime = System.nanoTime();
    ps.println("run time: " + (endTime - startTime) / 1e9 + "s");
  }

  @Test
      (enabled = false)
      public void runBackwardsPDESolver() {
    final PrintStream ps = System.out;
    CAL.runBackwardsPDESolver(ps, EXAMPLE_EXPIRY, EXAMPLE_STRIKE);
  }

  @Test
      (enabled = false)
      public void bucketedVega() {
    final PrintStream ps = System.out;
    final EuropeanVanillaOption option = new EuropeanVanillaOption(EXAMPLE_STRIKE, EXAMPLE_EXPIRY, true);
    CAL.bucketedVegaForwardPDE(ps, option);
    CAL.bucketedVegaBackwardsPDE(ps, option);
  }

  @Test
      (enabled = false)
      public void deltaAndGamma() {
    final PrintStream ps = System.out;
    CAL.deltaAndGamma(ps, EXAMPLE_EXPIRY, EXAMPLE_STRIKE);
  }

  /**
   * uses a pathological local volatility surface to debug problems with forward pde greek calculations
   */
  @Test
      (enabled = false)
      public void debugDeltaAndGamma() {
    final PrintStream ps = System.out;

    final double lVol = 0.20;
    final double hVol = 0.3;
    final Function<Double, Double> lvFunc = new Function<Double, Double>() {
      double a = (lVol + hVol) / 2.0;
      double b = (hVol - lVol) / 2.0;
      double width = 0.02;
      double lambda = Math.PI / 2 / width;

      @Override
      public Double evaluate(final Double... x) {
        final double t = x[0];
        final double k = x[1];
        final double d = Math.abs(Math.log(k / FORWARDS[0])) / Math.sqrt(0.1 + t);
        if (d < (0.1 - width)) {
          return hVol;
        } else if (d < (0.1 + width)) {
          return a + b * Math.sin(-(d - 0.1) * lambda);
        } else if (d > (0.3 + width)) {
          return hVol;
        } else if (d > (0.3 - width)) {
          return a + b * Math.sin((d - 0.3) * lambda);
        } else {
          return lVol;
        }
      }
    };
    final LocalVolatilitySurfaceStrike lv = new LocalVolatilitySurfaceStrike(FunctionalDoublesSurface.from(lvFunc));
    PDEUtilityTools.printSurface("LV surface", lv.getSurface(), 0, 10, 0.3, 3.0, 200, 100);
    CAL.deltaAndGamma(ps, EXAMPLE_EXPIRY, FORWARDS[0], lv);
  }

  @Test
      (enabled = false)
      public void smileDynamic() {
    final PrintStream ps = System.out;
    CAL.smileDynamic(ps, EXAMPLE_EXPIRY, 0.1);
  }

  /**
   * print out vega based greeks
   */
  @Test
      (enabled = false)
      public void vega() {
    final PrintStream ps = System.out;
    final EuropeanVanillaOption option = new EuropeanVanillaOption(EXAMPLE_STRIKE, EXAMPLE_EXPIRY, true);
    CAL.vega(ps, option);
  }

  @SuppressWarnings("unused")
  private Function1D<Double, Double> getStrikeForDeltaFunction(final double forward, final double expiry, final boolean isCall,
      final Function1D<Double, Double> volFunc) {
    final BracketRoot bracketer = new BracketRoot();
    final BisectionSingleRootFinder rootFinder = new BisectionSingleRootFinder(1e-8);

    return new Function1D<Double, Double>() {

      @Override
      public Double evaluate(final Double delta) {

        final Function1D<Double, Double> deltaFunc = new Function1D<Double, Double>() {

          @Override
          public Double evaluate(final Double strike) {
            final double vol = volFunc.evaluate(strike);
            final double deltaTry = BlackFormulaRepository.delta(forward, strike, expiry, vol, isCall);
            return deltaTry - delta;
          }
        };

        final double[] brackets = bracketer.getBracketedPoints(deltaFunc, 0.5, 1.5, 0, 5);
        return rootFinder.getRoot(deltaFunc, brackets[0], brackets[1]);
      }
    };
  }

  @SuppressWarnings("unused")
  private Surface<Double, Double, Double> toDeltaProxySurface(final LocalVolatilitySurface<?> lv) {

    final ForwardCurve fc = MARKET_DATA.getForwardCurve();

    final Function<Double, Double> func = new Function<Double, Double>() {

      @SuppressWarnings("synthetic-access")
      @Override
      public Double evaluate(final Double... tx) {
        final double t = tx[0];
        final double x = tx[1];
        final double f = fc.getForward(t);
        final double k = f * Math.exp(-x * Math.sqrt(t));
        return lv.getVolatility(t, k);
      }
    };

    return FunctionalDoublesSurface.from(func);
  }

  private Surface<Double, Double, Double> toDeltaProxySurface(final BlackVolatilitySurface<?> lv) {
    final ForwardCurve fc = MARKET_DATA.getForwardCurve();
    final Function<Double, Double> func = new Function<Double, Double>() {

      @SuppressWarnings("synthetic-access")
      @Override
      public Double evaluate(final Double... tx) {
        final double t = tx[0];
        final double x = tx[1];
        final double f = fc.getForward(t);
        final double k = f * Math.exp(-x * Math.sqrt(t));
        return lv.getVolatility(t, k);
      }
    };
    return FunctionalDoublesSurface.from(func);
  }
}
TOP

Related Classes of com.opengamma.analytics.financial.model.volatility.local.ForexLocalVolatilityTest

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.