/** * 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 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.surface.ParameterizedVolatilitySurfaceProvider; import com.opengamma.analytics.financial.model.volatility.surface.VolatilitySurfaceProvider; 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.matrix.DoubleMatrix2D; import com.opengamma.analytics.util.AssertMatrix; import com.opengamma.util.test.TestGroup; import com.opengamma.util.tuple.DoublesPair; /** * Set up a {@link VolatilitySurfaceProvider} that is quadratic in time-to-expiry (t) and strike (k) * (so-called practitioners Black-Scholes, with 6 parameters), then convert this to a {@link DiscreteVolatilityFunctionProvider} * and obtain a {@link DiscreteVolatilityFunction} at randomly chosen expiry-strike points. Check the volatilities and * their sensitivity to the model parameters are correct. */ @Test(groups = TestGroup.UNIT) public class DiscreteVolatilityFunctionProviderFromVolSurfaceTest { private static final RandomEngine RANDOM = new MersenneTwister64(MersenneTwister.DEFAULT_SEED); private static final ParameterizedSurface SURFACE; private static final VolatilitySurfaceProvider VOL_SURF_PRO; 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); } }; } }; VOL_SURF_PRO = new ParameterizedVolatilitySurfaceProvider(SURFACE); } @Test public void test() { final DiscreteVolatilityFunctionProvider discPro = new DiscreteVolatilityFunctionProviderFromVolSurface(VOL_SURF_PRO); final int nSamples = 35; final DoublesPair[] points = new DoublesPair[nSamples]; for (int i = 0; i < nSamples; i++) { final double t = RANDOM.nextDouble() * 20.0; final double k = RANDOM.nextDouble() * 0.15; points[i] = DoublesPair.of(t, k); } final DiscreteVolatilityFunction func = discPro.from(points); //parameters of the vol surface final DoubleMatrix1D a = new DoubleMatrix1D(0.3, -0.02, -0.4, 0.003, 15.6, -0.05); final DoubleMatrix1D vols = func.evaluate(a); final Function1D<DoublesPair, Double> volFunc = SURFACE.asFunctionOfArguments(a); for (int i = 0; i < nSamples; i++) { assertEquals(volFunc.evaluate(points[i]), vols.getEntry(i), 1e-15); } final DoubleMatrix2D jac = func.calculateJacobian(a); final DoubleMatrix2D fdJac = func.calculateJacobianViaFD(a); AssertMatrix.assertEqualsMatrix(fdJac, jac, 1e-11); assertEquals(SURFACE.getNumberOfParameters(), func.getLengthOfDomain()); assertEquals(nSamples, func.getLengthOfRange()); } }