Skip to content

Commit

Permalink
finos#850 Added first cut of rpc services for basket trading
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisjstevo committed Oct 16, 2023
1 parent 110a91b commit d38d600
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 14 deletions.
4 changes: 2 additions & 2 deletions vuu/src/main/resources/runconfigurations/SimulMain.run.xml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="SimulMain" type="Application" factoryName="Application" folderName="runConfigs">
<option name="ALTERNATIVE_JRE_PATH" value="11" />
<option name="ALTERNATIVE_JRE_PATH" value="17" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
<option name="MAIN_CLASS_NAME" value="org.finos.vuu.SimulMain" />
<module name="vuu" />
<option name="PROGRAM_PARAMETERS" value="-Xmx20G -Xlog:gc*=debug:stdout " />
<option name="VM_PARAMETERS" value="-Dlogback.configurationFile=logback.xml" />
<option name="VM_PARAMETERS" value="-Dlogback.configurationFile=logback-socket.xml" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="org.finos.vuu.*" />
Expand Down
2 changes: 1 addition & 1 deletion vuu/src/main/resources/static/sp500.csv
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#,Company,Symbol,Weight,Price,Change,Change %
#,Name,Symbol,Weight,Price,Change,Change %
1,Apple Inc,AAPL,6.992488,171.90,1.47,(0.86%)
2,Microsoft Corp,MSFT,6.487978,314.55,1.76,(0.56%)
3,Amazon.com Inc,AMZN,3.193379,126.25,0.27,(0.22%)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import org.finos.vuu.provider.Provider

class PermissionsProvider(val table: DataTable, val sessionsContainer: ClientSessionContainer)(implicit clock: Clock, lifecycleContainer: LifecycleContainer) extends Provider {

private val runner = new LifeCycleRunner("PermissionsProvider", () => runOnce)
private val runner = new LifeCycleRunner("PermissionsProvider", () => runOnce(), minCycleTime = 10_000)

lifecycleContainer(this).dependsOn(runner)

Expand All @@ -27,6 +27,10 @@ class PermissionsProvider(val table: DataTable, val sessionsContainer: ClientSes
Map(User -> session.user, Bitmask -> PermissionSet.NoPermissions, BitmaskAsString -> PermissionSet.toBinaryString(PermissionSet.NoPermissions), BitmaskAsRoles -> PermissionSet.rolesToString(PermissionSet.NoPermissions) ))
, clock.now())
case row: RowWithData =>
// if(!table.hasChanged(row)){
//
// }

val newData = row.data ++ Map(BitmaskAsString -> PermissionSet.toBinaryString(row.get(Bitmask).asInstanceOf[Int]), BitmaskAsRoles -> PermissionSet.rolesToString(row.get(Bitmask).asInstanceOf[Int]))
table.processUpdate(session.user, RowWithData(session.user, newData), clock.now())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,20 @@ package org.finos.vuu.core.module.basket

import org.finos.toolbox.lifecycle.LifecycleContainer
import org.finos.toolbox.time.Clock
import org.finos.vuu.api.{TableDef, VisualLinks}
import org.finos.vuu.api.{Link, TableDef, ViewPortDef, VisualLinks}
import org.finos.vuu.core.module.basket.provider.{BasketConstituentProvider, BasketProvider, NotYetImplementedProvider, PriceStrategyProvider}
import org.finos.vuu.core.module.basket.service.BasketService
import org.finos.vuu.core.module.{DefaultModule, ModuleFactory, ViewServerModule}
import org.finos.vuu.core.table.Columns

