Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Approvedpush 20241205 basket off #1090

Merged
merged 10 commits into from
Dec 29, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package org.finos.vuu.core.module.basket

object BasketConstants {

object Side{
object Side {
final val Buy = "BUY"
final val Sell = "SELL"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,9 +202,4 @@ object BasketModule extends DefaultModule {
final val OrderStatus = "orderStatus"
final val FilledQty = "filledQty"
}

object Sides{
final val Buy = "Buy"
final val Sell = "Sell"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class BasketConstituentProvider(val table: DataTable)(implicit lifecycle: Lifecy
val weighting = row("Weighting")
val side = BasketConstants.Side.Buy
val ricBasketId = symbol + "." + basketId
table.processUpdate(ricBasketId, RowWithData(symbol, Map(
table.processUpdate(ricBasketId, RowWithData(ricBasketId, Map(
Ric -> symbol,
BasketId -> basketId,
RicBasketId -> ricBasketId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@ class BasketTradingConstituentProvider(val table: DataTable, val omsApi: OmsApi)
table.processUpdate(ack.clientOrderId, RowWithData(ack.clientOrderId, Map[String, Any](BTC.InstanceIdRic -> ack.clientOrderId,
BTC.OrderStatus -> OrderStates.ACKED)),clock.now())
}
override def onCancelAck(ack: CancelAck): Unit = ???
override def onCancelAck(ack: CancelAck): Unit = {
table.processUpdate(ack.clientOrderId, RowWithData(ack.clientOrderId, Map[String, Any](BTC.InstanceIdRic -> ack.clientOrderId,
BTC.OrderStatus -> OrderStates.CANCELLED)), clock.now())
}
override def onReplaceAck(ack: ReplaceAck): Unit = ???
override def onFill(fill: Fill): Unit = {
val state = if(fill.orderQty == fill.totalFilledQty) OrderStates.FILLED else OrderStates.ACKED
table.processUpdate(fill.clientOrderId,
RowWithData(fill.clientOrderId, Map[String, Any](BTC.InstanceIdRic -> fill.clientOrderId,
BTC.FilledQty -> fill.totalFilledQty, BTC.OrderStatus -> state))
,clock.now())
BTC.FilledQty -> fill.totalFilledQty, BTC.OrderStatus -> state)),clock.now())
}
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ 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.BasketConstants.Side
import org.finos.vuu.core.module.basket.BasketModule
import org.finos.vuu.core.module.basket.BasketModule.{BasketConstituentTable, Sides}
import org.finos.vuu.core.module.basket.BasketModule.{BasketConstituentTable}
import org.finos.vuu.core.table.{DataTable, RowData, RowWithData, TableContainer}
import org.finos.vuu.net.rpc.RpcHandler
import org.finos.vuu.net.{ClientSessionId, RequestContext}
Expand Down Expand Up @@ -57,7 +58,7 @@ class BasketService(val table: DataTable, val tableContainer: TableContainer, va
}

private def mkTradingBasketRow(sourceBasketId: String, basketTradeName: String, basketTradeInstanceId: String) = {
RowWithData(basketTradeInstanceId, Map(BT.InstanceId -> basketTradeInstanceId, BT.Status -> "OFF-MARKET", BT.BasketId -> sourceBasketId, BT.BasketName -> basketTradeName, BT.Side -> Sides.Buy, BT.Units -> 1))
RowWithData(basketTradeInstanceId, Map(BT.InstanceId -> basketTradeInstanceId, BT.Status -> "OFF-MARKET", BT.BasketId -> sourceBasketId, BT.BasketName -> basketTradeName, BT.Side -> Side.Buy, BT.Units -> 1))
}

def createBasketFromRpc(basketId: String, name: String)(ctx: RequestContext): ViewPortAction = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import org.finos.toolbox.time.Clock
import org.finos.vuu.api.JoinTableDef
import org.finos.vuu.core.module.basket.BasketConstants.Side
import org.finos.vuu.core.module.basket.BasketModule
import org.finos.vuu.core.module.basket.BasketModule.{BasketTradingColumnNames => BTColumnName, BasketTradingConstituentColumnNames => ColumnName}
import org.finos.vuu.core.module.basket.BasketModule.{BasketConstituentColumnNames => BCColumnName, BasketTradingColumnNames => BTColumnName, BasketTradingConstituentColumnNames => ColumnName}
import org.finos.vuu.core.module.basket.result.ErrorReason
import org.finos.vuu.core.table.{DataTable, JoinTable, RowWithData, TableContainer}
import org.finos.vuu.core.table.{DataTable, JoinTable, RowData, RowWithData, TableContainer}
import org.finos.vuu.net.rpc.{EditRpcHandler, RpcHandler}
import org.finos.vuu.net.{ClientSessionId, RequestContext}
import org.finos.vuu.viewport._
Expand Down Expand Up @@ -64,11 +64,18 @@ class BasketTradingConstituentJoinService(val table: DataTable, val tableContain
val basketId = tradeRow.get(BTColumnName.BasketId).asInstanceOf[String]
val tradeUnit = tradeRow.get(BTColumnName.Units).asInstanceOf[Int]

val basketConstituentRows = getConstituentsWith(ric) //todo what to do when multiple result?
val description =
if(basketConstituentRows.nonEmpty)
basketConstituentRows.head.get(BCColumnName.Description).asInstanceOf[String]
else ""

val newRow = mkTradingConstituentRow(
basketTradeInstanceId = tradeId,
sourceBasketId = basketId,
tradeUnit = tradeUnit,
ric = ric)
ric = ric,
description = description)

//todo should we guard against adding row for ric that already exist?
updateJoinTable(Array(newRow)) match {
Expand All @@ -79,6 +86,12 @@ class BasketTradingConstituentJoinService(val table: DataTable, val tableContain
}
}

private def getConstituentsWith(ric: String): List[RowData] = {
val table = tableContainer.getTable(BasketModule.BasketConstituentTable)
val keys = table.primaryKeys.toList
keys.map(key => table.pullRow(key)).filter(_.get(BCColumnName.Ric).toString == ric)
}

private def onEditCell(key: String, columnName: String, data: Any, vp: ViewPort, session: ClientSessionId): ViewPortEditAction = {
try {
getBaseTable() match {
Expand Down Expand Up @@ -180,7 +193,7 @@ class BasketTradingConstituentJoinService(val table: DataTable, val tableContain
}
}

private def mkTradingConstituentRow(basketTradeInstanceId: String, sourceBasketId: String, tradeUnit: Int, ric: String): RowWithData = {
private def mkTradingConstituentRow(basketTradeInstanceId: String, sourceBasketId: String, tradeUnit: Int, ric: String, description: String): RowWithData = {
val constituentKey = s"$basketTradeInstanceId.$ric"
val weighting: Double = 0.1
RowWithData(
Expand All @@ -191,7 +204,7 @@ class BasketTradingConstituentJoinService(val table: DataTable, val tableContain
ColumnName.InstanceId -> basketTradeInstanceId,
ColumnName.InstanceIdRic -> constituentKey,
ColumnName.Quantity -> (weighting * 100).asInstanceOf[Long],
ColumnName.Description -> "", //todo look up description from instrument table
ColumnName.Description -> description,
ColumnName.Side -> Side.Buy,
ColumnName.Weighting -> weighting,
ColumnName.PriceStrategyId -> 2,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@ 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.{BasketTradingConstituentTable, Sides}
import org.finos.vuu.core.table.{DataTable, RowWithData, TableContainer, ViewPortColumnCreator}
import org.finos.vuu.core.module.basket.BasketConstants.Side
import org.finos.vuu.core.module.basket.BasketModule.{BasketTradingConstituentTable}
import org.finos.vuu.core.table.{DataTable, RowData, RowWithData, TableContainer, ViewPortColumnCreator}
import org.finos.vuu.net.rpc.{EditRpcHandler, RpcHandler}
import org.finos.vuu.net.{ClientSessionId, RequestContext}
import org.finos.vuu.order.oms.{NewOrder, OmsApi}
import org.finos.vuu.order.oms.{CancelOrder, NewOrder, OmsApi}
import org.finos.vuu.viewport._
trait BasketTradingServiceIF extends EditRpcHandler{

trait BasketTradingServiceIF extends EditRpcHandler {
def sendToMarket(basketInstanceId: String)(ctx: RequestContext): ViewPortAction

def takeOffMarket(basketInstanceId: String)(ctx: RequestContext): ViewPortAction
}


Expand All @@ -20,18 +24,14 @@ class BasketTradingService(val table: DataTable, val tableContainer: TableContai


/**
* Send basket to market
* Send basket to market rpc call
*/
override def sendToMarket(name: String)(ctx: RequestContext): ViewPortAction = {
val tableRow = table.asTable.pullRow(name)

logger.info("Sending basket to market:" + name + " (row:" + tableRow + ")")
override def sendToMarket(basketInstanceId: String)(ctx: RequestContext): ViewPortAction = {
val tableRow = table.asTable.pullRow(basketInstanceId)

val tradingConsTable = tableContainer.getTable(BasketModule.BasketTradingConstituentTable)
logger.info("Sending basket to market:" + basketInstanceId + " (row:" + tableRow + ")")

val constituents = tradingConsTable.primaryKeys.toList
.map(tradingConsTable.pullRow)
.filter(_.get(BTC.InstanceId) == name)
val constituents = getConstituents(basketInstanceId)

constituents.foreach(constituentRow => {

Expand All @@ -48,12 +48,43 @@ class BasketTradingService(val table: DataTable, val tableContainer: TableContai
omsApi.createOrder(nos)
})

table.processUpdate(name, RowWithData(name,
Map(BT.InstanceId -> name, BT.Status -> BasketStates.ON_MARKET)), clock.now())
updateBasketTradeStatus(basketInstanceId, state = BasketStates.ON_MARKET)

ViewPortEditSuccess()
}

/**
* Take basket off market rpc call
*/
override def takeOffMarket(basketInstanceId: String)(ctx: RequestContext): ViewPortAction = {
val tableRow = table.asTable.pullRow(basketInstanceId)

logger.info("Tasking basket off market:" + basketInstanceId + " (row:" + tableRow + ")")

updateBasketTradeStatus(basketInstanceId, BasketStates.OFF_MARKET)

getConstituents(basketInstanceId)
.flatMap(c => omsApi.getOrderId(clientOrderId = c.get(BTC.InstanceIdRic).toString))
.foreach(orderId => omsApi.cancelOrder(CancelOrder(orderId)))

ViewPortEditSuccess()
}

private def getConstituents(basketInstanceId: String): List[RowData] = {
val tradingConsTable = tableContainer.getTable(BasketModule.BasketTradingConstituentTable)

tradingConsTable.primaryKeys.toList
.map(tradingConsTable.pullRow)
.filter(_.get(BTC.InstanceId) == basketInstanceId)
}

private def updateBasketTradeStatus(basketInstanceId: String, state: String): Unit = {
table.processUpdate(
basketInstanceId,
RowWithData(basketInstanceId, Map(BT.InstanceId -> basketInstanceId, BT.Status -> state)),
clock.now())
}

private def onEditCell(key: String, columnName: String, data: Any, vp: ViewPort, session: ClientSessionId): ViewPortEditAction = {
logger.info("Change requested for cell value for key:" + key + "(" + columnName + ":" + data + ")")

Expand All @@ -80,8 +111,8 @@ class BasketTradingService(val table: DataTable, val tableContainer: TableContai
val constituents = constituentTable.primaryKeys.map(key => constituentTable.pullRow(key)).filter(_.get(BTC.InstanceId) == key)
constituents.foreach(row => {
val newSide = row.get(BTC.Side) match {
case Sides.Buy => Sides.Sell
case _ => Sides.Buy
case Side.Buy => Side.Sell
case _ => Side.Buy
}
constituentTable.processUpdate(row.key(), RowWithData(row.key(), Map(BTC.InstanceIdRic -> row.key(), BTC.Side -> newSide)), clock.now())
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ class BasketConstituentMutateTest extends VuuServerTestCase {
vuuServer.login("testUser", "testToken")

val basketName = "test_basket1"
val tradeId = GivenBasketTrade(vuuServer.tableContainer, basketName, "Buy")
val tradeId = GivenBasketTrade(vuuServer.tableContainer, basketName, "BUY")
GivenPrices(vuuServer.tableContainer, List(("VOD.L", 1.1, 1.4), ("BP.L", 2.1, 2.4)))
GivenBasketTradeConstituentsJoin(vuuServer.tableContainer, tradeId, Map(("VOD.L" -> "Buy"), ("BP.L" -> "Sell")))
GivenBasketTradeConstituentsJoin(vuuServer.tableContainer, tradeId, Map(("VOD.L" -> "BUY"), ("BP.L" -> "SELL")))

val vpBasketTrading = vuuServer.createViewPort(BasketModule.NAME, BasketTradingTable)
val vpBasketTradingConsJoin = vuuServer.createViewPort(BasketModule.NAME, BasketTradingConstituentJoin)
Expand All @@ -60,9 +60,9 @@ class BasketConstituentMutateTest extends VuuServerTestCase {
assertVpEq(filterByVp(vpBasketTradingConsJoin, updates)) {
Table(
("quantity", "side", "instanceId", "instanceIdRic", "basketId", "ric", "description", "notionalUsd", "notionalLocal", "venue", "algo", "algoParams", "pctFilled", "weighting", "priceSpread", "limitPrice", "priceStrategyId", "bid", "ask", "filledQty", "orderStatus"),
(10L, "Buy", "testUser-00001", "testUser-00001.BP.L", ".FTSE", "BP.L", "Beyond Petroleum", null, null, null, -1, null, null, 0.1, null, null, 2, 2.1, 2.4, 0, "PENDING"),
(10L, "Sell", "testUser-00001", "testUser-00001.BT.L", ".FTSE", "BT.L", "British Telecom", null, null, null, -1, null, null, 0.1, null, null, 2, null, null, 0, "PENDING"),
(10L, "Sell", "testUser-00001", "testUser-00001.VOD.L", ".FTSE", "VOD.L", "Vodafone", null, null, null, -1, null, null, 0.1, null, null, 2, 1.1, 1.4, 0, "PENDING")
(10L, "BUY", "testUser-00001", "testUser-00001.BP.L", ".FTSE", "BP.L", "Beyond Petroleum", null, null, null, -1, null, null, 0.1, null, null, 2, 2.1, 2.4, 0, "PENDING"),
(10L, "SELL", "testUser-00001", "testUser-00001.BT.L", ".FTSE", "BT.L", "British Telecom", null, null, null, -1, null, null, 0.1, null, null, 2, null, null, 0, "PENDING"),
(10L, "SELL", "testUser-00001", "testUser-00001.VOD.L", ".FTSE", "VOD.L", "Vodafone", null, null, null, -1, null, null, 0.1, null, null, 2, 1.1, 1.4, 0, "PENDING")
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class BasketCreateTest extends VuuServerTestCase {
assertVpEq(combineQsForVp(viewportBasketTrading)) {
Table(
("basketId", "instanceId", "basketName", "units", "status", "filledPct", "totalNotionalUsd", "totalNotional", "fxRateToUsd", "side"),
(".FTSE", BasketTradeId.current, "TestBasket", 100, "OFF-MARKET", null, null, null, null, "Buy")
(".FTSE", BasketTradeId.current, "TestBasket", 100, "OFF-MARKET", null, null, null, null, "BUY")
)
}
}
Expand Down
Loading
Loading