/** * 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.util.ArgumentChecker; /** * */ public class AnalyticSpreadSensitivityCalculator { private final MarketQuoteConverter _pufConverter; private final ISDACompliantCreditCurveBuilder _curveBuilder; private final AnalyticCDSPricer _pricer; public AnalyticSpreadSensitivityCalculator() { _pufConverter = new MarketQuoteConverter(); _curveBuilder = new FastCreditCurveBuilder(); _pricer = new AnalyticCDSPricer(); } public AnalyticSpreadSensitivityCalculator(final AccrualOnDefaultFormulae formula) { _pufConverter = new MarketQuoteConverter(formula); _curveBuilder = new FastCreditCurveBuilder(formula); _pricer = new AnalyticCDSPricer(formula); } //*************************************************************************************************************** // parallel CS01 of a CDS from single market quote of that CDS //*************************************************************************************************************** /** * The CS01 (or credit DV01) of a CDS - the sensitivity of the PV to a finite increase of market spread (on NOT the CDS's * coupon). If the CDS is quoted as points up-front, this is first converted to a quoted spread, and <b>this</b> is bumped * @param cds analytic description of a CDS traded at a certain time - it is this CDS that we are calculation CDV01 for * @param quote The market quote for the CDS - these can be ParSpread, PointsUpFront or QuotedSpread * @param yieldCurve The yield (or discount) curve * @return the parallel CS01 */ public double parallelCS01(final CDSAnalytic cds, final CDSQuoteConvention quote, final ISDACompliantYieldCurve yieldCurve) { return parallelCS01(cds, quote.getCoupon(), new CDSAnalytic[] {cds }, new CDSQuoteConvention[] {quote }, yieldCurve); } /** *The analytic CS01 (or credit DV01) * @param cds analytic description of a CDS traded at a certain time - it is this CDS that we are calculation CDV01 for * @param coupon the of the traded CDS (expressed as <b>fractions not basis points</b>) * @param yieldCurve The yield (or discount) curve * @param puf points up-front (as a fraction) * @return The credit DV01 */ public double parallelCS01FromPUF(final CDSAnalytic cds, final double coupon, final ISDACompliantYieldCurve yieldCurve, final double puf) { final ISDACompliantCreditCurve cc = _curveBuilder.calibrateCreditCurve(cds, coupon, yieldCurve, puf); final double a = _pricer.protectionLeg(cds, yieldCurve, cc); final double b = _pricer.annuity(cds, yieldCurve, cc, PriceType.CLEAN); final double aPrime = _pricer.protectionLegCreditSensitivity(cds, yieldCurve, cc, 0); final double bPrime = _pricer.pvPremiumLegCreditSensitivity(cds, yieldCurve, cc, 0); final double s = a / b; final double dPVdh = aPrime - coupon * bPrime; final double dSdh = (aPrime - s * bPrime) / b; return dPVdh / dSdh; } /** * The analytic CS01 (or credit DV01) * @param cds analytic description of a CDS traded at a certain time - it is this CDS that we are calculation CDV01 for * @param coupon the of the traded CDS (expressed as <b>fractions not basis points</b>) * @param yieldCurve The yield (or discount) curve * @param marketSpread the market spread of the reference CDS (in this case it is irrelevant whether this is par or quoted spread) * @return The credit DV01 */ public double parallelCS01FromSpread(final CDSAnalytic cds, final double coupon, final ISDACompliantYieldCurve yieldCurve, final double marketSpread) { final ISDACompliantCreditCurve cc = _curveBuilder.calibrateCreditCurve(cds, marketSpread, yieldCurve); final double a = _pricer.protectionLeg(cds, yieldCurve, cc); final double b = a / marketSpread; //shortcut calculation of RPV01 final double diff = marketSpread - coupon; if (diff == 0) { return b; } final double aPrime = _pricer.protectionLegCreditSensitivity(cds, yieldCurve, cc, 0); final double bPrime = _pricer.pvPremiumLegCreditSensitivity(cds, yieldCurve, cc, 0); final double dSdh = (aPrime - marketSpread * bPrime); //note - this has not been divided by b return b * (1 + diff * bPrime / dSdh); } public double parallelCS01(final CDSAnalytic cds, final double cdsCoupon, final CDSAnalytic[] pillarCDSs, final CDSQuoteConvention[] marketQuotes, final ISDACompliantYieldCurve yieldCurve) { final ISDACompliantCreditCurve creditCurve = _curveBuilder.calibrateCreditCurve(pillarCDSs, marketQuotes, yieldCurve); return parallelCS01FromCreditCurve(cds, cdsCoupon, pillarCDSs, yieldCurve, creditCurve); } public double parallelCS01FromCreditCurve(final CDSAnalytic cds, final double cdsCoupon, final CDSAnalytic[] bucketCDSs, final ISDACompliantYieldCurve yieldCurve, final ISDACompliantCreditCurve creditCurve) { final double[] temp = bucketedCS01FromCreditCurve(cds, cdsCoupon, bucketCDSs, yieldCurve, creditCurve); double sum = 0; for (final double cs : temp) { sum += cs; } return sum; } //*************************************************************************************************************** // bucketed CS01 of a CDS from single market quote of that CDS //*************************************************************************************************************** public double[] bucketedCS01FromSpread(final CDSAnalytic cds, final double coupon, final ISDACompliantYieldCurve yieldCurve, final double marketSpread, final CDSAnalytic[] buckets) { final ISDACompliantCreditCurve cc = _curveBuilder.calibrateCreditCurve(cds, marketSpread, yieldCurve); return bucketedCS01FromCreditCurve(cds, coupon, buckets, yieldCurve, cc); } public double[] bucketedCS01(final CDSAnalytic cds, final double cdsCoupon, final CDSAnalytic[] pillarCDSs, final CDSQuoteConvention[] marketQuotes, final ISDACompliantYieldCurve yieldCurve) { final ISDACompliantCreditCurve creditCurve = _curveBuilder.calibrateCreditCurve(pillarCDSs, marketQuotes, yieldCurve); return bucketedCS01FromCreditCurve(cds, cdsCoupon, pillarCDSs, yieldCurve, creditCurve); } public double[][] bucketedCS01(final CDSAnalytic[] cds, final double[] cdsCoupons, final CDSAnalytic[] pillarCDSs, final CDSQuoteConvention[] marketQuotes, final ISDACompliantYieldCurve yieldCurve) { final ISDACompliantCreditCurve creditCurve = _curveBuilder.calibrateCreditCurve(pillarCDSs, marketQuotes, yieldCurve); return bucketedCS01FromCreditCurve(cds, cdsCoupons, pillarCDSs, yieldCurve, creditCurve); } public double[] bucketedCS01FromParSpreads(final CDSAnalytic cds, final double cdsCoupon, final ISDACompliantYieldCurve yieldCurve, final CDSAnalytic[] pillarCDSs, final double[] spreads) { final ISDACompliantCreditCurve creditCurve = _curveBuilder.calibrateCreditCurve(pillarCDSs, spreads, yieldCurve); return bucketedCS01FromCreditCurve(cds, cdsCoupon, pillarCDSs, yieldCurve, creditCurve); } public double[] bucketedCS01FromCreditCurve(final CDSAnalytic cds, final double cdsCoupon, final CDSAnalytic[] bucketCDSs, final ISDACompliantYieldCurve yieldCurve, final ISDACompliantCreditCurve creditCurve) { ArgumentChecker.notNull(cds, "cds"); ArgumentChecker.noNulls(bucketCDSs, "bucketCDSs"); ArgumentChecker.notNull(creditCurve, "creditCurve"); ArgumentChecker.notNull(yieldCurve, "yieldCurve"); final LUDecompositionCommons decomp = new LUDecompositionCommons(); final int n = bucketCDSs.length; final double[] temp = new double[n]; final double[][] res = new double[n][n]; for (int i = 0; i < n; i++) { temp[i] = _pricer.pvCreditSensitivity(cds, yieldCurve, creditCurve, cdsCoupon, i); for (int j = 0; j < n; j++) { res[j][i] = _pricer.parSpreadCreditSensitivity(bucketCDSs[i], yieldCurve, creditCurve, j); } } final DoubleMatrix1D vLambda = new DoubleMatrix1D(temp); final DoubleMatrix2D jacT = new DoubleMatrix2D(res); final LUDecompositionResult luRes = decomp.evaluate(jacT); final DoubleMatrix1D vS = luRes.solve(vLambda); return vS.getData(); } public double[][] bucketedCS01FromCreditCurve(final CDSAnalytic[] cds, final double[] cdsCoupon, final CDSAnalytic[] bucketCDSs, final ISDACompliantYieldCurve yieldCurve, final ISDACompliantCreditCurve creditCurve) { ArgumentChecker.noNulls(cds, "cds"); ArgumentChecker.notEmpty(cdsCoupon, "cdsCoupons"); ArgumentChecker.noNulls(bucketCDSs, "bucketCDSs"); ArgumentChecker.notNull(creditCurve, "creditCurve"); ArgumentChecker.notNull(yieldCurve, "yieldCurve"); final int m = cds.length; ArgumentChecker.isTrue(m == cdsCoupon.length, m + " CDSs but " + cdsCoupon.length + " coupons"); final LUDecompositionCommons decomp = new LUDecompositionCommons(); final int n = bucketCDSs.length; final DoubleMatrix2D jacT = new DoubleMatrix2D(n, n); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { jacT.getData()[j][i] = _pricer.parSpreadCreditSensitivity(bucketCDSs[i], yieldCurve, creditCurve, j); } } final double[] vLambda = new double[n]; final double[][] res = new double[m][]; final LUDecompositionResult luRes = decomp.evaluate(jacT); for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { vLambda[j] = _pricer.pvCreditSensitivity(cds[i], yieldCurve, creditCurve, cdsCoupon[i], j); } res[i] = luRes.solve(vLambda); } return res; } }