/** * 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 com.opengamma.analytics.math.curve.InterpolatedDoublesCurve; import com.opengamma.analytics.math.function.Function; import com.opengamma.analytics.math.function.Function2D; import com.opengamma.analytics.math.interpolation.Interpolator1D; import com.opengamma.analytics.math.matrix.DoubleMatrix1D; import com.opengamma.analytics.math.surface.FunctionalDoublesSurface; import com.opengamma.analytics.math.surface.FunctionalSurface; import com.opengamma.analytics.math.surface.Surface; import com.opengamma.util.ArgumentChecker; import com.opengamma.util.tuple.ObjectsPair; import com.opengamma.util.tuple.Pair; /** *Produces a volatility surface that is backed by a single interpolated curve in the expiry dimension, i.e. there is no *strike variation */ public class InterpolatedVolatilityTermStructureProvider implements VolatilitySurfaceProvider { private final double[] _knots; private final Interpolator1D _interpolator; public InterpolatedVolatilityTermStructureProvider(final double[] knotPoints, final Interpolator1D interpolator) { ArgumentChecker.notEmpty(knotPoints, "null or empty knotPoints"); ArgumentChecker.notNull(interpolator, "null interpolator"); final int n = knotPoints.length; for (int i = 1; i < n; i++) { ArgumentChecker.isTrue(knotPoints[i] > knotPoints[i - 1], "knot points must be strictly ascending"); } _knots = knotPoints.clone(); _interpolator = interpolator; } /** * {@inheritDoc} */ @Override public VolatilitySurface getVolSurface(final DoubleMatrix1D modelParameters) { ArgumentChecker.notNull(modelParameters, "modelParameters"); //InterpolatedDoublesCurve checks length of modelParameters, so is not repeated here final InterpolatedDoublesCurve curve = new InterpolatedDoublesCurve(_knots, modelParameters.getData(), _interpolator, true); final Function<Double, Double> function = new Function<Double, Double>() { @Override public Double evaluate(final Double... tk) { return curve.getYValue(tk[0]); } }; final FunctionalDoublesSurface surface = new FunctionalDoublesSurface(function); return new VolatilitySurface(surface); } /** * {@inheritDoc} */ @Override public Surface<Double, Double, DoubleMatrix1D> getParameterSensitivitySurface(final DoubleMatrix1D modelParameters) { ArgumentChecker.notNull(modelParameters, "modelParameters"); //InterpolatedDoublesCurve checks length of modelParameters, so is not repeated here final InterpolatedDoublesCurve curve = new InterpolatedDoublesCurve(_knots, modelParameters.getData(), _interpolator, true); final Function2D<Double, DoubleMatrix1D> func = new Function2D<Double, DoubleMatrix1D>() { @Override public DoubleMatrix1D evaluate(final Double t, final Double k) { final Double[] sense = curve.getYValueParameterSensitivity(t); return new DoubleMatrix1D(sense); } }; return new FunctionalSurface<>(func); } @Override public Surface<Double, Double, Pair<Double, DoubleMatrix1D>> getVolAndParameterSensitivitySurface(final DoubleMatrix1D modelParameters) { ArgumentChecker.notNull(modelParameters, "modelParameters"); //InterpolatedDoublesCurve checks length of modelParameters, so is not repeated here final InterpolatedDoublesCurve curve = new InterpolatedDoublesCurve(_knots, modelParameters.getData(), _interpolator, true); final Function2D<Double, Pair<Double, DoubleMatrix1D>> func = new Function2D<Double, Pair<Double, DoubleMatrix1D>>() { @Override public Pair<Double, DoubleMatrix1D> evaluate(final Double t, final Double k) { final Double vol = curve.getYValue(t); final DoubleMatrix1D sense = new DoubleMatrix1D(curve.getYValueParameterSensitivity(t)); return ObjectsPair.of(vol, sense); } }; return new FunctionalSurface<>(func); } /** * {@inheritDoc} */ @Override public int getNumModelParameters() { return _knots.length; } }