object BasketModule extends DefaultModule {

private final val NAME = "BASKET"

final val BasketTradingTable = "basketTrading"
final val BasketConstituentTable = "basketConstituent"
final val BasketTradingConstituent = "basketTradingConstituent"

def apply()(implicit clock: Clock, lifecycle: LifecycleContainer): ViewServerModule = {

import org.finos.vuu.core.module.basket.BasketModule.{BasketColumnNames => B}
Expand All @@ -29,11 +34,15 @@ object BasketModule extends DefaultModule {
VisualLinks(),
joinFields = B.Id
),
(table, vs) => new BasketProvider(table),
(table, _) => new BasketProvider(table),
(table, _, _, tableContainer) => ViewPortDef(
columns = table.getTableDef.columns,
service = new BasketService(table, tableContainer)
)
)
.addTable(
TableDef(
name = "basketConstituent",
name = BasketConstituentTable,
keyField = BC.RicBasketId,
columns = Columns.fromNames(BC.RicBasketId.string(), BC.Ric.string(), BC.BasketId.string(), BC.Weighting.double(), BC.LastTrade.string(), BC.Change.string(), BC.Volume.string()), // we can join to instruments and other tables to get the rest of the data.....
VisualLinks(),
Expand All @@ -43,7 +52,7 @@ object BasketModule extends DefaultModule {
)
.addTable(
TableDef(
name = "basketTrading",
name = BasketTradingTable,
keyField = BT.InstanceId,
columns = Columns.fromNames(BT.InstanceId.string(), BT.BasketId.string(), BT.BasketName.string(), BT.Status.string(), BT.Units.int(), BT.FilledPct.double(), BT.FxRateToUsd.double(), BT.TotalNotional.double(), BT.TotalNotionalUsd.double()), // we can join to instruments and other tables to get the rest of the data.....
VisualLinks(),
Expand All @@ -53,7 +62,7 @@ object BasketModule extends DefaultModule {
)
.addTable(
TableDef(
name = "basketTradingConstituent",
name = BasketTradingConstituent,
keyField = BTC.InstanceIdRic,
columns = Columns.fromNames(BTC.InstanceIdRic.string(), BTC.InstanceId.string(), BTC.Ric.string(),
BTC.BasketId.string(), BTC.PriceStrategyId.int(),
Expand All @@ -66,7 +75,9 @@ object BasketModule extends DefaultModule {
BTC.PriceSpread.int(),
BTC.LimitPrice.double()
),// we can join to instruments and other tables to get the rest of the data.....
VisualLinks(),
VisualLinks(
Link(BTC.InstanceId, BasketTradingTable, BT.InstanceId),
),
joinFields = BTC.InstanceIdRic
),
(table, vs) => new NotYetImplementedProvider(table),
Expand All @@ -80,9 +91,8 @@ object BasketModule extends DefaultModule {
VisualLinks(),
joinFields = PS.Id
),
(table, _) => new PriceStrategyProvider(table),
)
.asModule()
(table, _) => new PriceStrategyProvider(table)
).asModule()
}

object PriceStrategy {
Expand All @@ -107,6 +117,7 @@ object BasketModule extends DefaultModule {
final val LastTrade = "lastTrade"
final val Change = "change"
final val Volume = "volume"
final val Description = "description"
}

object BasketTradingColumnNames {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ class BasketConstituentProvider(val table: DataTable)(implicit lifecycle: Lifecy
LastTrade -> lastTrade,
Change -> change,
Weighting -> weighting,
Volume -> volume
Volume -> volume,
Description -> name
)), clock.now())
}
})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package org.finos.vuu.core.module.basket.service

import com.typesafe.scalalogging.StrictLogging
import org.finos.toolbox.time.Clock
import org.finos.vuu.core.module.basket.BasketModule
import org.finos.vuu.core.module.basket.BasketModule.BasketConstituentTable
import org.finos.vuu.core.table.{DataTable, RowData, RowWithData, TableContainer}
import org.finos.vuu.net.ClientSessionId
import org.finos.vuu.net.rpc.RpcHandler
import org.finos.vuu.viewport.{NoAction, SelectionViewPortMenuItem, ViewPortAction, ViewPortMenu, ViewPortSelection}

import java.util.concurrent.atomic.AtomicInteger

class BasketService(val table: DataTable, val tableContainer: TableContainer)(implicit clock: Clock) extends RpcHandler with StrictLogging {

private val counter = new AtomicInteger(0)

import org.finos.vuu.core.module.basket.BasketModule.{BasketTradingColumnNames => BT}
import org.finos.vuu.core.module.basket.BasketModule.{BasketConstituentColumnNames => BC}
import org.finos.vuu.core.module.basket.BasketModule.{BasketTradingConstituentColumnNames => BTC}

private def getAndPadCounter(session: ClientSessionId): String = {
val counterValue = counter.incrementAndGet()
session.user + "-" + "".padTo(5 - counterValue.toString.length, "0").mkString + counterValue
}

private def getConstituentsForBasketKey(key: String): List[RowData] = {
val table = tableContainer.getTable(BasketConstituentTable)
val keys = table.primaryKeys.toList
keys.map( key => table.pullRow(key) ).filter(_.get(BC.BasketId).toString == key)
}

def createBasket(selection: ViewPortSelection, session: ClientSessionId): ViewPortAction = {

//logger.info("createBasket()")

val basketKey = selection.rowKeyIndex.map({ case (key, _) => key }).toList.head

val instanceKey = getAndPadCounter(session)

val constituents = getConstituentsForBasketKey(basketKey)

tableContainer.getTable(BasketModule.BasketTradingTable) match {
case table: DataTable =>
table.processUpdate(instanceKey, RowWithData(instanceKey, Map(BT.InstanceId -> instanceKey, BT.Status -> "OFF-MARKET", BT.BasketId -> basketKey)), clock.now())
case null =>
}

tableContainer.getTable(BasketModule.BasketTradingConstituent) match {
case table: DataTable =>
constituents.foreach( rowData => {
val constituentKey = instanceKey + "." + rowData.get(BTC.Ric)
table.processUpdate(constituentKey, RowWithData(constituentKey, Map(BTC.BasketId -> basketKey, BTC.Ric -> rowData.get(BC.Ric) , BTC.InstanceId -> instanceKey,
//BTC.Quantity -> rowData.get(BC.Quantity),
BTC.InstanceIdRic -> constituentKey,
BTC.Description -> rowData.get(BC.Description)
)), clock.now())
})
case null =>
}

NoAction()
}

override def menuItems(): ViewPortMenu = ViewPortMenu(
new SelectionViewPortMenuItem("Create New", "", (sel, sess) => this.createBasket(sel, sess), "CREATE_NEW_BASKET"),
)
}

0 comments on commit d38d600

Please sign in to comment.