Package com.opengamma.analytics.financial.credit.creditdefaultswap.pricing.vanilla.isdanew

Source Code of com.opengamma.analytics.financial.credit.creditdefaultswap.pricing.vanilla.isdanew.SpreadSensitivityCalculator

/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.credit.creditdefaultswap.pricing.vanilla.isdanew;

import java.util.Arrays;

import com.opengamma.analytics.financial.credit.PriceType;
import com.opengamma.analytics.financial.model.BumpType;
import com.opengamma.analytics.math.differentiation.FiniteDifferenceType;
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;

/**
* This calculates the sensitivity of the present value of a CDS to various (finite) shifts of the market spreads -
* this is performed by a "bump and reprice" so is accurate for arbitrarily large shifts/bumps.<br> For small bumps (typically
* less than 1bps) it approximates the derivative $$\frac{\partial V}{\partial S}$$  where $V$ is the present value and $S$ is
* either a single market spread or the entire market spread curve. However, it is better (in accuracy and speed) to use
* AnalyticSpreadSensitivityCalculator if this derivative is required.
*/
public class SpreadSensitivityCalculator {

  private final PointsUpFrontConverter _pufConverter;
  private final ISDACompliantCreditCurveBuilder _curveBuilder;
  private final AnalyticCDSPricer _pricer;

  public SpreadSensitivityCalculator() {
    _pufConverter = new PointsUpFrontConverter();
    _curveBuilder = new FastCreditCurveBuilder();
    _pricer = new AnalyticCDSPricer();
  }

  public SpreadSensitivityCalculator(final boolean useCorrectAccOnDefaultFormula) {
    _pufConverter = new PointsUpFrontConverter(useCorrectAccOnDefaultFormula);
    _curveBuilder = new FastCreditCurveBuilder(useCorrectAccOnDefaultFormula);
    _pricer = new AnalyticCDSPricer(useCorrectAccOnDefaultFormula);
  }

  // private static final ISDACompliantCreditCurveBuild BUILDER = new ISDACompliantCreditCurveBuild();

  //***************************************************************************************************************
  // 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
   * @param fracBumpAmount The fraction bump amount of the spread so a 1pb bump is 1e-4
   * @return the parallel CS01
   */
  public double parallelCS01(final CDSAnalytic cds, final CDSQuoteConvention quote, final ISDACompliantYieldCurve yieldCurve, final double fracBumpAmount) {
    if (quote instanceof QuotedSpread) {
      final QuotedSpread qSpread = (QuotedSpread) quote;
      return parallelCS01FromParSpreads(cds, qSpread.getCoupon(), yieldCurve, new CDSAnalytic[] {cds }, new double[] {qSpread.getQuotedSpread() }, fracBumpAmount, BumpType.ADDITIVE);
    } else if (quote instanceof PointsUpFront) {
      final PointsUpFront puf = (PointsUpFront) quote;
      return parallelCS01FromPUF(cds, puf.getCoupon(), yieldCurve, puf.getPointsUpFront(), fracBumpAmount);
    } else if (quote instanceof ParSpread) {
      return parallelCS01FromParSpreads(cds, quote.getCoupon(), yieldCurve, new CDSAnalytic[] {cds }, new double[] {quote.getCoupon() }, fracBumpAmount, BumpType.ADDITIVE);
    }
    throw new IllegalArgumentException("unknow type " + quote.getClass());
  }

  /**
   *The CS01 (or credit DV01) by a shift of the quoted (or flat) spread of the CDS <b>when the CDS is quoted as points up-front (PUF)</b>.<br>
   *This simply converts the PUF quote to a quoted (or flat) spread then calls parallelCS01FromQuotedSpread
   * @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)
   * @param fracBumpAmount The fraction bump amount <b>of the quoted (or flat) spread</b>, so a 1pb bump is 1e-4
   * @return  The credit DV01
   */
  public double parallelCS01FromPUF(final CDSAnalytic cds, final double coupon, final ISDACompliantYieldCurve yieldCurve, final double puf, final double fracBumpAmount) {
    final double bumpedQSpread = _pufConverter.pufToQuotedSpread(cds, coupon, yieldCurve, puf) + fracBumpAmount;
    final ISDACompliantCreditCurve bumpedCurve = _curveBuilder.calibrateCreditCurve(cds, bumpedQSpread, yieldCurve);
    final double bumpedPrice = _pricer.pv(cds, yieldCurve, bumpedCurve, coupon);
    return (bumpedPrice - puf) / fracBumpAmount;
  }

  /**
   * The CS01 (or credit DV01) by a shift of the market spread of the CDS (the coupon is unchanged). This finds two flat
   *  credit/hazard curves from  the CDS with its original spread and with the spread bumped. The traded CDS is then priced
   * off both curves, using its coupon, and the difference (divided by the bump size) is the 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)
   * @param fracBumpAmount The fraction bump amount, so a 1pb bump is 1e-4
   * @param bumpType ADDITIVE or MULTIPLICATIVE
   * @return The credit DV01
   */
  public double parallelCS01FromSpread(final CDSAnalytic cds, final double coupon, final ISDACompliantYieldCurve yieldCurve, final double marketSpread, final double fracBumpAmount,
      final BumpType bumpType) {
    return parallelCS01FromParSpreads(cds, coupon, yieldCurve, new CDSAnalytic[] {cds }, new double[] {marketSpread }, fracBumpAmount, bumpType);
  }

