Updated with new Tenor class that verifies string during construction.

Now uses new Tenor class for Interest Rate Oracle
This commit is contained in:
Richard Green 2016-03-22 11:45:08 +00:00
parent d7d05a2f70
commit 6c0e696107
6 changed files with 45 additions and 22 deletions

View File

@ -10,7 +10,6 @@ package core
import java.math.BigDecimal
import java.time.DayOfWeek
import java.time.Duration
import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.util.*
@ -79,7 +78,7 @@ fun Iterable<Amount>.sumOrZero(currency: Currency) = if (iterator().hasNext()) s
//
/** A [FixOf] identifies the question side of a fix: what day, tenor and type of fix ("LIBOR", "EURIBOR" etc) */
data class FixOf(val name: String, val forDay: LocalDate, val ofTenor: Duration)
data class FixOf(val name: String, val forDay: LocalDate, val ofTenor: Tenor)
/** A [Fix] represents a named interest rate, on a given day, for a given duration. It can be embedded in a tx. */
data class Fix(val of: FixOf, val value: BigDecimal) : CommandData
@ -87,7 +86,13 @@ data class Fix(val of: FixOf, val value: BigDecimal) : CommandData
/**
* Placeholder class for the Tenor datatype - which is a standardised duration of time until maturity */
data class Tenor(var name:String) {
data class Tenor(val name:String) {
init {
val verifier = Regex("([0-9])+([DMYW])") // Only doing Overnight, Day, Week, Month, Year for now.
if (!(name == "ON" || verifier.containsMatchIn(name))) {
throw IllegalArgumentException("Unrecognized tenor : $name")
}
}
override fun toString(): String = "$name"
}

View File

@ -12,6 +12,7 @@ import org.junit.Test
import java.time.LocalDate
import java.util.*
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
class FinanceTypesTest {
@ -21,6 +22,19 @@ class FinanceTypesTest {
assert("0.01" in x.toString())
}
@Test
fun `valid tenor tests`() {
val exampleTenors = ("ON,1D,2D,3D,4D,5D,6D,7D,1W,2W,3W,1M,3M,6M,1Y,2Y,3Y,5Y,10Y,12Y,20Y").split(",")
exampleTenors.all { Tenor(it).name.length > 0 } // Slightly obtuse way of ensuring no exception thrown in construction.
}
@Test
fun `invalid tenor tests`() {
val exampleTenors = ("W,M,D,Z,2Q,p0,W1").split(",")
for (t in exampleTenors) {
assertFailsWith<java.lang.IllegalArgumentException> { Tenor(t) }
}
}
@Test
fun `schedule generator 1`() {

View File

@ -1,6 +1,6 @@
# Some pretend noddy rate fixes, for the interest rate oracles.
LIBOR 2016-03-16 30 = 0.678
LIBOR 2016-03-16 60 = 0.655
EURIBOR 2016-03-15 30 = 0.123
EURIBOR 2016-03-15 60 = 0.111
LIBOR 2016-03-16 1M = 0.678
LIBOR 2016-03-16 2M = 0.655
EURIBOR 2016-03-15 1M = 0.123
EURIBOR 2016-03-15 2M = 0.111

View File

@ -33,7 +33,7 @@ import javax.annotation.concurrent.ThreadSafe
* for signing.
*/
object NodeInterestRates {
/** Parses a string of the form "LIBOR 16-March-2016 30 = 0.678" into a [FixOf] and [Fix] */
/** Parses a string of the form "LIBOR 16-March-2016 1M = 0.678" into a [FixOf] and [Fix] */
fun parseOneRate(s: String): Pair<FixOf, Fix> {
val (key, value) = s.split('=').map { it.trim() }
val of = parseFixOf(key)
@ -41,10 +41,10 @@ object NodeInterestRates {
return of to Fix(of, rate)
}
/** Parses a string of the form "LIBOR 16-March-2016 30" into a [FixOf] */
/** Parses a string of the form "LIBOR 16-March-2016 1M" into a [FixOf] */
fun parseFixOf(key: String): FixOf {
val (name, date, days) = key.split(' ')
return FixOf(name, LocalDate.parse(date), days.toInt().days)
val (name, date, tenorString) = key.split(' ')
return FixOf(name, LocalDate.parse(date), Tenor(tenorString))
}
/** Parses lines containing fixes */

View File

@ -37,7 +37,7 @@ fun main(args: Array<String>) {
val oracleAddrArg = parser.accepts("oracle").withRequiredArg().required()
val oracleIdentityArg = parser.accepts("oracle-identity-file").withRequiredArg().required()
val fixOfArg = parser.accepts("fix-of").withRequiredArg().defaultsTo("LIBOR 2016-03-16 30")
val fixOfArg = parser.accepts("fix-of").withRequiredArg().defaultsTo("LIBOR 2016-03-16 1M")
val expectedRateArg = parser.accepts("expected-rate").withRequiredArg().defaultsTo("0.67")
val rateToleranceArg = parser.accepts("rate-tolerance").withRequiredArg().defaultsTo("0.1")

View File

@ -11,6 +11,10 @@ package core.node.services
import contracts.Cash
import core.*
import core.testing.MockNetwork
import core.DOLLARS
import core.Fix
import core.TransactionBuilder
import core.bd
import core.testutils.*
import core.utilities.BriefLogFormatter
import org.junit.Test
@ -20,16 +24,16 @@ import kotlin.test.assertFailsWith
class NodeInterestRatesTest {
val TEST_DATA = NodeInterestRates.parseFile("""
LIBOR 2016-03-16 30 = 0.678
LIBOR 2016-03-16 60 = 0.655
EURIBOR 2016-03-15 30 = 0.123
EURIBOR 2016-03-15 60 = 0.111
LIBOR 2016-03-16 1M = 0.678
LIBOR 2016-03-16 2M = 0.655
EURIBOR 2016-03-15 1M = 0.123
EURIBOR 2016-03-15 2M = 0.111
""".trimIndent())
val service = NodeInterestRates.Oracle(MEGA_CORP, MEGA_CORP_KEY).apply { knownFixes = TEST_DATA }
@Test fun `query successfully`() {
val q = NodeInterestRates.parseFixOf("LIBOR 2016-03-16 30")
val q = NodeInterestRates.parseFixOf("LIBOR 2016-03-16 1M")
val res = service.query(listOf(q))
assertEquals(1, res.size)
assertEquals("0.678".bd, res[0].value)
@ -37,8 +41,8 @@ class NodeInterestRatesTest {
}
@Test fun `query with one success and one missing`() {
val q1 = NodeInterestRates.parseFixOf("LIBOR 2016-03-16 30")
val q2 = NodeInterestRates.parseFixOf("LIBOR 2016-03-19 30")
val q1 = NodeInterestRates.parseFixOf("LIBOR 2016-03-16 1M")
val q2 = NodeInterestRates.parseFixOf("LIBOR 2016-03-19 1M")
val e = assertFailsWith<NodeInterestRates.UnknownFix> { service.query(listOf(q1, q2)) }
assertEquals(e.fix, q2)
}
@ -56,7 +60,7 @@ class NodeInterestRatesTest {
@Test fun `sign successfully`() {
val tx = makeTX()
val fix = service.query(listOf(NodeInterestRates.parseFixOf("LIBOR 2016-03-16 30"))).first()
val fix = service.query(listOf(NodeInterestRates.parseFixOf("LIBOR 2016-03-16 1M"))).first()
tx.addCommand(fix, service.identity.owningKey)
// Sign successfully.
@ -66,7 +70,7 @@ class NodeInterestRatesTest {
@Test fun `do not sign with unknown fix`() {
val tx = makeTX()
val fixOf = NodeInterestRates.parseFixOf("LIBOR 2016-03-16 30")
val fixOf = NodeInterestRates.parseFixOf("LIBOR 2016-03-16 1M")
val badFix = Fix(fixOf, "0.6789".bd)
tx.addCommand(badFix, service.identity.owningKey)
@ -81,7 +85,7 @@ class NodeInterestRatesTest {
NodeInterestRates.Service(n2).oracle.knownFixes = TEST_DATA
val tx = TransactionBuilder()
val fixOf = NodeInterestRates.parseFixOf("LIBOR 2016-03-16 30")
val fixOf = NodeInterestRates.parseFixOf("LIBOR 2016-03-16 1M")
val protocol = RatesFixProtocol(tx, n2.legallyIdentifableAddress, fixOf, "0.675".bd, "0.1".bd)
BriefLogFormatter.initVerbose("rates")
val future = n1.smm.add("rates", protocol)