/**
* 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 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.math.function.Function1D;
import com.opengamma.analytics.math.function.ParameterizedSurface;
import com.opengamma.analytics.math.matrix.DoubleMatrix1D;
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;
/**
* Set up a {@link ParameterizedSurface} that is quadratic in time-to-expiry (t) and strike (k) (so-called practitioners
* Black-Scholes, with 6 parameters), and use this to make a {@link VolatilitySurfaceProvider}. <P>
* A {@link ParameterizedSurface} and a {@link VolatilitySurfaceProvider} are conceptually similar things in that
* they both give a volatility and its sensitivity at a particular (expiry-strike) point dependent on same parameters.
*/
@Test(groups = TestGroup.UNIT)
public class ParameterizedVolatilitySurfaceProviderTest {
private static final RandomEngine RANDOM = new MersenneTwister64(MersenneTwister.DEFAULT_SEED);
private static final ParameterizedSurface SURFACE;
static {
SURFACE = new ParameterizedSurface() {
@Override
public int getNumberOfParameters() {
return 6;
}
@Override
public Double evaluate(final DoublesPair tk, final DoubleMatrix1D parameters) {
final double[] a = parameters.getData();
final double t = tk.first;
final double k = tk.second;
return a[0] + a[1] * t + a[2] * k + a[3] * t * t + a[4] * k * k + a[5] * k * t;
}
@Override
public Function1D<DoublesPair, DoubleMatrix1D> getZParameterSensitivity(final DoubleMatrix1D params) {
return new Function1D<DoublesPair, DoubleMatrix1D>() {
@Override
public DoubleMatrix1D evaluate(final DoublesPair tk) {
final double t = tk.first;
final double k = tk.second;
return new DoubleMatrix1D(1.0, t, k, t * t, k * k, k * t);
}
};
}
};
}
@Test
public void test() {
//parameters of the vol surface
final DoubleMatrix1D a = new DoubleMatrix1D(0.3, -0.02, -0.4, 0.003, 15.6, -0.05);
final VolatilitySurfaceProvider pro = new ParameterizedVolatilitySurfaceProvider(SURFACE);
final VolatilitySurface vs = pro.getVolSurface(a);
final Function1D<DoublesPair, Double> vf = SURFACE.asFunctionOfArguments(a);
assertEquals(SURFACE.getNumberOfParameters(), pro.getNumModelParameters());
//check values
final int nSamples = 35;
for (int i = 0; i < nSamples; i++) {
final double t = RANDOM.nextDouble() * 20.0;
final double k = RANDOM.nextDouble() * 0.15;
final DoublesPair point = DoublesPair.of(t, k);
final double v1 = vf.evaluate(point);
final double v2 = vs.getVolatility(point);
assertEquals(v1, v2, 1e-14);
}
//check sensitivities
final Function1D<DoublesPair, DoubleMatrix1D> senseFunc = SURFACE.getZParameterSensitivity(a);
final Surface<Double, Double, DoubleMatrix1D> senseSurf = pro.getParameterSensitivitySurface(a);
for (int i = 0; i < nSamples; i++) {
final double t = RANDOM.nextDouble() * 20.0;
final double k = RANDOM.nextDouble() * 0.15;
final DoublesPair point = DoublesPair.of(t, k);
final DoubleMatrix1D s1 = senseFunc.evaluate(point);
final DoubleMatrix1D s2 = senseSurf.getZValue(point);
AssertMatrix.assertEqualsVectors(s1, s2, 1e-13);
}
final Surface<Double, Double, Pair<Double, DoubleMatrix1D>> vsSurf = pro.getVolAndParameterSensitivitySurface(a);
for (int i = 0; i < nSamples; i++) {
final double t = RANDOM.nextDouble() * 20.0;
final double k = RANDOM.nextDouble() * 0.15;
final DoublesPair point = DoublesPair.of(t, k);
final Double vol = vs.getVolatility(point);
final DoubleMatrix1D sense = senseSurf.getZValue(point);
final Pair<Double, DoubleMatrix1D> volAndSense = vsSurf.getZValue(point);
assertEquals(vol, volAndSense.getFirst(), 1e-14);
AssertMatrix.assertEqualsVectors(sense, volAndSense.getSecond(), 1e-13);
}
}
}