public double protectionLeg(IsdaCompliantCreditCurve creditCurve) { double ht0 = creditCurve.getRT(_proLegIntPoints[0]); double rt0 = _proYieldCurveRT[0]; double b0 = _proDF[0] * Math.exp(-ht0); double pv = 0.0; for (int i = 1; i < _nProPoints; ++i) { double ht1 = creditCurve.getRT(_proLegIntPoints[i]); double rt1 = _proYieldCurveRT[i]; double b1 = _proDF[i] * Math.exp(-ht1); double dht = ht1 - ht0; double drt = rt1 - rt0; double dhrt = dht + drt; // this is equivalent to the ISDA code without explicitly calculating the time step - it // also handles the limit double dPV; if (Math.abs(dhrt) < 1e-5) { dPV = dht * b0 * epsilon(-dhrt); } else { dPV = (b0 - b1) * dht / dhrt; } pv += dPV; ht0 = ht1; rt0 = rt1; b0 = b1; } pv *= _lgdDF; // multiply by LGD and adjust to valuation date return pv; }
private double calculateSinglePeriodAccrualOnDefault( int paymentIndex, IsdaCompliantCreditCurve creditCurve) { double[] knots = _premLegIntPoints[paymentIndex]; if (knots == null) { return 0.0; } double[] df = _premDF[paymentIndex]; double[] deltaT = _premDt[paymentIndex]; double[] rt = _rt[paymentIndex]; double accRate = _accRate[paymentIndex]; double accStart = _offsetAccStart[paymentIndex]; double t = knots[0]; double ht0 = creditCurve.getRT(t); double rt0 = rt[0]; double b0 = df[0] * Math.exp(-ht0); double t0 = t - accStart + _omega; double pv = 0.0; int nItems = knots.length; for (int j = 1; j < nItems; ++j) { t = knots[j]; double ht1 = creditCurve.getRT(t); double rt1 = rt[j]; double b1 = df[j] * Math.exp(-ht1); double dt = deltaT[j - 1]; double dht = ht1 - ht0; double drt = rt1 - rt0; double dhrt = dht + drt + 1e-50; // to keep consistent with ISDA c code double tPV; if (getAccOnDefaultFormula() == AccrualOnDefaultFormulae.MARKIT_FIX) { if (Math.abs(dhrt) < 1e-5) { tPV = dht * dt * b0 * epsilonP(-dhrt); } else { tPV = dht * dt / dhrt * ((b0 - b1) / dhrt - b1); } } else { double t1 = t - accStart + _omega; if (Math.abs(dhrt) < 1e-5) { tPV = dht * b0 * (t0 * epsilon(-dhrt) + dt * epsilonP(-dhrt)); } else { tPV = dht / dhrt * (t0 * b0 - t1 * b1 + dt / dhrt * (b0 - b1)); } t0 = t1; } pv += tPV; ht0 = ht1; rt0 = rt1; b0 = b1; } return accRate * pv; }
public double rpv01(IsdaCompliantCreditCurve creditCurve, CdsPriceType cleanOrDirty) { double pv = 0.0; for (int i = 0; i < _nPayments; i++) { CdsCoupon c = _cds.getCoupon(i); double q = creditCurve.getDiscountFactor(c.getEffEnd()); pv += c.getYearFrac() * _paymentDF[i] * q; } if (_cds.isPayAccOnDefault()) { double accPV = 0.0; for (int i = 0; i < _nPayments; i++) { accPV += calculateSinglePeriodAccrualOnDefault(i, creditCurve); } pv += accPV; } pv /= _valuationDF; if (cleanOrDirty == CdsPriceType.CLEAN) { pv -= _cds.getAccruedYearFraction(); } return pv; }
/** {@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; }