/**
   * 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(
      CdsAnalytic cds,
      double cdsCoupon,
      IsdaCompliantYieldCurve yieldCurve,
      CdsAnalytic[] marketCDSs,
      CdsQuoteConvention[] quotes,
      double fracBumpAmount) {

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

    IsdaCompliantCreditCurve baseCurve =
        _curveBuilder.calibrateCreditCurve(marketCDSs, quotes, yieldCurve);
    double basePrice = _pricer.pv(cds, yieldCurve, baseCurve, cdsCoupon);
    double[] res = new double[n];
    for (int i = 0; i < n; i++) {
      CdsQuoteConvention[] bumpedQuotes =
          bumpQuoteAtIndex(marketCDSs, quotes, yieldCurve, fracBumpAmount, i);
      IsdaCompliantCreditCurve bumpedCurve =
          _curveBuilder.calibrateCreditCurve(marketCDSs, bumpedQuotes, yieldCurve);
      double price = _pricer.pv(cds, yieldCurve, bumpedCurve, cdsCoupon);
      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 shiftType ABSOLUTE or RELATIVE
   * @return The bucked CS01 for a set of CDSs
   */
  public double[][] bucketedCS01FromQuotedSpreads(
      CdsAnalytic[] cds,
      double dealSpread,
      IsdaCompliantYieldCurve yieldCurve,
      CdsAnalytic[] marketCDSs,
      double[] quotedSpreads,
      double fracBumpAmount,
      ShiftType shiftType) {

    ArgChecker.noNulls(cds, "cds");
    ArgChecker.noNulls(marketCDSs, "curvePoints");
    ArgChecker.notEmpty(quotedSpreads, "spreads");
    ArgChecker.notNull(yieldCurve, "yieldCurve");
    ArgChecker.notNull(shiftType, "shiftType");
    ArgChecker.isTrue(Math.abs(fracBumpAmount) > 1e-10, "bump amount too small");
    int nMarketCDSs = marketCDSs.length;
    ArgChecker.isTrue(
        nMarketCDSs == quotedSpreads.length, "speads length does not match curvePoints");
    CdsPriceType priceType = CdsPriceType.DIRTY;
    double[] premiums = new double[nMarketCDSs];
    Arrays.fill(premiums, dealSpread); // assume the premiums of all CDS are equal

    int nTradeCDSs = cds.length;

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

    double[] bumpedPUF = new double[nMarketCDSs];
    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);
      double bumpedSpread = bumpedSpread(quotedSpreads[i], fracBumpAmount, shiftType);
      bumpedPUF[i] =
          _pufConverter.quotedSpreadToPUF(marketCDSs[i], premiums[i], yieldCurve, bumpedSpread);
      // TODO a lot of unnecessary recalibration here
      IsdaCompliantCreditCurve bumpedCurve =
          _curveBuilder.calibrateCreditCurve(marketCDSs, premiums, yieldCurve, bumpedPUF);
      for (int j = 0; j < nTradeCDSs; j++) {
        double price = _pricer.pv(cds[j], yieldCurve, bumpedCurve, dealSpread, priceType);
        res[j][i] = (price - basePrices[j]) / fracBumpAmount;
      }
    }
    return res;
  }
