Added more type information to various API endpoints to make it possible to test. Integration test passes.

This commit is contained in:
Clinton Alexander 2016-12-16 14:47:29 +00:00
parent 234ffb141c
commit 008fcf50fd
2 changed files with 78 additions and 42 deletions
samples/simm-valuation-demo/src
integration-test/kotlin/net/corda/vega
main/kotlin/net/corda/vega/api

View File

@ -9,28 +9,38 @@ import net.corda.testing.IntegrationTestCategory
import net.corda.testing.getHostAndPort
import net.corda.testing.http.HttpApi
import net.corda.vega.api.PortfolioApi
import net.corda.vega.api.PortfolioApiUtils
import net.corda.vega.api.SwapDataModel
import net.corda.vega.portfolio.Portfolio
import org.junit.Test
import java.math.BigDecimal
import java.time.LocalDate
import java.util.*
class SimmValuationTest: IntegrationTestCategory {
private companion object {
// SIMM demo can only currently handle one valuation date due to a lack of market data or a market data source.
val valuationDate = LocalDate.parse("2016-06-06")
val nodeALegalName = "Bank A"
val nodeBLegalName = "Bank B"
}
@Test fun `runs SIMM valuation demo`() {
driver(isDebug = true) {
val nodeBLegalName = "Bank B"
val controller = startNode("Controller", setOf(ServiceInfo(SimpleNotaryService.type))).getOrThrow()
val nodeAAddr = startNode("Bank A").getOrThrow().config.getHostAndPort("webAddress")
startNode("Controller", setOf(ServiceInfo(SimpleNotaryService.type))).getOrThrow()
val nodeAAddr = startNode(nodeALegalName).getOrThrow().config.getHostAndPort("webAddress")
val nodeBAddr = startNode(nodeBLegalName).getOrThrow().config.getHostAndPort("webAddress")
val nodeA = HttpApi.fromHostAndPort(nodeAAddr, "api/simmvaluationdemo")
val nodeB = HttpApi.fromHostAndPort(nodeBAddr, "api/simmvaluationdemo")
val parties = getAvailablePartiesFor(nodeA)
val nodeB = parties.counterparties.single { it.text == nodeBLegalName}
assert(createTradeBetween(nodeA, nodeB))
assert(runValuationsBetween(nodeA, nodeB))
waitForAllNodesToFinish()
val nodeBParty = getAvailablePartiesFor(nodeA).counterparties.single { it.text == nodeBLegalName }
val nodeAParty = getAvailablePartiesFor(nodeB).counterparties.single { it.text == nodeALegalName }
assert(createTradeBetween(nodeA, nodeBParty))
assert(tradeExists(nodeB, nodeAParty))
assert(runValuationsBetween(nodeA, nodeBParty))
assert(valuationExists(nodeB, nodeAParty))
}
}
@ -39,12 +49,22 @@ class SimmValuationTest: IntegrationTestCategory {
}
private fun createTradeBetween(api: HttpApi, counterparty: PortfolioApi.ApiParty): Boolean {
val trade = SwapDataModel("trade1", "desc", LocalDate.parse("2016-01-01"), "EUR_FIXED_1Y_EURIBOR_3M",
LocalDate.parse("2016-01-02"), LocalDate.parse("2020-01-02"), BuySell.BUY, BigDecimal.valueOf(1000), BigDecimal.valueOf(0.1))
val trade = SwapDataModel("trade1", "desc", valuationDate, "EUR_FIXED_1Y_EURIBOR_3M",
valuationDate, LocalDate.parse("2020-01-02"), BuySell.BUY, BigDecimal.valueOf(1000), BigDecimal.valueOf(0.1))
return api.putJson("${counterparty.id}/trades", trade)
}
private fun tradeExists(api: HttpApi, counterparty: PortfolioApi.ApiParty): Boolean {
val trades = api.getJson<List<Map<String, Any>>>("${counterparty.id}/trades")
return (!trades.isEmpty())
}
private fun runValuationsBetween(api: HttpApi, counterparty: PortfolioApi.ApiParty): Boolean {
return api.postJson("${counterparty.id}/trade/TODO/valuations/calculate")
return api.postJson("${counterparty.id}/portfolio/valuations/calculate", PortfolioApi.ValuationCreationParams(valuationDate))
}
private fun valuationExists(api: HttpApi, counterparty: PortfolioApi.ApiParty): Boolean {
val valuations = api.getJson<PortfolioApiUtils.ValuationsView>("${counterparty.id}/portfolio/valuations")
return (valuations.initialMargin.call["total"] != 0.0)
}
}