  //***************************************************************************************************************
  // parallel CS01 of CDS from single market quote of (potentially) different CDS
  //***************************************************************************************************************

  /**
   * The CS01 (or credit DV01) by a shift of the quoted (or flat) spread of the reference CDS. This finds two flat credit/hazard curves from
   * a reference CDS with its original quoted (or flat) spread and with the spread bumped. The traded CDS is then priced off both curves, using its coupon,
   * and the difference (divided by the bump size) is the 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 coupon of the traded CDS  (expressed as <b>fractions not basis points</b>)
   * @param yieldCurve  The yield (or discount) curve
   * @param referenceCDS the reference CDS use to find the flat credit/hazard curve (this is often the same as the traded CDS)
   * @param quotedSpread the quoted (or flat) spread of the reference CDS
   * @param fracBumpAmount The fraction bump amount, so a 1pb bump is 1e-4
   * @param bumpType ADDITIVE or MULTIPLICATIVE
   * @return The credit DV01
   */
  public double parallelCS01FromQuotedSpread(final CDSAnalytic cds, final double coupon, final ISDACompliantYieldCurve yieldCurve, final CDSAnalytic referenceCDS, final double quotedSpread,
      final double fracBumpAmount, final BumpType bumpType) {
    ArgumentChecker.notNull(cds, "cds");
    ArgumentChecker.notNull(referenceCDS, "referanceCDS");
    ArgumentChecker.notNull(yieldCurve, "yieldCurve");
    ArgumentChecker.notNull(bumpType, "bumpType");
    ArgumentChecker.isTrue(Math.abs(fracBumpAmount) > 1e-10, "bump amount too small");
    return parallelCS01FromParSpreads(cds, coupon, yieldCurve, new CDSAnalytic[] {referenceCDS }, new double[] {quotedSpread }, fracBumpAmount, bumpType);
  }

  //***************************************************************************************************************
  // parallel CS01 of a CDS from a set of market quotes at pillar dates (e.g. 6M, 1Y, 3Y, 5Y, 10Y)
  //***************************************************************************************************************

  /**
   * The CS01 (or credit DV01) by a parallel shift of the market spreads (CDS spread curve). This takes an extraneous yield curve,
   *  a set of reference CDSs (marketCDSs) and their market quotes and bootstraps a credit (hazard) curve -
   * the target CDS is then priced with this credit curve. This is then repeated with the market spreads bumped in parallel by
   * some amount. The result is the difference (bumped minus base price) is divided by the bump amount.<br>
   * This can take quotes as ParSpread, PointsUpFront or QuotedSpread (or some mix).  For par-spreads, these are bumped and a
   * new credit curve built; for quoted-spreads, there are bumped and a new curve build be first converting to PUF; and finally
   * for PUF, these are converted to quoted spreads, bumped and converted back to build the credit curve.
   * @param cds analytic description of a CDS traded at a certain time - it is this CDS that we are calculation CDV01 for
   * @param cdsCoupon the coupon of the traded CDS  (expressed as <b>fractions not basis points</b>)
   * @param yieldCurve The yield (or discount) curve
   * @param marketCDSs The market CDSs - these are the reference instruments used to build the credit curve
   * @param quotes The quotes for the market CDSs - these can be ParSpread, PointsUpFront or QuotedSpread (or any mixture of these)
   * @param fracBumpAmount The fraction bump amount, so a 1pb bump is 1e-4
   * @return  The credit DV01
   */
  public double parallelCS01FromPillarQuotes(final CDSAnalytic cds, final double cdsCoupon, final ISDACompliantYieldCurve yieldCurve, final CDSAnalytic[] marketCDSs,
      final CDSQuoteConvention[] quotes, final double fracBumpAmount) {
    ArgumentChecker.notNull(cds, "cds");
    ArgumentChecker.noNulls(marketCDSs, "curvePoints");
    ArgumentChecker.notNull(yieldCurve, "yieldCurve");
    ArgumentChecker.noNulls(quotes, "quotes");
    ArgumentChecker.isTrue(Math.abs(fracBumpAmount) > 1e-10, "bump amount too small");
    final int n = marketCDSs.length;
    ArgumentChecker.isTrue(n == quotes.length, "speads length does not match curvePoints");

    final ISDACompliantCreditCurve baseCurve = _curveBuilder.calibrateCreditCurve(marketCDSs, quotes, yieldCurve);
    final double basePrice = _pricer.pv(cds, yieldCurve, baseCurve, cdsCoupon);

    final CDSQuoteConvention[] bumpedQuotes = bumpQuotes(marketCDSs, quotes, yieldCurve, fracBumpAmount);
    final ISDACompliantCreditCurve bumpedCurve = _curveBuilder.calibrateCreditCurve(marketCDSs, bumpedQuotes, yieldCurve);
    final double bumpedPrice = _pricer.pv(cds, yieldCurve, bumpedCurve, cdsCoupon);

    return (bumpedPrice - basePrice) / fracBumpAmount;
  }

