public virtual void test_zeroRate() { LegalEntitySurvivalProbabilities test = LegalEntitySurvivalProbabilities.of(LEGAL_ENTITY, DFS); double relativeYearFraction = ACT_365F.relativeYearFraction(VALUATION, DATE_AFTER); double discountFactor = test.survivalProbability(DATE_AFTER); double zeroRate = test.zeroRate(relativeYearFraction); assertEquals(Math.Exp(-zeroRate * relativeYearFraction), discountFactor); }
// computes protection leg pv per unit notional, without loss-given-default rate multiplied internal virtual double protectionFull(ResolvedCds cds, CreditDiscountFactors discountFactors, LegalEntitySurvivalProbabilities survivalProbabilities, LocalDate referenceDate, LocalDate effectiveStartDate) { DoubleArray integrationSchedule = DoublesScheduleGenerator.getIntegrationsPoints(discountFactors.relativeYearFraction(effectiveStartDate), discountFactors.relativeYearFraction(cds.ProtectionEndDate), discountFactors.ParameterKeys, survivalProbabilities.ParameterKeys); double pv = 0d; double ht0 = survivalProbabilities.zeroRate(integrationSchedule.get(0)) * integrationSchedule.get(0); double rt0 = discountFactors.zeroRate(integrationSchedule.get(0)) * integrationSchedule.get(0); double b0 = Math.Exp(-ht0 - rt0); int n = integrationSchedule.size(); for (int i = 1; i < n; ++i) { double ht1 = survivalProbabilities.zeroRate(integrationSchedule.get(i)) * integrationSchedule.get(i); double rt1 = discountFactors.zeroRate(integrationSchedule.get(i)) * integrationSchedule.get(i); double b1 = Math.Exp(-ht1 - rt1); double dht = ht1 - ht0; double drt = rt1 - rt0; double dhrt = dht + drt; // The formula has been modified from ISDA (but is equivalent) to avoid log(exp(x)) and explicitly // calculating the time step - it also handles the limit double dPV = 0d; if (Math.Abs(dhrt) < SMALL) { dPV = dht * b0 * epsilon(-dhrt); } else { dPV = (b0 - b1) * dht / dhrt; } pv += dPV; ht0 = ht1; rt0 = rt1; b0 = b1; } // roll to the cash settle date double df = discountFactors.discountFactor(referenceDate); return(pv / df); }
private Pair <double, PointSensitivityBuilder> singlePeriodAccrualOnDefaultSensitivity(CreditCouponPaymentPeriod coupon, LocalDate effectiveStartDate, DoubleArray integrationSchedule, CreditDiscountFactors discountFactors, LegalEntitySurvivalProbabilities survivalProbabilities) { LocalDate start = coupon.EffectiveStartDate.isBefore(effectiveStartDate) ? effectiveStartDate : coupon.EffectiveStartDate; if (!start.isBefore(coupon.EffectiveEndDate)) { return(Pair.of(0d, PointSensitivityBuilder.none())); //this coupon has already expired } DoubleArray knots = DoublesScheduleGenerator.truncateSetInclusive(discountFactors.relativeYearFraction(start), discountFactors.relativeYearFraction(coupon.EffectiveEndDate), integrationSchedule); // pv double pv = 0d; //JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final': //ORIGINAL LINE: final int nItems = knots.size(); int nItems = knots.size(); double[] dhrtBar = new double[nItems - 1]; double[] dhtBar = new double[nItems - 1]; double[] bBar = new double[nItems]; double[] p = new double[nItems]; double[] q = new double[nItems]; double t = knots.get(0); double ht0 = survivalProbabilities.zeroRate(t) * t; double rt0 = discountFactors.zeroRate(t) * t; q[0] = Math.Exp(-ht0); p[0] = Math.Exp(-rt0); double b0 = q[0] * p[0]; double effStart = discountFactors.relativeYearFraction(coupon.EffectiveStartDate); double t0 = t - effStart + omega; for (int i = 1; i < nItems; ++i) { t = knots.get(i); double ht1 = survivalProbabilities.zeroRate(t) * t; double rt1 = discountFactors.zeroRate(t) * t; q[i] = Math.Exp(-ht1); p[i] = Math.Exp(-rt1); double b1 = q[i] * p[i]; double dt = knots.get(i) - knots.get(i - 1); double dht = ht1 - ht0; double drt = rt1 - rt0; double dhrt = dht + drt; double tPv; if (formula == AccrualOnDefaultFormula.MARKIT_FIX) { if (Math.Abs(dhrt) < SMALL) { double eps = epsilonP(-dhrt); tPv = dht * dt * b0 * eps; dhtBar[i - 1] = dt * b0 * eps; dhrtBar[i - 1] = -dht *dt *b0 *epsilonPP(-dhrt); bBar[i - 1] += dht * eps; } else { tPv = dht * dt / dhrt * ((b0 - b1) / dhrt - b1); dhtBar[i - 1] = dt / dhrt * ((b0 - b1) / dhrt - b1); dhrtBar[i - 1] = dht * dt / (dhrt * dhrt) * (b1 - 2d * (b0 - b1) / dhrt); bBar[i - 1] += dht * dt / (dhrt * dhrt); bBar[i] += -dht * dt / dhrt * (1d + 1d / dhrt); } } else { double t1 = t - effStart + omega; if (Math.Abs(dhrt) < SMALL) { double eps = epsilon(-dhrt); double epsp = epsilonP(-dhrt); tPv = dht * b0 * (t0 * eps + dt * epsp); dhtBar[i - 1] = b0 * (t0 * eps + dt * epsp); dhrtBar[i - 1] = -dht * b0 * (t0 * epsp + dt * epsilonPP(-dhrt)); bBar[i - 1] += dht * (t0 * eps + dt * epsp); } else { tPv = dht / dhrt * (t0 * b0 - t1 * b1 + dt / dhrt * (b0 - b1)); dhtBar[i - 1] = (t0 * b0 - t1 * b1 + dt / dhrt * (b0 - b1)) / dhrt; dhrtBar[i - 1] = dht / (dhrt * dhrt) * (-2d * dt / dhrt * (b0 - b1) - t0 * b0 + t1 * b1); bBar[i - 1] += dht / dhrt * (t0 + dt / dhrt); bBar[i] += dht / dhrt * (-t1 - dt / dhrt); } t0 = t1; } pv += tPv; ht0 = ht1; rt0 = rt1; b0 = b1; } double yfRatio = coupon.YearFraction / discountFactors.DayCount.relativeYearFraction(coupon.StartDate, coupon.EndDate); // pv sensitivity PointSensitivityBuilder qSensiFirst = survivalProbabilities.zeroRatePointSensitivity(knots.get(0)).multipliedBy(yfRatio * ((dhrtBar[0] + dhtBar[0]) / q[0] + bBar[0] * p[0])); PointSensitivityBuilder pSensiFirst = discountFactors.zeroRatePointSensitivity(knots.get(0)).multipliedBy(yfRatio * (dhrtBar[0] / p[0] + bBar[0] * q[0])); PointSensitivityBuilder pvSensi = pSensiFirst.combinedWith(qSensiFirst); for (int i = 1; i < nItems - 1; ++i) { PointSensitivityBuilder qSensi = survivalProbabilities.zeroRatePointSensitivity(knots.get(i)).multipliedBy(yfRatio * (-(dhrtBar[i - 1] + dhtBar[i - 1]) / q[i] + (dhrtBar[i] + dhtBar[i]) / q[i] + bBar[i] * p[i])); PointSensitivityBuilder pSensi = discountFactors.zeroRatePointSensitivity(knots.get(i)).multipliedBy(yfRatio * (-dhrtBar[i - 1] / p[i] + dhrtBar[i] / p[i] + bBar[i] * q[i])); pvSensi = pvSensi.combinedWith(pSensi).combinedWith(qSensi); } if (nItems > 1) { PointSensitivityBuilder qSensiLast = survivalProbabilities.zeroRatePointSensitivity(knots.get(nItems - 1)).multipliedBy(yfRatio * (-(dhrtBar[nItems - 2] + dhtBar[nItems - 2]) / q[nItems - 1] + bBar[nItems - 1] * p[nItems - 1])); PointSensitivityBuilder pSensiLast = discountFactors.zeroRatePointSensitivity(knots.get(nItems - 1)).multipliedBy(yfRatio * (-dhrtBar[nItems - 2] / p[nItems - 1] + bBar[nItems - 1] * q[nItems - 1])); pvSensi = pvSensi.combinedWith(pSensiLast).combinedWith(qSensiLast); } return(Pair.of(yfRatio * pv, pvSensi)); }
//------------------------------------------------------------------------- internal virtual PointSensitivityBuilder protectionLegSensitivity(ResolvedCds cds, CreditDiscountFactors discountFactors, LegalEntitySurvivalProbabilities survivalProbabilities, LocalDate referenceDate, LocalDate effectiveStartDate, double recoveryRate) { DoubleArray integrationSchedule = DoublesScheduleGenerator.getIntegrationsPoints(discountFactors.relativeYearFraction(effectiveStartDate), discountFactors.relativeYearFraction(cds.ProtectionEndDate), discountFactors.ParameterKeys, survivalProbabilities.ParameterKeys); int n = integrationSchedule.size(); double[] dht = new double[n - 1]; double[] drt = new double[n - 1]; double[] dhrt = new double[n - 1]; double[] p = new double[n]; double[] q = new double[n]; // pv double pv = 0d; double ht0 = survivalProbabilities.zeroRate(integrationSchedule.get(0)) * integrationSchedule.get(0); double rt0 = discountFactors.zeroRate(integrationSchedule.get(0)) * integrationSchedule.get(0); p[0] = Math.Exp(-rt0); q[0] = Math.Exp(-ht0); double b0 = p[0] * q[0]; for (int i = 1; i < n; ++i) { double ht1 = survivalProbabilities.zeroRate(integrationSchedule.get(i)) * integrationSchedule.get(i); double rt1 = discountFactors.zeroRate(integrationSchedule.get(i)) * integrationSchedule.get(i); p[i] = Math.Exp(-rt1); q[i] = Math.Exp(-ht1); double b1 = p[i] * q[i]; dht[i - 1] = ht1 - ht0; drt[i - 1] = rt1 - rt0; dhrt[i - 1] = dht[i - 1] + drt[i - 1]; double dPv = 0d; if (Math.Abs(dhrt[i - 1]) < SMALL) { double eps = epsilon(-dhrt[i - 1]); dPv = dht[i - 1] * b0 * eps; } else { dPv = (b0 - b1) * dht[i - 1] / dhrt[i - 1]; } pv += dPv; ht0 = ht1; rt0 = rt1; b0 = b1; } double df = discountFactors.discountFactor(referenceDate); // pv sensitivity double factor = (1d - recoveryRate) / df; double eps0 = computeExtendedEpsilon(-dhrt[0], p[1], q[1], p[0], q[0]); PointSensitivityBuilder pvSensi = discountFactors.zeroRatePointSensitivity(integrationSchedule.get(0)).multipliedBy(-dht[0] * q[0] * eps0 * factor); pvSensi = pvSensi.combinedWith(survivalProbabilities.zeroRatePointSensitivity(integrationSchedule.get(0)).multipliedBy(factor * (drt[0] * p[0] * eps0 + p[0]))); for (int i = 1; i < n - 1; ++i) { double epsp = computeExtendedEpsilon(-dhrt[i], p[i + 1], q[i + 1], p[i], q[i]); double epsm = computeExtendedEpsilon(dhrt[i - 1], p[i - 1], q[i - 1], p[i], q[i]); PointSensitivityBuilder pSensi = discountFactors.zeroRatePointSensitivity(integrationSchedule.get(i)).multipliedBy(factor * (-dht[i] * q[i] * epsp - dht[i - 1] * q[i] * epsm)); PointSensitivityBuilder qSensi = survivalProbabilities.zeroRatePointSensitivity(integrationSchedule.get(i)).multipliedBy(factor * (drt[i - 1] * p[i] * epsm + drt[i] * p[i] * epsp)); pvSensi = pvSensi.combinedWith(pSensi).combinedWith(qSensi); } if (n > 1) { double epsLast = computeExtendedEpsilon(dhrt[n - 2], p[n - 2], q[n - 2], p[n - 1], q[n - 1]); pvSensi = pvSensi.combinedWith(discountFactors.zeroRatePointSensitivity(integrationSchedule.get(n - 1)).multipliedBy(-dht[n - 2] * q[n - 1] * epsLast * factor)); pvSensi = pvSensi.combinedWith(survivalProbabilities.zeroRatePointSensitivity(integrationSchedule.get(n - 1)).multipliedBy(factor * (drt[n - 2] * p[n - 1] * epsLast - p[n - 1]))); } PointSensitivityBuilder dfSensi = discountFactors.zeroRatePointSensitivity(referenceDate).multipliedBy(-pv * factor / df); return(dfSensi.combinedWith(pvSensi)); }
// computes accrual-on-default pv per unit notional for a single payment period private double singlePeriodAccrualOnDefault(CreditCouponPaymentPeriod coupon, LocalDate effectiveStartDate, DoubleArray integrationSchedule, CreditDiscountFactors discountFactors, LegalEntitySurvivalProbabilities survivalProbabilities) { LocalDate start = coupon.EffectiveStartDate.isBefore(effectiveStartDate) ? effectiveStartDate : coupon.EffectiveStartDate; if (!start.isBefore(coupon.EffectiveEndDate)) { return(0d); // this coupon has already expired } DoubleArray knots = DoublesScheduleGenerator.truncateSetInclusive(discountFactors.relativeYearFraction(start), discountFactors.relativeYearFraction(coupon.EffectiveEndDate), integrationSchedule); double t0Knot = knots.get(0); double ht0 = survivalProbabilities.zeroRate(t0Knot) * t0Knot; double rt0 = discountFactors.zeroRate(t0Knot) * t0Knot; double b0 = Math.Exp(-rt0 - ht0); double effStart = discountFactors.relativeYearFraction(coupon.EffectiveStartDate); double t0 = t0Knot - effStart + omega; double pv = 0d; //JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final': //ORIGINAL LINE: final int nItems = knots.size(); int nItems = knots.size(); for (int j = 1; j < nItems; ++j) { double t = knots.get(j); double ht1 = survivalProbabilities.zeroRate(t) * t; double rt1 = discountFactors.zeroRate(t) * t; double b1 = Math.Exp(-rt1 - ht1); double dt = knots.get(j) - knots.get(j - 1); double dht = ht1 - ht0; double drt = rt1 - rt0; double dhrt = dht + drt; double tPV; if (formula == AccrualOnDefaultFormula.MARKIT_FIX) { if (Math.Abs(dhrt) < SMALL) { tPV = dht * dt * b0 * Epsilon.epsilonP(-dhrt); } else { tPV = dht * dt / dhrt * ((b0 - b1) / dhrt - b1); } } else { double t1 = t - effStart + omega; if (Math.Abs(dhrt) < SMALL) { tPV = dht * b0 * (t0 * epsilon(-dhrt) + dt * Epsilon.epsilonP(-dhrt)); } else { tPV = dht / dhrt * (t0 * b0 - t1 * b1 + dt / dhrt * (b0 - b1)); } t0 = t1; } pv += tPV; ht0 = ht1; rt0 = rt1; b0 = b1; } double yearFractionCurve = discountFactors.DayCount.relativeYearFraction(coupon.StartDate, coupon.EndDate); return(coupon.YearFraction * pv / yearFractionCurve); }