/**
* Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.interestrate.capletstripping;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang.Validate;
import com.opengamma.analytics.financial.interestrate.YieldCurveBundle;
import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.EuropeanVanillaOption;
import com.opengamma.analytics.financial.model.volatility.BlackFormulaRepository;
import com.opengamma.analytics.financial.model.volatility.SABRTermStructureParameters;
import com.opengamma.analytics.financial.model.volatility.VolatilityModel1D;
import com.opengamma.analytics.financial.model.volatility.smile.function.SABRFormulaData;
import com.opengamma.analytics.financial.model.volatility.smile.function.SABRHaganVolatilityFunction;
import com.opengamma.analytics.math.curve.Curve;
import com.opengamma.analytics.math.curve.InterpolatedCurveBuildingFunction;
import com.opengamma.analytics.math.curve.InterpolatedDoublesCurve;
import com.opengamma.analytics.math.function.Function1D;
import com.opengamma.analytics.math.interpolation.Interpolator1D;
import com.opengamma.analytics.math.interpolation.TransformedInterpolator1D;
import com.opengamma.analytics.math.interpolation.data.Interpolator1DDataBundle;
import com.opengamma.analytics.math.interpolation.data.Interpolator1DDataBundleBuilderFunction;
import com.opengamma.analytics.math.matrix.DoubleMatrix1D;
import com.opengamma.analytics.math.matrix.DoubleMatrix2D;
import com.opengamma.analytics.math.minimization.ParameterLimitsTransform;
/**
* @deprecated {@link YieldCurveBundle} is deprecated
*/
@Deprecated
public class CapletStrippingJacobian extends Function1D<DoubleMatrix1D, DoubleMatrix2D> {
private static final String ALPHA = "alpha";
private static final String BETA = "beta";
private static final String NU = "nu";
private static final String RHO = "rho";
private static final SABRHaganVolatilityFunction SABR = new SABRHaganVolatilityFunction();
private final LinkedHashMap<String, Interpolator1D> _interpolators;
private final Set<String> _parameterNames;
private final List<CapFloorPricer> _capPricers;
private final LinkedHashMap<String, InterpolatedDoublesCurve> _knownParameterTermSturctures;
private final InterpolatedCurveBuildingFunction _curveBuilder;
private final Interpolator1DDataBundleBuilderFunction _dataBundleBuilder;
public CapletStrippingJacobian(final List<CapFloor> caps, final YieldCurveBundle yieldCurves,
final LinkedHashMap<String, double[]> knotPoints,
final LinkedHashMap<String, Interpolator1D> interpolators,
final LinkedHashMap<String, ParameterLimitsTransform> parameterTransforms,
final LinkedHashMap<String, InterpolatedDoublesCurve> knownParameterTermSturctures) {
Validate.notNull(caps, "caps null");
Validate.notNull(knotPoints, "null node points");
Validate.notNull(interpolators, "null interpolators");
Validate.isTrue(knotPoints.size() == interpolators.size(), "size mismatch between nodes and interpolators");
_knownParameterTermSturctures = knownParameterTermSturctures;
final LinkedHashMap<String, Interpolator1D> transInterpolators = new LinkedHashMap<>();
final Set<String> names = interpolators.keySet();
_parameterNames = names;
for (final String name : names) {
final Interpolator1D temp = new TransformedInterpolator1D(interpolators.get(name), parameterTransforms.get(name));
transInterpolators.put(name, temp);
}
_capPricers = new ArrayList<>(caps.size());
for (final CapFloor cap : caps) {
_capPricers.add(new CapFloorPricer(cap, yieldCurves));
}
_interpolators = transInterpolators;
_curveBuilder = new InterpolatedCurveBuildingFunction(knotPoints, transInterpolators);
_dataBundleBuilder = new Interpolator1DDataBundleBuilderFunction(knotPoints, transInterpolators);
}
@Override
public DoubleMatrix2D evaluate(final DoubleMatrix1D x) {
final LinkedHashMap<String, Interpolator1DDataBundle> db = _dataBundleBuilder.evaluate(x); //TODO merge these - they do the same work!
final LinkedHashMap<String, InterpolatedDoublesCurve> curves = _curveBuilder.evaluate(x);
// set any known (i.e. fixed) curves
if (_knownParameterTermSturctures != null) {
curves.putAll(_knownParameterTermSturctures);
}
//TODO make this general - not SABR specific
final Curve<Double, Double> cAlpha = curves.get(ALPHA);
final Curve<Double, Double> cBeta = curves.get(BETA);
final Curve<Double, Double> cRho = curves.get(RHO);
final Curve<Double, Double> cNu = curves.get(NU);
final VolatilityModel1D volModel = new SABRTermStructureParameters(cAlpha, cBeta, cRho, cNu);
final int nCaps = _capPricers.size();
final int m = x.getNumberOfElements();
final double[][] jac = new double[nCaps][m];
double f, k, t;
for (int i = 0; i < nCaps; i++) { //outer loop over caps
final CapFloorPricer capPricer = _capPricers.get(i);
final double vega = capPricer.vega(volModel);
final int nCaplets = capPricer.getNumberCaplets();
final double[][] greeks = new double[nCaplets][]; //the sensitivity of vol to the model parameters
final double[] capletVega = new double[nCaplets];
final double[] capletExpiries = capPricer.getExpiries();
final double[] capletFwds = capPricer.getForwards();
final double[] capletDF = capPricer.getDiscountFactors();
final double[][][] nodeSens = new double[_parameterNames.size()][nCaplets][]; //Sensitivity to the nodes of a particular curve at a particular time
k = capPricer.getStrike();
//TODO There will be much repeated calculations here, as many of the caplets are shared across caps
for (int tIndex = 0; tIndex < nCaplets; tIndex++) {
f = capletFwds[tIndex];
t = capletExpiries[tIndex];
final EuropeanVanillaOption option = new EuropeanVanillaOption(k, t, true);
//TODO again this is SABR specific
final SABRFormulaData data = new SABRFormulaData(cAlpha.getYValue(t), cBeta.getYValue(t), cRho.getYValue(t), cNu.getYValue(t));
greeks[tIndex] = SABR.getVolatilityAdjoint(option, f, data); //2nd and 3rd entries are forward & strike sensitivity which we don't use
capletVega[tIndex] = capletDF[tIndex] * BlackFormulaRepository.vega(f, k, t, greeks[tIndex][0]);
int parmIndex = 0;
for (final String name : _parameterNames) {
final Interpolator1D itrp = _interpolators.get(name);
nodeSens[parmIndex++][tIndex] = itrp.getNodeSensitivitiesForValue(db.get(name), t);
}
}
final double[] res = new double[x.getNumberOfElements()];
for (int tIndex = 0; tIndex < nCaplets; tIndex++) {
int index = 0;
for (int parmIndex = 0; parmIndex < _parameterNames.size(); parmIndex++) {
final double temp = capletVega[tIndex] * greeks[tIndex][parmIndex + 3]; //1st 3 are vol, dForward & dStrike
final double[] ns = nodeSens[parmIndex][tIndex];
for (final double element : ns) {
res[index] += element * temp;
index++;
}
}
}
for (int j = 0; j < res.length; j++) {
jac[i][j] = res[j] / vega;
}
}
return new DoubleMatrix2D(jac);
}
}