  /**
   * The CS01 (or credit DV01) by a parallel shift of the market par spreads (CDS par spread curve). This takes an extraneous yield curve, a set of reference CDSs
   * (marketCDSs) and their par-spreads (expressed as <b>fractions not basis points</b>) and bootstraps a credit (hazard) curve -
   * the target CDS is then priced with this credit curve. This is then repeated with the market spreads bumped in parallel by
   * some amount. The result is the difference (bumped minus base price) is divided by the bump amount.<br>
   * For small bumps (<1e-4) this approximates $$\frac{\partial V}{\partial S}$$<br>
   * Credit DV01 is (often) defined as -( V(S + 1bp) - V(s)) - to achieve this use fracBumpAmount = 1e-4 and bumpType ADDITIVE
   * @param cds analytic description of a CDS traded at a certain time
   * @param cdsFracSpread The <b>fraction</b> spread of the CDS
   * @param yieldCurve The yield (or discount) curve
   * @param marketCDSs The market CDSs - these are the reference instruments used to build the credit curve
   * @param parSpreads The <b>fractional</b> spreads of the market CDSs
   * @param fracBumpAmount The fraction bump amount, so a 1pb bump is 1e-4
   * @param bumpType ADDITIVE or MULTIPLICATIVE
   * @return The credit DV01
   */
  public double parallelCS01FromParSpreads(final CDSAnalytic cds, final double cdsFracSpread, final ISDACompliantYieldCurve yieldCurve, final CDSAnalytic[] marketCDSs, final double[] parSpreads,
      final double fracBumpAmount, final BumpType bumpType) {
    ArgumentChecker.notNull(cds, "cds");
    ArgumentChecker.noNulls(marketCDSs, "curvePoints");
    ArgumentChecker.notEmpty(parSpreads, "spreads");
    ArgumentChecker.notNull(yieldCurve, "yieldCurve");
    ArgumentChecker.notNull(bumpType, "bumpType");
    ArgumentChecker.isTrue(Math.abs(fracBumpAmount) > 1e-10, "bump amount too small");
    final int n = marketCDSs.length;
    ArgumentChecker.isTrue(n == parSpreads.length, "speads length does not match curvePoints");
    final double[] bumpedSpreads = makeBumpedSpreads(parSpreads, fracBumpAmount, bumpType);
    final double diff = fdCreditDV01(cds, cdsFracSpread, marketCDSs, bumpedSpreads, parSpreads, yieldCurve, PriceType.DIRTY);
    return diff / fracBumpAmount;
  }

  //***************************************************************************************************************
  // bucked CS01 - the sensitivity of the CDS's PV to the market spreads used to build the credit curve - these are
  // the pillar dates (e.g. 6M, 1Y, 3Y, 5Y, 10Y)
  //***************************************************************************************************************

  /**
   * The bucked CS01 (or credit DV01) by a shift of each the market spread in turn. This takes an extraneous yield curve,
   *  a set of reference CDSs (marketCDSs) and their market quotes and bootstraps a credit (hazard) curve -
   * the target CDS is then priced with this credit curve. This is then repeated with each market spreads bumped in turn by
   * some amount. The result is the array of differences (bumped minus base price) is divided by the bump amount.<br>
   * This can take quotes as ParSpread, PointsUpFront or QuotedSpread (or some mix).  For par-spreads, these are bumped and a
   * new credit curve built; for quoted-spreads, there are bumped and a new curve build be first converting to PUF; and finally
   * for PUF, these are converted to quoted spreads, bumped and converted back to build the credit curve.
   * @param cds analytic description of a CDS traded at a certain time - it is this CDS that we are calculation CDV01 for
   * @param cdsCoupon the coupon of the traded CDS  (expressed as <b>fractions not basis points</b>)
   * @param yieldCurve The yield (or discount) curve
   * @param marketCDSs The market CDSs - these are the reference instruments used to build the credit curve
   * @param quotes The quotes for the market CDSs - these can be ParSpread, PointsUpFront or QuotedSpread (or any mixture of these)
   * @param fracBumpAmount The fraction bump amount, so a 1pb bump is 1e-4
   * @return  The bucketed credit DV01
   */
  public double[] bucketedCS01FromPillarQuotes(final CDSAnalytic cds, final double cdsCoupon, final ISDACompliantYieldCurve yieldCurve, final CDSAnalytic[] marketCDSs,
      final CDSQuoteConvention[] quotes, final double fracBumpAmount) {

    ArgumentChecker.notNull(cds, "cds");
    ArgumentChecker.noNulls(marketCDSs, "curvePoints");
    ArgumentChecker.noNulls(quotes, "quotes");
    ArgumentChecker.notNull(yieldCurve, "yieldCurve");
    ArgumentChecker.isTrue(Math.abs(fracBumpAmount) > 1e-10, "bump amount too small");
    final int n = marketCDSs.length;
    ArgumentChecker.isTrue(n == quotes.length, "speads length does not match curvePoints");

    final ISDACompliantCreditCurve baseCurve = _curveBuilder.calibrateCreditCurve(marketCDSs, quotes, yieldCurve);
    final double basePrice = _pricer.pv(cds, yieldCurve, baseCurve, cdsCoupon);
    final double[] res = new double[n];
    for (int i = 0; i < n; i++) {
      final CDSQuoteConvention[] bumpedQuotes = bumpQuoteAtIndex(marketCDSs, quotes, yieldCurve, fracBumpAmount, i);
      final ISDACompliantCreditCurve bumpedCurve = _curveBuilder.calibrateCreditCurve(marketCDSs, bumpedQuotes, yieldCurve);
      final double price = _pricer.pv(cds, yieldCurve, bumpedCurve, cdsCoupon);
      res[i] = (price - basePrice) / fracBumpAmount;
    }
    return res;
  }

