ArgumentChecker.notNull(startDate, "CDS start date");
ArgumentChecker.notNull(maturity, "CDS maturity");
ArgumentChecker.notNull(frequency, "frequency");
ArgumentChecker.notNull(convention, "convention");
final DayCount dayCount = convention.getDayCount();
ArgumentChecker.isTrue(!(dayCount instanceof ActualActualICMA) | !(dayCount instanceof ActualActualICMANormal), "Coupon per year required for Actual Actual ICMA");
// TODO: Handle stubType == StubType.NONE
final boolean isStubShort = stubType == StubType.SHORT_START || stubType == StubType.SHORT_END;
final boolean isStubAtEnd = stubType == StubType.SHORT_END || stubType == StubType.LONG_END;
// If the stub is at the end of the schedule, compute the schedule from the beginning, and vice versa
final ZonedDateTime[] paymentDates = ScheduleCalculator.getAdjustedDateSchedule(startDate, maturity, frequency,
isStubShort, !isStubAtEnd, convention.getBusinessDayConvention(), convention.getWorkingDayCalendar(), /* EOM */ false);
final ZonedDateTime maturityWithOffset = protectStart ? maturity.plusDays(1) : maturity;
final ISDACDSCouponDefinition[] coupons = new ISDACDSCouponDefinition[paymentDates.length];
final int maturityIndex = coupons.length - 1;
if (maturityIndex > 0) {
// accrual start date is not adjusted for the first coupon
coupons[0] = new ISDACDSCouponDefinition(currency, paymentDates[0], startDate, paymentDates[0],
dayCount.getDayCountFraction(startDate, paymentDates[0]), notional, spread);
for (int i = 1; i < maturityIndex; i++) {
coupons[i] = new ISDACDSCouponDefinition(currency, paymentDates[i], paymentDates[i - 1], paymentDates[i],
dayCount.getDayCountFraction(paymentDates[i - 1], paymentDates[i]), notional, spread);
}
// Accrual end date is not adjusted for the last coupon
coupons[maturityIndex] = new ISDACDSCouponDefinition(currency, paymentDates[maturityIndex], paymentDates[maturityIndex - 1], maturity,
dayCount.getDayCountFraction(paymentDates[maturityIndex - 1], maturityWithOffset), notional, spread);
} else {
// For a premium consisting of a single payment, neither the accrual start nor end date is adjusted
coupons[0] = new ISDACDSCouponDefinition(currency, paymentDates[0], startDate, maturity,
dayCount.getDayCountFraction(startDate, maturityWithOffset), notional, spread);
}
return new ISDACDSPremiumDefinition(coupons, calendar);
}