/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.interestrate; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.commons.lang.Validate; import com.opengamma.analytics.financial.model.interestrate.curve.DiscountCurve; import com.opengamma.analytics.financial.model.interestrate.curve.YieldAndDiscountCurve; import com.opengamma.analytics.financial.model.interestrate.curve.YieldCurve; import com.opengamma.analytics.math.curve.InterpolatedDoublesCurve; import com.opengamma.analytics.math.interpolation.Interpolator1D; import com.opengamma.analytics.math.interpolation.data.Interpolator1DDataBundle; import com.opengamma.analytics.math.matrix.DoubleMatrix1D; import com.opengamma.util.tuple.DoublesPair; /** * For an instrument, calculates the sensitivity of a value (often either the present value (PV) or par rate) to the yield at the knot points of the interpolated yield curves. * The return format is a DoubleMatrix1D (i.e. a vector) with length equal to the total number of nodes in all the curves, and ordered as sensitivity to nodes of first curve, second curve etc. * The change of a curve due to the movement of a single knot is interpolator-dependent, and can affect the entire curve, so an instrument can have sensitivity to nodes at times (way) * beyond its maturity. * @deprecated {@link YieldCurveBundle} is deprecated */ @Deprecated public abstract class NodeYieldSensitivityCalculator { /* package */ NodeYieldSensitivityCalculator() { } public abstract DoubleMatrix1D calculateSensitivities(final InstrumentDerivative ird, final YieldCurveBundle fixedCurves, final YieldCurveBundle interpolatedCurves); /** * Computes the sensitivities to the yield at the node points for an instrument from a yield sensitivity calculator. * @param derivative The instrument. * @param calculator The yield sensitivity calculator. * @param fixedCurves The fixed curves. * @param interpolatedCurves The curves with respect to which the sensitivities should be computed. The curves should be based on InterpolatedDoublesCurve. * @return The yield sensitivities to the node points. */ public DoubleMatrix1D calculateSensitivities(final InstrumentDerivative derivative, final InstrumentDerivativeVisitor<YieldCurveBundle, Map<String, List<DoublesPair>>> calculator, final YieldCurveBundle fixedCurves, final YieldCurveBundle interpolatedCurves) { Validate.notNull(derivative, "null InterestRateDerivative"); Validate.notNull(calculator, "null calculator"); Validate.notNull(interpolatedCurves, "interpolated curves"); final YieldCurveBundle allCurves = interpolatedCurves.copy(); if (fixedCurves != null) { for (final String name : interpolatedCurves.getAllNames()) { Validate.isTrue(!fixedCurves.containsName(name), "fixed curves contain a name that is also in interpolated curves"); } allCurves.addAll(fixedCurves); } final Map<String, List<DoublesPair>> sensitivityMap = derivative.accept(calculator, allCurves); return curveToNodeSensitivities(sensitivityMap, interpolatedCurves); } /** * Computes the sensitivity to the yield at the node points from the sensitivities to the yield at arbitrary points. * @param curveSensitivities The sensitivity to the yield at arbitrary points on the different curves. * @param interpolatedCurves The curve bundle. The curves should be YieldCurve based on InterpolatedDoublesCurve. * @return The yield sensitivities to the node points. */ public DoubleMatrix1D curveToNodeSensitivities(final Map<String, List<DoublesPair>> curveSensitivities, final YieldCurveBundle interpolatedCurves) { final List<Double> result = new ArrayList<>(); for (final String name : interpolatedCurves.getAllNames()) { // loop over all curves (by name) final YieldAndDiscountCurve curve = interpolatedCurves.getCurve(name); // Split between Yield and Discount if (curve instanceof YieldCurve) { result.addAll(curveToNodeSensitivity(curveSensitivities.get(name), (YieldCurve) curve)); } else if (curve instanceof DiscountCurve) { result.addAll(curveToNodeSensitivity(curveSensitivities.get(name), (DiscountCurve) curve)); } else { throw new IllegalArgumentException("Can only handle YieldCurve and DiscountCurve at the moment"); } } return new DoubleMatrix1D(result.toArray(new Double[result.size()])); } /** * Computes the node yield sensitivity for one YieldCurve. * @param sensitivityList The sensitivity to the yield at arbitrary points on the curve. * @param curve The YieldCurve. * @return The node sensitivity. */ public List<Double> curveToNodeSensitivity(final List<DoublesPair> sensitivityList, final YieldCurve curve) { final List<Double> result = new ArrayList<>(); if (!(curve.getCurve() instanceof InterpolatedDoublesCurve)) { throw new IllegalArgumentException("Can only handle interpolated curves at the moment"); } final InterpolatedDoublesCurve interpolatedCurve = (InterpolatedDoublesCurve) curve.getCurve(); final Interpolator1D interpolator = interpolatedCurve.getInterpolator(); final Interpolator1DDataBundle data = interpolatedCurve.getDataBundle(); if (sensitivityList != null && sensitivityList.size() > 0) { final double[][] sensitivityYY = new double[sensitivityList.size()][]; // Implementation note: Sensitivity of the interpolated yield to the node yields int k = 0; for (final DoublesPair timeAndS : sensitivityList) { sensitivityYY[k++] = interpolator.getNodeSensitivitiesForValue(data, timeAndS.getFirst()); } for (int j = 0; j < sensitivityYY[0].length; j++) { double temp = 0.0; k = 0; for (final DoublesPair timeAndS : sensitivityList) { temp += timeAndS.getSecond() * sensitivityYY[k++][j]; } result.add(temp); } } else { for (int i = 0; i < interpolatedCurve.size(); i++) { result.add(0.); } } return result; } /** * Computes the node yield sensitivity for one YieldCurve. * @param sensitivityList The sensitivity to the yield at arbitrary points on the curve. * @param curve The YieldCurve. * @return The node sensitivity. */ public List<Double> curveToNodeSensitivity(final List<DoublesPair> sensitivityList, final DiscountCurve curve) { final List<Double> result = new ArrayList<>(); if (!(curve.getCurve() instanceof InterpolatedDoublesCurve)) { throw new IllegalArgumentException("Can only handle interpolated curves at the moment"); } final InterpolatedDoublesCurve interpolatedCurve = (InterpolatedDoublesCurve) curve.getCurve(); final Interpolator1D interpolator = interpolatedCurve.getInterpolator(); final Interpolator1DDataBundle data = interpolatedCurve.getDataBundle(); if (sensitivityList != null && sensitivityList.size() > 0) { final double[][] sensitivityDD = new double[sensitivityList.size()][]; // Implementation note: Sensitivity of the interpolated discount factor to the node discount factor final double[] df = new double[sensitivityList.size()]; int k = 0; for (final DoublesPair timeAndS : sensitivityList) { df[k] = interpolator.interpolate(data, timeAndS.first); sensitivityDD[k++] = interpolator.getNodeSensitivitiesForValue(data, timeAndS.getFirst()); } for (int j = 0; j < sensitivityDD[0].length; j++) { double temp = 0.0; k = 0; for (final DoublesPair timeAndS : sensitivityList) { temp += timeAndS.getSecond() / (timeAndS.first * df[k]) * sensitivityDD[k++][j] * (data.getKeys()[j] * data.getValues()[j]); } result.add(temp); } } else { for (int i = 0; i < interpolatedCurve.size(); i++) { result.add(0.); } } return result; } /** * Computes the node sensitivity from an InterestRateCurveSensitivity object and the corresponding yield curve bundle. * @param curveSensitivities The sensitivities. * @param interpolatedCurves The curve bundle. * @return The node sensitivities. */ public DoubleMatrix1D curveToNodeSensitivities(final InterestRateCurveSensitivity curveSensitivities, final YieldCurveBundle interpolatedCurves) { return curveToNodeSensitivities(curveSensitivities.getSensitivities(), interpolatedCurves); } /** * Computes the node yield sensitivity for one YieldCurve. * @param curveSensitivities The sensitivity to the yield at arbitrary points on the curve. * @param curve The YieldCurve. * @return The node sensitivity. */ public DoubleMatrix1D curveToNodeSensitivities(final List<DoublesPair> curveSensitivities, final YieldAndDiscountCurve curve) { final List<Double> result = new ArrayList<>(); if (curve instanceof YieldCurve) { result.addAll(curveToNodeSensitivity(curveSensitivities, (YieldCurve) curve)); } else if (curve instanceof DiscountCurve) { result.addAll(curveToNodeSensitivity(curveSensitivities, (DiscountCurve) curve)); } else { throw new IllegalArgumentException("Can only handle YieldCurve and DiscountCurve at the moment"); } return new DoubleMatrix1D(result.toArray(new Double[result.size()])); } }