internal virtual PointSensitivityBuilder riskyAnnuitySensitivity(ResolvedCds cds, CreditDiscountFactors discountFactors, LegalEntitySurvivalProbabilities survivalProbabilities, LocalDate referenceDate, LocalDate stepinDate, LocalDate effectiveStartDate) { double pv = 0d; PointSensitivityBuilder pvSensi = PointSensitivityBuilder.none(); foreach (CreditCouponPaymentPeriod coupon in cds.PaymentPeriods) { if (stepinDate.isBefore(coupon.EndDate)) { double q = survivalProbabilities.survivalProbability(coupon.EffectiveEndDate); PointSensitivityBuilder qSensi = survivalProbabilities.zeroRatePointSensitivity(coupon.EffectiveEndDate); double p = discountFactors.discountFactor(coupon.PaymentDate); PointSensitivityBuilder pSensi = discountFactors.zeroRatePointSensitivity(coupon.PaymentDate); pv += coupon.YearFraction * p * q; pvSensi = pvSensi.combinedWith(pSensi.multipliedBy(coupon.YearFraction * q).combinedWith(qSensi.multipliedBy(coupon.YearFraction * p))); } } if (cds.PaymentOnDefault.AccruedInterest) { // This is needed so that the code is consistent with ISDA C when the Markit `fix' is used. LocalDate start = cds.PaymentPeriods.size() == 1 ? effectiveStartDate : cds.AccrualStartDate; DoubleArray integrationSchedule = DoublesScheduleGenerator.getIntegrationsPoints(discountFactors.relativeYearFraction(start), discountFactors.relativeYearFraction(cds.ProtectionEndDate), discountFactors.ParameterKeys, survivalProbabilities.ParameterKeys); foreach (CreditCouponPaymentPeriod coupon in cds.PaymentPeriods) { Pair <double, PointSensitivityBuilder> pvAndSensi = singlePeriodAccrualOnDefaultSensitivity(coupon, effectiveStartDate, integrationSchedule, discountFactors, survivalProbabilities); pv += pvAndSensi.First; pvSensi = pvSensi.combinedWith(pvAndSensi.Second); } } double df = discountFactors.discountFactor(referenceDate); PointSensitivityBuilder dfSensi = discountFactors.zeroRatePointSensitivity(referenceDate).multipliedBy(-pv / (df * df)); pvSensi = pvSensi.multipliedBy(1d / df); return(dfSensi.combinedWith(pvSensi)); }
// computes risky annuity internal virtual double riskyAnnuity(ResolvedCds cds, CreditDiscountFactors discountFactors, LegalEntitySurvivalProbabilities survivalProbabilities, LocalDate referenceDate, LocalDate stepinDate, LocalDate effectiveStartDate, PriceType priceType) { double pv = 0d; foreach (CreditCouponPaymentPeriod coupon in cds.PaymentPeriods) { if (stepinDate.isBefore(coupon.EndDate)) { double q = survivalProbabilities.survivalProbability(coupon.EffectiveEndDate); double p = discountFactors.discountFactor(coupon.PaymentDate); pv += coupon.YearFraction * p * q; } } if (cds.PaymentOnDefault.AccruedInterest) { // This is needed so that the code is consistent with ISDA C when the Markit `fix' is used. LocalDate start = cds.PaymentPeriods.size() == 1 ? effectiveStartDate : cds.AccrualStartDate; DoubleArray integrationSchedule = DoublesScheduleGenerator.getIntegrationsPoints(discountFactors.relativeYearFraction(start), discountFactors.relativeYearFraction(cds.ProtectionEndDate), discountFactors.ParameterKeys, survivalProbabilities.ParameterKeys); foreach (CreditCouponPaymentPeriod coupon in cds.PaymentPeriods) { pv += singlePeriodAccrualOnDefault(coupon, effectiveStartDate, integrationSchedule, discountFactors, survivalProbabilities); } } // roll to the cash settle date double df = discountFactors.discountFactor(referenceDate); pv /= df; if (priceType.CleanPrice) { pv -= cds.accruedYearFraction(stepinDate); } return(pv); }
// 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); }
public Pricer(FastCreditCurveCalibrator outerInstance, ResolvedCds nodeCds, CreditDiscountFactors yieldCurve, DoubleArray creditCurveKnots, double fractionalSpread, double pointsUpfront, double lgd, LocalDate stepinDate, LocalDate effectiveStartDate, LocalDate settlementDate, double accruedYearFraction) { this.outerInstance = outerInstance; accYearFraction = accruedYearFraction; cds = nodeCds; fracSpread = fractionalSpread; puf = pointsUpfront; productEffectiveStart = yieldCurve.relativeYearFraction(effectiveStartDate); double protectionEnd = yieldCurve.relativeYearFraction(cds.ProtectionEndDate); // protection leg proLegIntPoints = DoublesScheduleGenerator.getIntegrationsPoints(productEffectiveStart, protectionEnd, yieldCurve.ParameterKeys, creditCurveKnots).toArray(); nProPoints = proLegIntPoints.Length; valuationDF = yieldCurve.discountFactor(settlementDate); lgdDF = lgd / valuationDF; proYieldCurveRT = new double[nProPoints]; proDF = new double[nProPoints]; for (int i = 0; i < nProPoints; i++) { proYieldCurveRT[i] = yieldCurve.zeroRate(proLegIntPoints[i]) * proLegIntPoints[i]; proDF[i] = Math.Exp(-proYieldCurveRT[i]); } // premium leg nPayments = cds.PaymentPeriods.size(); paymentDF = new double[nPayments]; int indexTmp = -1; for (int i = 0; i < nPayments; i++) { if (stepinDate.isBefore(cds.PaymentPeriods.get(i).EndDate)) { paymentDF[i] = yieldCurve.discountFactor(cds.PaymentPeriods.get(i).PaymentDate); } else { indexTmp = i; } } startPeriodIndex = indexTmp + 1; // accrual on default if (cds.PaymentOnDefault.AccruedInterest) { LocalDate tmp = nPayments == 1 ? effectiveStartDate : cds.AccrualStartDate; DoubleArray integrationSchedule = DoublesScheduleGenerator.getIntegrationsPoints(yieldCurve.relativeYearFraction(tmp), protectionEnd, yieldCurve.ParameterKeys, creditCurveKnots); accRate = new double[nPayments]; offsetAccStart = new double[nPayments]; offsetAccEnd = new double[nPayments]; premLegIntPoints = new double[nPayments][]; premDF = new double[nPayments][]; rt = new double[nPayments][]; premDt = new double[nPayments][]; for (int i = startPeriodIndex; i < nPayments; i++) { CreditCouponPaymentPeriod coupon = cds.PaymentPeriods.get(i); offsetAccStart[i] = yieldCurve.relativeYearFraction(coupon.EffectiveStartDate); offsetAccEnd[i] = yieldCurve.relativeYearFraction(coupon.EffectiveEndDate); accRate[i] = coupon.YearFraction / yieldCurve.DayCount.relativeYearFraction(coupon.StartDate, coupon.EndDate); double start = Math.Max(productEffectiveStart, offsetAccStart[i]); if (start >= offsetAccEnd[i]) { continue; } premLegIntPoints[i] = DoublesScheduleGenerator.truncateSetInclusive(start, offsetAccEnd[i], integrationSchedule).toArray(); int n = premLegIntPoints[i].Length; rt[i] = new double[n]; premDF[i] = new double[n]; for (int k = 0; k < n; k++) { rt[i][k] = yieldCurve.zeroRate(premLegIntPoints[i][k]) * premLegIntPoints[i][k]; premDF[i][k] = Math.Exp(-rt[i][k]); } premDt[i] = new double[n - 1]; for (int k = 1; k < n; k++) { //JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final': //ORIGINAL LINE: final double dt = premLegIntPoints[i][k] - premLegIntPoints[i][k - 1]; double dt = premLegIntPoints[i][k] - premLegIntPoints[i][k - 1]; premDt[i][k - 1] = dt; } } } else { accRate = null; offsetAccStart = null; offsetAccEnd = null; premDF = null; premDt = null; rt = null; premLegIntPoints = null; } }
//------------------------------------------------------------------------- public virtual void test_survivalProbability() { LegalEntitySurvivalProbabilities test = LegalEntitySurvivalProbabilities.of(LEGAL_ENTITY, DFS); assertEquals(test.survivalProbability(DATE_AFTER), DFS.discountFactor(DATE_AFTER)); }
//------------------------------------------------------------------------- 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)); }