final ZonedDateTime[] premiumLegSchedule = PREMIUM_LEG_SCHEDULE.constructISDACompliantCreditDefaultSwapPremiumLegSchedule(cds);
final ZonedDateTime[] accruedLegIntegrationSchedule = ACRRUED_INTEGRATION_SCHEDULE.constructCreditDefaultSwapAccruedLegIntegrationSchedule(cds, curves);
final ZonedDateTime adjustedMaturityDate = PREMIUM_LEG_SCHEDULE.getAdjustedMaturityDate(cds);
ArgumentChecker.isTrue(!valuationDate.isAfter(adjustedMaturityDate), "Valuation date {} must be on or before the adjusted maturity date {}", valuationDate, adjustedMaturityDate);
final ISDADateCurve yieldCurve = curves.getYieldCurve();
final HazardRateCurve hazardRateCurve = curves.getHazardRateCurve();
// TODO : Check the effective date calc here
// If the valuation date is exactly the adjusted maturity date then simply return zero
/*
if (valuationDate.equals(adjustedMaturityDate) || cds.getEffectiveDate().equals(adjustedMaturityDate)) {
return 0.0;
}
*/
final ZonedDateTime today = valuationDate;
final ZonedDateTime stepinDate = cds.getEffectiveDate(); //TODO this relies on the person that's set up the CDS to know that effective date = 1 day after valuation date by convention
// The value date is when cash settlement is made
// TODO : Add the extra logic for this calculation
final ZonedDateTime matDate = cds.getMaturityDate();
// TODO : Check valueDate >= today and stepinDate >= today
if (today.isAfter(matDate) || stepinDate.isAfter(matDate)) {
return 0;
}
double thisPV = 0.0;
for (int i = 1; i < premiumLegSchedule.length; i++) {
final int obsOffset = cds.getProtectionStart() ? -1 : 0;
final ZonedDateTime accrualStartDate = premiumLegSchedule[i - 1];
ZonedDateTime accrualEndDate = premiumLegSchedule[i];
final ZonedDateTime discountDate = accrualEndDate;
// The last coupon date has an extra day of accrued
if (i == premiumLegSchedule.length - 1) {
accrualEndDate = accrualEndDate.plusDays(1);
}
final double delta = accrualEndDate.isAfter(stepinDate) ? 1 : 0;
final double accTime = ACT_360.getDayCountFraction(accrualStartDate, accrualEndDate);
final ZonedDateTime offsetAccrual = accrualEndDate.plusDays(obsOffset);
double tObsOffset = today.isAfter(offsetAccrual) ? -ACT_365.getDayCountFraction(offsetAccrual, today) : ACT_365.getDayCountFraction(today, offsetAccrual);
if (Double.compare(tObsOffset, -0.0) == 0) {
tObsOffset = 0;
}
double t = today.isAfter(discountDate) ? -ACT_365.getDayCountFraction(discountDate, today) : ACT_365.getDayCountFraction(today, discountDate);
final double survival = hazardRateCurve.getSurvivalProbability(tObsOffset);
final double discount = yieldCurve.getDiscountFactor(t);
thisPV += delta * accTime * discount * survival;
double myPV = 0.0;
if (cds.getIncludeAccruedPremium()) {
final ZonedDateTime offsetStepinDate = stepinDate.plusDays(obsOffset); // stepinDate
final ZonedDateTime offsetAccStartDate = accrualStartDate.plusDays(obsOffset); // startDate
final ZonedDateTime offsetAccEndDate = accrualEndDate.plusDays(obsOffset); // endDate
// TODO : Check endDate > startDate
final ZonedDateTime[] truncatedDateList = ScheduleUtils.getTruncatedTimeLine(accruedLegIntegrationSchedule, offsetAccStartDate, offsetAccEndDate, true);
ZonedDateTime subStartDate = offsetStepinDate.isAfter(offsetAccStartDate) ? offsetStepinDate : offsetAccStartDate;
final double tAcc = ACT_365.getDayCountFraction(offsetAccStartDate, offsetAccEndDate);
final double accRate = accTime / tAcc;
if (today.equals(subStartDate)) {
t = 0;
} else {
t = today.isBefore(subStartDate) ? ACT_365.getDayCountFraction(today, subStartDate) : -ACT_365.getDayCountFraction(subStartDate, today);
}
if (Double.compare(t, -0.0) == 0) {
t = 0;
}
double s0 = hazardRateCurve.getSurvivalProbability(t);
double df0 = yieldCurve.getDiscountFactor(t);
for (int j = 1; j < truncatedDateList.length; ++j) {
double thisAccPV = 0.0;
final ZonedDateTime date = truncatedDateList[j];
if (date.isAfter(offsetStepinDate)) {
t = today.isBefore(date) ? ACT_365.getDayCountFraction(today, date) : -ACT_365.getDayCountFraction(date, today); //TimeCalculator.getTimeBetween(today, truncatedDateList[j], ACT_365);
if (Double.compare(t, -0.0) == 0) {
t = 0;
}
final double s1 = hazardRateCurve.getSurvivalProbability(t);
final double df1 = yieldCurve.getDiscountFactor(t);
final double t0 = (offsetAccStartDate.isBefore(subStartDate) ? ACT_365.getDayCountFraction(offsetAccStartDate, subStartDate)
: ACT_365.getDayCountFraction(subStartDate, offsetAccStartDate)) + 0.5 / 365.0;
final double t1 = (offsetAccStartDate.isBefore(date) ? ACT_365.getDayCountFraction(offsetAccStartDate, date)
: ACT_365.getDayCountFraction(date, offsetAccStartDate)) + 0.5 / 365.0;