/**
* Copyright (C) 2014 - 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 java.util.ArrayList;
import java.util.List;
import org.testng.annotations.Test;
import cern.jet.random.engine.MersenneTwister;
import cern.jet.random.engine.MersenneTwister64;
import cern.jet.random.engine.RandomEngine;
import com.opengamma.analytics.financial.model.volatility.discrete.DiscreteVolatilityFunction;
import com.opengamma.analytics.financial.model.volatility.discrete.DiscreteVolatilityFunctionProvider;
import com.opengamma.analytics.financial.model.volatility.discrete.DiscreteVolatilityFunctionProviderFromVolSurface;
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.matrix.DoubleMatrix1D;
import com.opengamma.analytics.math.matrix.DoubleMatrix2D;
import com.opengamma.analytics.math.surface.Surface;
import com.opengamma.analytics.util.AssertMatrix;
import com.opengamma.util.test.TestGroup;
import com.opengamma.util.tuple.DoublesPair;
import com.opengamma.util.tuple.Pair;
/**
*
*/
@Test(groups = TestGroup.UNIT)
public class InterpolatedVolatilityTermStructureProviderTest {
private static final RandomEngine RANDOM = new MersenneTwister64(MersenneTwister.DEFAULT_SEED);
private static final double[] KNOTS = new double[] {0.5, 1.0, 2.0, 3.0, 5.0, 7.0, 10.0 };
private static final Interpolator1D INTERPOLATOR = CombinedInterpolatorExtrapolatorFactory
.getInterpolator(Interpolator1DFactory.CLAMPED_CUBIC_NONNEGATIVE, Interpolator1DFactory.LINEAR_EXTRAPOLATOR);
private static final double[] KNOT_VAULES = new double[] {0.3, 0.35, 0.4, 0.36, 0.31, 0.25, 0.2 };
private static final VolatilitySurfaceProvider SURF_PRO = new InterpolatedVolatilityTermStructureProvider(KNOTS, INTERPOLATOR);
/**
* Check the vols from the surface against a curve build with the same data
*/
@Test
public void valueTest() {
assertEquals(KNOTS.length, SURF_PRO.getNumModelParameters());
final VolatilitySurface vs = SURF_PRO.getVolSurface(new DoubleMatrix1D(KNOT_VAULES));
final InterpolatedDoublesCurve curve = new InterpolatedDoublesCurve(KNOTS, KNOT_VAULES, INTERPOLATOR, true);
for (int i = 0; i < 20; i++) {
final double t = 12.0 * i / (19.0);
final double k = RANDOM.nextDouble();
final double vol1 = curve.getYValue(t);
final double vol2 = vs.getVolatility(t, k);
assertEquals(vol1, vol2, 1e-15);
}
}
/**
* Check the combined method getVolAndParameterSensitivitySurface agrees with getVolSurface and getParameterSensitivitySurface
*/
@Test
public void valueAndSenseTest() {
final VolatilitySurface vs = SURF_PRO.getVolSurface(new DoubleMatrix1D(KNOT_VAULES));
final Surface<Double, Double, DoubleMatrix1D> senseSurf = SURF_PRO.getParameterSensitivitySurface(new DoubleMatrix1D(KNOT_VAULES));
final Surface<Double, Double, Pair<Double, DoubleMatrix1D>> valAndSenseSurf = SURF_PRO.getVolAndParameterSensitivitySurface(new DoubleMatrix1D(KNOT_VAULES));
for (int i = 0; i < 20; i++) {
final double t = 12.0 * i / (19.0);
final double k = RANDOM.nextDouble();
final double vol = vs.getVolatility(t, k);
final DoubleMatrix1D sense = senseSurf.getZValue(t, k);
final Pair<Double, DoubleMatrix1D> vAndSense = valAndSenseSurf.getZValue(t, k);
assertEquals(vol, vAndSense.getFirst());
AssertMatrix.assertEqualsVectors(sense, vAndSense.getSecond(), 1e-15);
}
}
/**
* Check the sensitivity to the model parameters at a set of sample points - this uses {@link DiscreteVolatilityFunctionProviderFromVolSurface}
* to handle the finite-difference calculation of the Jacobian
*/
@Test
public void sensitivityTest() {
final DiscreteVolatilityFunctionProvider discPro = new DiscreteVolatilityFunctionProviderFromVolSurface(SURF_PRO);
final int nSamples = 30;
final List<DoublesPair> points = new ArrayList<>(nSamples);
for (int i = 0; i < nSamples; i++) {
final double t = 15.0 * i / (nSamples - 1.0);
final double k = RANDOM.nextDouble();
points.add(DoublesPair.of(t, k));
}
final DiscreteVolatilityFunction func = discPro.from(points);
final DoubleMatrix1D x = new DoubleMatrix1D(KNOT_VAULES);
final DoubleMatrix2D jac = func.calculateJacobian(x);
final DoubleMatrix2D fdJac = func.calculateJacobianViaFD(x);
AssertMatrix.assertEqualsMatrix(fdJac, jac, 2e-4);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void knotsOutOfOrderTest() {
double[] knots = new double[] {0.5, 1.0, 2.0, 7.0, 5.0, 3.0, 10.0 };
@SuppressWarnings("unused")
final VolatilitySurfaceProvider surfPro = new InterpolatedVolatilityTermStructureProvider(knots, INTERPOLATOR);
}
}