  /**
   * The bucked CS01 (or credit DV01) by shifting each  market par-spread in turn. This takes an extraneous yield curve, a set of reference CDSs
   * (marketCDSs) and their par-spreads (expressed as <b>fractions not basis points</b>) and bootstraps a credit (hazard) curve -
   * the target CDS is then priced with this credit curve. This is then repeated with each market spreads bumped in turn.
   * The result is the vector of differences (bumped minus base price) divided by the bump amount.<br>
   * For small bumps (<1e-4) this approximates $$\frac{\partial V}{\partial S_i}$$ where $$S_i$$ is the spread of the $$1^{th}$$
   * market CDS<br>
   * @param cds analytic description of a CDS traded at a certain time
   * @param cdsCoupon The <b>fraction</b> spread of the CDS
   * @param yieldCurve The yield (or discount) curve
   * @param marketCDSs The market CDSs - these are the reference instruments used to build the credit curve
   * @param marketParSpreads The <b>fractional</b> par-spreads of the market CDSs
   * @param fracBumpAmount The fraction bump amount, so a 1pb bump is 1e-4
   * @param bumpType ADDITIVE or MULTIPLICATIVE
   * @return The credit CS01
   */
  public double[] bucketedCS01FromParSpreads(final CDSAnalytic cds, final double cdsCoupon, final ISDACompliantYieldCurve yieldCurve, final CDSAnalytic[] marketCDSs, final double[] marketParSpreads,
      final double fracBumpAmount, final BumpType bumpType) {
    ArgumentChecker.notNull(cds, "cds");
    ArgumentChecker.noNulls(marketCDSs, "curvePoints");
    ArgumentChecker.notEmpty(marketParSpreads, "spreads");
    ArgumentChecker.notNull(yieldCurve, "yieldCurve");
    ArgumentChecker.notNull(bumpType, "bumpType");
    ArgumentChecker.isTrue(Math.abs(fracBumpAmount) > 1e-10, "bump amount too small");
    final int n = marketCDSs.length;
    ArgumentChecker.isTrue(n == marketParSpreads.length, "speads length does not match curvePoints");
    final PriceType priceType = PriceType.DIRTY;

    final ISDACompliantCreditCurve baseCurve = _curveBuilder.calibrateCreditCurve(marketCDSs, marketParSpreads, yieldCurve);
    final double basePrice = _pricer.pv(cds, yieldCurve, baseCurve, cdsCoupon, priceType);

    final double[] res = new double[n];
    for (int i = 0; i < n; i++) {
      final double[] temp = makeBumpedSpreads(marketParSpreads, fracBumpAmount, bumpType, i);
      final ISDACompliantCreditCurve bumpedCurve = _curveBuilder.calibrateCreditCurve(marketCDSs, temp, yieldCurve);
      final double price = _pricer.pv(cds, yieldCurve, bumpedCurve, cdsCoupon, priceType);
      res[i] = (price - basePrice) / fracBumpAmount;
    }

    return res;
  }

  /**
   * The bucked CS01 (or credit DV01) by bumping each quoted (or flat) spread in turn. This takes an extraneous yield curve,
   *  a set of reference CDSs (marketCDSs) and their quoted (or flat) spreads (expressed as <b>fractions not basis points</b>) and
   *  bootstraps a credit (hazard) curve -
   * the target CDS is then priced with this credit curve. This is then repeated with each market spreads bumped in turn.
   * The result is the vector of differences (bumped minus base price) divided by the bump amount.<br>
   * For small bumps (<1e-4) this approximates $$\frac{\partial V}{\partial S_i}$$ for a flat curve where $$S_i$$
   * is the spread of the $$1^{th}$$ market CDS
   * @param cds analytic description of a CDS traded at a certain time
   * @param dealSpread The <b>fraction</b> spread of the CDS
   * @param yieldCurve The yield (or discount) curve
   * @param marketCDSs The market CDSs - these are the reference instruments used to build the credit curve
   * @param quotedSpreads The <b>fractional</b> spreads of the market CDSs
   * @param fracBumpAmount The fraction bump amount, so a 1pb bump is 1e-4
   * @param bumpType ADDITIVE or MULTIPLICATIVE
   * @return The bucked CS01 for a single CDS
   */
  public double[] bucketedCS01FromQuotedSpreads(final CDSAnalytic cds, final double dealSpread, final ISDACompliantYieldCurve yieldCurve, final CDSAnalytic[] marketCDSs, final double[] quotedSpreads,
      final double fracBumpAmount, final BumpType bumpType) {
    ArgumentChecker.notNull(cds, "cds");
    ArgumentChecker.noNulls(marketCDSs, "curvePoints");
    ArgumentChecker.notEmpty(quotedSpreads, "spreads");
    ArgumentChecker.notNull(yieldCurve, "yieldCurve");
    ArgumentChecker.notNull(bumpType, "bumpType");
    ArgumentChecker.isTrue(Math.abs(fracBumpAmount) > 1e-10, "bump amount too small");
    final int n = marketCDSs.length;
    ArgumentChecker.isTrue(n == quotedSpreads.length, "speads length does not match curvePoints");
    final PriceType priceType = PriceType.DIRTY;
    final double[] premiums = new double[n];
    Arrays.fill(premiums, dealSpread); // assume the premiums of all CDS are equal

    final double[] puf = _pufConverter.quotedSpreadsToPUF(marketCDSs, premiums, yieldCurve, quotedSpreads);
    final ISDACompliantCreditCurve baseCurve = _curveBuilder.calibrateCreditCurve(marketCDSs, premiums, yieldCurve, puf);
    final double basePrice = _pricer.pv(cds, yieldCurve, baseCurve, dealSpread, priceType);

    final double[] bumpedPUF = new double[n];
    final double[] res = new double[n];
    for (int i = 0; i < n; i++) {
      System.arraycopy(puf, 0, bumpedPUF, 0, n);
      final double bumpedSpread = bumpedSpread(quotedSpreads[i], fracBumpAmount, bumpType);
      bumpedPUF[i] = _pufConverter.quotedSpreadToPUF(marketCDSs[i], premiums[i], yieldCurve, bumpedSpread);
      // TODO a lot of unnecessary recalibration here
      final ISDACompliantCreditCurve bumpedCurve = _curveBuilder.calibrateCreditCurve(marketCDSs, premiums, yieldCurve, bumpedPUF);
      final double price = _pricer.pv(cds, yieldCurve, bumpedCurve, dealSpread, priceType);
      res[i] = (price - basePrice) / fracBumpAmount;
    }
    return res;
  }

