Package com.opengamma.analytics.financial.interestrate.capletstripping

Source Code of com.opengamma.analytics.financial.interestrate.capletstripping.CapletStrippingTest

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

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

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;

import org.testng.annotations.Test;
import org.threeten.bp.Period;

import com.opengamma.analytics.financial.instrument.index.IborIndex;
import com.opengamma.analytics.financial.interestrate.YieldCurveBundle;
import com.opengamma.analytics.financial.model.interestrate.curve.YieldCurve;
import com.opengamma.analytics.financial.model.volatility.SABRTermStructureParameters;
import com.opengamma.analytics.financial.model.volatility.VolatilityModel1D;
import com.opengamma.analytics.financial.model.volatility.VolatilityModelProvider;
import com.opengamma.analytics.math.curve.AddCurveSpreadFunction;
import com.opengamma.analytics.math.curve.Curve;
import com.opengamma.analytics.math.curve.FunctionalDoublesCurve;
import com.opengamma.analytics.math.curve.InterpolatedCurveBuildingFunction;
import com.opengamma.analytics.math.curve.InterpolatedDoublesCurve;
import com.opengamma.analytics.math.curve.SpreadDoublesCurve;
import com.opengamma.analytics.math.differentiation.VectorFieldFirstOrderDifferentiator;
import com.opengamma.analytics.math.function.Function1D;
import com.opengamma.analytics.math.interpolation.DoubleQuadraticInterpolator1D;
import com.opengamma.analytics.math.interpolation.Interpolator1D;
import com.opengamma.analytics.math.interpolation.TransformedInterpolator1D;
import com.opengamma.analytics.math.matrix.DoubleMatrix1D;
import com.opengamma.analytics.math.matrix.DoubleMatrix2D;
import com.opengamma.analytics.math.minimization.DoubleRangeLimitTransform;
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.statistics.leastsquare.LeastSquareResults;
import com.opengamma.analytics.math.statistics.leastsquare.NonLinearLeastSquare;
import com.opengamma.financial.convention.businessday.BusinessDayConvention;
import com.opengamma.financial.convention.businessday.BusinessDayConventionFactory;
import com.opengamma.financial.convention.daycount.DayCount;
import com.opengamma.financial.convention.daycount.DayCountFactory;
import com.opengamma.util.money.Currency;

/**
* @deprecated This class tests deprecated functionality
*/
@Deprecated
public class CapletStrippingTest {

  private static final LinkedHashMap<String, Function1D<Double, Double>> PARAMETER_FUNCTIONS = new LinkedHashMap<>();

  protected static final Currency CUR = Currency.USD;
  private static final Period TENOR = Period.ofMonths(3);
  private static final int SETTLEMENT_DAYS = 2;
  private static final DayCount DAY_COUNT_INDEX = DayCountFactory.INSTANCE.getDayCount("Actual/360");
  private static final BusinessDayConvention BUSINESS_DAY = BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Modified Following");
  private static final boolean IS_EOM = true;
  private static final IborIndex INDEX = new IborIndex(CUR, TENOR, SETTLEMENT_DAYS, DAY_COUNT_INDEX, BUSINESS_DAY, IS_EOM, "Ibor");

  private static Function1D<Double, Double> ALPHA = new Function1D<Double, Double>() {

    private static final double a = -0.01;
    private static final double b = 0.05;
    private static final double c = 0.3;
    private static final double d = 0.04;

    @Override
    public Double evaluate(final Double t) {
      return (a + t * b) * Math.exp(-c * t) + d;
    }
  };

  private static Function1D<Double, Double> BETA = new Function1D<Double, Double>() {

    @Override
    public Double evaluate(final Double t) {
      return 0.5;
    }
  };

  private static Function1D<Double, Double> RHO = new Function1D<Double, Double>() {

    private static final double a = -0.7;
    private static final double b = 0.0;
    private static final double c = 0.1;
    private static final double d = 0.0;

    @Override
    public Double evaluate(final Double t) {
      return (a + t * b) * Math.exp(-c * t) + d;
    }
  };

