Universal: more refactor + cap rollout unit test

This commit is contained in:
sofusmortensen 2016-09-17 16:16:08 +02:00
parent 1d5c7963c4
commit 9c5ef6cdfe
14 changed files with 515 additions and 276 deletions

View File

@ -35,7 +35,6 @@ data class Transfer(val amount: Perceivable<BigDecimal>, val currency: Currency,
// The ``And`` combinator cannot be root in a arrangement.
data class And(val arrangements: Set<Arrangement>) : Arrangement
data class Action(val name: String, val condition: Perceivable<Boolean>,
val actors: Set<Party>, val arrangement: Arrangement)

View File

@ -38,10 +38,11 @@ data class Const<T>(val value: T) : Perceivable<T> {
return false
}
override fun hashCode(): Int {
val h = value!!.hashCode()
return h
}
override fun hashCode(): Int =
if (value is BigDecimal)
value.toDouble().hashCode()
else
value!!.hashCode()
}
fun<T> const(k: T) = Const(k)

View File

@ -245,7 +245,7 @@ class UniversalContract : Contract {
val expectedArr = replaceFixing(tx, arr,
value.fixes.associateBy({ it.of }, { it.value }), unusedFixes)
// debugCompare(expectedArr, outState.details)
// debugCompare(expectedArr, outState.details)
requireThat {
"relevant fixing must be included" by unusedFixes.isEmpty()

View File

@ -17,10 +17,11 @@ fun swap(partyA: Party, amountA: BigDecimal, currencyA: Currency, partyB: Party,
fun fx_swap(expiry: String, notional: BigDecimal, strike: BigDecimal,
foreignCurrency: Currency, domesticCurrency: Currency,
partyA: Party, partyB: Party) = arrange {
(partyA or partyB).may {
"execute".givenThat(after(expiry)) {
swap(partyA, notional * strike, domesticCurrency, partyB, notional, foreignCurrency)
actions {
(partyA or partyB).may {
"execute".givenThat(after(expiry)) {
swap(partyA, notional * strike, domesticCurrency, partyB, notional, foreignCurrency)
}
}
}
}

View File

@ -22,8 +22,44 @@ val Double.bd: BigDecimal get() = BigDecimal(this)
val zero = Zero()
class ActionsBuilder {
private var actions = mutableSetOf<Action>()
fun final() =
if (actions.isEmpty())
zero
else
Actions(actions.toSet())
fun Party.may(init: ActionBuilder.() -> Action): Action {
val builder = ActionBuilder(setOf(this))
builder.init()
actions.addAll( builder.actions )
return builder.actions.first()
}
fun Set<Party>.may(init: ActionBuilder.() -> Action): Action {
val builder = ActionBuilder(this)
builder.init()
actions.addAll( builder.actions )
return builder.actions.first()
}
infix fun Party.or(party: Party) = setOf(this, party)
infix fun Set<Party>.or(party: Party) = this.plus(party)
}
open class ContractBuilder {
val contracts = mutableListOf<Arrangement>()
private val contracts = mutableListOf<Arrangement>()
fun actions(init: ActionsBuilder.() -> Action ) : Arrangement {
val b = ActionsBuilder()
b.init()
val c = b.final()
contracts.add(c)
return c
}
fun Party.gives(beneficiary: Party, amount: BigDecimal, currency: Currency): Transfer {
val c = Transfer(const(amount), currency, this, beneficiary)
@ -37,25 +73,6 @@ open class ContractBuilder {
return c
}
fun Party.may(init: ActionBuilder.() -> Unit): Actions {
val b = ActionBuilder(setOf(this))
b.init()
val c = Actions(b.actions.toSet())
contracts.add(c)
return c
}
fun Set<Party>.may(init: ActionBuilder.() -> Unit): Actions {
val b = ActionBuilder(this)
b.init()
val c = Actions(b.actions.toSet())
contracts.add(c)
return c
}
infix fun Party.or(party: Party) = setOf(this, party)
infix fun Set<Party>.or(party: Party) = this.plus(party)
@Deprecated(level = DeprecationLevel.ERROR, message = "Not allowed")
fun Action(@Suppress("UNUSED_PARAMETER") name: String, @Suppress("UNUSED_PARAMETER") condition: Perceivable<Boolean>,
@Suppress("UNUSED_PARAMETER") actors: Set<Party>, @Suppress("UNUSED_PARAMETER") arrangement: Arrangement) {
@ -77,7 +94,7 @@ open class ContractBuilder {
contracts.add( Transfer(amount, currency, this, beneficiary))
}*/
infix fun Arrangement.and(arrangement: Arrangement) = And(setOf(this, arrangement))
// infix fun Arrangement.and(arrangement: Arrangement) = And(setOf(this, arrangement))
val start = StartDate()
val end = EndDate()
@ -130,10 +147,12 @@ interface GivenThatResolve {
class ActionBuilder(val actors: Set<Party>) {
val actions = mutableListOf<Action>()
fun String.givenThat(condition: Perceivable<Boolean>, init: ContractBuilder.() -> Arrangement ) {
fun String.givenThat(condition: Perceivable<Boolean>, init: ContractBuilder.() -> Arrangement ) : Action {
val b = ContractBuilder()
b.init()
actions.add( Action(this, condition, actors, b.final() ) )
val a = Action(this, condition, actors, b.final() )
actions.add( a )
return a
}
fun String.givenThat(condition: Perceivable<Boolean> ) : GivenThatResolve {
@ -145,10 +164,12 @@ class ActionBuilder(val actors: Set<Party>) {
}
}
fun String.anytime(init: ContractBuilder.() -> Unit ) {
fun String.anytime(init: ContractBuilder.() -> Unit ) : Action {
val b = ContractBuilder()
b.init()
actions.add( Action(this, const(true), actors, b.final() ) )
val a = Action(this, const(true), actors, b.final() )
actions.add( a )
return a
}
}

View File

@ -1,5 +1,6 @@
package com.r3corda.contracts.universal
import com.r3corda.core.contracts.BusinessCalendar
import com.r3corda.core.contracts.FixOf
import com.r3corda.core.contracts.Frequency
import com.r3corda.core.contracts.Tenor
@ -23,89 +24,174 @@ class Cap {
val tradeDate: LocalDate = LocalDate.of(2016, 9, 1)
val contract = arrange {
rollOut("2016-09-01".ld, "2017-04-01".ld, Frequency.Quarterly) {
rollOut("2016-09-01".ld, "2017-09-01".ld, Frequency.Quarterly) {
actions {
(acmeCorp or highStreetBank).may {
"exercise".anytime {
val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("3M")), start, end)
val fixed = interest(notional, "act/365", 0.5.bd, start, end)
highStreetBank.gives(acmeCorp, floating - fixed, currency)
next()
}
}
acmeCorp.may {
"skip".anytime {
next()
}
}
}
}
}
val contractFixed = arrange {
actions {
(acmeCorp or highStreetBank).may {
"exercise".anytime {
val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("3M")), start, end)
val fixed = interest(notional, "act/365", 0.5.bd, start, end)
highStreetBank.gives(acmeCorp, (floating - fixed).plus(), currency)
next()
"exercise".anytime() {
val floating1 = interest(notional, "act/365", 1.0.bd, "2016-09-01", "2016-12-01")
val fixed1 = interest(notional, "act/365", 0.5.bd, "2016-09-01", "2016-12-01")
highStreetBank.gives(acmeCorp, floating1 - fixed1, currency)
rollOut("2016-12-01".ld, "2017-09-01".ld, Frequency.Quarterly) {
actions {
(acmeCorp or highStreetBank).may {
"exercise".anytime {
val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("3M")), start, end)
val fixed = interest(notional, "act/365", 0.5.bd, start, end)
highStreetBank.gives(acmeCorp, floating - fixed, currency)
next()
}
}
acmeCorp.may {
"skip".anytime {
next()
}
}
}
}
}
}
acmeCorp.may {
"skip".anytime {
next()
}
}
}
}
val contractFixed = arrange {
(acmeCorp or highStreetBank).may {
"exercise".anytime() {
val floating1 = interest(notional, "act/365", 1.0.bd, "2016-09-01", "2016-12-01")
val fixed1 = interest(notional, "act/365", 0.5.bd, "2016-09-01", "2016-12-01")
highStreetBank.gives(acmeCorp, (floating1 - fixed1).plus(), currency)
rollOut("2016-12-01".ld, "2017-04-01".ld, Frequency.Quarterly) {
(acmeCorp or highStreetBank).may {
"exercise".anytime {
val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("3M")), start, end)
val fixed = interest(notional, "act/365", 0.5.bd, start, end)
highStreetBank.gives(acmeCorp, (floating - fixed).plus(), currency)
next()
}
}
acmeCorp.may {
"skip".anytime {
next()
}
}
}
}
}
acmeCorp.may {
"skip".anytime {
rollOut("2016-12-01".ld, "2017-04-01".ld, Frequency.Quarterly) {
(acmeCorp or highStreetBank).may {
"exercise".anytime {
val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("3M")), start, end)
val fixed = interest(notional, "act/365", 0.5.bd, start, end)
highStreetBank.gives(acmeCorp, (floating - fixed).plus(), currency)
next()
}
}
acmeCorp.may {
"skip".anytime {
next()
rollOut("2016-12-01".ld, "2017-09-01".ld, Frequency.Quarterly) {
actions {
(acmeCorp or highStreetBank).may {
"exercise".anytime {
val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("3M")), start, end)
val fixed = interest(notional, "act/365", 0.5.bd, start, end)
highStreetBank.gives(acmeCorp, floating - fixed, currency)
next()
}
}
acmeCorp.may {
"skip".anytime {
next()
}
}
}
}
}
}
}
}
val contractFixed2 = arrange {
actions {
(acmeCorp or highStreetBank).may {
"exercise".anytime() {
val floating1 = interest(notional, "act/365", 1.0.bd, "2016-12-01", "2017-03-01")
val fixed1 = interest(notional, "act/365", 0.5.bd, "2016-12-01", "2017-03-01")
highStreetBank.gives(acmeCorp, floating1 - fixed1, currency)
rollOut("2017-03-01".ld, "2017-09-01".ld, Frequency.Quarterly) {
actions {
(acmeCorp or highStreetBank).may {
"exercise".anytime {
val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("3M")), start, end)
val fixed = interest(notional, "act/365", 0.5.bd, start, end)
highStreetBank.gives(acmeCorp, floating - fixed, currency)
next()
}
}
acmeCorp.may {
"skip".anytime {
next()
}
}
}
}
}
}
acmeCorp.may {
"skip".anytime {
rollOut("2017-03-01".ld, "2017-09-01".ld, Frequency.Quarterly) {
actions {
(acmeCorp or highStreetBank).may {
"exercise".anytime {
val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("3M")), start, end)
val fixed = interest(notional, "act/365", 0.5.bd, start, end)
highStreetBank.gives(acmeCorp, floating - fixed, currency)
next()
}
}
acmeCorp.may {
"skip".anytime {
next()
}
}
}
}
}
}
}
}
val contractAfterExecute = arrange {
rollOut("2016-12-01".ld, "2017-09-01".ld, Frequency.Quarterly) {
actions {
(acmeCorp or highStreetBank).may {
"exercise".anytime {
val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("3M")), start, end)
val fixed = interest(notional, "act/365", 0.5.bd, start, end)
highStreetBank.gives(acmeCorp, floating - fixed, currency)
next()
}
}
acmeCorp.may {
"skip".anytime {
next()
}
}
}
}
}
val paymentFirst = arrange { highStreetBank.gives(acmeCorp, 250.K, EUR) }
val stateStart = UniversalContract.State(listOf(DUMMY_NOTARY.owningKey), contract)
val stateFixed = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), contractFixed)
val stateAfterExecute = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), contractAfterExecute)
val statePaymentFirst = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), paymentFirst)
val stateFixed2 = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), contractFixed2)
val contractLimitedCap = arrange {
rollOut("2016-04-01".ld, "2017-04-01".ld, Frequency.Quarterly, object {
val limit = variable(150.K)
}) {
(acmeCorp or highStreetBank).may {
"exercise".anytime {
val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("3M")), start, end)
val fixed = interest(notional, "act/365", 0.5.bd, start, end)
val payout = min(floating - fixed)
highStreetBank.gives(acmeCorp, payout, currency)
next(vars.limit to vars.limit - payout)
actions {
(acmeCorp or highStreetBank).may {
"exercise".anytime {
val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("3M")), start, end)
val fixed = interest(notional, "act/365", 0.5.bd, start, end)
val payout = min(floating - fixed)
highStreetBank.gives(acmeCorp, payout, currency)
next(vars.limit to vars.limit - payout)
}
}
}
acmeCorp.may {
"skip".anytime {
next()
acmeCorp.may {
"skip".anytime {
next()
}
}
}
}
@ -131,12 +217,7 @@ class Cap {
}
@Test
fun `print debugging`() {
// debugprint(contract)
}
@Test
fun `fixing`() {
fun `first fixing`() {
transaction {
input { stateStart }
output { stateFixed }
@ -180,4 +261,68 @@ class Cap {
}
}
@Test
fun `first execute`() {
transaction {
input { stateFixed }
output { stateAfterExecute }
output { statePaymentFirst }
timestamp(TEST_TX_TIME_1)
tweak {
command(highStreetBank.owningKey) { UniversalContract.Commands.Action("some undefined name") }
this `fails with` "action must be defined"
}
command(highStreetBank.owningKey) { UniversalContract.Commands.Action("exercise") }
this.verifies()
}
}
@Test
fun `second fixing`() {
transaction {
input { stateAfterExecute }
output { stateFixed2 }
timestamp(TEST_TX_TIME_1)
tweak {
command(highStreetBank.owningKey) { UniversalContract.Commands.Action("some undefined name") }
this `fails with` "action must be defined"
}
tweak {
// wrong source
command(highStreetBank.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBORx", BusinessCalendar.parseDateFromString("2016-12-01"), Tenor("3M")), 1.0.bd))) }
this `fails with` "relevant fixing must be included"
}
tweak {
// wrong date
command(highStreetBank.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBOR", BusinessCalendar.parseDateFromString("2016-12-01").plusYears(1), Tenor("3M")), 1.0.bd))) }
this `fails with` "relevant fixing must be included"
}
tweak {
// wrong tenor
command(highStreetBank.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBOR", BusinessCalendar.parseDateFromString("2016-12-01"), Tenor("9M")), 1.0.bd))) }
this `fails with` "relevant fixing must be included"
}
tweak {
command(highStreetBank.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBOR", BusinessCalendar.parseDateFromString("2016-12-01"), Tenor("3M")), 1.5.bd))) }
this `fails with` "output state does not reflect fix command"
}
command(highStreetBank.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBOR", BusinessCalendar.parseDateFromString("2016-12-01"), Tenor("3M")), 1.0.bd))) }
this.verifies()
}
}
}

View File

@ -24,21 +24,25 @@ class Caplet {
val currency = EUR
val contract = arrange {
(acmeCorp or highStreetBank).may {
"exercise".anytime() {
val floating = interest(notional, "act/365", fix("LIBOR", tradeDate, Tenor("6M")), "2016-04-01", "2016-10-01")
val fixed = interest(notional, "act/365", 0.5.bd, "2016-04-01", "2016-10-01")
highStreetBank.gives(acmeCorp, (floating - fixed).plus(), currency)
actions {
(acmeCorp or highStreetBank).may {
"exercise".anytime() {
val floating = interest(notional, "act/365", fix("LIBOR", tradeDate, Tenor("6M")), "2016-04-01", "2016-10-01")
val fixed = interest(notional, "act/365", 0.5.bd, "2016-04-01", "2016-10-01")
highStreetBank.gives(acmeCorp, (floating - fixed).plus(), currency)
}
}
}
}
val contractFixed = arrange {
(acmeCorp or highStreetBank).may {
"exercise".anytime() {
val floating = interest(notional, "act/365", 1.0.bd, "2016-04-01", "2016-10-01")
val fixed = interest(notional, "act/365", 0.5.bd, "2016-04-01", "2016-10-01")
highStreetBank.gives(acmeCorp, (floating - fixed).plus(), currency)
actions {
(acmeCorp or highStreetBank).may {
"exercise".anytime() {
val floating = interest(notional, "act/365", 1.0.bd, "2016-04-01", "2016-10-01")
val fixed = interest(notional, "act/365", 0.5.bd, "2016-04-01", "2016-10-01")
highStreetBank.gives(acmeCorp, (floating - fixed).plus(), currency)
}
}
}
}

View File

@ -28,48 +28,54 @@ class ContractDefinition {
val cds_contract = arrange {
acmeCorp.may {
"payout".givenThat(acmeCorporationHasDefaulted and before("2017-09-01")) {
highStreetBank.gives(acmeCorp, 1.M, USD)
actions {
acmeCorp.may {
"payout".givenThat(acmeCorporationHasDefaulted and before("2017-09-01")) {
highStreetBank.gives(acmeCorp, 1.M, USD)
}
}
}
highStreetBank.may {
"expire".givenThat(after("2017-09-01")) {
zero
highStreetBank.may {
"expire".givenThat(after("2017-09-01")) {
zero
}
}
}
}
val american_fx_option = arrange {
acmeCorp.may {
"exercise".anytime {
highStreetBank.gives(acmeCorp, 1.M, EUR)
acmeCorp.gives(highStreetBank, 1200.K, USD)
actions {
acmeCorp.may {
"exercise".anytime {
highStreetBank.gives(acmeCorp, 1.M, EUR)
acmeCorp.gives(highStreetBank, 1200.K, USD)
}
}
}
highStreetBank.may {
"expire".givenThat(after("2017-09-01")) {
zero
highStreetBank.may {
"expire".givenThat(after("2017-09-01")) {
zero
}
}
}
}
val european_fx_option = arrange {
acmeCorp.may {
"exercise".anytime {
(acmeCorp or highStreetBank).may {
"execute".givenThat(after("2017-09-01")) {
highStreetBank.gives(acmeCorp, 1.M, EUR)
acmeCorp.gives(highStreetBank, 1200.K, USD)
actions {
acmeCorp.may {
"exercise".anytime {
(acmeCorp or highStreetBank).may {
"execute".givenThat(after("2017-09-01")) {
highStreetBank.gives(acmeCorp, 1.M, EUR)
acmeCorp.gives(highStreetBank, 1200.K, USD)
}
}
}
}
}
highStreetBank.may {
"expire".givenThat(after("2017-09-01")) {
zero
highStreetBank.may {
"expire".givenThat(after("2017-09-01")) {
zero
}
}
}
}

View File

@ -15,10 +15,12 @@ class FXSwap {
val TEST_TX_TIME_TOO_EARLY: Instant get() = Instant.parse("2017-08-31T12:00:00.00Z")
val contract = arrange {
(acmeCorp or highStreetBank).may {
"execute".givenThat(after("2017-09-01")) {
highStreetBank.gives(acmeCorp, 1200.K, USD)
acmeCorp.gives(highStreetBank, 1.M, EUR)
actions {
(acmeCorp or highStreetBank).may {
"execute".givenThat(after("2017-09-01")) {
highStreetBank.gives(acmeCorp, 1200.K, USD)
acmeCorp.gives(highStreetBank, 1.M, EUR)
}
}
}
}

View File

@ -23,17 +23,19 @@ class IRS {
val contract = arrange {
rollOut("2016-09-01".ld, "2018-09-01".ld, Frequency.Quarterly) {
(acmeCorp or highStreetBank).may {
val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("3M")), start, end)
val fixed = interest(notional, "act/365", 0.5.bd, start, end)
actions {
(acmeCorp or highStreetBank).may {
val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("3M")), start, end)
val fixed = interest(notional, "act/365", 0.5.bd, start, end)
"pay 1".anytime {
highStreetBank.gives(acmeCorp, floating - fixed, currency)
next()
}
"pay 2".anytime {
highStreetBank.gives(acmeCorp, fixed - floating, currency)
next()
"pay 1".anytime {
highStreetBank.gives(acmeCorp, floating - fixed, currency)
next()
}
"pay 2".anytime {
highStreetBank.gives(acmeCorp, fixed - floating, currency)
next()
}
}
}
}

View File

@ -18,21 +18,26 @@ class RollOutTests {
val contract = arrange {
rollOut("2016-09-01".ld, "2017-09-01".ld, Frequency.Monthly) {
(acmeCorp or highStreetBank).may {
"transfer".givenThat(after(end)) {
highStreetBank.gives(acmeCorp, 10.K, USD)
next()
actions {
(acmeCorp or highStreetBank).may {
"transfer".givenThat(after(end)) {
highStreetBank.gives(acmeCorp, 10.K, USD)
next()
}
}
}
}
}
val contract2 = arrange {
rollOut("2016-09-01".ld, "2017-09-01".ld, Frequency.Monthly) {
(acmeCorp or highStreetBank).may {
"transfer".givenThat(after(end)) {
highStreetBank.gives(acmeCorp, 10.K, USD)
next()
actions {
(acmeCorp or highStreetBank).may {
"transfer".givenThat(after(end)) {
highStreetBank.gives(acmeCorp, 10.K, USD)
next()
}
}
}
}
@ -41,10 +46,12 @@ class RollOutTests {
val contractStep1a = arrange {
rollOut("2016-10-03".ld, "2017-09-01".ld, Frequency.Monthly) {
(acmeCorp or highStreetBank).may {
"transfer".givenThat(after(end)) {
highStreetBank.gives(acmeCorp, 10.K, USD)
next()
actions {
(acmeCorp or highStreetBank).may {
"transfer".givenThat(after(end)) {
highStreetBank.gives(acmeCorp, 10.K, USD)
next()
}
}
}
}
@ -64,41 +71,54 @@ class RollOutTests {
highStreetBank.gives(acmeCorp, 10.K, USD)
}
val contract_action1 = arrange {
highStreetBank.may {
"do it".anytime {
highStreetBank.gives(acmeCorp, 10.K, USD)
actions {
highStreetBank.may {
"do it".anytime {
highStreetBank.gives(acmeCorp, 10.K, USD)
}
}
}
}
val contract_action2 = arrange {
highStreetBank.may {
"do it".anytime {
highStreetBank.gives(acmeCorp, 10.K, USD)
actions {
highStreetBank.may {
"do it".anytime {
highStreetBank.gives(acmeCorp, 10.K, USD)
}
}
}
}
val contract_and1 = arrange {
highStreetBank.may {
"do it".anytime {
highStreetBank.gives(acmeCorp, 10.K, USD)
actions {
highStreetBank.may {
"do it".anytime {
highStreetBank.gives(acmeCorp, 10.K, USD)
}
}
}
acmeCorp.may {
"do it".anytime {
acmeCorp.gives(momAndPop, 10.K, USD)
actions {
acmeCorp.may {
"do it".anytime {
acmeCorp.gives(momAndPop, 10.K, USD)
}
}
}
next()
}
val contract_and2 = arrange {
highStreetBank.may {
"do it".anytime {
highStreetBank.gives(acmeCorp, 10.K, USD)
actions {
highStreetBank.may {
"do it".anytime {
highStreetBank.gives(acmeCorp, 10.K, USD)
}
}
}
acmeCorp.may {
"do it".anytime {
acmeCorp.gives(momAndPop, 10.K, USD)
actions {
acmeCorp.may {
"do it".anytime {
acmeCorp.gives(momAndPop, 10.K, USD)
}
}
}
next()

View File

@ -17,30 +17,37 @@ class Swaption {
val coupon = 1.5.bd
val dreary_contract = arrange {
(highStreetBank or acmeCorp).may {
"proceed".givenThat(after("01/07/2015")) {
highStreetBank.gives(acmeCorp, libor(notional, "01/04/2015", "01/07/2015"), currency)
acmeCorp.gives(highStreetBank, interest(notional, "act/365", coupon, "01/04/2015", "01/07/2015"), currency)
(highStreetBank or acmeCorp).may {
"proceed".givenThat(after("01/10/2015")) {
highStreetBank.gives(acmeCorp, libor(notional, "01/07/2015", "01/10/2015"), currency)
acmeCorp.gives(highStreetBank, interest(notional, "act/365", coupon, "01/07/2015", "01/10/2015"), currency)
actions {
(highStreetBank or acmeCorp).may {
"proceed".givenThat(after("01/07/2015")) {
highStreetBank.gives(acmeCorp, libor(notional, "01/04/2015", "01/07/2015"), currency)
acmeCorp.gives(highStreetBank, interest(notional, "act/365", coupon, "01/04/2015", "01/07/2015"), currency)
(highStreetBank or acmeCorp).may {
"proceed".givenThat(after("01/10/2015")) {
highStreetBank.gives(acmeCorp, libor(notional, "01/07/2015", "01/10/2015"), currency)
acmeCorp.gives(highStreetBank, interest(notional, "act/365", coupon, "01/07/2015", "01/10/2015"), currency)
(highStreetBank or acmeCorp).may {
// etc ...
actions {
(highStreetBank or acmeCorp).may {
"dummy".anytime { zero }
// etc ...
}
}
}
}
actions {
acmeCorp.may {
"cancel".anytime {
acmeCorp.gives(highStreetBank, 10.K, USD)
}
}
}
}
acmeCorp.may {
"cancel".anytime {
acmeCorp.gives(highStreetBank, 10.K, USD)
}
}
}
}
acmeCorp.may {
"cancel".anytime {
acmeCorp.gives(highStreetBank, 10.K, USD)
acmeCorp.may {
"cancel".anytime {
acmeCorp.gives(highStreetBank, 10.K, USD)
}
}
}
}
@ -48,16 +55,18 @@ class Swaption {
val elegant_contract = arrange {
rollOut("01/04/2015".ld, "01/04/2025".ld, Frequency.Quarterly) {
(highStreetBank or acmeCorp).may {
"proceed".givenThat(after(start)) {
highStreetBank.gives(acmeCorp, libor(notional, start, end), currency)
acmeCorp.gives(highStreetBank, interest(notional, "act/365", coupon, start, end), currency)
next()
actions {
(highStreetBank or acmeCorp).may {
"proceed".givenThat(after(start)) {
highStreetBank.gives(acmeCorp, libor(notional, start, end), currency)
acmeCorp.gives(highStreetBank, interest(notional, "act/365", coupon, start, end), currency)
next()
}
}
}
acmeCorp.may {
"cancel".anytime {
acmeCorp.gives(highStreetBank, 10.K, currency)
acmeCorp.may {
"cancel".anytime {
acmeCorp.gives(highStreetBank, 10.K, currency)
}
}
}
}
@ -69,21 +78,25 @@ class Swaption {
rollOut("01/04/2015".ld, "01/04/2016".ld, Frequency.Quarterly, object {
val cap = variable(150.K)
}) {
acmeCorp.may {
"exercise".givenThat(before(end)) {
val payout = (EUR / USD - strike).plus() * notional
actions {
acmeCorp.may {
"exercise".givenThat(before(end)) {
val payout = (EUR / USD - strike).plus() * notional
(acmeCorp or highStreetBank).may {
"proceed".givenThat(after(end)) {
highStreetBank.gives(acmeCorp, payout, USD)
next(vars.cap to vars.cap - payout)
actions {
(acmeCorp or highStreetBank).may {
"proceed".givenThat(after(end)) {
highStreetBank.gives(acmeCorp, payout, USD)
next(vars.cap to vars.cap - payout)
}
}
}
}
}
}
(acmeCorp or highStreetBank).may {
"proceedWithoutExercise".givenThat(after(end)) {
next()
(acmeCorp or highStreetBank).may {
"proceedWithoutExercise".givenThat(after(end)) {
next()
}
}
}
}
@ -93,21 +106,25 @@ class Swaption {
rollOut("01/04/2015".ld, "01/04/2016".ld, Frequency.Quarterly, object {
val uses = variable(4)
}) {
acmeCorp.may {
"exercise".givenThat(before(end)) {
val payout = (EUR / USD - strike).plus() * notional
actions {
acmeCorp.may {
"exercise".givenThat(before(end)) {
val payout = (EUR / USD - strike).plus() * notional
(acmeCorp or highStreetBank).may {
"proceed".givenThat(after(end)) {
highStreetBank.gives(acmeCorp, payout, currency)
next(vars.uses to vars.uses - 1)
actions {
(acmeCorp or highStreetBank).may {
"proceed".givenThat(after(end)) {
highStreetBank.gives(acmeCorp, payout, currency)
next(vars.uses to vars.uses - 1)
}
}
}
}
}
}
(acmeCorp or highStreetBank).may {
"proceedWithoutExercise".givenThat(after(end)) {
next()
(acmeCorp or highStreetBank).may {
"proceedWithoutExercise".givenThat(after(end)) {
next()
}
}
}
}

View File

@ -12,18 +12,21 @@ import java.time.Instant
class ZeroCouponBond {
val contract = arrange {
(acmeCorp or highStreetBank).may {
"execute".givenThat(after("2017-09-01")) {
highStreetBank.gives(acmeCorp, 100.K, GBP)
actions {
(acmeCorp or highStreetBank).may {
"execute".givenThat(after("2017-09-01")) {
highStreetBank.gives(acmeCorp, 100.K, GBP)
}
}
}
}
val contractMove = arrange {
(momAndPop or highStreetBank).may {
"execute".givenThat(after("2017-09-01")) {
highStreetBank.gives(momAndPop, 100.K, GBP)
actions {
(momAndPop or highStreetBank).may {
"execute".givenThat(after("2017-09-01")) {
highStreetBank.gives(momAndPop, 100.K, GBP)
}
}
}
}

View File

@ -14,9 +14,11 @@ import java.util.*
// various example arrangements using basic syntax
val cds_contract = arrange {
acmeCorp.may {
"claim".givenThat(acmeCorporationHasDefaulted and before("2017-09-01")) {
highStreetBank.gives(acmeCorp, 1.M, USD)
actions {
acmeCorp.may {
"claim".givenThat(acmeCorporationHasDefaulted and before("2017-09-01")) {
highStreetBank.gives(acmeCorp, 1.M, USD)
}
}
}
}
@ -24,49 +26,59 @@ val cds_contract = arrange {
// fx swap
// both parties have the right to trigger the exchange of cash flows
val an_fx_swap = arrange {
(acmeCorp or highStreetBank).may {
"execute".givenThat(after("2017-09-01")) {
highStreetBank.gives(acmeCorp, 1200.K, USD)
acmeCorp.gives(highStreetBank, 1.M, EUR)
actions {
(acmeCorp or highStreetBank).may {
"execute".givenThat(after("2017-09-01")) {
highStreetBank.gives(acmeCorp, 1200.K, USD)
acmeCorp.gives(highStreetBank, 1.M, EUR)
}
}
}
}
val american_fx_option = arrange {
acmeCorp.may {
"exercise".givenThat(before("2017-09-01")) {
highStreetBank.gives(acmeCorp, 1200.K, USD)
acmeCorp.gives(highStreetBank, 1.M, EUR)
actions {
acmeCorp.may {
"exercise".givenThat(before("2017-09-01")) {
highStreetBank.gives(acmeCorp, 1200.K, USD)
acmeCorp.gives(highStreetBank, 1.M, EUR)
}
}
}
}
val european_fx_option = arrange {
acmeCorp.may {
"exercise".givenThat(before("2017-09-01")) {
fx_swap("2017-09-01", 1.M, 1.2.bd, EUR, USD, acmeCorp, highStreetBank)
actions {
acmeCorp.may {
"exercise".givenThat(before("2017-09-01")) {
fx_swap("2017-09-01", 1.M, 1.2.bd, EUR, USD, acmeCorp, highStreetBank)
}
}
}
(acmeCorp or highStreetBank).may {
"expire".anytime {
zero
(acmeCorp or highStreetBank).may {
"expire".anytime {
zero
}
}
}
}
val contractZeroCouponBond = arrange {
acmeCorp.may {
"execute".givenThat(after("2017-11-01")) {
highStreetBank.gives(acmeCorp, 1.M, USD)
actions {
acmeCorp.may {
"execute".givenThat(after("2017-11-01")) {
highStreetBank.gives(acmeCorp, 1.M, USD)
}
}
}
}
// maybe in the presence of negative interest rates you would want other side of contract to be able to take initiative as well
val zero_coupon_bond_2 = arrange {
(acmeCorp or highStreetBank).may {
"execute".givenThat(after("2017-09-01")) {
highStreetBank.gives(acmeCorp, 1.M, USD)
actions {
(acmeCorp or highStreetBank).may {
"execute".givenThat(after("2017-09-01")) {
highStreetBank.gives(acmeCorp, 1.M, USD)
}
}
}
}
@ -81,25 +93,31 @@ val zero_coupon_bond_2 = arrange {
// Assume observable is using FX fixing
//
val no_touch = arrange {
(acmeCorp or highStreetBank).may {
"execute".givenThat(after("2017-09-01")) {
highStreetBank.gives(acmeCorp, 1.M, USD)
actions {
(acmeCorp or highStreetBank).may {
"execute".givenThat(after("2017-09-01")) {
highStreetBank.gives(acmeCorp, 1.M, USD)
}
}
highStreetBank.may {
"knock out".givenThat(EUR / USD gt 1.3) {
zero
}
}
}
highStreetBank.may {
"knock out".givenThat(EUR/USD gt 1.3)
}
}
val one_touch = arrange {
highStreetBank.may {
"expire".givenThat(after("2017-09-01")) {
zero
actions {
highStreetBank.may {
"expire".givenThat(after("2017-09-01")) {
zero
}
}
}
acmeCorp.may {
"knock in".givenThat(EUR / USD gt 1.3) {
highStreetBank.gives(acmeCorp, 1.M, USD)
acmeCorp.may {
"knock in".givenThat(EUR / USD gt 1.3) {
highStreetBank.gives(acmeCorp, 1.M, USD)
}
}
}
}