View File

@ -15,7 +15,16 @@ import java.time.LocalDate
* API JSON generation functions for larger JSON outputs.
*/
class PortfolioApiUtils(private val ownParty: Party) {
fun createValuations(state: PortfolioState, portfolio: Portfolio): Any {
data class InitialMarginView(val baseCurrency: String, val post: Map<String, Double>, val call: Map<String, Double>, val agreed: Boolean)
data class ValuationsView(
val businessDate: LocalDate,
val portfolio: Map<String, Any>,
val marketData: Map<String, Any>,
val sensitivities: Map<String, Any>,
val initialMargin: InitialMarginView,
val confirmation: Map<String, Any>)
fun createValuations(state: PortfolioState, portfolio: Portfolio): ValuationsView {
val valuation = state.valuation!!
val currency = if (portfolio.trades.isNotEmpty()) {
@ -61,10 +70,28 @@ class PortfolioApiUtils(private val ownParty: Party) {
val processedSensitivities = valuation.totalSensivities.sensitivities.map { it.marketDataName to it.parameterMetadata.map { it.label }.zip(it.sensitivity.toList()).toMap() }.toMap()
return json {
val initialMarginView = InitialMarginView(
baseCurrency = currency,
post = mapOf(
"IRFX" to valuation.margin.first,
"commodity" to 0.0,
"equity" to 0.0,
"credit" to 0.0,
"total" to valuation.margin.first
),
call = mapOf(
"IRFX" to valuation.margin.first,
"commodity" to 0.0,
"equity" to 0.0,
"credit" to 0.0,
"total" to valuation.margin.first
),
agreed = true)
return ValuationsView(
businessDate = LocalDate.now(),
portfolio = json {
obj(
"businessDate" to LocalDate.now(),
"portfolio" to obj(
"trades" to tradeCount,
"baseCurrency" to currency,
"IRFX" to tradeCount,
@ -73,13 +100,17 @@ class PortfolioApiUtils(private val ownParty: Party) {
"credit" to 0,
"total" to tradeCount,
"agreed" to true
),
"marketData" to obj(
)
},
marketData = json {
obj(
"yieldCurves" to yieldCurves,
"fixings" to fixings,
"agreed" to true
),
"sensitivities" to obj("curves" to processedSensitivities,
)
},
sensitivities = json {
obj("curves" to processedSensitivities,
"currency" to valuation.currencySensitivies.amounts.toList().map {
obj(
"currency" to it.currency.code,
@ -87,31 +118,16 @@ class PortfolioApiUtils(private val ownParty: Party) {
)
},
"agreed" to true
),
"initialMargin" to obj(
"baseCurrency" to currency,
"post" to obj(
"IRFX" to valuation.margin.first,
"commodity" to 0,
"equity" to 0,
"credit" to 0,
"total" to valuation.margin.first
),
"call" to obj(
"IRFX" to valuation.margin.first,
"commodity" to 0,
"equity" to 0,
"credit" to 0,
"total" to valuation.margin.first
),
"agreed" to true
),
"confirmation" to obj(
)
},
initialMargin = initialMarginView,
confirmation = json {
obj(
"hash" to state.hash().toString(),
"agreed" to true
)
)
}
)
}
fun createTradeView(state: IRSState): Any {