  /**
   * The bucked CS01 (or credit DV01) on a set of CDSS by bumping each quoted (or flat) spread in turn. This takes an extraneous yield curve,
   *  a set of reference CDSs (marketCDSs) and their quoted (or flat) spreads (expressed as <b>fractions not basis points</b>) and
   *  bootstraps a credit (hazard) curve -
   * the target CDS is then priced with this credit curve. This is then repeated with each market spreads bumped in turn.
   * The result is the vector of differences (bumped minus base price) divided by the bump amount.<br>
   * For small bumps (<1e-4) this approximates $$\frac{\partial V}{\partial S_i}$$ for a flat curve where $$S_i$$
   * @param cds a set of analytic description of  CDSs traded at a certain times
   * @param dealSpread The <b>fraction</b> spread of the CDS
   * @param yieldCurve The yield (or discount) curve
   * @param marketCDSs The market CDSs - these are the reference instruments used to build the credit curve
   * @param quotedSpreads The <b>fractional</b> spreads of the market CDSs
   * @param fracBumpAmount The fraction bump amount, so a 1pb bump is 1e-4
   * @param bumpType ADDITIVE or MULTIPLICATIVE
   * @return The bucked CS01 for a set of  CDSs
   */
  public double[][] bucketedCS01FromQuotedSpreads(final CDSAnalytic[] cds, final double dealSpread, final ISDACompliantYieldCurve yieldCurve, final CDSAnalytic[] marketCDSs,
      final double[] quotedSpreads, final double fracBumpAmount, final BumpType bumpType) {
    ArgumentChecker.noNulls(cds, "cds");
    ArgumentChecker.noNulls(marketCDSs, "curvePoints");
    ArgumentChecker.notEmpty(quotedSpreads, "spreads");
    ArgumentChecker.notNull(yieldCurve, "yieldCurve");
    ArgumentChecker.notNull(bumpType, "bumpType");
    ArgumentChecker.isTrue(Math.abs(fracBumpAmount) > 1e-10, "bump amount too small");
    final int nMarketCDSs = marketCDSs.length;
    ArgumentChecker.isTrue(nMarketCDSs == quotedSpreads.length, "speads length does not match curvePoints");
    final PriceType priceType = PriceType.DIRTY;
    final double[] premiums = new double[nMarketCDSs];
    Arrays.fill(premiums, dealSpread); // assume the premiums of all CDS are equal

    final int nTradeCDSs = cds.length;

    final double[] puf = _pufConverter.quotedSpreadsToPUF(marketCDSs, premiums, yieldCurve, quotedSpreads);
    //TODO not needed
    final ISDACompliantCreditCurve baseCurve = _curveBuilder.calibrateCreditCurve(marketCDSs, premiums, yieldCurve, puf);
    final double[] basePrices = new double[nTradeCDSs];
    for (int j = 0; j < nTradeCDSs; j++) {
      basePrices[j] = _pricer.pv(cds[j], yieldCurve, baseCurve, dealSpread, priceType);
    }

    final double[] bumpedPUF = new double[nMarketCDSs];
    final double[][] res = new double[nTradeCDSs][nMarketCDSs];

    for (int i = 0; i < nMarketCDSs; i++) { //Outer loop is over bumps
      System.arraycopy(puf, 0, bumpedPUF, 0, nMarketCDSs);
      final double bumpedSpread = bumpedSpread(quotedSpreads[i], fracBumpAmount, bumpType);
      bumpedPUF[i] = _pufConverter.quotedSpreadToPUF(marketCDSs[i], premiums[i], yieldCurve, bumpedSpread);
      // TODO a lot of unnecessary recalibration here
      final ISDACompliantCreditCurve bumpedCurve = _curveBuilder.calibrateCreditCurve(marketCDSs, premiums, yieldCurve, bumpedPUF);
      for (int j = 0; j < nTradeCDSs; j++) {
        final double price = _pricer.pv(cds[j], yieldCurve, bumpedCurve, dealSpread, priceType);
        res[j][i] = (price - basePrices[j]) / fracBumpAmount;
      }
    }
    return res;
  }

