/**
* Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.calculator;
import java.util.LinkedHashSet;
import org.apache.commons.lang.ArrayUtils;
import com.opengamma.analytics.financial.forex.method.FXMatrix;
import com.opengamma.analytics.financial.provider.sensitivity.multicurve.MultipleCurrencyParameterSensitivity;
import com.opengamma.analytics.math.linearalgebra.SVDecompositionCommons;
import com.opengamma.analytics.math.linearalgebra.SVDecompositionResult;
import com.opengamma.analytics.math.matrix.CommonsMatrixAlgebra;
import com.opengamma.analytics.math.matrix.DoubleMatrix1D;
import com.opengamma.analytics.math.matrix.DoubleMatrix2D;
import com.opengamma.util.money.Currency;
import com.opengamma.util.tuple.ObjectsPair;
import com.opengamma.util.tuple.Pair;
/**
* Computes the optimal hedging portfolio made of reference instruments to hedge a given sensitivity.
* <p> Reference: Portfolio hedging with reference securities, version 1.0, OG notes, October 2010.
*/
public class PortfolioHedgingCalculator {
/**
* The matrix algebra used (mainly multiplying matrices and solving systems).
*/
private static final CommonsMatrixAlgebra MATRIX = new CommonsMatrixAlgebra();
/**
* The decomposition method used.
*/
private static final SVDecompositionCommons DECOMPOSITION = new SVDecompositionCommons();
/**
* Computes the quantity of each reference instrument that optimally hedge a given sensitivity.
* @param ps The parameter sensitivity of the portfolio to hedge.
* @param rs The parameter sensitivities of the reference instruments.
* @param w The related parameters weight matrix. The order of the curve should be their "natural" order.
* @param order The ordered set of name.
* @param fxMatrix The matrix with exchange rates.
* @return The optimal hedging quantities. The quantities are in the same order as the reference instruments sensitivities.
* Note that the output is the optimal hedge quantity and not the portfolio equivalent. The hedge has the opposite sign of wrt the equivalent.
*/
public static double[] hedgeQuantity(final MultipleCurrencyParameterSensitivity ps, final MultipleCurrencyParameterSensitivity[] rs, final DoubleMatrix2D w,
final LinkedHashSet<Pair<String, Integer>> order, final FXMatrix fxMatrix) {
final Currency ccy = ps.getAllNamesCurrency().iterator().next().getSecond();
// Implementation note: currency used for the conversion in a common currency. Any currency is fine.
final int nbReference = rs.length;
final MultipleCurrencyParameterSensitivity psConverted = ps.converted(fxMatrix, ccy);
final MultipleCurrencyParameterSensitivity[] rsConverted = new MultipleCurrencyParameterSensitivity[nbReference];
for (int loopref = 0; loopref < nbReference; loopref++) {
rsConverted[loopref] = rs[loopref].converted(fxMatrix, ccy);
}
// Implementation note: converting the ParameterSensitivity into a matrix.
final DoubleMatrix1D p = toMatrix(psConverted, order);
final double[][] rsArray = new double[nbReference][];
for (int loopref = 0; loopref < nbReference; loopref++) {
rsArray[loopref] = toMatrix(rsConverted[loopref], order).getData();
}
final DoubleMatrix2D r = new DoubleMatrix2D(rsArray);
final DoubleMatrix2D wtW = (DoubleMatrix2D) MATRIX.multiply(MATRIX.getTranspose(w), w);
final DoubleMatrix2D rWtW = (DoubleMatrix2D) MATRIX.multiply(r, wtW);
final DoubleMatrix2D rWtWRt = (DoubleMatrix2D) MATRIX.multiply(rWtW, MATRIX.getTranspose(r));
final DoubleMatrix1D rWtWP = ((DoubleMatrix2D) MATRIX.scale(MATRIX.multiply(rWtW, p), -1.0)).getColumnVector(0);
final SVDecompositionResult dec = DECOMPOSITION.evaluate(rWtWRt);
final DoubleMatrix1D q = dec.solve(rWtWP);
return q.getData();
}
/**
* Convert the parameter sensitivity into a matrix (DoubleMatrix1D). All the sensitivities should be in the same currency.
* The matrix is composed of the sensitivity vectors (currency is ignored) one after the other.
* The matrix order is the one of the set.
* @param sensi The sensitivity.
* @param order The ordered set of name.
* @return The sensitivity matrix.
*/
public static DoubleMatrix1D toMatrix(final MultipleCurrencyParameterSensitivity sensi, final LinkedHashSet<Pair<String, Integer>> order) {
double[] psArray = new double[0];
final Currency ccy = sensi.getAllNamesCurrency().iterator().next().getSecond();
// Implementation note: all the currencies are supposed to be the same, we choose any of them.
for (final Pair<String, Integer> nameSize : order) {
if (sensi.getSensitivities().containsKey(new ObjectsPair<>(nameSize.getFirst(), ccy))) {
psArray = ArrayUtils.addAll(psArray, sensi.getSensitivity(nameSize.getFirst(), ccy).getData());
} else { // When curve is not in the sensitivity, add zeros.
psArray = ArrayUtils.addAll(psArray, new double[nameSize.getSecond()]);
}
}
return new DoubleMatrix1D(psArray);
}
}