  private static Function1D<Double, Double> NU = new Function1D<Double, Double>() {

    private static final double a = 0.8;
    private static final double b = 0.0;
    private static final double c = 0.1;
    private static final double d = 0.4;

    @Override
    public Double evaluate(final Double t) {
      return (a + t * b) * Math.exp(-c * t) + d;
    }
  };

  protected static final Function1D<Double, Double> DISCOUNT_CURVE = new Function1D<Double, Double>() {

    private static final double a = -0.0375;
    private static final double b = 0.0021;
    private static final double c = 0.2;
    private static final double d = 0.04;

    @Override
    public Double evaluate(final Double x) {
      return (a + b * x) * Math.exp(-c * x) + d;
    }
  };

  protected static final Function1D<Double, Double> SPREAD_CURVE = new Function1D<Double, Double>() {

    private static final double a = 0.005;
    private static final double b = 0.002;
    private static final double c = 0.3;
    private static final double d = 0.001;

    @Override
    public Double evaluate(final Double x) {
      return (a + b * x) * Math.exp(-c * x) + d;
    }
  };

  private static final LinkedHashMap<String, Curve<Double, Double>> CURVES;

  private static VolatilityModel1D VOL_MODEL;

  private static YieldCurveBundle YIELD_CURVES;
  private static List<CapFloor> CAPS;
  private static double[] MARKET_PRICES;
  private static double[] MARKET_VOLS;
  private static double[] MARKET_VEGAS;

  private static int[] CAP_MATURITIES = new int[] {1, 2, 3, 5, 10, 15, 20 };
  private static double[] NODES = new double[] {0., 1, 2, 3, 5, 10, 15, 20 };
  private static double[] STRIKES = new double[] {0.005, 0.01, 0.02, 0.03, 0.04, 0.05, 0.07, 0.1 };
  private static LinkedHashMap<String, double[]> CURVE_NODES;
  private static LinkedHashMap<String, Interpolator1D> INTERPOLATORS;
  private static LinkedHashMap<String, ParameterLimitsTransform> TRANSFORMS;
  private static final InterpolatedCurveBuildingFunction CURVE_BUILDER;
  private static String[] NAMES = new String[] {"alpha", "beta", "rho", "nu" };
  private static final DoubleMatrix1D START;
  private static final DoubleMatrix1D END;

  private static final VolatilityModelProvider VOL_MODEL_PROVIDER;