  /**
   * The bucked CS01 (or credit DV01) by shifting each implied par-spread in turn. This takes an extraneous yield curve,
   *  a set of pillar CDSs and their corresponding par-spread, and  a set of bucket CDSs (CDSs with maturities equal to the bucket
   *  points). A credit curve is bootstrapped from the pillar CDSs - this is then used to imply spreads at the bucket maturities.
   *  These spreads form pseudo market spreads to bootstraps a new credit (hazard) curve -
   * the target CDS is then priced with this credit curve. This is then repeated with each  spreads bumped in turn.
   * The result is the vector of differences (bumped minus base price) divided by the bump amount.
   * @param cds analytic description of a CDS traded at a certain time
   * @param cdsCoupon The <b>fraction</b> spread of the CDS
   * @param bucketCDSs these are the reference instruments that correspond to maturity buckets
   * @param yieldCurve The yield (or discount) curve
   * @param pillarCDSs  These are the market CDSs used to build the credit curve
   * @param pillarSpreads These are the par-spreads of the market (pillar) CDSs
   * @param fracBumpAmount The fraction bump amount, so a 1pb bump is 1e-4
   * @return The credit DV01
   */
  public double[] bucketedCS01FromParSpreads(final CDSAnalytic cds, final double cdsCoupon, final CDSAnalytic[] bucketCDSs, final ISDACompliantYieldCurve yieldCurve, final CDSAnalytic[] pillarCDSs,
      final double[] pillarSpreads, final double fracBumpAmount) {
    ArgumentChecker.noNulls(pillarCDSs, "pillarCDSs");
    ArgumentChecker.notEmpty(pillarSpreads, "pillarSpreads");
    final ISDACompliantCreditCurve creditCurve = _curveBuilder.calibrateCreditCurve(pillarCDSs, pillarSpreads, yieldCurve);
    return bucketedCS01FromCreditCurve(cds, cdsCoupon, bucketCDSs, yieldCurve, creditCurve, fracBumpAmount);
  }

  /**
   * The bucked CS01 (or credit DV01) by shifting each  implied par-spread in turn. This takes an extraneous yield curve and a credit
   *  curve and a set of bucket CDSs (CDSs with maturities equal to the bucket points). Par-spreads at the bucket maturities are
   *  implied from the credit curve. These spreads form pseudo market spreads to bootstraps a new credit (hazard) curve -
   * the target CDS is then priced with this credit curve. This is then repeated with each  spreads bumped in turn.
   * The result is the vector of differences (bumped minus base price) divided by the bump amount.
   * @param cds analytic description of a CDS traded at a certain time
   * @param cdsCoupon The <b>fraction</b> spread of the CDS
   * @param bucketCDSs  these are the reference instruments that correspond to maturity buckets
   * @param yieldCurve The yield (or discount) curve
   * @param creditCurve the credit curve
   * @param fracBumpAmount The fraction bump amount, so a 1pb bump is 1e-4
   * @return The credit DV01
   */
  public double[] bucketedCS01FromCreditCurve(final CDSAnalytic cds, final double cdsCoupon, final CDSAnalytic[] bucketCDSs, final ISDACompliantYieldCurve yieldCurve,
      final ISDACompliantCreditCurve creditCurve, final double fracBumpAmount) {
    ArgumentChecker.notNull(cds, "cds");
    ArgumentChecker.noNulls(bucketCDSs, "bucketCDSs");
    ArgumentChecker.notNull(creditCurve, "creditCurve");
    ArgumentChecker.notNull(yieldCurve, "yieldCurve");
    ArgumentChecker.isTrue(Math.abs(fracBumpAmount) > 1e-10, "bump amount too small");
    final int n = bucketCDSs.length;

    final double[] impSpreads = new double[n];
    for (int i = 0; i < n; i++) {
      impSpreads[i] = _pricer.parSpread(bucketCDSs[i], yieldCurve, creditCurve);
    }

    //build a new curve from the implied spreads
    final ISDACompliantCreditCurve baseCurve = _curveBuilder.calibrateCreditCurve(bucketCDSs, impSpreads, yieldCurve);
    final double basePrice = _pricer.pv(cds, yieldCurve, baseCurve, cdsCoupon);
    final double[] res = new double[n];
    for (int i = 0; i < n; i++) {
      final double[] bumpedSpreads = makeBumpedSpreads(impSpreads, fracBumpAmount, BumpType.ADDITIVE, i);
      final ISDACompliantCreditCurve bumpedCurve = _curveBuilder.calibrateCreditCurve(bucketCDSs, bumpedSpreads, yieldCurve);
      final double price = _pricer.pv(cds, yieldCurve, bumpedCurve, cdsCoupon);
      res[i] = (price - basePrice) / fracBumpAmount;
    }
    return res;
  }

