/**
* 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.discrete;
import static org.testng.AssertJUnit.assertEquals;
import java.util.ArrayList;
import java.util.Arrays;
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.interestrate.curve.ForwardCurve;
import com.opengamma.analytics.financial.model.volatility.smile.function.SABRHaganVolatilityFunction;
import com.opengamma.analytics.math.function.DoublesVectorFunctionProvider;
import com.opengamma.analytics.math.function.InterpolatedVectorFunctionProvider;
import com.opengamma.analytics.math.function.ParameterizedCurve;
import com.opengamma.analytics.math.function.ParameterizedCurveVectorFunctionProvider;
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.util.AssertMatrix;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.test.TestGroup;
import com.opengamma.util.tuple.DoublesPair;
/**
*
*/
@Test(groups = TestGroup.UNIT)
public class ParameterizedSABRModelDiscreteVolatilityFunctionProviderTest {
private static final RandomEngine RANDOM = new MersenneTwister64(MersenneTwister.DEFAULT_SEED);
private static final ForwardCurve s_fwdCurve = new ForwardCurve(0.01, 0.02);
private static final ParameterizedCurve s_flat = new ParameterizedCurve() {
@Override
public int getNumberOfParameters() {
return 1;
}
@Override
public Double evaluate(Double x, DoubleMatrix1D parameters) {
ArgumentChecker.notNull(parameters, "parameters");
ArgumentChecker.isTrue(parameters.getNumberOfElements() == getNumberOfParameters(), "parameters wrong size");
return parameters.getEntry(0);
}
};
/**
* set up using constant (across expiry) SABR parameters
*/
@Test
public void test() {
ParameterizedCurve[] curves = new ParameterizedCurve[4];
Arrays.fill(curves, s_flat);
ParameterizedSABRModelDiscreteVolatilityFunctionProvider dvfp = new ParameterizedSABRModelDiscreteVolatilityFunctionProvider(s_fwdCurve, curves);
double[] expiries = new double[] {0.5, 1.0, 4.0 };
double[] strikes = new double[] {0.002, 0.004, 0.006, 0.01, 0.02 };
int nExp = expiries.length;
int nStrikes = strikes.length;
List<DoublesPair> points = new ArrayList<>(nExp * nStrikes);
for (int i = 0; i < nExp; i++) {
for (int j = 0; j < nStrikes; j++) {
points.add(DoublesPair.of(expiries[i], strikes[j]));
}
}
DiscreteVolatilityFunction func = dvfp.from(points);
double alpha = 0.2;
double beta = 0.78;
double rho = -0.3;
double nu = 0.5;
DoubleMatrix1D sabrParms = new DoubleMatrix1D(alpha, beta, rho, nu);
DoubleMatrix1D vols = func.evaluate(sabrParms);
SABRHaganVolatilityFunction hagan = new SABRHaganVolatilityFunction();
for (int i = 0; i < nExp; i++) {
double t = expiries[i];
double fwd = s_fwdCurve.getForward(t);
for (int j = 0; j < nStrikes; j++) {
double vol = hagan.getVolatility(fwd, strikes[j], t, alpha, beta, rho, nu);
assertEquals(vol, vols.getEntry(i * nStrikes + j), 1e-15);
}
}
DoubleMatrix2D jac = func.calculateJacobian(sabrParms);
DoubleMatrix2D jacFD = func.calculateJacobianViaFD(sabrParms);
AssertMatrix.assertEqualsMatrix(jacFD, jac, 1e-8);
}
/**
* set up with a mix of interpolated and parameterised curves representing the SABR parameter term structures
*/
@Test
public void mixedTSTest() {
Interpolator1D interpolator = CombinedInterpolatorExtrapolatorFactory.getInterpolator(Interpolator1DFactory.DOUBLE_QUADRATIC, Interpolator1DFactory.LINEAR_EXTRAPOLATOR);
DoublesVectorFunctionProvider alpha = new InterpolatedVectorFunctionProvider(interpolator, new double[] {1.0, 3.0, 5.0, 7.0, 10.0 });
DoublesVectorFunctionProvider beta = new ParameterizedCurveVectorFunctionProvider(s_flat);
DoublesVectorFunctionProvider rho = new InterpolatedVectorFunctionProvider(interpolator, new double[] {3.0, 7.0, 10.0 });
DoublesVectorFunctionProvider nu = new InterpolatedVectorFunctionProvider(interpolator, new double[] {1.0, 3.0, 5.0, 7.0, 10.0 });
DoublesVectorFunctionProvider[] toSmileParms = new DoublesVectorFunctionProvider[] {alpha, beta, rho, nu };
DiscreteVolatilityFunctionProvider dvfp = new ParameterizedSABRModelDiscreteVolatilityFunctionProvider(s_fwdCurve, toSmileParms);
final int nSamples = 50;
DoublesPair[] points = new DoublesPair[nSamples];
for (int i = 0; i < nSamples; i++) {
double t = 10.0 * RANDOM.nextDouble();
double k = 0.03 * RANDOM.nextDouble();
points[i] = DoublesPair.of(t, k);
}
DiscreteVolatilityFunction func = dvfp.from(points);
assertEquals(nSamples, func.getLengthOfRange());
DoubleMatrix1D parms = new DoubleMatrix1D(func.getLengthOfDomain());
int pos = 0;
for (; pos < 5; pos++) {
parms.getData()[pos] = 0.1 + 0.2 * RANDOM.nextDouble();
}
parms.getData()[pos++] = 0.8;
for (; pos < 9; pos++) {
parms.getData()[pos] = -0.3 + 0.6 * RANDOM.nextDouble();
}
for (; pos < 14; pos++) {
parms.getData()[pos] = 0.2 + 0.6 * RANDOM.nextDouble();
}
DoubleMatrix2D jac = func.calculateJacobian(parms);
DoubleMatrix2D jacFD = func.calculateJacobianViaFD(parms);
AssertMatrix.assertEqualsMatrix(jacFD, jac, 5e-5);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void noPointsTest() {
ParameterizedCurve[] curves = new ParameterizedCurve[4];
Arrays.fill(curves, s_flat);
ParameterizedSABRModelDiscreteVolatilityFunctionProvider dvfp = new ParameterizedSABRModelDiscreteVolatilityFunctionProvider(s_fwdCurve, curves);
List<DoublesPair> points = new ArrayList<>();
@SuppressWarnings("unused")
DiscreteVolatilityFunction func = dvfp.from(points);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void nonUniquePointsTest() {
ParameterizedCurve[] curves = new ParameterizedCurve[4];
Arrays.fill(curves, s_flat);
ParameterizedSABRModelDiscreteVolatilityFunctionProvider dvfp = new ParameterizedSABRModelDiscreteVolatilityFunctionProvider(s_fwdCurve, curves);
List<DoublesPair> points = new ArrayList<>();
points.add(DoublesPair.of(1.0, 0.05));
points.add(DoublesPair.of(1.2, 0.05));
points.add(DoublesPair.of(1.0, 0.06));
points.add(DoublesPair.of(1.0, 0.05));
@SuppressWarnings("unused")
DiscreteVolatilityFunction func = dvfp.from(points);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void wrongNumberOfModelParmsTest() {
ParameterizedCurve[] curves = new ParameterizedCurve[4];
Arrays.fill(curves, s_flat);
ParameterizedSABRModelDiscreteVolatilityFunctionProvider dvfp = new ParameterizedSABRModelDiscreteVolatilityFunctionProvider(s_fwdCurve, curves);
List<DoublesPair> points = new ArrayList<>();
points.add(DoublesPair.of(1.0, 0.05));
points.add(DoublesPair.of(1.2, 0.05));
points.add(DoublesPair.of(1.5, 0.06));
points.add(DoublesPair.of(2.0, 0.05));
DiscreteVolatilityFunction func = dvfp.from(points);
func.evaluate(new DoubleMatrix1D(15, 1.0));
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void wrongNumberOfCurvesTest() {
ParameterizedCurve[] curves = new ParameterizedCurve[3];
Arrays.fill(curves, s_flat);
ParameterizedSABRModelDiscreteVolatilityFunctionProvider dvfp = new ParameterizedSABRModelDiscreteVolatilityFunctionProvider(s_fwdCurve, curves);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void wrongNumberOfMixedCurvesTest() {
Interpolator1D interpolator = CombinedInterpolatorExtrapolatorFactory.getInterpolator(Interpolator1DFactory.DOUBLE_QUADRATIC, Interpolator1DFactory.LINEAR_EXTRAPOLATOR);
DoublesVectorFunctionProvider alpha = new InterpolatedVectorFunctionProvider(interpolator, new double[] {1.0, 3.0, 5.0, 7.0, 10.0 });
DoublesVectorFunctionProvider beta = new ParameterizedCurveVectorFunctionProvider(s_flat);
DoublesVectorFunctionProvider rho = new InterpolatedVectorFunctionProvider(interpolator, new double[] {3.0, 7.0, 10.0 });
DoublesVectorFunctionProvider nu = new InterpolatedVectorFunctionProvider(interpolator, new double[] {1.0, 3.0, 5.0, 7.0, 10.0 });
DoublesVectorFunctionProvider[] toSmileParms = new DoublesVectorFunctionProvider[] {alpha, beta, rho };
DiscreteVolatilityFunctionProvider dvfp = new ParameterizedSABRModelDiscreteVolatilityFunctionProvider(s_fwdCurve, toSmileParms);
}
}