Example #3
0
  /**
   * Make a set of CDS by specifying all dates.
   *
   * @param tradeDate the trade date
   * @param stepinDate (aka Protection Effective sate or assignment date). Date when party assumes
   *     ownership. This is usually T+1. This is when protection (and risk) starts in terms of the
   *     model. Note, this is sometimes just called the Effective Date, however this can cause
   *     confusion with the legal effective date which is T-60 or T-90.
   * @param valueDate the valuation date. The date that values are PVed to. Is is normally today + 3
   *     business days. Aka cash-settle date.
   * @param accStartDate this is when the CDS nominally starts in terms of premium payments. i.e.
   *     the number of days in the first period (and thus the amount of the first premium payment)
   *     is counted from this date.
   * @param maturities The maturities of the CDSs. For a standard CDS these are IMM dates
   * @return an array of CDS analytic descriptions
   */
  public CdsAnalytic[] makeCds(
      LocalDate tradeDate,
      LocalDate stepinDate,
      LocalDate valueDate,
      LocalDate accStartDate,
      LocalDate[] maturities) {

    ArgChecker.noNulls(maturities, "maturities");
    int n = maturities.length;
    CdsAnalytic[] cds = new CdsAnalytic[n];
    for (int i = 0; i < n; i++) {
      cds[i] =
          new CdsAnalytic(
              tradeDate,
              stepinDate,
              valueDate,
              accStartDate,
              maturities[i],
              _payAccOnDefault,
              _couponInterval,
              _stubType,
              _protectStart,
              _recoveryRate,
              _businessdayAdjustmentConvention,
              _calendar,
              _accrualDayCount,
              _curveDayCount);
    }
    return cds;
  }
 /**
  * Puts all the specified dates and values into this builder.
  *
  * <p>The date and value collections must be the same size.
  *
  * <p>The date-value pairs are added one by one. If a date is duplicated it will overwrite an
  * earlier entry.
  *
  * @param dates the dates to be added
  * @param values the values to be added
  * @return this builder
  */
 public LocalDateDoubleTimeSeriesBuilder putAll(
     Collection<LocalDate> dates, Collection<Double> values) {
   ArgChecker.noNulls(dates, "dates");
   ArgChecker.noNulls(values, "values");
   ArgChecker.isTrue(
       dates.size() == values.size(),
       "Arrays are of different sizes - dates: {}, values: {}",
       dates.size(),
       values.size());
   Iterator<LocalDate> itDate = dates.iterator();
   Iterator<Double> itValue = values.iterator();
   for (int i = 0; i < dates.size(); i++) {
     put(itDate.next(), itValue.next());
   }
   return this;
 }
  /**
   * 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 shiftType ABSOLUTE or RELATIVE
   * @return The credit CS01
   */
  public double[] bucketedCS01FromParSpreads(
      CdsAnalytic cds,
      double cdsCoupon,
      IsdaCompliantYieldCurve yieldCurve,
      CdsAnalytic[] marketCDSs,
      double[] marketParSpreads,
      double fracBumpAmount,
      ShiftType shiftType) {

    ArgChecker.notNull(cds, "cds");
    ArgChecker.noNulls(marketCDSs, "curvePoints");
    ArgChecker.notEmpty(marketParSpreads, "spreads");
    ArgChecker.notNull(yieldCurve, "yieldCurve");
    ArgChecker.notNull(shiftType, "shiftType");
    ArgChecker.isTrue(Math.abs(fracBumpAmount) > 1e-10, "bump amount too small");
    int n = marketCDSs.length;
    ArgChecker.isTrue(n == marketParSpreads.length, "speads length does not match curvePoints");
    CdsPriceType priceType = CdsPriceType.DIRTY;

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

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

    return res;
  }
  /**
   * 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 shiftType ABSOLUTE
   *
   * @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 shiftType ABSOLUTE or RELATIVE
   * @return The credit DV01
   */
  public double parallelCS01FromParSpreads(
      CdsAnalytic cds,
      double cdsFracSpread,
      IsdaCompliantYieldCurve yieldCurve,
      CdsAnalytic[] marketCDSs,
      double[] parSpreads,
      double fracBumpAmount,
      ShiftType shiftType) {

    ArgChecker.notNull(cds, "cds");
    ArgChecker.noNulls(marketCDSs, "curvePoints");
    ArgChecker.notEmpty(parSpreads, "spreads");
    ArgChecker.notNull(yieldCurve, "yieldCurve");
    ArgChecker.notNull(shiftType, "shiftType");
    ArgChecker.isTrue(Math.abs(fracBumpAmount) > 1e-10, "bump amount too small");
    int n = marketCDSs.length;
    ArgChecker.isTrue(n == parSpreads.length, "speads length does not match curvePoints");
    double[] bumpedSpreads = makeBumpedSpreads(parSpreads, fracBumpAmount, shiftType);
    double diff =
        fdCreditDV01(
            cds,
            cdsFracSpread,
            marketCDSs,
            bumpedSpreads,
            parSpreads,
            yieldCurve,
            CdsPriceType.DIRTY);
    return diff / fracBumpAmount;
  }
