cleanup, testing rollout syntax

This commit is contained in:
sofusmortensen 2016-07-10 12:12:15 +02:00
parent 757bddb9f9
commit f0fc8f414f
9 changed files with 134 additions and 95 deletions

View File

@ -3,7 +3,9 @@ package com.r3corda.contracts.universal
import com.google.common.collect.ImmutableSet
import com.google.common.collect.Sets
import com.r3corda.core.contracts.Amount
import com.r3corda.core.contracts.Frequency
import com.r3corda.core.crypto.Party
import java.math.BigDecimal
import java.security.PublicKey
import java.util.*
@ -15,15 +17,21 @@ interface Arrangement
// A base arrangement with no rights and no obligations. Contract cancellation/termination is a transition to ``Zero``.
data class Zero(val dummy: Int = 0) : Arrangement
class Zero() : Arrangement {
override fun hashCode(): Int {
return 0;
}
override fun equals(other: Any?): Boolean {
return other is Zero
}
}
// A base arrangement representing immediate transfer of Cash - X amount of currency CCY from party A to party B.
// A basic arrangement representing immediate transfer of Cash - X amount of currency CCY from party A to party B.
// X is an observable of type BigDecimal.
//
// todo: should be replaced with something that uses Corda assets and/or cash?
data class Transfer(val amount: Perceivable<Long>, val currency: Currency, val from: Party, val to: Party) : Arrangement {
constructor(amount: Amount<Currency>, from: Party, to: Party ) : this(const(amount.quantity), amount.token, from, to)
data class Transfer(val amount: Perceivable<Amount<Currency>>, val from: Party, val to: Party) : Arrangement {
constructor(amount: Amount<Currency>, from: Party, to: Party ) : this(const(amount), from, to)
}
@ -42,3 +50,6 @@ data class Action(val name: String, val condition: Perceivable<Boolean>,
// only actions can be or'ed togetherA combinator that can only be used on action arrangements. This means only one of the action can be executed. Should any one action be executed, all other actions are discarded.
data class Or(val actions: Set<Action>) : Arrangement
data class RollOut(val startDate: String, val endDate: String, val frequency: Frequency, val arrangement: Arrangement) : Arrangement

View File

@ -1,5 +1,6 @@
package com.r3corda.contracts.universal
import com.r3corda.core.contracts.Amount
import java.math.BigDecimal
import java.text.DateFormat
import java.time.Instant
@ -62,7 +63,16 @@ enum class Operation {
data class PerceivableOperation<T>(val left: Perceivable<T>, val op: Operation, val right: Perceivable<T>) : Perceivable<T>
infix fun Perceivable<BigDecimal>.plus(n: BigDecimal) = PerceivableOperation(this, Operation.PLUS, const(n))
infix fun Perceivable<BigDecimal>.minus(n: BigDecimal) = PerceivableOperation(this, Operation.MINUS, const(n))
infix fun Perceivable<BigDecimal>.times(n: BigDecimal) = PerceivableOperation(this, Operation.TIMES, const(n))
infix fun Perceivable<BigDecimal>.div(n: BigDecimal) = PerceivableOperation(this, Operation.DIV, const(n))
operator fun Perceivable<BigDecimal>.plus(n: BigDecimal) = PerceivableOperation(this, Operation.PLUS, const(n))
operator fun Perceivable<BigDecimal>.minus(n: BigDecimal) = PerceivableOperation(this, Operation.MINUS, const(n))
operator fun Perceivable<BigDecimal>.plus(n: Double) = PerceivableOperation(this, Operation.PLUS, const(BigDecimal(n)))
operator fun Perceivable<BigDecimal>.minus(n: Double) = PerceivableOperation(this, Operation.MINUS, const(BigDecimal(n)))
operator fun Perceivable<BigDecimal>.times(n: BigDecimal) = PerceivableOperation(this, Operation.TIMES, const(n))
operator fun Perceivable<BigDecimal>.div(n: BigDecimal) = PerceivableOperation(this, Operation.DIV, const(n))
operator fun Perceivable<BigDecimal>.times(n: Double) = PerceivableOperation(this, Operation.TIMES, const(BigDecimal(n)))
operator fun Perceivable<BigDecimal>.div(n: Double) = PerceivableOperation(this, Operation.DIV, const(BigDecimal(n)))
data class ScaleAmount<T>(val left: Perceivable<BigDecimal>, val right: Perceivable<Amount<T>>) : Perceivable<Amount<T>>
operator fun Perceivable<BigDecimal>.times(n: Amount<Currency>) = ScaleAmount(this, const(n))
//PerceivableOperation(this, Operation.TIMES, const(BigDecimal(n)))

View File

@ -27,7 +27,7 @@ class UniversalContract : Contract {
// must be signed by all parties present in contract before and after command
class Move(val from: Party, val to: Party) : TypeOnlyCommandData(), Commands
// must be signed by all parties present in contract
// must be signed by all liable parties present in contract
class Issue : TypeOnlyCommandData(), Commands
}

View File

@ -66,7 +66,7 @@ fun replaceParty(action: Action, from: Party, to: Party) : Action {
fun replaceParty(arrangement: Arrangement, from: Party, to: Party) : Arrangement {
return when (arrangement) {
is Zero -> arrangement
is Transfer -> Transfer( arrangement.amount, arrangement.currency,
is Transfer -> Transfer( arrangement.amount,
if (arrangement.from == from) to else arrangement.from,
if (arrangement.to == from) to else arrangement.to )
is Action -> replaceParty(arrangement, from, to)

View File

@ -1,6 +1,7 @@
package com.r3corda.contracts.universal
import com.r3corda.core.contracts.Amount
import com.r3corda.core.contracts.Frequency
import com.r3corda.core.crypto.Party
import java.math.BigDecimal
import java.util.*
@ -30,10 +31,14 @@ class ContractBuilder {
contracts.add( Transfer(amount, this, beneficiary))
}
fun Party.gives(beneficiary: Party, amount: Perceivable<Long>, currency: Currency) {
contracts.add( Transfer(amount, currency, this, beneficiary))
fun Party.gives(beneficiary: Party, amount: Perceivable<Amount<Currency>>) {
contracts.add( Transfer(amount, this, beneficiary))
}
/* fun Party.gives(beneficiary: Party, amount: Perceivable<Long>, currency: Currency) {
contracts.add( Transfer(amount, currency, this, beneficiary))
}*/
fun final() =
when (contracts.size) {
0 -> zero
@ -89,87 +94,21 @@ infix fun Set<Party>.or(party: Party) = this.plus(party)
fun arrange(init: ContractBuilder.() -> Unit ) : Arrangement {
val b = ContractBuilder()
b.init()
return b.final();
return b.final()
}
class RolloutBuilder(val startDate: String, val endDate: String, val frequency: Frequency) {
val start = "start date"
val end = "end date"
fun recurse() = zero
/*
val my_cds_contract =
fun final() =
RollOut(startDate, endDate, frequency, zero)
}
roadRunner.may {
"exercise".givenThat(acmeCorporationHasDefaulted and before("2017-09-01")) {
wileECoyote.gives(roadRunner, 1.M*USD)
}
} or (roadRunner or wileECoyote).may {
"expire".givenThat(after("2017-09-01")) {}
}
val my_fx_swap =
(roadRunner or wileECoyote).may {
"execute".givenThat(after("2017-09-01")) {
wileECoyote.gives(roadRunner, 1200.K*USD)
roadRunner.gives(wileECoyote, 1.M*EUR)
}
}
val my_fx_option =
roadRunner.may {
"exercise".anytime {
(roadRunner or wileECoyote).may {
"execute".givenThat(after("2017-09-01")) {
wileECoyote.gives(roadRunner, 1200.K*USD)
roadRunner.gives(wileECoyote, 1.M*EUR)
}
}
}
} or wileECoyote.may {
"expire".givenThat(after("2017-09-01")) {}
}
val my_fx_knock_out_barrier_option =
roadRunner.may {
"exercise".anytime {
(roadRunner or wileECoyote).may {
"execute".givenThat(after("2017-09-01")) {
wileECoyote.gives(roadRunner, 1200.K*USD)
roadRunner.gives(wileECoyote, 1.M*EUR)
}
}
}
} or wileECoyote.may {
"expire".givenThat(after("2017-09-01")) {}
"knock out".givenThat( EUR / USD gt 1.3 ) {}
}
val my_fx_knock_in_barrier_option =
roadRunner.may {
"knock in".givenThat(EUR / USD gt 1.3) {
roadRunner.may {
"exercise".anytime {
(roadRunner or wileECoyote).may {
"execute".givenThat(after("2017-09-01")) {
wileECoyote.gives(roadRunner, 1200.K*USD)
roadRunner.gives(wileECoyote, 1.M*EUR)
}
}
}
} or wileECoyote.may {
"expire".givenThat(after("2017-09-01")) {}
}
}
} or wileECoyote.may {
"expire".givenThat(after("2017-09-01")) {}
}
////
fun fwd(partyA: Party, partyB: Party, maturity: String, contract: Kontract) =
(partyA or partyB).may {
"execute".givenThat(after(maturity)).resolve(contract)
}
*/
fun rollout(startDate: String, endDate: String, frequency: Frequency, init: RolloutBuilder.() -> Unit) : Arrangement {
val b = RolloutBuilder(startDate, endDate, frequency)
b.init()
return b.final()
}

View File

@ -1,5 +1,6 @@
package com.r3corda.contracts.universal
import com.r3corda.core.contracts.Amount
import com.r3corda.core.crypto.Party
import com.r3corda.core.crypto.generateKeyPair
import org.junit.Test
@ -18,8 +19,11 @@ class DummyPerceivable<T> : Perceivable<T>
// example:
val acmeCorporationHasDefaulted = DummyPerceivable<Boolean>()
// example:
val euribor3M = DummyPerceivable<BigDecimal>()
fun libor(amount: Amount<Currency>, start: String, end: String) : Perceivable<Amount<Currency>> = DummyPerceivable()
fun interest(rate: Amount<Currency>, dayCountConvention: String, interest: Double /* todo - appropriate type */,
start: String, end: String) : Perceivable<Amount<Currency>> = DummyPerceivable()
// Test parties
val roadRunner = Party("Road Runner", generateKeyPair().public)

View File

@ -0,0 +1,74 @@
package com.r3corda.contracts.universal
import com.r3corda.core.contracts.Frequency
/**
* Created by sofusmortensen on 28/06/16.
*/
// Swaption
class Swaption {
val notional = 10.M * USD
val coupon = 1.5
val contract =
(wileECoyote or roadRunner).may {
"proceed".givenThat(after("01/07/2015")) {
wileECoyote.gives(roadRunner, libor( notional, "01/04/2015", "01/07/2015" ) )
roadRunner.gives(wileECoyote, interest( notional, "act/365", coupon, "01/04/2015", "01/07/2015" ) )
(wileECoyote or roadRunner).may {
"proceed".givenThat(after("01/10/2015")) {
wileECoyote.gives(roadRunner, libor( notional, "01/07/2015", "01/10/2015" ) )
roadRunner.gives(wileECoyote, interest( notional, "act/365", coupon, "01/07/2015", "01/10/2015" ) )
(wileECoyote or roadRunner).may {
// etc ...
}
}
} or roadRunner.may {
"cancel".anytime {
roadRunner.gives( wileECoyote, 10.K * USD )
}
}
}
} or roadRunner.may {
"cancel".anytime {
roadRunner.gives( wileECoyote, 10.K * USD )
}
}
val contract2 = rollout( "01/04/2015", "01/04/2025", Frequency.Quarterly ) {
(wileECoyote or roadRunner).may {
"proceed".givenThat(after(start)) {
wileECoyote.gives(roadRunner, libor( notional, start, end ) )
roadRunner.gives(wileECoyote, interest( notional, "act/365", coupon, start, end ) )
recurse()
}
} or roadRunner.may {
"cancel".anytime {
roadRunner.gives( wileECoyote, 10.K * USD )
}
}
}
val strike = 1.2
val tarf = rollout( "01/04/2015", "01/04/2016", Frequency.Quarterly ) {
roadRunner.may {
"exercise".givenThat(before(start)) {
wileECoyote.gives(roadRunner, (EUR / USD - strike) * notional )
recurse()
}
} or (roadRunner or wileECoyote).may {
"proceed".givenThat(after(start)) {
recurse()
}
}
}
}

View File

@ -8,7 +8,7 @@ import org.junit.Test
* Created by sofusmortensen on 01/06/16.
*/
class ZCB {
class ZeroCouponBond {
val contract =
(roadRunner or wileECoyote).may {

View File

@ -11,6 +11,7 @@ import java.util.*
* Created by sofusmortensen on 23/05/16.
*/
// various example arrangements using basic syntax
val cds_contract = Action("payout", acmeCorporationHasDefaulted and before("2017-09-01"),
roadRunner,