From 86203709c095e1bf748bfb838517da12d58a36c3 Mon Sep 17 00:00:00 2001 From: Richard Green Date: Mon, 13 Jun 2016 19:00:27 +0100 Subject: [PATCH 1/3] Payment dates now are calculated as an offset to the period end date --- .../main/kotlin/com/r3corda/contracts/IRS.kt | 13 ++++++++----- .../kotlin/com/r3corda/contracts/IRSTests.kt | 6 +++--- .../r3corda/core/contracts/FinanceTypes.kt | 19 ++++++++++++++----- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/IRS.kt b/contracts/src/main/kotlin/com/r3corda/contracts/IRS.kt index eb662a3cd0..1a96194a4c 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/IRS.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/IRS.kt @@ -1,6 +1,5 @@ package com.r3corda.contracts -import com.r3corda.core.* import com.r3corda.core.contracts.* import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.SecureHash @@ -672,15 +671,18 @@ class InterestRateSwap() : Contract { // Create a schedule for the fixed payments for (periodEndDate in dates) { + val paymentDate = BusinessCalendar.getOffsetDate(periodEndDate, Frequency.Daily, fixedLeg.paymentDelay) // + fixedLeg.paymentDelay val paymentEvent = FixedRatePaymentEvent( // TODO: We are assuming the payment date is the end date of the accrual period. - periodEndDate, periodStartDate, periodEndDate, + paymentDate, + periodStartDate, + periodEndDate, fixedLeg.dayCountBasisDay, fixedLeg.dayCountBasisYear, fixedLeg.notional, fixedLeg.fixedRate ) - fixedLegPaymentSchedule[periodEndDate] = paymentEvent + fixedLegPaymentSchedule[paymentDate] = paymentEvent periodStartDate = periodEndDate } @@ -695,8 +697,9 @@ class InterestRateSwap() : Contract { // Now create a schedule for the floating and fixes. for (periodEndDate in dates) { + val paymentDate = BusinessCalendar.getOffsetDate(periodEndDate, Frequency.Daily, floatingLeg.paymentDelay) // + fixedLeg.paymentDelay val paymentEvent = FloatingRatePaymentEvent( - periodEndDate, + paymentDate, periodStartDate, periodEndDate, floatingLeg.dayCountBasisDay, @@ -706,7 +709,7 @@ class InterestRateSwap() : Contract { ReferenceRate(floatingLeg.indexSource, floatingLeg.indexTenor, floatingLeg.index) ) - floatingLegPaymentSchedule.put(periodEndDate, paymentEvent) + floatingLegPaymentSchedule[paymentDate] = paymentEvent periodStartDate = periodEndDate } diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/IRSTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/IRSTests.kt index 0d94e41e5e..9becc9a9d3 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/IRSTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/IRSTests.kt @@ -27,7 +27,7 @@ fun createDummyIRS(irsSelect: Int): InterestRateSwap.State { rollConvention = DateRollConvention.ModifiedFollowing, dayInMonth = 10, paymentRule = PaymentRule.InArrears, - paymentDelay = 0, + paymentDelay = 3, paymentCalendar = BusinessCalendar.getInstance("London", "NewYork"), interestPeriodAdjustment = AccrualAdjustment.Adjusted ) @@ -47,7 +47,7 @@ fun createDummyIRS(irsSelect: Int): InterestRateSwap.State { dayInMonth = 10, resetDayInMonth = 10, paymentRule = PaymentRule.InArrears, - paymentDelay = 0, + paymentDelay = 3, paymentCalendar = BusinessCalendar.getInstance("London", "NewYork"), interestPeriodAdjustment = AccrualAdjustment.Adjusted, fixingPeriod = DateOffset.TWODAYS, @@ -360,7 +360,7 @@ class IRSTests { for (i in stuffToPrint) { println(i) - var z = dummyIRS.evaluateCalculation(LocalDate.of(2016, 9, 12), Expression(i)) + var z = dummyIRS.evaluateCalculation(LocalDate.of(2016, 9, 15), Expression(i)) println(z.javaClass) println(z) println("-----------") diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/FinanceTypes.kt b/core/src/main/kotlin/com/r3corda/core/contracts/FinanceTypes.kt index 0ec4c99d3c..3347342aa0 100644 --- a/core/src/main/kotlin/com/r3corda/core/contracts/FinanceTypes.kt +++ b/core/src/main/kotlin/com/r3corda/core/contracts/FinanceTypes.kt @@ -8,7 +8,6 @@ import com.fasterxml.jackson.databind.JsonSerializer import com.fasterxml.jackson.databind.SerializerProvider import com.fasterxml.jackson.databind.annotation.JsonDeserialize import com.fasterxml.jackson.databind.annotation.JsonSerialize -import com.r3corda.core.contracts.CommandData import java.math.BigDecimal import java.time.DayOfWeek import java.time.LocalDate @@ -267,6 +266,9 @@ enum class Frequency(val annualCompoundCount: Int) { }, BiWeekly(26) { override fun offset(d: LocalDate) = d.plusWeeks(2) + }, + Daily(365) { + override fun offset(d: LocalDate) = d.plusDays(1) }; abstract fun offset(d: LocalDate): LocalDate @@ -317,11 +319,9 @@ open class BusinessCalendar private constructor(val calendars: Array var currentDate = startDate while (true) { - currentDate = period.offset(currentDate) - val scheduleDate = calendar.applyRollConvention(currentDate, dateRollConvention) - + currentDate = getOffsetDate(currentDate, period) if (periodOffset == null || periodOffset <= ctr) - ret.add(scheduleDate) + ret.add(calendar.applyRollConvention(currentDate, dateRollConvention)) ctr += 1 // TODO: Fix addl period logic if ((ctr > noOfAdditionalPeriods ) || (currentDate >= endDate ?: currentDate )) @@ -329,8 +329,17 @@ open class BusinessCalendar private constructor(val calendars: Array } return ret } + + fun getOffsetDate(startDate: LocalDate, period: Frequency, howMany: Int = 1): LocalDate { + if (howMany == 0) return startDate + var nextDate = startDate + repeat(howMany) { nextDate = period.offset(nextDate) } + return nextDate + } } + + override fun equals(other: Any?): Boolean = if (other is BusinessCalendar) { /** Note this comparison is OK as we ensure they are sorted in getInstance() */ this.holidayDates == other.holidayDates From 2ce0dce0aafa7c0309e47d9a06acde9fe403c482 Mon Sep 17 00:00:00 2001 From: Richard Green Date: Tue, 14 Jun 2016 11:28:58 +0100 Subject: [PATCH 2/3] . --- .../main/kotlin/com/r3corda/contracts/IRS.kt | 1 - .../r3corda/core/contracts/FinanceTypes.kt | 31 +++++++++---------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/IRS.kt b/contracts/src/main/kotlin/com/r3corda/contracts/IRS.kt index 1a96194a4c..542670e7ca 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/IRS.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/IRS.kt @@ -673,7 +673,6 @@ class InterestRateSwap() : Contract { for (periodEndDate in dates) { val paymentDate = BusinessCalendar.getOffsetDate(periodEndDate, Frequency.Daily, fixedLeg.paymentDelay) // + fixedLeg.paymentDelay val paymentEvent = FixedRatePaymentEvent( - // TODO: We are assuming the payment date is the end date of the accrual period. paymentDate, periodStartDate, periodEndDate, diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/FinanceTypes.kt b/core/src/main/kotlin/com/r3corda/core/contracts/FinanceTypes.kt index 3347342aa0..bcd41b52b0 100644 --- a/core/src/main/kotlin/com/r3corda/core/contracts/FinanceTypes.kt +++ b/core/src/main/kotlin/com/r3corda/core/contracts/FinanceTypes.kt @@ -250,28 +250,28 @@ enum class DateOffset { */ enum class Frequency(val annualCompoundCount: Int) { Annual(1) { - override fun offset(d: LocalDate) = d.plusYears(1) + override fun offset(d: LocalDate, n: Long) = d.plusYears(1 * n) }, SemiAnnual(2) { - override fun offset(d: LocalDate) = d.plusMonths(6) + override fun offset(d: LocalDate, n: Long) = d.plusMonths(6 * n) }, Quarterly(4) { - override fun offset(d: LocalDate) = d.plusMonths(3) + override fun offset(d: LocalDate, n: Long) = d.plusMonths(3 * n) }, Monthly(12) { - override fun offset(d: LocalDate) = d.plusMonths(1) + override fun offset(d: LocalDate, n: Long) = d.plusMonths(1 * n) }, Weekly(52) { - override fun offset(d: LocalDate) = d.plusWeeks(1) + override fun offset(d: LocalDate, n: Long) = d.plusWeeks(1 * n) }, BiWeekly(26) { - override fun offset(d: LocalDate) = d.plusWeeks(2) + override fun offset(d: LocalDate, n: Long) = d.plusWeeks(2 * n) }, Daily(365) { - override fun offset(d: LocalDate) = d.plusDays(1) + override fun offset(d: LocalDate, n: Long) = d.plusDays(1 * n) }; - abstract fun offset(d: LocalDate): LocalDate + abstract fun offset(d: LocalDate, n: Long = 1): LocalDate // Daily() // Let's not worry about this for now. } @@ -324,22 +324,21 @@ open class BusinessCalendar private constructor(val calendars: Array ret.add(calendar.applyRollConvention(currentDate, dateRollConvention)) ctr += 1 // TODO: Fix addl period logic - if ((ctr > noOfAdditionalPeriods ) || (currentDate >= endDate ?: currentDate )) + if ((ctr > noOfAdditionalPeriods) || (currentDate >= endDate ?: currentDate)) break } return ret } - fun getOffsetDate(startDate: LocalDate, period: Frequency, howMany: Int = 1): LocalDate { - if (howMany == 0) return startDate - var nextDate = startDate - repeat(howMany) { nextDate = period.offset(nextDate) } - return nextDate + /** Calculates the date from @startDate moving forward @steps of time size @period. Does not apply calendar + * logic / roll conventions. + */ + fun getOffsetDate(startDate: LocalDate, period: Frequency, steps: Int = 1): LocalDate { + if (steps == 0) return startDate + return period.offset(startDate, steps.toLong()) } } - - override fun equals(other: Any?): Boolean = if (other is BusinessCalendar) { /** Note this comparison is OK as we ensure they are sorted in getInstance() */ this.holidayDates == other.holidayDates From 3ab3955213b585b4f1949a14eb982428e50d9261 Mon Sep 17 00:00:00 2001 From: Richard Green Date: Tue, 14 Jun 2016 11:57:55 +0100 Subject: [PATCH 3/3] . --- contracts/src/main/kotlin/com/r3corda/contracts/IRS.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/IRS.kt b/contracts/src/main/kotlin/com/r3corda/contracts/IRS.kt index 542670e7ca..49bb534a87 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/IRS.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/IRS.kt @@ -671,7 +671,7 @@ class InterestRateSwap() : Contract { // Create a schedule for the fixed payments for (periodEndDate in dates) { - val paymentDate = BusinessCalendar.getOffsetDate(periodEndDate, Frequency.Daily, fixedLeg.paymentDelay) // + fixedLeg.paymentDelay + val paymentDate = BusinessCalendar.getOffsetDate(periodEndDate, Frequency.Daily, fixedLeg.paymentDelay) val paymentEvent = FixedRatePaymentEvent( paymentDate, periodStartDate, @@ -696,7 +696,7 @@ class InterestRateSwap() : Contract { // Now create a schedule for the floating and fixes. for (periodEndDate in dates) { - val paymentDate = BusinessCalendar.getOffsetDate(periodEndDate, Frequency.Daily, floatingLeg.paymentDelay) // + fixedLeg.paymentDelay + val paymentDate = BusinessCalendar.getOffsetDate(periodEndDate, Frequency.Daily, floatingLeg.paymentDelay) val paymentEvent = FloatingRatePaymentEvent( paymentDate, periodStartDate,