Example #7
0
 /**
  * Make a set of CDSs with a common trade date and maturities dates the given periods after the
  * next IMM date (after the trade-date).
  *
  * @param tradeDate the trade date
  * @param accStartDate this is when the CDS nominally starts in terms of premium payments. For a
  *     standard CDS this is the previous IMM date, and for a `legacy' CDS it is T+1
  * @param tenors the tenors (lengths) of the CDSs
  * @return an array of CDS analytic descriptions
  */
 public CdsAnalytic[] makeImmCds(LocalDate tradeDate, LocalDate accStartDate, Period[] tenors) {
   ArgChecker.notNull(tradeDate, "tradeDate");
   ArgChecker.notNull(accStartDate, "effectiveDate");
   ArgChecker.noNulls(tenors, "tenors");
   LocalDate nextIMM = ImmDateLogic.getNextIMMDate(tradeDate);
   LocalDate[] maturities = ImmDateLogic.getIMMDateSet(nextIMM, tenors);
   return makeCds(tradeDate, accStartDate, maturities);
 }
Example #8
0
 /**
  * Set up a strip of on-the-run indexes represented as a single name CDSs (i.e. by CdsAnalytic).
  * The index roll dates (when new indices are issued) are 20 Mar & Sep, and the index is defined
  * to have a maturity that is its nominal tenor plus 3M on issuance, so a 5Y index on the
  * 6-Feb-2014 will have a maturity of 20-Dec-2018 (5Y3M on the issue date of 20-Sep-2013). The
  * accrual start date will be the previous IMM date (before the trade date), business-day
  * adjusted. <b>Note</b> it payment interval is changed from the default of 3M, this will produce
  * a (possibly incorrect) non-standard first coupon.
  *
  * @param tradeDate the trade date
  * @param tenors the nominal lengths of the indexes
  * @return an array of CDS analytic descriptions
  */
 public CdsAnalytic[] makeCdx(LocalDate tradeDate, Period[] tenors) {
   ArgChecker.notNull(tradeDate, "tradeDate");
   ArgChecker.noNulls(tenors, "tenors");
   LocalDate effectiveDate =
       _businessdayAdjustmentConvention.adjust(ImmDateLogic.getPrevIMMDate(tradeDate), _calendar);
   LocalDate mid = ImmDateLogic.getNextIndexRollDate(tradeDate).minusMonths(3);
   LocalDate[] maturities = ImmDateLogic.getIMMDateSet(mid, tenors);
   return makeCds(tradeDate, effectiveDate, maturities);
 }
  /**
   * 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(
      CdsAnalytic cds,
      double cdsCoupon,
      CdsAnalytic[] bucketCDSs,
      IsdaCompliantYieldCurve yieldCurve,
      CdsAnalytic[] pillarCDSs,
      double[] pillarSpreads,
      double fracBumpAmount) {

    ArgChecker.noNulls(pillarCDSs, "pillarCDSs");
    ArgChecker.notEmpty(pillarSpreads, "pillarSpreads");
    IsdaCompliantCreditCurve creditCurve =
        _curveBuilder.calibrateCreditCurve(pillarCDSs, pillarSpreads, yieldCurve);
    return bucketedCS01FromCreditCurve(
        cds, cdsCoupon, bucketCDSs, yieldCurve, creditCurve, fracBumpAmount);
  }
Example #10
0
  /**
   * Make a set of standard CDS represented as a MultiCdsAnalytic instance.
   *
   * @param tradeDate the trade date
   * @param accStartDate the accrual start date
   * @param tenors the tenors (length) of the CDS
   * @return a set of CDS represented as a MultiCdsAnalytic
   */
  public MultiCdsAnalytic makeMultiImmCds(
      LocalDate tradeDate, LocalDate accStartDate, Period[] tenors) {

    ArgChecker.noNulls(tenors, "tenors");
    int n = tenors.length;

    int immNMonths = (int) DEFAULT_COUPON_INT.toTotalMonths();
    int[] matIndices = new int[n];
    for (int i = 0; i < n; i++) {
      int months = (int) tenors[i].toTotalMonths();
      if (months % immNMonths != 0) {
        throw new IllegalArgumentException(
            "tenors index " + i + " is not a multiple of " + DEFAULT_COUPON_INT.toString());
      }
      matIndices[i] = months / immNMonths;
    }

    return makeMultiImmCds(tradeDate, accStartDate, matIndices);
  }
  /**
   * 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(
      CdsAnalytic cds,
      double cdsCoupon,
      CdsAnalytic[] bucketCDSs,
      IsdaCompliantYieldCurve yieldCurve,
      IsdaCompliantCreditCurve creditCurve,
      double fracBumpAmount) {

    ArgChecker.notNull(cds, "cds");
    ArgChecker.noNulls(bucketCDSs, "bucketCDSs");
    ArgChecker.notNull(creditCurve, "creditCurve");
    ArgChecker.notNull(yieldCurve, "yieldCurve");
    ArgChecker.isTrue(Math.abs(fracBumpAmount) > 1e-10, "bump amount too small");
    int n = bucketCDSs.length;

    double[] impSpreads = new double[n];
    double[] t = new double[n];
    for (int i = 0; i < n; i++) {
      impSpreads[i] = _pricer.parSpread(bucketCDSs[i], yieldCurve, creditCurve);
      t[i] = bucketCDSs[i].getProtectionEnd();
      if (i > 0) {
        ArgChecker.isTrue(t[i] > t[i - 1], "buckets must be assending");
      }
    }
    int index = Arrays.binarySearch(t, cds.getProtectionEnd());
    if (index < 0) {
      index = -1 - index;
    }
    index = Math.min(index, n - 1);

    IsdaCompliantCreditCurve baseCurve =
        _curveBuilder.calibrateCreditCurve(bucketCDSs, impSpreads, yieldCurve);
    double basePrice = _pricer.pv(cds, yieldCurve, baseCurve, cdsCoupon);
    double[] res = new double[n];
    for (int i = 0; i <= index; i++) { // don't bother calculating where there is no sensitivity
      double[] bumpedSpreads = makeBumpedSpreads(impSpreads, fracBumpAmount, ShiftType.ABSOLUTE, i);
      IsdaCompliantCreditCurve bumpedCurve =
          _curveBuilder.calibrateCreditCurve(bucketCDSs, bumpedSpreads, yieldCurve);
      double price = _pricer.pv(cds, yieldCurve, bumpedCurve, cdsCoupon);
      res[i] = (price - basePrice) / fracBumpAmount;
    }
    return res;
  }
  public double parallelCS01FromCreditCurve(
      CdsAnalytic cds,
      double cdsCoupon,
      CdsAnalytic[] pillarCDSs,
      IsdaCompliantYieldCurve yieldCurve,
      IsdaCompliantCreditCurve creditCurve,
      double fracBumpAmount) {

    ArgChecker.notNull(cds, "cds");
    ArgChecker.noNulls(pillarCDSs, "pillarCDSs");
    ArgChecker.notNull(creditCurve, "creditCurve");
    ArgChecker.notNull(yieldCurve, "yieldCurve");
    ArgChecker.isTrue(Math.abs(fracBumpAmount) > 1e-10, "bump amount too small");
    int n = pillarCDSs.length;

    double[] impSpreads = new double[n];
    double[] t = new double[n];
    for (int i = 0; i < n; i++) {
      impSpreads[i] = _pricer.parSpread(pillarCDSs[i], yieldCurve, creditCurve);
      t[i] = pillarCDSs[i].getProtectionEnd();
      if (i > 0) {
        ArgChecker.isTrue(t[i] > t[i - 1], "pillars must be assending");
      }
    }

    IsdaCompliantCreditCurve baseCurve =
        _curveBuilder.calibrateCreditCurve(pillarCDSs, impSpreads, yieldCurve);
    double basePrice = _pricer.pv(cds, yieldCurve, baseCurve, cdsCoupon);
    double[] bumpedSpreads = makeBumpedSpreads(impSpreads, fracBumpAmount, ShiftType.ABSOLUTE);
    IsdaCompliantCreditCurve bumpedCurve =
        _curveBuilder.calibrateCreditCurve(pillarCDSs, bumpedSpreads, yieldCurve);
    double price = _pricer.pv(cds, yieldCurve, bumpedCurve, cdsCoupon);
    double res = (price - basePrice) / fracBumpAmount;

    return res;
  }
Example #13
0
 /**
  * Adds measures to the pricing rule.
  *
  * @param measures measures handled by the pricing rule
  * @return this builder
  */
 public PricingRuleBuilder<T> addMeasures(Measure... measures) {
   ArgChecker.noNulls(measures, "measures");
   this.measures.addAll(Arrays.asList(measures));
   return this;
 }
  /** {@inheritDoc} */
  @Override
  public IsdaCompliantCreditCurve calibrateCreditCurve(
      CdsAnalytic[] cds,
      double[] premiums,
      IsdaCompliantYieldCurve yieldCurve,
      double[] pointsUpfront) {

    ArgChecker.noNulls(cds, "null CDSs");
    ArgChecker.notEmpty(premiums, "empty fractionalSpreads");
    ArgChecker.notEmpty(pointsUpfront, "empty pointsUpfront");
    ArgChecker.notNull(yieldCurve, "null yieldCurve");
    int n = cds.length;
    ArgChecker.isTrue(n == premiums.length, "Number of CDSs does not match number of spreads");
    ArgChecker.isTrue(
        n == pointsUpfront.length, "Number of CDSs does not match number of pointsUpfront");
    double proStart = cds[0].getEffectiveProtectionStart();
    for (int i = 1; i < n; i++) {
      ArgChecker.isTrue(
          proStart == cds[i].getEffectiveProtectionStart(),
          "all CDSs must has same protection start");
      ArgChecker.isTrue(
          cds[i].getProtectionEnd() > cds[i - 1].getProtectionEnd(),
          "protection end must be ascending");
    }

    // use continuous premiums as initial guess
    double[] guess = new double[n];
    double[] t = new double[n];
    for (int i = 0; i < n; i++) {
      t[i] = cds[i].getProtectionEnd();
      guess[i] = (premiums[i] + pointsUpfront[i] / t[i]) / cds[i].getLGD();
    }

    IsdaCompliantCreditCurve creditCurve = new IsdaCompliantCreditCurve(t, guess);
    for (int i = 0; i < n; i++) {
      Pricer pricer = new Pricer(cds[i], yieldCurve, t, premiums[i], pointsUpfront[i]);
      Function1D<Double, Double> func = pricer.getPointFunction(i, creditCurve);

      switch (getArbHanding()) {
        case Ignore:
          {
            try {
              double[] bracket =
                  BRACKER.getBracketedPoints(
                      func,
                      0.8 * guess[i],
                      1.25 * guess[i],
                      Double.NEGATIVE_INFINITY,
                      Double.POSITIVE_INFINITY);
              double zeroRate =
                  bracket[0] > bracket[1]
                      ? ROOTFINDER.getRoot(func, bracket[1], bracket[0])
                      : ROOTFINDER.getRoot(func, bracket[0], bracket[1]); // Negative guess handled
              creditCurve = creditCurve.withRate(zeroRate, i);
            } catch (
                MathException e) { // handling bracketing failure due to small survival probability
              if (Math.abs(func.evaluate(creditCurve.getZeroRateAtIndex(i - 1))) < 1.e-12) {
                creditCurve = creditCurve.withRate(creditCurve.getZeroRateAtIndex(i - 1), i);
              } else {
                throw new MathException(e);
              }
            }
            break;
          }
        case Fail:
          {
            double minValue =
                i == 0 ? 0.0 : creditCurve.getRTAtIndex(i - 1) / creditCurve.getTimeAtIndex(i);
            if (i > 0 && func.evaluate(minValue) > 0.0) { // can never fail on the first spread
              StringBuilder msg = new StringBuilder();
              if (pointsUpfront[i] == 0.0) {
                msg.append("The par spread of " + premiums[i] + " at index " + i);
              } else {
                msg.append(
                    "The premium of "
                        + premiums[i]
                        + "and points up-front of "
                        + pointsUpfront[i]
                        + " at index "
                        + i);
              }
              msg.append(
                  " is an arbitrage; cannot fit a curve with positive forward hazard rate. ");
              throw new IllegalArgumentException(msg.toString());
            }
            guess[i] = Math.max(minValue, guess[i]);
            double[] bracket =
                BRACKER.getBracketedPoints(
                    func, guess[i], 1.2 * guess[i], minValue, Double.POSITIVE_INFINITY);
            double zeroRate = ROOTFINDER.getRoot(func, bracket[0], bracket[1]);
            creditCurve = creditCurve.withRate(zeroRate, i);
            break;
          }
        case ZeroHazardRate:
          {
            double minValue =
                i == 0 ? 0.0 : creditCurve.getRTAtIndex(i - 1) / creditCurve.getTimeAtIndex(i);
            if (i > 0 && func.evaluate(minValue) > 0.0) { // can never fail on the first spread
              creditCurve = creditCurve.withRate(minValue, i);
            } else {
              guess[i] = Math.max(minValue, guess[i]);
              double[] bracket =
                  BRACKER.getBracketedPoints(
                      func, guess[i], 1.2 * guess[i], minValue, Double.POSITIVE_INFINITY);
              double zeroRate = ROOTFINDER.getRoot(func, bracket[0], bracket[1]);
              creditCurve = creditCurve.withRate(zeroRate, i);
            }
            break;
          }
        default:
          throw new IllegalArgumentException("unknow case " + getArbHanding());
      }
    }
    return creditCurve;
  }
 /**
  * Puts all the entries from the supplied map into this builder.
  *
  * <p>If a date is duplicated it will overwrite an earlier entry.
  *
  * @param map the map of points to be added
  * @return this builder
  */
 public LocalDateDoubleTimeSeriesBuilder putAll(Map<LocalDate, Double> map) {
   ArgChecker.noNulls(map, "map");
   map.entrySet().forEach(e -> put(e.getKey(), e.getValue()));
   return this;
 }
  /**
   * 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(
      CdsAnalytic cds,
      double cdsFracSpread,
      CdsPriceType priceType,
      IsdaCompliantYieldCurve yieldCurve,
      CdsAnalytic[] marketCDSs,
      double[] marketFracSpreads,
      double[] fracDeltaSpreads,
      FiniteDifferenceType fdType) {

    ArgChecker.notNull(cds, "cds");
    ArgChecker.noNulls(marketCDSs, "curvePoints");
    ArgChecker.notEmpty(marketFracSpreads, "spreads");
    ArgChecker.notEmpty(fracDeltaSpreads, "deltaSpreads");
    ArgChecker.notNull(yieldCurve, "yieldCurve");
    ArgChecker.notNull(priceType, "priceType");

    int n = marketCDSs.length;
    ArgChecker.isTrue(n == marketFracSpreads.length, "speads length does not match curvePoints");
    ArgChecker.isTrue(
        n == fracDeltaSpreads.length, "deltaSpreads length does not match curvePoints");
    for (int i = 0; i < n; i++) {
      ArgChecker.isTrue(marketFracSpreads[i] > 0, "spreads must be positive");
      ArgChecker.isTrue(fracDeltaSpreads[i] >= 0, "deltaSpreads must none negative");
      ArgChecker.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);
    }
  }