First working commit

First working commit

Formatting clean up

Revert All_tests.xml

Remove extra space

Feedback from code review

First working commit

Revert All_tests.xml

Remove extra space

Feedback from code review
This commit is contained in:
rick.parker 2016-03-23 11:15:09 +00:00
parent c450c70f9a
commit 791022f130
18 changed files with 260 additions and 102 deletions

View File

@ -8,6 +8,15 @@
package contracts
import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonDeserializer
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.fasterxml.jackson.databind.type.SimpleType
import core.*
import core.crypto.SecureHash
import core.node.services.DummyTimestampingAuthority
@ -15,6 +24,7 @@ import org.apache.commons.jexl3.JexlBuilder
import org.apache.commons.jexl3.MapContext
import java.math.BigDecimal
import java.math.RoundingMode
import java.security.PublicKey
import java.time.LocalDate
import java.util.*
@ -167,8 +177,6 @@ class InterestRateSwap() : Contract {
val hashLegalDocs: String
)
data class Expression(val expr: String)
/**
* The Calculation data class is "mutable" through out the life of the swap, as in, it's the only thing that contains
* data that will changed from state to state (Recall that the design insists that everything is immutable, so we actually
@ -177,7 +185,7 @@ class InterestRateSwap() : Contract {
data class Calculation(
val expression: Expression,
val floatingLegPaymentSchedule: Map<LocalDate, FloatingRatePaymentEvent>,
val fixedLegpaymentSchedule: Map<LocalDate, FixedRatePaymentEvent>
val fixedLegPaymentSchedule: Map<LocalDate, FixedRatePaymentEvent>
) {
/**
* Gets the date of the next fixing.
@ -185,7 +193,7 @@ class InterestRateSwap() : Contract {
*/
fun nextFixingDate(): LocalDate? {
return floatingLegPaymentSchedule.
filter { it.value.rate is OracleRetrievableReferenceRate }.// TODO - a better way to determine what fixings remain to be fixed
filter { it.value.rate is ReferenceRate }.// TODO - a better way to determine what fixings remain to be fixed
minBy { it.value.fixingDate.toEpochDay() }?.value?.fixingDate
}
@ -203,7 +211,7 @@ class InterestRateSwap() : Contract {
val newFloatingLPS = floatingLegPaymentSchedule + (paymentEvent.date to paymentEvent.withNewRate(newRate))
return Calculation(expression = expression,
floatingLegPaymentSchedule = newFloatingLPS,
fixedLegpaymentSchedule = fixedLegpaymentSchedule)
fixedLegPaymentSchedule = fixedLegPaymentSchedule)
}
fun exportSchedule() {
@ -297,7 +305,7 @@ class InterestRateSwap() : Contract {
*/
override fun verify(tx: TransactionForVerification) {
val command = tx.commands.requireSingleCommand<InterestRateSwap.Commands>()
val time = tx.getTimestampBy(DummyTimestampingAuthority.identity)?.midpoint
val time = tx.commands.getTimestampByName("Mock Company 0", "Bank of Zurich")?.midpoint
if (time == null) throw IllegalArgumentException("must be timestamped")
val irs = tx.outStates.filterIsInstance<InterestRateSwap.State>().single()
@ -306,7 +314,7 @@ class InterestRateSwap() : Contract {
requireThat {
"There are no in states for an agreement" by tx.inStates.isEmpty()
"The fixed rate is non zero" by (irs.fixedLeg.fixedRate != FixedRate(PercentageRatioUnit("0.0")))
"There are events in the fix schedule" by (irs.calculation.fixedLegpaymentSchedule.size > 0)
"There are events in the fix schedule" by (irs.calculation.fixedLegPaymentSchedule.size > 0)
"There are events in the float schedule" by (irs.calculation.floatingLegPaymentSchedule.size > 0)
// "There are fixes in the schedule" by (irs.calculation.floatingLegPaymentSchedule!!.size > 0)
// TODO: shortlist of other tests
@ -348,8 +356,14 @@ class InterestRateSwap() : Contract {
val floatingLeg: FloatingLeg,
val calculation: Calculation,
val common: Common
) : ContractState {
) : LinearState {
override val programRef = IRS_PROGRAM_ID
override val thread = SecureHash.sha256(common.tradeID)
override val ref = common.tradeID
override fun isRelevant(ourKeys: Set<PublicKey>): Boolean {
return (fixedLeg.fixedRatePayer.owningKey in ourKeys) || (floatingLeg.floatingRatePayer.owningKey in ourKeys)
}
/**
* For evaluating arbitrary java on the platform
@ -408,9 +422,6 @@ class InterestRateSwap() : Contract {
var floatingLegPaymentSchedule: MutableMap<LocalDate, FloatingRatePaymentEvent> = HashMap()
periodStartDate = floatingLeg.effectiveDate
// TODO: Temporary until implemented via Rates Oracle.
val telerate = TelerateOracle("3750")
// Now create a schedule for the floating and fixes.
for (periodEndDate in dates) {
val paymentEvent = FloatingRatePaymentEvent(
@ -421,8 +432,7 @@ class InterestRateSwap() : Contract {
floatingLeg.dayCountBasisYear,
calcFixingDate(periodStartDate, floatingLeg.fixingPeriod, floatingLeg.fixingCalendar),
floatingLeg.notional,
// TODO: OracleRetrievableReferenceRate will be replaced via oracle v soon.
OracleRetrievableReferenceRate(telerate, floatingLeg.indexTenor, floatingLeg.index)
ReferenceRate(floatingLeg.indexSource, floatingLeg.indexTenor, floatingLeg.index)
)
floatingLegPaymentSchedule.put(periodEndDate, paymentEvent)

View File

@ -10,6 +10,6 @@ package contracts
fun InterestRateSwap.State.exportIRSToCSV() : String =
"Fixed Leg\n" + FixedRatePaymentEvent.CSVHeader + "\n" +
this.calculation.fixedLegpaymentSchedule.toSortedMap().values.map{ it.asCSV() }.joinToString("\n") + "\n" +
this.calculation.fixedLegPaymentSchedule.toSortedMap().values.map{ it.asCSV() }.joinToString("\n") + "\n" +
"Floating Leg\n" + FloatingRatePaymentEvent.CSVHeader + "\n" +
this.calculation.floatingLegPaymentSchedule.toSortedMap().values.map{ it.asCSV() }.joinToString("\n") + "\n"

View File

@ -1,5 +1,13 @@
package contracts
import com.fasterxml.jackson.core.JsonParseException
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonDeserializer
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import com.fasterxml.jackson.databind.annotation.JsonSerialize
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer
import com.fasterxml.jackson.databind.type.SimpleType
import core.Amount
import core.Tenor
import java.math.BigDecimal
@ -50,43 +58,7 @@ open class FloatingRate: Rate(null)
* So a reference rate is a rate that takes its value from a source at a given date
* e.g. LIBOR 6M as of 17 March 2016. Hence it requires a source (name) and a value date in the getAsOf(..) method.
*/
abstract class ReferenceRate(val name: String): FloatingRate() {
abstract fun getAsOf(date: LocalDate?) : RatioUnit
}
/**
* A concrete implementation of the above for testing purposes
*/
open class TestReferenceRate(val testrate: String) : ReferenceRate(testrate) {
override fun getAsOf(date: LocalDate?) : RatioUnit {
return testrate.percent
}
}
/**
* This represents a source of data.
*/
abstract class Oracle() { abstract fun retrieve(tenor: Tenor, date: LocalDate) : RatioUnit }
class ReutersOracle() : Oracle() {
override fun retrieve(tenor: Tenor, date: LocalDate): RatioUnit {
TODO("Reuters Oracle retrieval")
}
}
class TelerateOracle(page: String) : Oracle() {
override fun retrieve(tenor: Tenor, date: LocalDate): RatioUnit {
TODO("Telerate Oracle retrieval")
}
}
/**
* A Reference rate that is retrieved via an Oracle.
*/
open class OracleRetrievableReferenceRate(val oracle: Oracle, val tenor: Tenor, referenceRate: String) : ReferenceRate(referenceRate) {
override fun getAsOf(date: LocalDate?): RatioUnit {
return oracle.retrieve(tenor,date!!)
}
class ReferenceRate(val oracle: String, val tenor: Tenor, val name: String) : FloatingRate() {
override fun toString(): String = "$name - $tenor"
}

View File

@ -47,4 +47,7 @@ dependencies {
// Apache JEXL: An embeddable expression evaluation library.
// This may be temporary until we experiment with other ways to do on-the-fly contract specialisation via an API.
compile "org.apache.commons:commons-jexl3:3.0"
// For JSON
compile "com.fasterxml.jackson.core:jackson-databind:2.5.5"
}

View File

@ -8,6 +8,14 @@
package core
import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonDeserializer
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 java.math.BigDecimal
import java.time.DayOfWeek
import java.time.LocalDate
@ -82,7 +90,25 @@ 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
/**
* Represents a textual expression of e.g. a formula
*
*/
@JsonDeserialize(using = ExpressionDeserializer::class)
@JsonSerialize(using = ExpressionSerializer::class)
data class Expression(val expr: String)
object ExpressionSerializer: JsonSerializer<Expression>() {
override fun serialize(expr: Expression, generator: JsonGenerator, provider: SerializerProvider) {
generator.writeString(expr.expr)
}
}
object ExpressionDeserializer: JsonDeserializer<Expression>() {
override fun deserialize(parser: JsonParser, context: DeserializationContext): Expression {
return Expression(parser.text)
}
}
/**
* Placeholder class for the Tenor datatype - which is a standardised duration of time until maturity */

View File

@ -4,3 +4,48 @@ 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
LIBOR 2016-03-08 3M = 0.01
LIBOR 2016-06-08 3M = 0.01
LIBOR 2016-09-08 3M = 0.01
LIBOR 2016-12-08 3M = 0.01
LIBOR 2017-03-08 3M = 0.01
LIBOR 2017-06-08 3M = 0.01
LIBOR 2017-09-07 3M = 0.01
LIBOR 2017-12-07 3M = 0.01
LIBOR 2018-03-08 3M = 0.01
LIBOR 2018-06-07 3M = 0.01
LIBOR 2018-09-06 3M = 0.01
LIBOR 2018-12-06 3M = 0.01
LIBOR 2019-03-07 3M = 0.01
LIBOR 2019-06-06 3M = 0.01
LIBOR 2019-09-06 3M = 0.01
LIBOR 2019-12-06 3M = 0.01
LIBOR 2020-03-06 3M = 0.01
LIBOR 2020-06-08 3M = 0.01
LIBOR 2020-09-08 3M = 0.01
LIBOR 2020-12-08 3M = 0.01
LIBOR 2021-03-08 3M = 0.01
LIBOR 2021-06-08 3M = 0.01
LIBOR 2021-09-08 3M = 0.01
LIBOR 2021-12-08 3M = 0.01
LIBOR 2022-03-08 3M = 0.01
LIBOR 2022-06-08 3M = 0.01
LIBOR 2022-09-08 3M = 0.01
LIBOR 2022-12-08 3M = 0.01
LIBOR 2023-03-08 3M = 0.01
LIBOR 2023-06-08 3M = 0.01
LIBOR 2023-09-07 3M = 0.01
LIBOR 2023-12-07 3M = 0.01
LIBOR 2024-03-07 3M = 0.01
LIBOR 2024-06-06 3M = 0.01
LIBOR 2024-09-06 3M = 0.01
LIBOR 2024-12-06 3M = 0.01
LIBOR 2025-03-06 3M = 0.01
LIBOR 2025-06-06 3M = 0.01
LIBOR 2025-09-08 3M = 0.01
LIBOR 2025-12-08 3M = 0.01
LIBOR 2026-03-06 3M = 0.01
LIBOR 2026-06-08 3M = 0.01
LIBOR 2026-09-08 3M = 0.01
LIBOR 2026-12-08 3M = 0.01

View File

@ -7,6 +7,7 @@ import core.crypto.SecureHash
import core.node.AbstractNode
import core.protocols.ProtocolLogic
import core.serialization.SerializedBytes
import core.utilities.ANSIProgressRenderer
import java.time.LocalDateTime
import java.util.*
import kotlin.reflect.KParameter
@ -87,6 +88,7 @@ class APIServerImpl(val node: AbstractNode): APIServer {
}
// If we get here then we matched every parameter
val protocol = constructor.callBy(params) as ProtocolLogic<*>
ANSIProgressRenderer.progressTracker = protocol.progressTracker
val future = node.smm.add("api-call",protocol)
return future
}

View File

@ -0,0 +1,33 @@
package api
import javax.ws.rs.container.ContainerRequestContext
import javax.ws.rs.container.ContainerResponseContext
import javax.ws.rs.container.ContainerResponseFilter
import javax.ws.rs.ext.Provider
/**
* This adds headers needed for cross site scripting on API clients
*/
@Provider
class ResponseFilter: ContainerResponseFilter {
override fun filter(requestContext: ContainerRequestContext, responseContext: ContainerResponseContext) {
val headers = responseContext.headers
/**
* TODO we need to revisit this for security reasons
*
* We don't want this scriptable from any web page anywhere, but for demo reasons
* we're making this really easy to access pending a proper security approach including
* access control and authentication at a network and software level
*
*/
headers.add("Access-Control-Allow-Origin","*")
if(requestContext.method == "OPTIONS") {
headers.add("Access-Control-Allow-Headers", "Content-Type,Accept,Origin")
headers.add("Access-Control-Allow-Methods", "POST,PUT,GET,OPTIONS")
}
}
}

View File

@ -26,6 +26,7 @@ data class LegallyIdentifiableNode(val address: SingleMessageRecipient, val iden
*/
interface NetworkMapService {
val timestampingNodes: List<LegallyIdentifiableNode>
val ratesOracleNodes: List<LegallyIdentifiableNode>
val partyNodes: List<LegallyIdentifiableNode>
fun nodeForPartyName(name: String): LegallyIdentifiableNode? = partyNodes.singleOrNull { it.identity.name == name }
@ -37,6 +38,7 @@ class MockNetworkMapService : NetworkMapService {
data class MockAddress(val id: String): SingleMessageRecipient
override val timestampingNodes = Collections.synchronizedList(ArrayList<LegallyIdentifiableNode>())
override val ratesOracleNodes = Collections.synchronizedList(ArrayList<LegallyIdentifiableNode>())
override val partyNodes = Collections.synchronizedList(ArrayList<LegallyIdentifiableNode>())
init {

View File

@ -168,10 +168,11 @@ class StateMachineManager(val serviceHub: ServiceHub, val runInThread: Executor)
fun <T> add(loggerName: String, logic: ProtocolLogic<T>): ListenableFuture<T> {
val logger = LoggerFactory.getLogger(loggerName)
val fiber = ProtocolStateMachine(logic)
// Need to add before iterating in case of immediate completion
_stateMachines.add(logic)
iterateStateMachine(fiber, serviceHub.networkService, logger, null, null) {
it.start()
}
_stateMachines.add(logic)
totalStartedProtocols.inc()
return fiber.resultFuture
}

View File

@ -76,7 +76,8 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
CASH_PROGRAM_ID to Cash::class.java,
CP_PROGRAM_ID to CommercialPaper::class.java,
CROWDFUND_PROGRAM_ID to CrowdFund::class.java,
DUMMY_PROGRAM_ID to DummyContract::class.java
DUMMY_PROGRAM_ID to DummyContract::class.java,
IRS_PROGRAM_ID to InterestRateSwap::class.java
)
override fun <T : Contract> get(hash: SecureHash): T {

View File

@ -9,6 +9,7 @@
package core.node
import api.Config
import api.ResponseFilter
import com.codahale.metrics.JmxReporter
import com.google.common.net.HostAndPort
import core.messaging.LegallyIdentifiableNode
@ -94,6 +95,7 @@ class Node(dir: Path, val p2pAddr: HostAndPort, configuration: NodeConfiguration
val resourceConfig = ResourceConfig()
// Add your API provider classes (annotated for JAX-RS) here
resourceConfig.register(Config(services))
resourceConfig.register(ResponseFilter())
resourceConfig.register(api)
// Give the app a slightly better name in JMX rather than a randomly generated one and enable JMX
resourceConfig.addProperties(mapOf(ServerProperties.APPLICATION_NAME to "node.api",

View File

@ -135,9 +135,9 @@ class ArtemisMessagingService(val directory: Path, val myHostPort: HostAndPort)
session.createQueue(myHostPort.toString(), "inbound", false)
inboundConsumer = session.createConsumer("inbound").setMessageHandler { message: ClientMessage ->
// This code runs for every inbound message.
try {
if (!message.containsProperty(TOPIC_PROPERTY)) {
log.warn("Received message without a ${TOPIC_PROPERTY} property, ignoring")
// TODO: Figure out whether we always need to acknowledge messages, even when invalid.
return@setMessageHandler
}
val topic = message.getStringProperty(TOPIC_PROPERTY)
@ -171,8 +171,10 @@ class ArtemisMessagingService(val directory: Path, val myHostPort: HostAndPort)
}
}
}
} finally {
message.acknowledge()
}
}
session.start()
mutex.locked { running = true }

View File

@ -0,0 +1,34 @@
package demos
import java.time.*
import javax.annotation.concurrent.ThreadSafe
/**
* A [Clock] that can have the date advanced for use in demos
*/
@ThreadSafe
class DemoClock(private var delegateClock: Clock = Clock.systemUTC()) : Clock() {
@Synchronized fun updateDate(date: LocalDate): Boolean {
val currentDate = LocalDate.now(this)
if(currentDate.isBefore(date)) {
// It's ok to increment
delegateClock = Clock.offset(delegateClock, Duration.between(currentDate.atStartOfDay(),date.atStartOfDay()))
return true
}
return false
}
@Synchronized override fun instant(): Instant {
return delegateClock.instant()
}
@Synchronized override fun withZone(zone: ZoneId): Clock {
return DemoClock(delegateClock.withZone(zone))
}
@Synchronized override fun getZone(): ZoneId {
return delegateClock.zone
}
}

View File

@ -50,10 +50,13 @@ open class RatesFixProtocol(protected val tx: TransactionBuilder,
@Suspendable
override fun call() {
progressTracker.currentStep = progressTracker.steps[0]
val fix = query()
progressTracker.currentStep = WORKING
checkFixIsNearExpected(fix)
tx.addCommand(fix, oracle.identity.owningKey)
beforeSigning(fix)
progressTracker.currentStep = SIGNING
tx.addSignatureUnchecked(sign())
}

View File

@ -20,6 +20,7 @@ import core.node.services.TimestamperService
import core.protocols.ProtocolLogic
import core.random63BitValue
import core.serialization.SerializedBytes
import core.utilities.ProgressTracker
/**
* The TimestampingProtocol class is the client code that talks to a [NodeTimestamperService] on some remote node. It is a
@ -31,7 +32,8 @@ import core.serialization.SerializedBytes
* a network message: use it only from spare application threads that don't have to respond to anything.
*/
class TimestampingProtocol(private val node: LegallyIdentifiableNode,
private val wtxBytes: SerializedBytes<WireTransaction>) : ProtocolLogic<DigitalSignature.LegallyIdentifiable>() {
private val wtxBytes: SerializedBytes<WireTransaction>,
override val progressTracker: ProgressTracker = TimestampingProtocol.tracker()) : ProtocolLogic<DigitalSignature.LegallyIdentifiable>() {
class Client(private val stateMachineManager: StateMachineManager, private val node: LegallyIdentifiableNode) : TimestamperService {
override val identity: Party = node.identity
@ -41,9 +43,18 @@ class TimestampingProtocol(private val node: LegallyIdentifiableNode,
}
}
companion object {
object REQUESTING : ProgressTracker.Step("Requesting signature by timestamping service")
object VALIDATING : ProgressTracker.Step("Validating received signature from timestamping service")
fun tracker() = ProgressTracker(REQUESTING, VALIDATING)
}
@Suspendable
override fun call(): DigitalSignature.LegallyIdentifiable {
progressTracker.currentStep = REQUESTING
val sessionID = random63BitValue()
val replyTopic = "${NodeTimestamperService.TIMESTAMPING_PROTOCOL_TOPIC}.$sessionID"
val req = Request(wtxBytes, serviceHub.networkService.myAddress, replyTopic)
@ -52,6 +63,7 @@ class TimestampingProtocol(private val node: LegallyIdentifiableNode,
NodeTimestamperService.TIMESTAMPING_PROTOCOL_TOPIC, node.address, 0, sessionID, req)
// Check that the timestamping authority gave us back a valid signature and didn't break somehow
progressTracker.currentStep = VALIDATING
maybeSignature.validate { sig ->
sig.verifyWithECDSA(wtxBytes)
return sig

View File

@ -74,11 +74,11 @@ fun createDummyIRS(irsSelect: Int): InterestRateSwap.State {
//expression = "( fixedLeg.notional * (fixedLeg.fixedRate)) - (floatingLeg.notional * (rateSchedule.get(context.getDate('currentDate'))))",
// How it's ended up looking, which I think is now broken but it's a WIP.
expression = InterestRateSwap.Expression("( fixedLeg.notional.pennies * (fixedLeg.fixedRate.ratioUnit.value)) -" +
expression = Expression("( fixedLeg.notional.pennies * (fixedLeg.fixedRate.ratioUnit.value)) -" +
"(floatingLeg.notional.pennies * (calculation.fixingSchedule.get(context.getDate('currentDate')).rate.ratioUnit.value))"),
floatingLegPaymentSchedule = HashMap(),
fixedLegpaymentSchedule = HashMap()
fixedLegPaymentSchedule = HashMap()
)
val EUR = currency("EUR")
@ -94,13 +94,13 @@ fun createDummyIRS(irsSelect: Int): InterestRateSwap.State {
valuationDate = "Every Local Business Day",
notificationTime = "2:00pm London",
resolutionTime = "2:00pm London time on the first LocalBusiness Day following the date on which the notice is given ",
interestRate = OracleRetrievableReferenceRate(TelerateOracle("T3270"), Tenor("6M"), "EONIA"),
interestRate = ReferenceRate("T3270", Tenor("6M"), "EONIA"),
addressForTransfers = "",
exposure = UnknownType(),
localBusinessDay = BusinessCalendar.getInstance("London"),
tradeID = "trade1",
hashLegalDocs = "put hash here",
dailyInterestAmount = InterestRateSwap.Expression("(CashAmount * InterestRate ) / (fixedLeg.notional.currency.currencyCode.equals('GBP')) ? 365 : 360")
dailyInterestAmount = Expression("(CashAmount * InterestRate ) / (fixedLeg.notional.currency.currencyCode.equals('GBP')) ? 365 : 360")
)
InterestRateSwap.State(fixedLeg = fixedLeg, floatingLeg = floatingLeg, calculation = calculation, common = common)
@ -165,11 +165,11 @@ fun createDummyIRS(irsSelect: Int): InterestRateSwap.State {
//expression = "( fixedLeg.notional * (fixedLeg.fixedRate)) - (floatingLeg.notional * (rateSchedule.get(context.getDate('currentDate'))))",
// How it's ended up looking, which I think is now broken but it's a WIP.
expression = InterestRateSwap.Expression("( fixedLeg.notional.pennies * (fixedLeg.fixedRate.ratioUnit.value)) -" +
expression = Expression("( fixedLeg.notional.pennies * (fixedLeg.fixedRate.ratioUnit.value)) -" +
"(floatingLeg.notional.pennies * (calculation.fixingSchedule.get(context.getDate('currentDate')).rate.ratioUnit.value))"),
floatingLegPaymentSchedule = HashMap(),
fixedLegpaymentSchedule = HashMap()
fixedLegPaymentSchedule = HashMap()
)
val EUR = currency("EUR")
@ -185,13 +185,13 @@ fun createDummyIRS(irsSelect: Int): InterestRateSwap.State {
valuationDate = "Every Local Business Day",
notificationTime = "2:00pm London",
resolutionTime = "2:00pm London time on the first LocalBusiness Day following the date on which the notice is given ",
interestRate = OracleRetrievableReferenceRate(TelerateOracle("T3270"), Tenor("6M"), "EONIA"),
interestRate = ReferenceRate("T3270", Tenor("6M"), "EONIA"),
addressForTransfers = "",
exposure = UnknownType(),
localBusinessDay = BusinessCalendar.getInstance("London"),
tradeID = "trade1",
hashLegalDocs = "put hash here",
dailyInterestAmount = InterestRateSwap.Expression("(CashAmount * InterestRate ) / (fixedLeg.notional.currency.currencyCode.equals('GBP')) ? 365 : 360")
dailyInterestAmount = Expression("(CashAmount * InterestRate ) / (fixedLeg.notional.currency.currencyCode.equals('GBP')) ? 365 : 360")
)
return InterestRateSwap.State(fixedLeg = fixedLeg, floatingLeg = floatingLeg, calculation = calculation, common = common)
@ -335,12 +335,6 @@ class IRSTests {
// TODO: r1*r2 ?
}
@Test
fun `reference rate testing`() {
val r1 = TestReferenceRate("5")
assert(100 * r1.getAsOf(null) == 5)
}
@Test
fun `expression calculation testing`() {
val dummyIRS = singleIRS()
@ -366,7 +360,7 @@ class IRSTests {
for (i in stuffToPrint) {
println(i)
var z = dummyIRS.evaluateCalculation(LocalDate.of(2016, 9, 12), InterestRateSwap.Expression(i))
var z = dummyIRS.evaluateCalculation(LocalDate.of(2016, 9, 12), Expression(i))
println(z.javaClass)
println(z)
println("-----------")

View File

@ -38,6 +38,8 @@ object TestUtils {
val keypair = generateKeyPair()
val keypair2 = generateKeyPair()
val keypair3 = generateKeyPair()
val keypair4 = generateKeyPair()
val keypair5 = generateKeyPair()
}
// A dummy time at which we will be pretending test transactions are created.
val TEST_TX_TIME = Instant.parse("2015-04-17T12:00:00.00Z")
@ -49,6 +51,14 @@ val MEGA_CORP_PUBKEY = MEGA_CORP_KEY.public
val MINI_CORP_KEY = TestUtils.keypair2
val MINI_CORP_PUBKEY = MINI_CORP_KEY.public
// TODO remove once mock API is retired
val EXCALIBUR_BANK_KEY = TestUtils.keypair4
val EXCALIBUR_BANK_PUBKEY = EXCALIBUR_BANK_KEY.public
// TODO remove once mock API is retired
val A_N_OTHER_BANK_KEY = TestUtils.keypair5
val A_N_OTHER_BANK_PUBKEY = A_N_OTHER_BANK_KEY.public
val ORACLE_KEY = TestUtils.keypair3
val ORACLE_PUBKEY = ORACLE_KEY.public
@ -64,11 +74,17 @@ val BOB = BOB_KEY.public
val MEGA_CORP = Party("MegaCorp", MEGA_CORP_PUBKEY)
val MINI_CORP = Party("MiniCorp", MINI_CORP_PUBKEY)
val ALL_TEST_KEYS = listOf(MEGA_CORP_KEY, MINI_CORP_KEY, ALICE_KEY, BOB_KEY, DummyTimestampingAuthority.key)
// TODO remove once mock API is retired
val EXCALIBUR_BANK = Party("Excalibur", EXCALIBUR_BANK_PUBKEY)
val A_N_OTHER_BANK = Party("ANOther",A_N_OTHER_BANK_PUBKEY)
val ALL_TEST_KEYS = listOf(MEGA_CORP_KEY, MINI_CORP_KEY, ALICE_KEY, BOB_KEY, EXCALIBUR_BANK_KEY, A_N_OTHER_BANK_KEY, DummyTimestampingAuthority.key)
val TEST_KEYS_TO_CORP_MAP: Map<PublicKey, Party> = mapOf(
MEGA_CORP_PUBKEY to MEGA_CORP,
MINI_CORP_PUBKEY to MINI_CORP,
EXCALIBUR_BANK_PUBKEY to EXCALIBUR_BANK,
A_N_OTHER_BANK_PUBKEY to A_N_OTHER_BANK,
DUMMY_TIMESTAMPER.identity.owningKey to DUMMY_TIMESTAMPER.identity
)