  /**
   * The difference in PV between two market spreads.
   * @param cds analytic description of a CDS traded at a certain time
   * @param cdsFracSpread The <b>fraction</b> spread of the CDS
   * @param priceType Clean or dirty price
   * @param yieldCurve The yield (or discount) curve
   * @param marketCDSs The market CDSs - these are the reference instruments used to build the credit curve
   * @param marketFracSpreads The <b>fractional</b> spreads of the market CDSs
   * @param fracDeltaSpreads Non-negative shifts
   * @param fdType The finite difference type (forward, central or backward)
   * @return The difference in PV between two market spreads
   */
  public double finiteDifferenceSpreadSensitivity(final CDSAnalytic cds, final double cdsFracSpread, final PriceType priceType, final ISDACompliantYieldCurve yieldCurve,
      final CDSAnalytic[] marketCDSs, final double[] marketFracSpreads, final double[] fracDeltaSpreads, final FiniteDifferenceType fdType) {
    ArgumentChecker.notNull(cds, "cds");
    ArgumentChecker.noNulls(marketCDSs, "curvePoints");
    ArgumentChecker.notEmpty(marketFracSpreads, "spreads");
    ArgumentChecker.notEmpty(fracDeltaSpreads, "deltaSpreads");
    ArgumentChecker.notNull(yieldCurve, "yieldCurve");
    ArgumentChecker.notNull(priceType, "priceType");

    final int n = marketCDSs.length;
    ArgumentChecker.isTrue(n == marketFracSpreads.length, "speads length does not match curvePoints");
    ArgumentChecker.isTrue(n == fracDeltaSpreads.length, "deltaSpreads length does not match curvePoints");
    for (int i = 0; i < n; i++) {
      ArgumentChecker.isTrue(marketFracSpreads[i] > 0, "spreads must be positive");
      ArgumentChecker.isTrue(fracDeltaSpreads[i] >= 0, "deltaSpreads must none negative");
      ArgumentChecker.isTrue(fdType == FiniteDifferenceType.FORWARD || fracDeltaSpreads[i] < marketFracSpreads[i], "deltaSpread must be less spread, unless forward difference is used");
    }

    switch (fdType) {
      case CENTRAL:
        return fdCentral(cds, cdsFracSpread, marketCDSs, marketFracSpreads, fracDeltaSpreads, yieldCurve, priceType);
      case FORWARD:
        return fdForward(cds, cdsFracSpread, marketCDSs, marketFracSpreads, fracDeltaSpreads, yieldCurve, priceType);
      case BACKWARD:
        return fdBackwards(cds, cdsFracSpread, marketCDSs, marketFracSpreads, fracDeltaSpreads, yieldCurve, priceType);
      default:
        throw new IllegalArgumentException("unknown type " + fdType);
    }
  }

