mirror of
https://github.com/corda/corda.git
synced 2024-12-19 04:57:58 +00:00
Merge remote-tracking branch 'remotes/origin/master' into mnesbit-cor-261-artemis-over-ssl
This commit is contained in:
commit
09c795e341
@ -12,6 +12,13 @@ interface CordaPluginRegistry {
|
||||
*/
|
||||
val webApis: List<Class<*>>
|
||||
|
||||
/**
|
||||
* Map of static serving endpoints to the matching resource directory. All endpoints will be prefixed with "/web" and postfixed with "\*.
|
||||
* Resource directories can be either on disk directories (especially when debugging) in the form "a/b/c". Serving from a JAR can
|
||||
* be specified with: javaClass.getResource("<folder-in-jar>").toExternalForm()
|
||||
*/
|
||||
val staticServeDirs: Map<String, String>
|
||||
|
||||
/**
|
||||
* A Map with an entry for each consumed protocol used by the webAPIs.
|
||||
* The key of each map entry should contain the ProtocolLogic<T> class name.
|
||||
|
@ -8,6 +8,7 @@ so far. We have:
|
||||
how this works in :doc:`protocol-state-machines`.
|
||||
2. The IRS demo, which shows two nodes establishing an interest rate swap between them and performing fixings with a
|
||||
rates oracle, all driven via the HTTP API.
|
||||
3. The IRS demo web interface - a web interface to the IRS demo.
|
||||
|
||||
The demos create node data directories in the root of the project. If something goes wrong with them, blow away the
|
||||
directories and try again.
|
||||
@ -29,7 +30,7 @@ Open two terminals, and in the first run:
|
||||
|
||||
**Other**::
|
||||
|
||||
Other: ./gradlew installDist && ./build/install/r3prototyping/bin/trader-demo --role=BUYER
|
||||
./gradlew installDist && ./build/install/r3prototyping/bin/trader-demo --role=BUYER
|
||||
|
||||
It will compile things, if necessary, then create a directory named trader-demo/buyer with a bunch of files inside and
|
||||
start the node. You should see it waiting for a trade to begin.
|
||||
@ -96,3 +97,53 @@ can see the other terminals whilst you run this command!:
|
||||
**Other**::
|
||||
|
||||
./build/install/r3prototyping/bin/irsdemo --role=Date 2017-01-30
|
||||
|
||||
|
||||
IRS web demo
|
||||
------------
|
||||
|
||||
To install the web demo please follow these steps;
|
||||
|
||||
1. Install Node: https://nodejs.org/en/download/ and ensure the npm executable is on your classpath
|
||||
2. Open a terminal
|
||||
3. Run `npm install -g bower` or `sudo npm install -g bower` if on a *nix system.
|
||||
4. In the terminal navigate to `<corda>/src/main/resources/com/r3corda/demos/irswebdemo`
|
||||
5. Run `bower install`
|
||||
|
||||
To run the web demo, run the first two steps from the IRS Demo:
|
||||
|
||||
Open two terminals and in the first:
|
||||
|
||||
**Windows**::
|
||||
|
||||
gradlew.bat installDist & .\build\install\r3prototyping\bin\irsdemo.bat --role=NodeA
|
||||
|
||||
**Other**::
|
||||
|
||||
./gradlew installDist && ./build/install/r3prototyping/bin/irsdemo --role=NodeA
|
||||
|
||||
And in the second run:
|
||||
|
||||
**Windows**::
|
||||
|
||||
.\build\install\r3prototyping\bin\irsdemo.bat --role=NodeB
|
||||
|
||||
**Other**::
|
||||
|
||||
./build/install/r3prototyping/bin/irsdemo --role=NodeB
|
||||
|
||||
Now open your web browser to this URL:
|
||||
|
||||
.. note:: If using a custom node port address or port those must be used instead.
|
||||
|
||||
**Node A**:
|
||||
|
||||
http://localhost:31338/web/irsdemo
|
||||
|
||||
**Node B**:
|
||||
|
||||
http://localhost:31340/web/irsdemo
|
||||
|
||||
To use the demos click the "Create Deal" button, fill in the form, then click the "Submit" button. Now you will be
|
||||
able to use the time controls at the top left of the home page to run the fixings. Click any individual trade in the
|
||||
blotter to view it.
|
@ -16,8 +16,13 @@ import com.r3corda.node.servlets.Config
|
||||
import com.r3corda.node.servlets.DataUploadServlet
|
||||
import com.r3corda.node.servlets.ResponseFilter
|
||||
import com.r3corda.node.utilities.AffinityExecutor
|
||||
import org.eclipse.jetty.server.Handler
|
||||
import org.eclipse.jetty.server.Server
|
||||
import org.eclipse.jetty.server.handler.DefaultHandler
|
||||
import org.eclipse.jetty.server.handler.HandlerCollection
|
||||
import org.eclipse.jetty.server.handler.HandlerList
|
||||
import org.eclipse.jetty.server.handler.ResourceHandler
|
||||
import org.eclipse.jetty.servlet.DefaultServlet
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler
|
||||
import org.eclipse.jetty.servlet.ServletHolder
|
||||
import org.eclipse.jetty.webapp.WebAppContext
|
||||
@ -96,7 +101,15 @@ class Node(dir: Path, val p2pAddr: HostAndPort, val webServerAddr: HostAndPort,
|
||||
}
|
||||
|
||||
// API, data upload and download to services (attachments, rates oracles etc)
|
||||
handlerCollection.addHandler(ServletContextHandler().apply {
|
||||
handlerCollection.addHandler(buildServletContextHandler())
|
||||
|
||||
server.handler = handlerCollection
|
||||
server.start()
|
||||
return server
|
||||
}
|
||||
|
||||
private fun buildServletContextHandler(): ServletContextHandler {
|
||||
return ServletContextHandler().apply {
|
||||
contextPath = "/"
|
||||
setAttribute("node", this@Node)
|
||||
addServlet(DataUploadServlet::class.java, "/upload/*")
|
||||
@ -115,6 +128,16 @@ class Node(dir: Path, val p2pAddr: HostAndPort, val webServerAddr: HostAndPort,
|
||||
resourceConfig.register(customAPI)
|
||||
}
|
||||
|
||||
val staticDirMaps = pluginRegistries.map { x -> x.staticServeDirs }
|
||||
val staticDirs = staticDirMaps.flatMap { it.keys }.zip(staticDirMaps.flatMap { it.values })
|
||||
staticDirs.forEach {
|
||||
val staticDir = ServletHolder(DefaultServlet::class.java)
|
||||
staticDir.setInitParameter("resourceBase", it.second)
|
||||
staticDir.setInitParameter("dirAllowed", "true")
|
||||
staticDir.setInitParameter("pathInfoOnly", "true")
|
||||
addServlet(staticDir, "/web/${it.first}/*")
|
||||
}
|
||||
|
||||
// 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",
|
||||
ServerProperties.MONITORING_STATISTICS_MBEANS_ENABLED to "true"))
|
||||
@ -123,11 +146,7 @@ class Node(dir: Path, val p2pAddr: HostAndPort, val webServerAddr: HostAndPort,
|
||||
val jerseyServlet = ServletHolder(container)
|
||||
addServlet(jerseyServlet, "/api/*")
|
||||
jerseyServlet.initOrder = 0 // Initialise at server start
|
||||
})
|
||||
|
||||
server.handler = handlerCollection
|
||||
server.start()
|
||||
return server
|
||||
}
|
||||
}
|
||||
|
||||
override fun start(): Node {
|
||||
|
@ -102,7 +102,7 @@ object NodeInterestRates {
|
||||
class FixingServicePlugin : CordaPluginRegistry {
|
||||
override val webApis: List<Class<*>> = emptyList()
|
||||
override val requiredProtocols: Map<String, Set<String>> = mapOf(Pair(TwoPartyDealProtocol.FixingRoleDecider::class.java.name, setOf(Duration::class.java.name, StateRef::class.java.name)))
|
||||
|
||||
override val staticServeDirs: Map<String, String> = emptyMap()
|
||||
}
|
||||
|
||||
// File upload support
|
||||
|
@ -68,6 +68,10 @@ sealed class FiberRequest(val topic: String,
|
||||
override fun toString(): String {
|
||||
return "Expecting response via topic ${receiveTopic} of type ${responseTypeName}"
|
||||
}
|
||||
|
||||
// We have to do an unchecked cast, but unless the serialized form is damaged, this was
|
||||
// correct when the request was instantiated
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val responseType: Class<R>
|
||||
get() = Class.forName(responseTypeName) as Class<R>
|
||||
}
|
||||
|
@ -109,9 +109,10 @@ class ProtocolStateMachineImpl<R>(val logic: ProtocolLogic<R>,
|
||||
try {
|
||||
suspendAction(with)
|
||||
} catch (t: Throwable) {
|
||||
// Do not throw exception again - Quasar completely bins it.
|
||||
logger.warn("Captured exception which was swallowed by Quasar", t)
|
||||
// TODO to throw or not to throw, that is the question
|
||||
throw t
|
||||
actionOnEnd()
|
||||
_resultFuture?.setException(t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ class PerFileCheckpointStorageTests {
|
||||
|
||||
private var checkpointCount = 1
|
||||
private val request = FiberRequest.ExpectingResponse("topic", null, random63BitValue(), random63BitValue(), null,
|
||||
java.lang.String::class.java)
|
||||
kotlin.String::class.java)
|
||||
private fun newCheckpoint() = Checkpoint(SerializedBytes(Ints.toByteArray(checkpointCount++)), request)
|
||||
|
||||
}
|
@ -260,6 +260,7 @@ object CliParamsSpec {
|
||||
|
||||
class IRSDemoPluginRegistry : CordaPluginRegistry {
|
||||
override val webApis: List<Class<*>> = listOf(InterestRateSwapAPI::class.java)
|
||||
override val staticServeDirs: Map<String, String> = mapOf("irsdemo" to javaClass.getResource("irswebdemo").toExternalForm())
|
||||
override val requiredProtocols: Map<String, Set<String>> = mapOf(
|
||||
Pair(AutoOfferProtocol.Requester::class.java.name, setOf(InterestRateSwap.State::class.java.name)),
|
||||
Pair(UpdateBusinessDayProtocol.Broadcast::class.java.name, setOf(java.time.LocalDate::class.java.name)),
|
||||
@ -404,7 +405,6 @@ private fun startNode(params: CliParams.RunNode, networkMap: SingleMessageRecipi
|
||||
val node = logElapsedTime("Node startup", log) {
|
||||
Node(params.dir, params.networkAddress, params.apiAddress, config, networkMapId, advertisedServices, DemoClock()).start()
|
||||
}
|
||||
|
||||
// TODO: This should all be replaced by the identity service being updated
|
||||
// as the network map changes.
|
||||
for (identityFile in params.tradeWithIdentities) {
|
||||
|
@ -2,18 +2,23 @@ package com.r3corda.demos.api
|
||||
|
||||
import com.r3corda.contracts.InterestRateSwap
|
||||
import com.r3corda.core.contracts.SignedTransaction
|
||||
import com.r3corda.core.failure
|
||||
import com.r3corda.core.node.ServiceHub
|
||||
import com.r3corda.core.node.services.linearHeadsOfType
|
||||
import com.r3corda.core.success
|
||||
import com.r3corda.core.utilities.loggerFor
|
||||
import com.r3corda.demos.protocols.AutoOfferProtocol
|
||||
import com.r3corda.demos.protocols.ExitServerProtocol
|
||||
import com.r3corda.demos.protocols.UpdateBusinessDayProtocol
|
||||
import org.apache.commons.io.IOUtils
|
||||
import java.net.URI
|
||||
import java.net.URLConnection
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDateTime
|
||||
import javax.ws.rs.*
|
||||
import javax.ws.rs.core.MediaType
|
||||
import javax.ws.rs.core.Response
|
||||
import javax.ws.rs.core.*
|
||||
import java.nio.channels.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* This provides a simplified API, currently for demonstration use only.
|
||||
@ -65,8 +70,13 @@ class InterestRateSwapAPI(val services: ServiceHub) {
|
||||
@Path("deals")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
fun storeDeal(newDeal: InterestRateSwap.State): Response {
|
||||
services.invokeProtocolAsync<SignedTransaction>(AutoOfferProtocol.Requester::class.java, newDeal).get()
|
||||
return Response.created(URI.create(generateDealLink(newDeal))).build()
|
||||
try {
|
||||
services.invokeProtocolAsync<SignedTransaction>(AutoOfferProtocol.Requester::class.java, newDeal).get()
|
||||
return Response.created(URI.create(generateDealLink(newDeal))).build()
|
||||
} catch (ex: Throwable) {
|
||||
logger.info("Exception when creating deal: ${ex.toString()}")
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ex.toString()).build()
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
|
3
src/main/resources/com/r3corda/demos/irswebdemo/.bowerrc
Normal file
3
src/main/resources/com/r3corda/demos/irswebdemo/.bowerrc
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"directory": "js/bower_components"
|
||||
}
|
2
src/main/resources/com/r3corda/demos/irswebdemo/.gitignore
vendored
Normal file
2
src/main/resources/com/r3corda/demos/irswebdemo/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
bower_components
|
||||
|
25
src/main/resources/com/r3corda/demos/irswebdemo/bower.json
Normal file
25
src/main/resources/com/r3corda/demos/irswebdemo/bower.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "www",
|
||||
"description": "",
|
||||
"main": "",
|
||||
"license": "MIT",
|
||||
"homepage": "",
|
||||
"private": true,
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests"
|
||||
],
|
||||
"dependencies": {
|
||||
"angular": "^1.5.6",
|
||||
"jquery": "^3.0.0",
|
||||
"angular-route": "^1.5.7",
|
||||
"lodash": "^4.13.1",
|
||||
"angular-fcsa-number": "^1.5.3",
|
||||
"jquery.maskedinput": "^1.4.1",
|
||||
"requirejs": "^2.2.0",
|
||||
"semantic": "semantic-ui#^2.2.2"
|
||||
}
|
||||
}
|
15
src/main/resources/com/r3corda/demos/irswebdemo/css/main.css
Normal file
15
src/main/resources/com/r3corda/demos/irswebdemo/css/main.css
Normal file
@ -0,0 +1,15 @@
|
||||
#fixedleg tbody tr:nth-child(odd) {
|
||||
background-color: #EEFAEE;
|
||||
}
|
||||
|
||||
#createfixedleg, #fixedleg tbody tr:nth-child(even), #fixedleg thead th {
|
||||
background-color: #D0FAD0;
|
||||
}
|
||||
|
||||
#floatingleg tbody tr:nth-child(odd) {
|
||||
background-color: #FAEEEE;
|
||||
}
|
||||
|
||||
#createfloatingleg, #floatingleg tbody tr:nth-child(even), #floatingleg thead th {
|
||||
background-color: #FAD0D0;
|
||||
}
|
30
src/main/resources/com/r3corda/demos/irswebdemo/index.html
Normal file
30
src/main/resources/com/r3corda/demos/irswebdemo/index.html
Normal file
@ -0,0 +1,30 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<!-- Standard Meta -->
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
|
||||
|
||||
<!-- Site Properties -->
|
||||
<title>IRS Demo Viewer</title>
|
||||
<link rel="shortcut icon" type="image/x-icon" href="http://r3cev.com/favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="js/bower_components/semantic/dist/semantic.css" />
|
||||
<link rel="stylesheet" type="text/css" href="css/main.css" />
|
||||
|
||||
<script data-main="js/require-config" src="js/bower_components/requirejs/require.js"></script>
|
||||
</head>
|
||||
<body ng-controller="HomeController">
|
||||
<div class="ui attached inverted menu">
|
||||
<span class="header item"><a href="#/">IRS Web Demo</a></span>
|
||||
<span class="item"><a href="#/">Recent Deals</a></span>
|
||||
<span class="item"><a href="#/create-deal">Create Deal</a></span>
|
||||
</div>
|
||||
<div class="ui container">
|
||||
<div id="loading" class="ui modal">
|
||||
<div class="ui text loader">Loading</div>
|
||||
</div>
|
||||
<div ng-view></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
79
src/main/resources/com/r3corda/demos/irswebdemo/js/Deal.js
Normal file
79
src/main/resources/com/r3corda/demos/irswebdemo/js/Deal.js
Normal file
@ -0,0 +1,79 @@
|
||||
"use strict"
|
||||
|
||||
define(['viewmodel/FixedRate'], (fixedRateViewModel) => {
|
||||
let calculationModel = {
|
||||
expression: "( fixedLeg.notional.quantity * (fixedLeg.fixedRate.ratioUnit.value)) - (floatingLeg.notional.quantity * (calculation.fixingSchedule.get(context.getDate('currentDate')).rate.ratioUnit.value))",
|
||||
floatingLegPaymentSchedule: {
|
||||
|
||||
},
|
||||
fixedLegPaymentSchedule: {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
let indexLookup = {
|
||||
"GBP": "ICE LIBOR",
|
||||
"USD": "ICE LIBOR",
|
||||
"EUR": "EURIBOR"
|
||||
};
|
||||
|
||||
let calendarLookup = {
|
||||
"GBP": "London",
|
||||
"USD": "NewYork",
|
||||
"EUR": "London"
|
||||
};
|
||||
|
||||
let Deal = function(dealViewModel) {
|
||||
let now = new Date();
|
||||
let tradeId = `T${now.getUTCFullYear()}-${now.getUTCMonth()}-${now.getUTCDate()}.${now.getUTCHours()}:${now.getUTCMinutes()}:${now.getUTCSeconds()}:${now.getUTCMilliseconds()}`
|
||||
|
||||
this.toJson = () => {
|
||||
let fixedLeg = {};
|
||||
let floatingLeg = {};
|
||||
let common = {};
|
||||
_.assign(fixedLeg, dealViewModel.fixedLeg);
|
||||
_.assign(floatingLeg, dealViewModel.floatingLeg);
|
||||
_.assign(common, dealViewModel.common);
|
||||
_.assign(fixedLeg.fixedRate, fixedRateViewModel);
|
||||
|
||||
fixedLeg.fixedRate = Number(fixedLeg.fixedRate) / 100;
|
||||
fixedLeg.notional.token = common.baseCurrency;
|
||||
fixedLeg.effectiveDate = formatDateForNode(common.effectiveDate);
|
||||
fixedLeg.terminationDate = formatDateForNode(common.terminationDate);
|
||||
fixedLeg.fixedRate = { ratioUnit: { value: fixedLeg.fixedRate } };
|
||||
fixedLeg.dayCountBasisDay = fixedLeg.dayCountBasis.day;
|
||||
fixedLeg.dayCountBasisYear = fixedLeg.dayCountBasis.year;
|
||||
fixedLeg.paymentCalendar = calendarLookup[common.baseCurrency];
|
||||
delete fixedLeg.dayCountBasis;
|
||||
|
||||
floatingLeg.notional.token = common.baseCurrency;
|
||||
floatingLeg.effectiveDate = formatDateForNode(common.effectiveDate);
|
||||
floatingLeg.terminationDate = formatDateForNode(common.terminationDate);
|
||||
floatingLeg.dayCountBasisDay = floatingLeg.dayCountBasis.day;
|
||||
floatingLeg.dayCountBasisYear = floatingLeg.dayCountBasis.year;
|
||||
floatingLeg.index = indexLookup[common.baseCurrency];
|
||||
floatingLeg.fixingCalendar = [calendarLookup[common.baseCurrency]];
|
||||
floatingLeg.paymentCalendar = [calendarLookup[common.baseCurrency]];
|
||||
delete floatingLeg.dayCountBasis;
|
||||
|
||||
common.tradeID = tradeId;
|
||||
common.eligibleCurrency = common.baseCurrency;
|
||||
common.independentAmounts.token = common.baseCurrency;
|
||||
common.threshold.token = common.baseCurrency;
|
||||
common.minimumTransferAmount.token = common.baseCurrency;
|
||||
common.rounding.token = common.baseCurrency;
|
||||
delete common.effectiveDate;
|
||||
delete common.terminationDate;
|
||||
|
||||
let json = {
|
||||
fixedLeg: fixedLeg,
|
||||
floatingLeg: floatingLeg,
|
||||
calculation: calculationModel,
|
||||
common: common
|
||||
}
|
||||
|
||||
return json;
|
||||
};
|
||||
};
|
||||
return Deal;
|
||||
})
|
24
src/main/resources/com/r3corda/demos/irswebdemo/js/app.js
Normal file
24
src/main/resources/com/r3corda/demos/irswebdemo/js/app.js
Normal file
@ -0,0 +1,24 @@
|
||||
"use strict"
|
||||
|
||||
function formatDateForNode(date) {
|
||||
// Produces yyyy-dd-mm. JS is missing proper date formatting libs
|
||||
let day = ("0" + (date.getDate())).slice(-2);
|
||||
let month = ("0" + (date.getMonth() + 1)).slice(-2);
|
||||
return `${date.getFullYear()}-${month}-${day}`;
|
||||
}
|
||||
|
||||
function formatDateForAngular(dateStr) {
|
||||
let parts = dateStr.split("-");
|
||||
return new Date(parts[0], parts[1], parts[2]);
|
||||
}
|
||||
|
||||
define([
|
||||
'angular',
|
||||
'angularRoute',
|
||||
'jquery',
|
||||
'fcsaNumber',
|
||||
'semantic'
|
||||
], (angular, angularRoute, $, fcsaNumber, semantic) => {
|
||||
angular.module('irsViewer', ['ngRoute', 'fcsa-number']);
|
||||
requirejs(['routes']);
|
||||
});
|
@ -0,0 +1,36 @@
|
||||
'use strict';
|
||||
|
||||
define([
|
||||
'angular',
|
||||
'maskedInput',
|
||||
'utils/semantic',
|
||||
'utils/dayCountBasisLookup',
|
||||
'services/NodeApi',
|
||||
'Deal'
|
||||
], (angular, maskedInput, semantic, dayCountBasisLookup, nodeApi, Deal) => {
|
||||
angular.module('irsViewer').controller('CreateDealController', function CreateDealController($http, $scope, $location, nodeService) {
|
||||
semantic.init($scope, nodeService.isLoading);
|
||||
|
||||
$scope.dayCountBasisLookup = dayCountBasisLookup;
|
||||
$scope.deal = nodeService.newDeal();
|
||||
$scope.createDeal = () => {
|
||||
nodeService.createDeal(new Deal($scope.deal))
|
||||
.then((tradeId) => $location.path('#/deal/' + tradeId), (resp) => {
|
||||
$scope.formError = resp.data;
|
||||
});
|
||||
};
|
||||
$('input.percent').mask("9.999999%", {placeholder: "", autoclear: false});
|
||||
$('#swapirscolumns').click(() => {
|
||||
let first = $('#irscolumns .irscolumn:eq( 0 )');
|
||||
let last = $('#irscolumns .irscolumn:eq( 1 )');
|
||||
first.before(last);
|
||||
|
||||
let swapPayers = () => {
|
||||
let tmp = $scope.deal.floatingLeg.floatingRatePayer;
|
||||
$scope.deal.floatingLeg.floatingRatePayer = $scope.deal.fixedLeg.fixedRatePayer;
|
||||
$scope.deal.fixedLeg.fixedRatePayer = tmp;
|
||||
};
|
||||
$scope.$apply(swapPayers);
|
||||
});
|
||||
});
|
||||
});
|
@ -0,0 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
define(['angular', 'utils/semantic', 'services/NodeApi'], (angular, semantic, nodeApi) => {
|
||||
angular.module('irsViewer').controller('DealController', function DealController($http, $scope, $routeParams, nodeService) {
|
||||
semantic.init($scope, nodeService.isLoading);
|
||||
|
||||
nodeService.getDeal($routeParams.dealId).then((deal) => $scope.deal = deal);
|
||||
});
|
||||
});
|
@ -0,0 +1,23 @@
|
||||
'use strict';
|
||||
|
||||
define(['angular', 'utils/semantic', 'services/NodeApi'], (angular, semantic, nodeApi) => {
|
||||
angular.module('irsViewer').controller('HomeController', function HomeController($http, $scope, nodeService) {
|
||||
semantic.addLoadingModal($scope, nodeService.isLoading);
|
||||
|
||||
let handleHttpFail = (resp) => {
|
||||
$scope.httpError = resp.data
|
||||
}
|
||||
|
||||
$scope.infoMsg = "";
|
||||
$scope.errorText = "";
|
||||
$scope.date = { "year": "...", "month": "...", "day": "..." };
|
||||
$scope.updateDate = (type) => {
|
||||
nodeService.updateDate(type).then((newDate) => {
|
||||
$scope.date = newDate
|
||||
}, handleHttpFail);
|
||||
};
|
||||
|
||||
nodeService.getDate().then((date) => $scope.date = date);
|
||||
nodeService.getDeals().then((deals) => $scope.deals = deals);
|
||||
});
|
||||
})
|
@ -0,0 +1,28 @@
|
||||
'use strict';
|
||||
|
||||
require.config({
|
||||
paths: {
|
||||
angular: 'bower_components/angular/angular',
|
||||
angularRoute: 'bower_components/angular-route/angular-route',
|
||||
fcsaNumber: 'bower_components/angular-fcsa-number/src/fcsaNumber',
|
||||
jquery: 'bower_components/jquery/dist/jquery',
|
||||
semantic: 'bower_components/semantic/dist/semantic',
|
||||
lodash: 'bower_components/lodash/lodash',
|
||||
maskedInput: 'bower_components/jquery.maskedinput/dist/jquery.maskedinput'
|
||||
},
|
||||
shim: {
|
||||
'angular' : {'exports' : 'angular'},
|
||||
'angularRoute': ['angular'],
|
||||
'fcsaNumber': ['angular'],
|
||||
'semantic': ['jquery'],
|
||||
'maskedInput': ['jquery']
|
||||
},
|
||||
priority: [
|
||||
"angular"
|
||||
],
|
||||
baseUrl: 'js',
|
||||
});
|
||||
|
||||
require(['angular', 'app'], (angular, app) => {
|
||||
|
||||
});
|
33
src/main/resources/com/r3corda/demos/irswebdemo/js/routes.js
Normal file
33
src/main/resources/com/r3corda/demos/irswebdemo/js/routes.js
Normal file
@ -0,0 +1,33 @@
|
||||
'use strict';
|
||||
|
||||
define([
|
||||
'angular',
|
||||
'controllers/Home',
|
||||
'controllers/Deal',
|
||||
'controllers/CreateDeal'
|
||||
], (angular) => {
|
||||
angular.module('irsViewer').config(($routeProvider, $locationProvider) => {
|
||||
$routeProvider
|
||||
.when('/', {
|
||||
controller: 'HomeController',
|
||||
templateUrl: 'view/home.html'
|
||||
})
|
||||
.when('/deal/:dealId', {
|
||||
controller: 'DealController',
|
||||
templateUrl: 'view/deal.html'
|
||||
})
|
||||
.when('/party/:partyId', {
|
||||
templateUrl: 'view/party.html'
|
||||
})
|
||||
.when('/create-deal', {
|
||||
controller: 'CreateDealController',
|
||||
templateUrl: 'view/create-deal.html'
|
||||
})
|
||||
.otherwise({redirectTo: '/'});
|
||||
});
|
||||
|
||||
angular.element().ready(function() {
|
||||
// bootstrap the app manually
|
||||
angular.bootstrap(document, ['irsViewer']);
|
||||
});
|
||||
});
|
@ -0,0 +1,99 @@
|
||||
'use strict';
|
||||
|
||||
define(['angular', 'lodash', 'viewmodel/Deal'], (angular, _, dealViewModel) => {
|
||||
angular.module('irsViewer').factory('nodeService', ($http) => {
|
||||
return new (function() {
|
||||
let date = new Date(2016, 0, 1, 0, 0, 0);
|
||||
let curLoading = {};
|
||||
|
||||
let load = (type, promise) => {
|
||||
curLoading[type] = true;
|
||||
return promise.then((arg) => {
|
||||
curLoading[type] = false;
|
||||
return arg;
|
||||
}, (arg) => {
|
||||
curLoading[type] = false;
|
||||
throw arg;
|
||||
});
|
||||
}
|
||||
|
||||
let changeDateOnNode = (newDate) => {
|
||||
const dateStr = formatDateForNode(newDate);
|
||||
let endpoint = '/api/irs/demodate';
|
||||
return load('date', $http.put(endpoint, "\"" + dateStr + "\"")).then((resp) => {
|
||||
date = newDate;
|
||||
return this.getDateModel(date);
|
||||
});
|
||||
}
|
||||
|
||||
this.getDate = () => {
|
||||
return load('date', $http.get('/api/irs/demodate')).then((resp) => {
|
||||
const parts = resp.data.split("-");
|
||||
date = new Date(parts[0], parts[1] - 1, parts[2]); // JS uses 0 based months
|
||||
return this.getDateModel(date);
|
||||
});
|
||||
}
|
||||
|
||||
this.updateDate = (type) => {
|
||||
let newDate = date;
|
||||
switch(type) {
|
||||
case "year":
|
||||
newDate.setFullYear(date.getFullYear() + 1);
|
||||
break;
|
||||
|
||||
case "month":
|
||||
newDate.setMonth(date.getMonth() + 1);
|
||||
break;
|
||||
|
||||
case "day":
|
||||
newDate.setDate(date.getDate() + 1);
|
||||
break;
|
||||
}
|
||||
|
||||
return changeDateOnNode(newDate);
|
||||
};
|
||||
|
||||
this.getDeals = () => {
|
||||
return load('deals', $http.get('/api/irs/deals')).then((resp) => {
|
||||
return resp.data.reverse();
|
||||
});
|
||||
};
|
||||
|
||||
this.getDeal = (dealId) => {
|
||||
return load('deal' + dealId, $http.get('/api/irs/deals/' + dealId)).then((resp) => {
|
||||
// Do some data modification to simplify the model
|
||||
let deal = resp.data;
|
||||
deal.fixedLeg.fixedRate.value = (deal.fixedLeg.fixedRate.ratioUnit.value * 100).toString().slice(0, 6);
|
||||
return deal;
|
||||
});
|
||||
};
|
||||
|
||||
this.getDateModel = (date) => {
|
||||
return {
|
||||
"year": date.getFullYear(),
|
||||
"month": date.getMonth() + 1, // JS uses 0 based months
|
||||
"day": date.getDate()
|
||||
};
|
||||
}
|
||||
|
||||
this.isLoading = () => {
|
||||
return _.reduce(Object.keys(curLoading), (last, key) => {
|
||||
return (last || curLoading[key]);
|
||||
}, false);
|
||||
}
|
||||
|
||||
this.newDeal = () => {
|
||||
return dealViewModel;
|
||||
}
|
||||
|
||||
this.createDeal = (deal) => {
|
||||
return load('create-deal', $http.post('/api/irs/deals', deal.toJson()))
|
||||
.then((resp) => {
|
||||
return deal.tradeId;
|
||||
}, (resp) => {
|
||||
throw resp;
|
||||
})
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
@ -0,0 +1,34 @@
|
||||
'use strict';
|
||||
|
||||
define([], () => {
|
||||
return {
|
||||
"30/360": {
|
||||
"day": "D30",
|
||||
"year": "Y360"
|
||||
},
|
||||
"30E/360": {
|
||||
"day": "D30E",
|
||||
"year": "Y360"
|
||||
},
|
||||
"ACT/360": {
|
||||
"day": "DActual",
|
||||
"year": "Y360"
|
||||
},
|
||||
"ACT/365 Fixed": {
|
||||
"day": "DActual",
|
||||
"year": "Y365F"
|
||||
},
|
||||
"ACT/365 L": {
|
||||
"day": "DActual",
|
||||
"year": "Y365L"
|
||||
},
|
||||
"ACT/ACT ISDA": {
|
||||
"day": "DActual",
|
||||
"year": "YISDA"
|
||||
},
|
||||
"ACT/ACT ICMA": {
|
||||
"day": "DActual",
|
||||
"year": "YICMA"
|
||||
},
|
||||
};
|
||||
})
|
@ -0,0 +1,22 @@
|
||||
'use strict';
|
||||
|
||||
define(['jquery', 'semantic'], ($, semantic) => {
|
||||
return {
|
||||
init: function($scope, loadingFunc) {
|
||||
$('.ui.accordion').accordion();
|
||||
$('.ui.dropdown').dropdown();
|
||||
$('.ui.sticky').sticky();
|
||||
|
||||
this.addLoadingModal($scope, loadingFunc);
|
||||
},
|
||||
addLoadingModal: ($scope, loadingFunc) => {
|
||||
$scope.$watch(loadingFunc, (newVal) => {
|
||||
if(newVal === true) {
|
||||
$('#loading').modal('setting', 'closable', false).modal('show');
|
||||
} else {
|
||||
$('#loading').modal('hide');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
@ -0,0 +1,38 @@
|
||||
'use strict';
|
||||
|
||||
define([], () => {
|
||||
return {
|
||||
baseCurrency: "USD",
|
||||
effectiveDate: new Date(2016, 2, 11),
|
||||
terminationDate: new Date(2026, 2, 11),
|
||||
eligibleCreditSupport: "Cash in an Eligible Currency",
|
||||
independentAmounts: {
|
||||
quantity: 0
|
||||
},
|
||||
threshold: {
|
||||
quantity: 0
|
||||
},
|
||||
minimumTransferAmount: {
|
||||
quantity: 25000000
|
||||
},
|
||||
rounding: {
|
||||
quantity: 1000000
|
||||
},
|
||||
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: {
|
||||
oracle: "Rates Service Provider",
|
||||
tenor: {
|
||||
name: "6M"
|
||||
},
|
||||
ratioUnit: null,
|
||||
name: "EONIA"
|
||||
},
|
||||
addressForTransfers: "",
|
||||
exposure: {},
|
||||
localBusinessDay: [ "London" , "NewYork" ],
|
||||
dailyInterestAmount: "(CashAmount * InterestRate ) / (fixedLeg.notional.token.currencyCode.equals('GBP')) ? 365 : 360",
|
||||
hashLegalDocs: "put hash here"
|
||||
};
|
||||
});
|
@ -0,0 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
define(['viewmodel/FixedLeg', 'viewmodel/FloatingLeg', 'viewmodel/Common'], (fixedLeg, floatingLeg, common) => {
|
||||
return {
|
||||
fixedLeg: fixedLeg,
|
||||
floatingLeg: floatingLeg,
|
||||
common: common
|
||||
};
|
||||
});
|
@ -0,0 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
define(['utils/dayCountBasisLookup'], (dayCountBasisLookup) => {
|
||||
return {
|
||||
fixedRatePayer: "Bank A",
|
||||
notional: {
|
||||
quantity: 2500000000
|
||||
},
|
||||
paymentFrequency: "SemiAnnual",
|
||||
effectiveDateAdjustment: null,
|
||||
terminationDateAdjustment: null,
|
||||
fixedRate: "1.676",
|
||||
dayCountBasis: dayCountBasisLookup["ACT/360"],
|
||||
rollConvention: "ModifiedFollowing",
|
||||
dayInMonth: 10,
|
||||
paymentRule: "InArrears",
|
||||
paymentDelay: "0",
|
||||
interestPeriodAdjustment: "Adjusted"
|
||||
};
|
||||
});
|
@ -0,0 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
define([], () => {
|
||||
return {
|
||||
ratioUnit: {
|
||||
value: 0.01 // %
|
||||
}
|
||||
};
|
||||
});
|
@ -0,0 +1,28 @@
|
||||
'use strict';
|
||||
|
||||
define(['utils/dayCountBasisLookup'], (dayCountBasisLookup) => {
|
||||
return {
|
||||
floatingRatePayer: "Bank B",
|
||||
notional: {
|
||||
quantity: 2500000000
|
||||
},
|
||||
paymentFrequency: "Quarterly",
|
||||
effectiveDateAdjustment: null,
|
||||
terminationDateAdjustment: null,
|
||||
dayCountBasis: dayCountBasisLookup["ACT/360"],
|
||||
rollConvention: "ModifiedFollowing",
|
||||
fixingRollConvention: "ModifiedFollowing",
|
||||
dayInMonth: 10,
|
||||
resetDayInMonth: 10,
|
||||
paymentRule: "InArrears",
|
||||
paymentDelay: "0",
|
||||
interestPeriodAdjustment: "Adjusted",
|
||||
fixingPeriodOffset: 2,
|
||||
resetRule: "InAdvance",
|
||||
fixingsPerPayment: "Quarterly",
|
||||
indexSource: "Rates Service Provider",
|
||||
indexTenor: {
|
||||
name: "3M"
|
||||
}
|
||||
};
|
||||
});
|
@ -0,0 +1,186 @@
|
||||
<div class="ui container">
|
||||
<div class="ui negative message" id="form-error" ng-show="formError">{{formError}}</div>
|
||||
<h3 class="ui horizontal divider header">
|
||||
<i class="list icon"></i>
|
||||
New Deal
|
||||
</h3>
|
||||
<form id="deal-form" class="ui form" ng-submit="createDeal()">
|
||||
<div id="irscolumns" class="ui centered grid">
|
||||
<div class="sixteen wide tablet eight wide computer column">
|
||||
<div class="field">
|
||||
<label>Base Currency</label>
|
||||
<select class="ui fluid" name="token" ng-model="deal.common.baseCurrency">
|
||||
<option value="EUR">EUR</option>
|
||||
<option value="USD">USD</option>
|
||||
<option value="GBP">GBP</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Effective Date</label>
|
||||
<input type="date" name="effectiveDate" ng-model="deal.common.effectiveDate"/>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Termination Date</label>
|
||||
<input type="date" name="terminationDate" ng-model="deal.common.terminationDate"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sixteen wide column">
|
||||
<button type="button" id="swapirscolumns" class="ui icon button fluid">
|
||||
<i class="exchange icon"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="eight wide column irscolumn" id="createfixedleg">
|
||||
<h3>Fixed Leg</h3>
|
||||
<div class="field">
|
||||
<label>Fixed Rate Payer</label>
|
||||
<input type="text" name="fixedRatePayer" ng-model="deal.fixedLeg.fixedRatePayer"/>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Notional</label>
|
||||
<input type="text" name="quantity" ng-model="deal.fixedLeg.notional.quantity" fcsa-number/>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Fixed Rate</label>
|
||||
<input type="text" name="value" class="percent" ng-model="deal.fixedLeg.fixedRate"/>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Payment Frequency</label>
|
||||
<select class="ui selection" ng-model="deal.fixedLeg.paymentFrequency">
|
||||
<option value="Annual">Annual</option>
|
||||
<option value="SemiAnnual">Semi Annual</option>
|
||||
<option value="Quarterly">Quarterly</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Day Count Basis</label>
|
||||
<select class="ui selection"
|
||||
ng-model="deal.fixedLeg.dayCountBasis"
|
||||
ng-options="key for (key, value) in dayCountBasisLookup">
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Roll Convention</label>
|
||||
<select class="ui selection" ng-model="deal.fixedLeg.rollConvention">
|
||||
<option value="Following">Following</option>
|
||||
<option value="Preceding">Preceding</option>
|
||||
<option value="ModifiedFollowing">Modified following</option>
|
||||
<option value="ModifiedFollowingBimonthly">Modified following bimonthly</option>
|
||||
<option value="EndOfMonth">End of month</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Day in Month</label>
|
||||
<input type="number" name="dayInMonth" min="1" max="31" ng-model="deal.fixedLeg.dayInMonth"/>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Payment Delay</label>
|
||||
<select class="ui selection" ng-model="deal.fixedLeg.paymentDelay">
|
||||
<option value="0">T+00D</option>
|
||||
<option value="1">T+01D</option>
|
||||
<option value="2" selected="selected">T+02D</option>
|
||||
<option value="3">T+03D</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Interest Period Adjustment</label>
|
||||
<select class="ui selection" ng-model="deal.fixedLeg.interestPeriodAdjustment">
|
||||
<option value="Adjusted">Adjusted</option>
|
||||
<option value="Unadjusted">Unadjusted</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="eight wide column irscolumn" id="createfloatingleg">
|
||||
<h3>Floating Leg</h3>
|
||||
<div class="field">
|
||||
<label>Floating Rate Payer</label>
|
||||
<input type="text" name="floatingRatePayer" ng-model="deal.floatingLeg.floatingRatePayer"/>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Notional</label>
|
||||
<input type="text" name="quantity" ng-model="deal.floatingLeg.notional.quantity" fcsa-number/>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Payment Frequency</label>
|
||||
<select class="ui selection" ng-model="deal.floatingLeg.paymentFrequency">
|
||||
<option value="Annual">Annual</option>
|
||||
<option value="Quarterly">Quarterly</option>
|
||||
<option value="SemiAnnual">Semi Annual</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Day Count Basis</label>
|
||||
<select class="ui selection"
|
||||
ng-model="deal.floatingLeg.dayCountBasis"
|
||||
ng-options="key for (key, value) in dayCountBasisLookup">
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Roll Convention</label>
|
||||
<select class="ui selection" ng-model="deal.floatingLeg.rollConvention">
|
||||
<option value="Following">Following</option>
|
||||
<option value="Preceding">Preceding</option>
|
||||
<option value="ModifiedFollowing">Modified following</option>
|
||||
<option value="ModifiedFollowingBimonthly">Modified following bimonthly</option>
|
||||
<option value="EndOfMonth">End of month</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Fixing Roll Convention</label>
|
||||
<select class="ui selection" ng-model="deal.floatingLeg.fixingRollConvention">
|
||||
<option value="Following">Following</option>
|
||||
<option value="Preceding">Preceding</option>
|
||||
<option value="ModifiedFollowing">Modified following</option>
|
||||
<option value="ModifiedFollowingBimonthly">Modified following bimonthly</option>
|
||||
<option value="EndOfMonth">End of month</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Day In Month</label>
|
||||
<input type="number" name="dayInMonth" min="1" max="31" ng-model="deal.floatingLeg.dayInMonth"/>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Reset Day In Month</label>
|
||||
<input type="number" name="resetDayInMonth" min="1" max="31" ng-model="deal.floatingLeg.resetDayInMonth"/>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Payment Delay</label>
|
||||
<select class="ui selection" ng-model="deal.floatingLeg.paymentDelay">
|
||||
<option value="0">T+00D</option>
|
||||
<option value="1">T+01D</option>
|
||||
<option value="2">T+02D</option>
|
||||
<option value="3">T+03D</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Interest Period Adjustment</label>
|
||||
<select class="ui selection" ng-model="deal.floatingLeg.interestPeriodAdjustment">
|
||||
<option value="Adjusted">Adjusted</option>
|
||||
<option value="Unadjusted">Unadjusted</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Fixing Period Offset</label>
|
||||
<input type="number" min="0" name="fixingPeriodOffset" ng-model="deal.floatingLeg.fixingPeriodOffset"/>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Reset Rule</label>
|
||||
<select class="ui selection" ng-model="deal.floatingLeg.resetRule">
|
||||
<option value="InAdvance">In Advance</option>
|
||||
<option value="InArrears">In Arrears</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Fixings Per Payment</label>
|
||||
<select class="ui selection" ng-model="deal.floatingLeg.fixingsPerPayment">
|
||||
<option value="Annual">Annual</option>
|
||||
<option value="Quarterly" selected="selected">Quarterly</option>
|
||||
<option value="SemiAnnual">Semi Annual</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sixteen wide tablet eight wide computer column">
|
||||
<input type="submit" class="ui submit primary button fluid"/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
206
src/main/resources/com/r3corda/demos/irswebdemo/view/deal.html
Normal file
206
src/main/resources/com/r3corda/demos/irswebdemo/view/deal.html
Normal file
@ -0,0 +1,206 @@
|
||||
<div class="ui container">
|
||||
<div class="ui hidden divider"></div>
|
||||
<div class="ui grid">
|
||||
<div class="sixteen wide column" id="common">
|
||||
<table class="ui striped table">
|
||||
<thead>
|
||||
<tr class="center aligned">
|
||||
<th colspan="2">Common Information</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="center aligned">
|
||||
<td>Parties</td>
|
||||
<td>
|
||||
<span ng-repeat="party in deal.parties">
|
||||
{{party}}<span ng-show="!$last">,</span>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="center aligned">
|
||||
<td>Trade ID</td>
|
||||
<td>{{deal.ref}}</td>
|
||||
</tr>
|
||||
<tr class="center aligned">
|
||||
<td>Valuation Date</td>
|
||||
<td>{{deal.common.valuationDate}}</td>
|
||||
</tr>
|
||||
<tr class="center aligned">
|
||||
<td>Legal Document Hash</td>
|
||||
<td>{{deal.common.hashLegalDocs}}</td>
|
||||
</tr>
|
||||
<tr class="center aligned">
|
||||
<td>Interest Rates</td>
|
||||
<td>
|
||||
{{deal.common.interestRate.name}} with tenor
|
||||
{{deal.common.interestRate.tenor.name}} via oracle
|
||||
{{deal.common.interestRate.oracle}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="eight wide column" id="fixedleg">
|
||||
<table class="ui striped table">
|
||||
<thead>
|
||||
<tr class="center aligned">
|
||||
<th colspan="2">Fixed Leg</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="center aligned">
|
||||
<td>Payer</td>
|
||||
<td>{{deal.fixedLeg.fixedRatePayer}}</td>
|
||||
</tr>
|
||||
<tr class="center aligned">
|
||||
<td>Notional</td>
|
||||
<td>{{deal.fixedLeg.notional.quantity | number}} {{deal.fixedLeg.notional.token}}</td>
|
||||
</tr>
|
||||
<tr class="center aligned">
|
||||
<td>Payment Frequency</td>
|
||||
<td>{{deal.fixedLeg.paymentFrequency}}</td>
|
||||
</tr>
|
||||
<tr class="center aligned">
|
||||
<td>Effective From</td>
|
||||
<td>{{deal.fixedLeg.effectiveDate}}</td>
|
||||
</tr>
|
||||
<tr class="center aligned">
|
||||
<td>Fixed Rate</td>
|
||||
<td>
|
||||
<span ng-show="!deal.fixedLeg.fixedRate.positive">-</span>
|
||||
{{deal.fixedLeg.fixedRate.value}}%
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="center aligned">
|
||||
<td>Terminates</td>
|
||||
<td>{{deal.fixedLeg.terminationDate}}</td>
|
||||
</tr>
|
||||
<tr class="center aligned">
|
||||
<td>Payment Rule</td>
|
||||
<td>{{deal.fixedLeg.paymentRule}}</td>
|
||||
</tr>
|
||||
<tr class="center aligned">
|
||||
<td>Payment Calendars</td>
|
||||
<td>
|
||||
<span ng-repeat="calendar in deal.fixedLeg.paymentCalendar.calendars">
|
||||
<span>{{calendar}}</span><span ng-show="!$last">,</span>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="center aligned">
|
||||
<td colspan="2">
|
||||
<div class="ui accordion">
|
||||
<div class="title">
|
||||
<i class="dropdown icon"></i>
|
||||
Holiday Dates
|
||||
</div>
|
||||
<div class="content">
|
||||
<table class="ui celled small table">
|
||||
<tbody>
|
||||
<tr class="center aligned" ng-repeat="date in deal.fixedLeg.paymentCalendar.holidayDates">
|
||||
<td>{{date}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="eight wide column" id="floatingleg">
|
||||
<table class="ui striped table">
|
||||
<thead>
|
||||
<tr class="center aligned">
|
||||
<th colspan="2">Floating Leg</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="center aligned">
|
||||
<td>Payer</td>
|
||||
<td>{{deal.floatingLeg.floatingRatePayer}}</td>
|
||||
</tr>
|
||||
<tr class="center aligned">
|
||||
<td>Notional</td>
|
||||
<td>{{deal.floatingLeg.notional.quantity | number}} {{deal.floatingLeg.notional.token}}</td>
|
||||
</tr>
|
||||
<tr class="center aligned">
|
||||
<td>Payment Frequency</td>
|
||||
<td>{{deal.floatingLeg.paymentFrequency}}</td>
|
||||
</tr>
|
||||
<tr class="center aligned">
|
||||
<td>Effective From</td>
|
||||
<td>{{deal.floatingLeg.effectiveDate}}</td>
|
||||
</tr>
|
||||
<tr class="center aligned">
|
||||
<td>Index</td>
|
||||
<td>{{deal.floatingLeg.index}}</td>
|
||||
</tr>
|
||||
<tr class="center aligned">
|
||||
<td>Terminates</td>
|
||||
<td>{{deal.floatingLeg.terminationDate}}</td>
|
||||
</tr>
|
||||
<tr class="center aligned">
|
||||
<td>Payment Rule</td>
|
||||
<td>{{deal.floatingLeg.paymentRule}}</td>
|
||||
</tr>
|
||||
<tr class="center aligned">
|
||||
<td>Payment Calendars</td>
|
||||
<td>
|
||||
<span ng-repeat="calendar in deal.floatingLeg.paymentCalendar.calendars">
|
||||
<span>{{calendar}}</span><span ng-show="!$last">,</span>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="center aligned">
|
||||
<td colspan="2">
|
||||
<div class="ui accordion">
|
||||
<div class="title">
|
||||
<i class="dropdown icon"></i>
|
||||
Holiday Dates
|
||||
</div>
|
||||
<div class="content">
|
||||
<table class="ui celled small table">
|
||||
<tbody>
|
||||
<tr class="center aligned" ng-repeat="date in deal.floatingLeg.paymentCalendar.holidayDates">
|
||||
<td>{{date}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="center aligned">
|
||||
<td>Fixing Calendars</td>
|
||||
<td>
|
||||
<span ng-repeat="calendar in deal.floatingLeg.fixingCalendar.calendars">
|
||||
<span>{{calendar}}</span><span ng-show="!$last">,</span>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="center aligned">
|
||||
<td colspan="2">
|
||||
<div class="ui accordion">
|
||||
<div class="title">
|
||||
<i class="dropdown icon"></i>
|
||||
Holiday Dates
|
||||
</div>
|
||||
<div class="content">
|
||||
<table class="ui celled small table">
|
||||
<tbody>
|
||||
<tr class="center aligned" ng-repeat="date in deal.floatingLeg.fixingCalendar.holidayDates">
|
||||
<td>{{date}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,57 @@
|
||||
<div class="ui container">
|
||||
<div class="ui negative message" id="http-error" ng-show="httpError">{{httpError}}</div>
|
||||
<div class="ui info message" id="info-message" ng-show="infoMsg">{{infoMsg}}</div>
|
||||
<div class="ui active dimmer" ng-show="isLoading()">
|
||||
<div class="ui text loader">Loading</div>
|
||||
</div>
|
||||
<h3 class="ui horizontal divider header">
|
||||
<i class="options icon"></i>
|
||||
Controls
|
||||
</h3>
|
||||
<div class="ui card centered">
|
||||
<div class="content" style="width:110%">
|
||||
<div class="header">Run fixings</div>
|
||||
<div class="description">
|
||||
<div class="ui left labeled button">
|
||||
<span class="ui basic label">{{date.year}}</span>
|
||||
<button class="ui icon button" ng-click="updateDate('year')"><i class="plus icon"></i></button>
|
||||
</div>
|
||||
<div class="ui left labeled button">
|
||||
<span class="ui basic label">{{date.month}}</span>
|
||||
<button class="ui icon button" ng-click="updateDate('month')"><i class="plus icon"></i></button>
|
||||
</div>
|
||||
<div class="ui left labeled button">
|
||||
<span class="ui basic label">{{date.day}}</span>
|
||||
<button class="ui icon button" ng-click="updateDate('day')"><i class="plus icon"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui hidden divider"></div>
|
||||
<div class="ui main">
|
||||
<h3 class="ui horizontal divider header">
|
||||
<i class="browser icon"></i>
|
||||
Recent deals
|
||||
</h3>
|
||||
<table class="ui striped table">
|
||||
<thead>
|
||||
<tr class="center aligned">
|
||||
<th>Trade Id</th>
|
||||
<th>Fixed Leg Payer</th>
|
||||
<th>Amount</th>
|
||||
<th>Floating Rate Payer</th>
|
||||
<th>Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="center aligned" ng-repeat="deal in deals">
|
||||
<td><a href="#/deal/{{deal.ref}}">{{deal.ref}}</a></td>
|
||||
<td class="single line">{{deal.fixedLeg.fixedRatePayer}}</td>
|
||||
<td class="single line">{{deal.fixedLeg.notional.quantity | number}} {{deal.fixedLeg.notional.token}}</td>
|
||||
<td class="single line">{{deal.floatingLeg.floatingRatePayer}}</td>
|
||||
<td class="single line">{{deal.floatingLeg.notional.quantity | number}} {{deal.floatingLeg.notional.token}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
Loading…
Reference in New Issue
Block a user