  static {

    PARAMETER_FUNCTIONS.put(NAMES[0], ALPHA);
    PARAMETER_FUNCTIONS.put(NAMES[1], BETA);
    PARAMETER_FUNCTIONS.put(NAMES[2], RHO);
    PARAMETER_FUNCTIONS.put(NAMES[3], NU);

    TRANSFORMS = new LinkedHashMap<>();
    TRANSFORMS.put(NAMES[0], new SingleRangeLimitTransform(0.0, LimitType.GREATER_THAN)); // alpha > 0
    TRANSFORMS.put(NAMES[1], new DoubleRangeLimitTransform(0, 1)); // 0<beta<1
    TRANSFORMS.put(NAMES[2], new DoubleRangeLimitTransform(-1, 1)); // -0.95<rho<0.95
    TRANSFORMS.put(NAMES[3], new SingleRangeLimitTransform(0.0, LimitType.GREATER_THAN));

    final double[][] values = new double[4][NODES.length];
    for (int i = 0; i < 4; i++) {
      final Function1D<Double, Double> func = PARAMETER_FUNCTIONS.get(NAMES[i]);
      final ParameterLimitsTransform trans = TRANSFORMS.get(NAMES[i]);
      for (int j = 0; j < NODES.length; j++) {
        values[i][j] = trans.transform(func.evaluate(NODES[j])); // fitting parameters
      }
    }

    CURVES = new LinkedHashMap<>();
    CURVE_NODES = new LinkedHashMap<>();
    INTERPOLATORS = new LinkedHashMap<>();
    final DoubleQuadraticInterpolator1D baseInterpolator = new DoubleQuadraticInterpolator1D();
    int index = 0;
    for (final String name : NAMES) {
      CURVE_NODES.put(name, NODES);
      INTERPOLATORS.put(name, baseInterpolator);
      final Interpolator1D intp = new TransformedInterpolator1D(baseInterpolator, TRANSFORMS.get(name));
      final InterpolatedDoublesCurve intpCurve = InterpolatedDoublesCurve.from(NODES, values[index++], intp);
      CURVES.put(name, intpCurve);
    }

    VOL_MODEL = new SABRTermStructureParameters(CURVES.get(NAMES[0]), CURVES.get(NAMES[1]), CURVES.get(NAMES[2]), CURVES.get(NAMES[3]));

    YIELD_CURVES = new YieldCurveBundle();
    YIELD_CURVES.setCurve("funding", YieldCurve.from(FunctionalDoublesCurve.from(DISCOUNT_CURVE)));
    YIELD_CURVES.setCurve("3m Libor", YieldCurve.from(SpreadDoublesCurve.from(new AddCurveSpreadFunction(), FunctionalDoublesCurve.from(DISCOUNT_CURVE), FunctionalDoublesCurve.from(SPREAD_CURVE))));

    CAPS = new ArrayList<>(CAP_MATURITIES.length * STRIKES.length);
    MARKET_PRICES = new double[CAP_MATURITIES.length * STRIKES.length];
    MARKET_VOLS = new double[CAP_MATURITIES.length * STRIKES.length];
    MARKET_VEGAS = new double[CAP_MATURITIES.length * STRIKES.length];

    int count = 0;
    for (final int element : CAP_MATURITIES) {
      for (final double element2 : STRIKES) {
        final CapFloor cap = SimpleCapFloorMaker.makeCap(CUR, INDEX, 0, 4 * element, "funding", "3m Libor", element2, true);
        //final CapFloor cap = new CapFloor(CUR, INDEX, element, SimpleFrequency.QUARTERLY, "funding", "3m Libor", element2,true);
        //makeCap(element, SimpleFrequency.QUARTERLY, "funding", "3m Libor", element2);
        CAPS.add(cap);
        final CapFloorPricer pricer = new CapFloorPricer(cap, YIELD_CURVES);
        MARKET_PRICES[count] = pricer.price(VOL_MODEL);
        MARKET_VOLS[count] = pricer.impliedVol(VOL_MODEL);
        MARKET_VEGAS[count] = 0.001 * pricer.vega(VOL_MODEL);
        count++;
      }
    }

    CURVE_BUILDER = new InterpolatedCurveBuildingFunction(CURVE_NODES, INTERPOLATORS);

    // start from some realistic values, and transform these into the fitting parameters
    final double[] start = new double[4 * NODES.length];
    Arrays.fill(start, 0, NODES.length, TRANSFORMS.get(NAMES[0]).transform(0.3));
    Arrays.fill(start, NODES.length, 2 * NODES.length, TRANSFORMS.get(NAMES[1]).transform(0.7));
    Arrays.fill(start, 2 * NODES.length, 3 * NODES.length, TRANSFORMS.get(NAMES[2]).transform(-0.2));
    Arrays.fill(start, 3 * NODES.length, 4 * NODES.length, TRANSFORMS.get(NAMES[3]).transform(0.35));
    START = new DoubleMatrix1D(start);
    END = new DoubleMatrix1D(join(values));

    VOL_MODEL_PROVIDER = new SABRTermStructureModelProvider(CURVE_NODES, INTERPOLATORS, TRANSFORMS, null);
  }

  private static double[] join(final double[]... from) {
    final int n = from.length;
    int sum = 0;
    for (int i = 0; i < n; i++) {
      sum += from[i].length;
    }
    final double[] res = new double[sum];
    int index = 0;
    for (int i = 0; i < n; i++) {
      final int m = from[i].length;
      System.arraycopy(from[i], 0, res, index, m);
      index += m;
    }
    return res;
  }