  //analytic calculators
  public double[] analyticCS01FromCreditCurve(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[][] analyticCS01FromCreditCurve(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;
  }

  private double fdCreditDV01(final CDSAnalytic pricingCDS, final double cdsSpread, final CDSAnalytic[] curvePoints, final double[] spreadsUp, final double[] spreadsDown,
      final ISDACompliantYieldCurve yieldCurve, final PriceType priceType) {

    final ISDACompliantCreditCurve curveUp = _curveBuilder.calibrateCreditCurve(curvePoints, spreadsUp, yieldCurve);
    final ISDACompliantCreditCurve curveDown = _curveBuilder.calibrateCreditCurve(curvePoints, spreadsDown, yieldCurve);
    final double up = _pricer.pv(pricingCDS, yieldCurve, curveUp, cdsSpread, priceType);
    final double down = _pricer.pv(pricingCDS, yieldCurve, curveDown, cdsSpread, priceType);
    return up - down;
  }

  private double fdCentral(final CDSAnalytic pricingCDS, final double cdsSpread, final CDSAnalytic[] curvePoints, final double[] spreads, final double[] deltaSpreads,
      final ISDACompliantYieldCurve yieldCurve, final PriceType priceType) {
    final int n = curvePoints.length;
    final double[] spreadUp = new double[n];
    final double[] spreadDown = new double[n];
    for (int i = 0; i < n; i++) {
      spreadUp[i] = spreads[i] + deltaSpreads[i];
      spreadDown[i] = spreads[i] - deltaSpreads[i];
    }
    final ISDACompliantCreditCurve curveUp = _curveBuilder.calibrateCreditCurve(curvePoints, spreadUp, yieldCurve);
    final ISDACompliantCreditCurve curveDown = _curveBuilder.calibrateCreditCurve(curvePoints, spreadDown, yieldCurve);
    final double up = _pricer.pv(pricingCDS, yieldCurve, curveUp, cdsSpread, priceType);
    final double down = _pricer.pv(pricingCDS, yieldCurve, curveDown, cdsSpread, priceType);

    return up - down;
  }

  private double fdForward(final CDSAnalytic pricingCDS, final double cdsSpread, final CDSAnalytic[] curvePoints, final double[] spreads, final double[] deltaSpreads,
      final ISDACompliantYieldCurve yieldCurve, final PriceType priceType) {
    final int n = curvePoints.length;
    final double[] spreadUp = new double[n];
    for (int i = 0; i < n; i++) {
      spreadUp[i] = spreads[i] + deltaSpreads[i];
    }
    final ISDACompliantCreditCurve curveUp = _curveBuilder.calibrateCreditCurve(curvePoints, spreadUp, yieldCurve);
    final ISDACompliantCreditCurve curveMid = _curveBuilder.calibrateCreditCurve(curvePoints, spreads, yieldCurve);
    final double up = _pricer.pv(pricingCDS, yieldCurve, curveUp, cdsSpread, priceType);
    final double mid = _pricer.pv(pricingCDS, yieldCurve, curveMid, cdsSpread, priceType);

    return up - mid;
  }

  private double fdBackwards(final CDSAnalytic pricingCDS, final double cdsSpread, final CDSAnalytic[] curvePoints, final double[] spreads, final double[] deltaSpreads,
      final ISDACompliantYieldCurve yieldCurve, final PriceType priceType) {
    final int n = curvePoints.length;
    final double[] spreadDown = new double[n];
    for (int i = 0; i < n; i++) {
      spreadDown[i] = spreads[i] - deltaSpreads[i];
    }
    final ISDACompliantCreditCurve curveMid = _curveBuilder.calibrateCreditCurve(curvePoints, spreads, yieldCurve);
    final ISDACompliantCreditCurve curveDown = _curveBuilder.calibrateCreditCurve(curvePoints, spreadDown, yieldCurve);
    final double mid = _pricer.pv(pricingCDS, yieldCurve, curveMid, cdsSpread, priceType);
    final double down = _pricer.pv(pricingCDS, yieldCurve, curveDown, cdsSpread, priceType);

    return mid - down;
  }

  private double bumpedSpread(final double spread, final double amount, final BumpType bumpType) {
    if (bumpType == BumpType.ADDITIVE) {
      return spread + amount;
    } else if (bumpType == BumpType.MULTIPLICATIVE) {
      return spread * (1 + amount);
    } else {
      throw new IllegalArgumentException("BumpType " + bumpType + " is not supported");
    }
  }

  private double[] makeBumpedSpreads(final double[] spreads, final double amount, final BumpType bumpType) {
    final int n = spreads.length;
    final double[] res = new double[n];

    if (bumpType == BumpType.ADDITIVE) {
      for (int i = 0; i < n; i++) {
        res[i] = spreads[i] + amount;
      }
    } else if (bumpType == BumpType.MULTIPLICATIVE) {
      final double a = 1 + amount;
      for (int i = 0; i < n; i++) {
        res[i] = spreads[i] * a;
      }
    } else {
      throw new IllegalArgumentException("BumpType " + bumpType + " is not supported");
    }
    return res;
  }

  private CDSQuoteConvention bumpQuote(final CDSAnalytic cds, final CDSQuoteConvention quote, final ISDACompliantYieldCurve yieldCurve, final double eps) {
    if (quote instanceof ParSpread) {
      return new ParSpread(quote.getCoupon() + eps);
    } else if (quote instanceof QuotedSpread) {
      final QuotedSpread qSpread = (QuotedSpread) quote;
      return new QuotedSpread(qSpread.getCoupon(), qSpread.getQuotedSpread() + eps);
    } else if (quote instanceof PointsUpFront) {
      final PointsUpFront puf = (PointsUpFront) quote;
      final double bumpedQSpread = _pufConverter.pufToQuotedSpread(cds, puf.getCoupon(), yieldCurve, puf.getPointsUpFront()) + eps;
      return new PointsUpFront(puf.getCoupon(), _pufConverter.quotedSpreadToPUF(cds, puf.getCoupon(), yieldCurve, bumpedQSpread));
    } else {
      throw new IllegalArgumentException("unknow type " + quote.getClass());
    }
  }

  private CDSQuoteConvention[] bumpQuotes(final CDSAnalytic[] cds, final CDSQuoteConvention[] quotes, final ISDACompliantYieldCurve yieldCurve, final double eps) {
    final int n = cds.length;
    final CDSQuoteConvention[] res = new CDSQuoteConvention[n];
    for (int i = 0; i < n; i++) {
      res[i] = bumpQuote(cds[i], quotes[i], yieldCurve, eps);
    }
    return res;
  }

  private CDSQuoteConvention[] bumpQuoteAtIndex(final CDSAnalytic[] cds, final CDSQuoteConvention[] quotes, final ISDACompliantYieldCurve yieldCurve, final double eps, final int index) {
    final int n = cds.length;
    final CDSQuoteConvention[] res = new CDSQuoteConvention[n];
    System.arraycopy(quotes, 0, res, 0, n);
    res[index] = bumpQuote(cds[index], quotes[index], yieldCurve, eps);
    return res;
  }

  private double[] makeBumpedSpreads(final double[] spreads, final double amount, final BumpType bumpType, final int index) {
    final int n = spreads.length;
    final double[] res = new double[n];
    System.arraycopy(spreads, 0, res, 0, n);

    switch (bumpType) {
      case ADDITIVE:
        res[index] += amount;
        break;
      case MULTIPLICATIVE:
        res[index] += res[index] * amount;
        break;
      default:
        throw new IllegalArgumentException("BumpType " + bumpType + " is not supported");
    }
    return res;
  }
}
TOP

Related Classes of com.opengamma.analytics.financial.credit.creditdefaultswap.pricing.vanilla.isdanew.SpreadSensitivityCalculator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.