/** * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.credit.isdastandardmodel; import com.opengamma.analytics.math.linearalgebra.LUDecompositionCommons; import com.opengamma.analytics.math.linearalgebra.LUDecompositionResult; import com.opengamma.analytics.math.matrix.DoubleMatrix1D; import com.opengamma.analytics.math.matrix.DoubleMatrix2D; import com.opengamma.analytics.math.matrix.MatrixAlgebra; import com.opengamma.analytics.math.matrix.OGMatrixAlgebra; import com.opengamma.util.ArgumentChecker; /** * */ public class HedgeRatioCalculator { MatrixAlgebra MA = new OGMatrixAlgebra(); private final AnalyticCDSPricer _pricer; private final ISDACompliantCreditCurveBuilder _builder; public HedgeRatioCalculator() { _pricer = new AnalyticCDSPricer(); _builder = new FastCreditCurveBuilder(); } /** * Constructor specifying formula used in pricer and credit curve builder * @param formula The formula */ public HedgeRatioCalculator(AccrualOnDefaultFormulae formula) { ArgumentChecker.notNull(formula, "formula"); _pricer = new AnalyticCDSPricer(formula); _builder = new FastCreditCurveBuilder(formula); } /** * The sensitivity of the PV of a CDS to the zero hazard rates at the knots of the credit curve *TODO this should be handled directly by the pricer * @param cds The CDS * @param creditCurve The credit Curve * @param yieldCurve the yield curve * @return vector of sensitivities */ public DoubleMatrix1D getCurveSensitivities(final CDSAnalytic cds, final double coupon, final ISDACompliantCreditCurve creditCurve, final ISDACompliantYieldCurve yieldCurve) { ArgumentChecker.notNull(cds, "cds"); ArgumentChecker.notNull(creditCurve, "creditCurve"); ArgumentChecker.notNull(yieldCurve, "yieldCurve"); final int nKnots = creditCurve.getNumberOfKnots(); final double[] sense = new double[nKnots]; for (int i = 0; i < nKnots; i++) { sense[i] = _pricer.pvCreditSensitivity(cds, yieldCurve, creditCurve, coupon, i); } return new DoubleMatrix1D(sense); } /** * The sensitivity of a set of CDSs to the zero hazard rates at the knots of the credit curve. The element (i,j) is the sensitivity of the PV of the * jth CDS to the ith knot. * @param cds Set of CDSs * @param coupons The coupons of the CDSs * @param creditCurve The credit Curve * @param yieldCurve the yield curve * @return matrix of sensitivities */ public DoubleMatrix2D getCurveSensitivities(final CDSAnalytic[] cds, final double[] coupons, final ISDACompliantCreditCurve creditCurve, final ISDACompliantYieldCurve yieldCurve) { ArgumentChecker.noNulls(cds, "cds"); ArgumentChecker.notEmpty(coupons, "coupons"); ArgumentChecker.notNull(creditCurve, "creditCurve"); ArgumentChecker.notNull(yieldCurve, "yieldCurve"); final int nCDS = cds.length; ArgumentChecker.isTrue(nCDS == coupons.length, "number of coupons not equal number of CDS"); final int nKnots = creditCurve.getNumberOfKnots(); final double[][] sense = new double[nKnots][nCDS]; for (int i = 0; i < nCDS; i++) { for (int j = 0; j < nKnots; j++) { sense[j][i] = _pricer.pvCreditSensitivity(cds[i], yieldCurve, creditCurve, coupons[i], j); } } return new DoubleMatrix2D(sense); } /** * Hedge a CDS with other CDSs on the same underlying (single-name or index) at different maturities. The hedge is such that the total portfolio (the CDS <b>minus</b> * the hedging CDSs, with notionals of the CDS notional times the computed hedge ratios) is insensitive to infinitesimal changes to the the credit curve. <br> * Here the credit curve is built using the hedging CDSs as pillars. * @param cds The CDS to be hedged * @param coupon The coupon of the CDS to be hedged * @param hedgeCDSs The CDSs to hedge with - these are also used to build the credit curve * @param hedgeCDSCoupons The coupons of the CDSs to hedge with/build credit curve * @param hegdeCDSPUF The PUF of the CDSs to build credit curve * @param yieldCurve he yield curve * @return The hedge ratios. Since we use a unit notional, there ratios should be multiplied by -notional to give the hedge notional amounts. */ public DoubleMatrix1D getHedgeRatios(final CDSAnalytic cds, final double coupon, final CDSAnalytic[] hedgeCDSs, final double[] hedgeCDSCoupons, final double[] hegdeCDSPUF, final ISDACompliantYieldCurve yieldCurve) { final ISDACompliantCreditCurve cc = _builder.calibrateCreditCurve(hedgeCDSs, hedgeCDSCoupons, yieldCurve, hegdeCDSPUF); return getHedgeRatios(cds, coupon, hedgeCDSs, hedgeCDSCoupons, cc, yieldCurve); } /** * Hedge a CDS with other CDSs on the same underlying (single-name or index) at different maturities. The hedge is such that the total portfolio (the CDS <b>minus</b> * the hedging CDSs, with notionals of the CDS notional times the computed hedge ratios) is insensitive to infinitesimal changes to the the credit curve. * If the number of hedge-CDSs equals the number of credit-curve knots, the system is square and is solved exactly (see below).<br> * If the number of hedge-CDSs is less than the number of credit-curve knots, the system is solved in a least-square sense (i.e. is hedge is not exact).<br> * If the number of hedge-CDSs is greater than the number of credit-curve knots, the system cannot be solved. <br> * The system may not solve if the maturities if the hedging CDSs and very different from the knot times (i.e. the sensitivity matrix is singular). * @param cds The CDS to be hedged * @param coupon The coupon of the CDS to be hedged * @param hedgeCDSs The CDSs to hedge with * @param hedgeCDSCoupons The coupons of the CDSs to hedge with * @param creditCurve The credit curve * @param yieldCurve the yield curve * @return The hedge ratios. Since we use a unit notional, there ratios should be multiplied by -notional to give the hedge notional amounts. */ public DoubleMatrix1D getHedgeRatios(final CDSAnalytic cds, final double coupon, final CDSAnalytic[] hedgeCDSs, final double[] hedgeCDSCoupons, final ISDACompliantCreditCurve creditCurve, final ISDACompliantYieldCurve yieldCurve) { final DoubleMatrix1D cdsSense = getCurveSensitivities(cds, coupon, creditCurve, yieldCurve); final DoubleMatrix2D hedgeSense = getCurveSensitivities(hedgeCDSs, hedgeCDSCoupons, creditCurve, yieldCurve); return getHedgeRatios(cdsSense, hedgeSense); } /** * Hedge a CDS with other CDSs on the same underlying (single-name or index) at different maturities. The hedge is such that the total portfolio (the CDS <b>minus</b> * the hedging CDSs, with notionals of the CDS notional times the computed hedge ratios) is insensitive to infinitesimal changes to the the credit curve. * If the number of hedge-CDSs equals the number of credit-curve knots, the system is square and is solved exactly (see below).<br> * If the number of hedge-CDSs is less than the number of credit-curve knots, the system is solved in a least-square sense (i.e. is hedge is not exact).<br> * If the number of hedge-CDSs is greater than the number of credit-curve knots, the system cannot be solved. <br> * The system may not solve if the maturities if the hedging CDSs and very different from the knot times (i.e. the sensitivity matrix is singular). * @param cdsSensitivities vector of sensitivities of the CDS to the zero hazard rates at the credit curve knots. * @param hedgeCDSSensitivities matrix of sensitivities of the hedging-CDSs to the zero hazard rates at the credit curve knots. The (i,j) element is the sensitivity * of the jth CDS to the ith knot. * @return The hedge ratios. Since we use a unit notional, there ratios should be multiplied by -notional to give the hedge notional amounts. */ public DoubleMatrix1D getHedgeRatios(final DoubleMatrix1D cdsSensitivities, final DoubleMatrix2D hedgeCDSSensitivities) { ArgumentChecker.notNull(hedgeCDSSensitivities, "hedgeCDSSensitivities"); final int nRows = hedgeCDSSensitivities.getNumberOfRows(); final int nCols = hedgeCDSSensitivities.getNumberOfColumns(); ArgumentChecker.isTrue(nRows == cdsSensitivities.getNumberOfElements(), "Number of matrix rows does not match vector length"); if (nCols == nRows) { final LUDecompositionCommons decomp = new LUDecompositionCommons(); final LUDecompositionResult luRes = decomp.evaluate(hedgeCDSSensitivities); return getHedgeRatios(cdsSensitivities, luRes); } else { if (nRows < nCols) { //Under-specified. No unique solution exists. There are curve knots but hedging instruments throw new IllegalArgumentException("Under-specified. No unique solution exists. There are " + nRows + " curve knots but " + nCols + " hedging instruments."); } else { //over-specified. Solve in a least-square sense final DoubleMatrix2D senseT = MA.getTranspose(hedgeCDSSensitivities); final DoubleMatrix2D a = (DoubleMatrix2D) MA.multiply(senseT, hedgeCDSSensitivities); final DoubleMatrix1D b = (DoubleMatrix1D) MA.multiply(senseT, cdsSensitivities); final LUDecompositionCommons decomp = new LUDecompositionCommons(); final LUDecompositionResult luRes = decomp.evaluate(a); return getHedgeRatios(b, luRes); } } } public DoubleMatrix1D getHedgeRatios(final DoubleMatrix1D cdsSensitivities, final LUDecompositionResult luRes) { ArgumentChecker.notNull(cdsSensitivities, "cdsSensitivities"); ArgumentChecker.notNull(luRes, " luRes"); final DoubleMatrix1D w = luRes.solve(cdsSensitivities); return w; } }