  @Test
  public void testJacobian() {

    final VectorFieldFirstOrderDifferentiator jacFDCal = new VectorFieldFirstOrderDifferentiator();
    final Function1D<DoubleMatrix1D, DoubleMatrix1D> func = new CapletStrippingFunction(CAPS, YIELD_CURVES, VOL_MODEL_PROVIDER);
    final Function1D<DoubleMatrix1D, DoubleMatrix2D> jacFDFunc = jacFDCal.differentiate(func);
    final Function1D<DoubleMatrix1D, DoubleMatrix2D> jacAnalFunc = new CapletStrippingJacobian(CAPS, YIELD_CURVES, CURVE_NODES, INTERPOLATORS, TRANSFORMS, null);

    final DoubleMatrix2D jacFD = jacFDFunc.evaluate(END);
    final DoubleMatrix2D jacAnal = jacAnalFunc.evaluate(END);
    final int rows = jacFD.getNumberOfRows();
    final int cols = jacFD.getNumberOfColumns();

    assertEquals("# rows does not match", rows, jacAnal.getNumberOfRows(), 0);
    assertEquals("# cols does not match", cols, jacAnal.getNumberOfColumns(), 0);

    // System.out.println(jacFD);
    // System.out.println("");
    // System.out.println(jacAnal);

    for (int i = 0; i < rows; i++) {
      for (int j = 0; j < cols; j++) {
        assertEquals("row: " + i + " cols: " + j, jacFD.getEntry(i, j), jacAnal.getEntry(i, j), 1e-6);
      }
    }
  }

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

    final CapletStrippingFunction func = new CapletStrippingFunction(CAPS, YIELD_CURVES, VOL_MODEL_PROVIDER);
    final CapletStrippingJacobian jac = new CapletStrippingJacobian(CAPS, YIELD_CURVES, CURVE_NODES, INTERPOLATORS, TRANSFORMS, null);

    final double[] sigma = new double[MARKET_PRICES.length];
    Arrays.fill(sigma, 0.0001); // 1bps

    final NonLinearLeastSquare ls = new NonLinearLeastSquare();
    final LeastSquareResults lsRes = ls.solve(new DoubleMatrix1D(MARKET_VOLS), new DoubleMatrix1D(sigma), func, jac, START);

    final DoubleMatrix1D res = lsRes.getFitParameters();

    assertTrue("chi^2 too large", lsRes.getChiSq() < 0.3);

    // We don't recover exactly the initial curves. Why?
    final LinkedHashMap<String, InterpolatedDoublesCurve> curves = CURVE_BUILDER.evaluate(res);
    for (final String name : NAMES) {
      final Curve<Double, Double> fitCurve = curves.get(name);
      final ParameterLimitsTransform trans = TRANSFORMS.get(name);
      final Curve<Double, Double> initialCurve = CURVES.get(name);
      for (int i = 0; i < 25; i++) {
        final double t = i * 20. / 25;
        assertEquals(name + " - time: " + t, initialCurve.getYValue(t), trans.inverseTransform(fitCurve.getYValue(t)), 5e-2);
      }

    }

    // diagnostics
    final boolean print = false;
    if (print) {
      System.out.println("CapletStripingTest");
    }

    final VolatilityModel1D volModel = VOL_MODEL_PROVIDER.evaluate(lsRes.getFitParameters());
    final Iterator<CapFloor> iter = CAPS.iterator();

    CapFloor cap;
    int i = 0;
    while (iter.hasNext()) {
      cap = iter.next();
      final CapFloorPricer pricer = new CapFloorPricer(cap, YIELD_CURVES);
      final double fittedVol = pricer.impliedVol(volModel);
      assertEquals("Cap: strike = " + cap.getStrike() + ", start = " + cap.getStartTime() + ", end = " + cap.getEndTime(),
          MARKET_VOLS[i], fittedVol, 1e-5);
      if (print) {
        System.out.println("strike = " + cap.getStrike() + ", start = " + cap.getStartTime() + ", end = " + cap.getEndTime() +
            ", Market vol = " + MARKET_VOLS[i] + ", fitted vol = " + fittedVol);
      }
      // fittedCapVols[i++] = ;
      i++;
    }

  }

}
TOP

Related Classes of com.opengamma.analytics.financial.interestrate.capletstripping.CapletStrippingTest

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.