Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for duplicate dates removal if combinePeriodsIfNecessary is set to true #2603

Merged
merged 7 commits into from
Nov 23, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ public Schedule createSchedule(ReferenceData refData, boolean combinePeriodsIfNe
adj = new ArrayList<>(adj);
unadj = new ArrayList<>(unadj);
for (int i = 0; i < adj.size() - 1; i++) {
if (adj.get(i).equals(adj.get(i + 1))) {
while (i < adj.size() - 1 && adj.get(i).equals(adj.get(i + 1))) {
adj.remove(i);
unadj.remove(i);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import static com.opengamma.strata.basics.date.HolidayCalendarIds.NO_HOLIDAYS;
import static com.opengamma.strata.basics.date.HolidayCalendarIds.SAT_SUN;
import static com.opengamma.strata.basics.schedule.Frequency.P12M;
import static com.opengamma.strata.basics.schedule.Frequency.P1D;
import static com.opengamma.strata.basics.schedule.Frequency.P1M;
import static com.opengamma.strata.basics.schedule.Frequency.P1W;
import static com.opengamma.strata.basics.schedule.Frequency.P2M;
Expand Down Expand Up @@ -73,6 +74,7 @@
import com.opengamma.strata.basics.date.BusinessDayConvention;
import com.opengamma.strata.basics.date.HolidayCalendar;
import com.opengamma.strata.basics.date.HolidayCalendarId;
import com.opengamma.strata.basics.date.HolidayCalendarIds;
import com.opengamma.strata.basics.date.HolidayCalendars;

/**
Expand Down Expand Up @@ -1208,6 +1210,49 @@ public HolidayCalendarId getId() {
assertThat(schedule.getPeriod(2).getStartDate()).isEqualTo(date(2020, 10, 9));
}

@Test
public void test_combinePeriodsWhenNecessary_1d_createSchedule_duplicate_exception() {
HolidayCalendarId id = SAT_SUN;
HolidayCalendar calendar = HolidayCalendars.SAT_SUN;

ReferenceData referenceData = ImmutableReferenceData.of(id, calendar);
BusinessDayAdjustment businessDayAdjustment = BusinessDayAdjustment.of(MODIFIED_FOLLOWING, id);
PeriodicSchedule defn = PeriodicSchedule.builder()
.startDate(date(2020, 9, 18))
.endDate(date(2020, 12, 18))
.frequency(P1D)
.businessDayAdjustment(businessDayAdjustment)
.stubConvention(SHORT_FINAL)
.rollConvention(null)
.build();

Schedule schedule = defn.createSchedule(referenceData, true);
assertThat(schedule.getPeriods()).hasSize(65);
assertThat(schedule.getPeriod(0).getStartDate()).isEqualTo(date(2020, 9, 18));
assertThat(schedule.getPeriod(0).getEndDate()).isEqualTo(date(2020, 9, 21));
}

@Test
public void test_combinePeriodsWhenNecessary_1d_createSchedule() {
HolidayCalendarId id = SAT_SUN;
HolidayCalendar calendar = HolidayCalendars.SAT_SUN;

ReferenceData referenceData = ImmutableReferenceData.of(id, calendar);
BusinessDayAdjustment businessDayAdjustment = BusinessDayAdjustment.of(MODIFIED_FOLLOWING, id);
PeriodicSchedule defn = PeriodicSchedule.builder()
.startDate(date(2020, 9, 18))
.endDate(date(2020, 12, 18))
.frequency(P1D)
.businessDayAdjustment(businessDayAdjustment)
.stubConvention(SHORT_FINAL)
.rollConvention(null)
.build();

assertThatExceptionOfType(ScheduleException.class)
.isThrownBy(() -> defn.createSchedule(referenceData, false))
.withMessageMatching(".*duplicate adjusted dates.*");
}

@Test
public void test_emptyWhenAdjusted_twoPeriods_createUnadjustedDates() {
PeriodicSchedule defn = PeriodicSchedule.builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,16 @@ private void validate() {
"The ex-coupon period is measured from the payment date, thus the days must be non-positive");
}

//-------------------------------------------------------------------------
/**
* Resolves fixed coupon bond using specified reference data.
* @param refData the reference data to use when resolving
* @return the resolved instance
* @throws ReferenceDataNotFoundException if an identifier cannot be resolved in the reference data
* @throws RuntimeException if unable to resolve due to an invalid definition
*/
@Override
public ResolvedFixedCouponBond resolve(ReferenceData refData) {
Schedule adjustedSchedule = accrualSchedule.createSchedule(refData);
Schedule adjustedSchedule = accrualSchedule.createSchedule(refData, true);
Schedule unadjustedSchedule = adjustedSchedule.toUnadjusted();
DateAdjuster exCouponPeriodAdjuster = exCouponPeriod.resolve(refData);

Expand Down
Loading