Skip to content

Commit

Permalink
#966 when updating basket trade cell value, only update if different …
Browse files Browse the repository at this point in the history
…from current value
  • Loading branch information
naleeha committed Dec 5, 2023
1 parent aa372a6 commit 436c889
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,21 @@ 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}
import org.finos.vuu.core.table.{DataTable, 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.viewport._

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


class BasketTradingService(val table: DataTable, val tableContainer: TableContainer, val omsApi: OmsApi)(implicit clock: Clock) extends RpcHandler with BasketTradingServiceIF with StrictLogging {

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


/**
* Send basket to market
*/
Expand Down Expand Up @@ -54,37 +55,47 @@ class BasketTradingService(val table: DataTable, val tableContainer: TableContai
}

private def onEditCell(key: String, columnName: String, data: Any, vp: ViewPort, session: ClientSessionId): ViewPortEditAction = {
logger.info("Changing cell value for key:" + key + "(" + columnName + ":" + data + ")")
table.processUpdate(key, RowWithData(key, Map(BT.InstanceId -> key, columnName -> data)), clock.now())

columnName match {
case BT.Units =>
val constituentTable = tableContainer.getTable(BasketTradingConstituentTable)
val constituents = constituentTable.primaryKeys.map(key => constituentTable.pullRow(key)).filter(_.get(BTC.InstanceId) == key)
constituents.foreach(row => {
val unitsAsInt = data.asInstanceOf[Int]
val weighting = row.get(BTC.Weighting)
val quantity = (weighting.asInstanceOf[Double] * unitsAsInt).toLong
constituentTable.processUpdate(row.key(), RowWithData(row.key(), Map(BTC.InstanceIdRic -> row.key(), BTC.Quantity -> quantity)), clock.now())
})
case BT.Side =>
val constituentTable = tableContainer.getTable(BasketTradingConstituentTable)
val constituents = constituentTable.primaryKeys.map(key => constituentTable.pullRow(key)).filter(_.get(BTC.InstanceId) == key)
val side = data.asInstanceOf[String]
constituents.foreach(row => {
val newSide = row.get(BTC.Side) match {
case Sides.Buy => Sides.Sell
case _ => Sides.Buy
}
constituentTable.processUpdate(row.key(), RowWithData(row.key(), Map(BTC.InstanceIdRic -> row.key(), BTC.Side -> newSide)), clock.now())
})

case _ =>
}
logger.info("Change requested for cell value for key:" + key + "(" + columnName + ":" + data + ")")

val currentData = getRowData(key, columnName)
if (currentData == data) {
logger.info("Current cell value is same and therefore skipping update for key:" + key + "(" + columnName + ":" + data + ")")
}
else {
logger.info("Changing cell value for key:" + key + "(" + columnName + ":" + data + ")")
table.processUpdate(key, RowWithData(key, Map(BT.InstanceId -> key, columnName -> data)), clock.now())

columnName match {
case BT.Units =>
val constituentTable = tableContainer.getTable(BasketTradingConstituentTable)
val constituents = constituentTable.primaryKeys.map(key => constituentTable.pullRow(key)).filter(_.get(BTC.InstanceId) == key)
constituents.foreach(row => {
val unitsAsInt = data.asInstanceOf[Int]
val weighting = row.get(BTC.Weighting)
val quantity = (weighting.asInstanceOf[Double] * unitsAsInt).toLong
constituentTable.processUpdate(row.key(), RowWithData(row.key(), Map(BTC.InstanceIdRic -> row.key(), BTC.Quantity -> quantity)), clock.now())
})
case BT.Side =>
val constituentTable = tableContainer.getTable(BasketTradingConstituentTable)
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
}
constituentTable.processUpdate(row.key(), RowWithData(row.key(), Map(BTC.InstanceIdRic -> row.key(), BTC.Side -> newSide)), clock.now())
})
case _ =>
}
}
ViewPortEditSuccess()
}

private def getRowData(rowKey: String, columnName: String): Any = {
val row = table.pullRow(rowKey, ViewPortColumnCreator.create(table, List(columnName)))
row.get(columnName)
}

override def deleteRowAction(): ViewPortDeleteRowAction = ???

override def deleteCellAction(): ViewPortDeleteCellAction = ???
Expand All @@ -98,6 +109,4 @@ class BasketTradingService(val table: DataTable, val tableContainer: TableContai
override def onFormSubmit(): ViewPortFormSubmitAction = ???

override def onFormClose(): ViewPortFormCloseAction = ???


}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import org.finos.toolbox.lifecycle.LifecycleContainer
import org.finos.toolbox.time.{Clock, TestFriendlyClock}
import org.finos.vuu.api.ViewPortDef
import org.finos.vuu.core.module.TableDefContainer
import org.finos.vuu.core.module.basket.BasketModule.{BasketColumnNames => B, BasketConstituentColumnNames => BC}
import org.finos.vuu.core.module.basket.service.{BasketServiceIF, BasketTradingServiceIF}
import org.finos.vuu.core.module.price.PriceModule
import org.finos.vuu.order.oms.OmsApi
import org.finos.vuu.test.VuuServerTestCase
import org.finos.vuu.test.{TestVuuServer, VuuServerTestCase}
import org.finos.vuu.util.table.TableAsserts.assertVpEq
import org.scalatest.prop.Tables.Table

Expand All @@ -17,17 +18,68 @@ class BasketMutateOffMarketTest extends VuuServerTestCase {
import BasketTestCaseHelper._

Feature("Basket Service Test Case") {
implicit val clock: Clock = new TestFriendlyClock(10001L)
implicit val lifecycle: LifecycleContainer = new LifecycleContainer()
implicit val tableDefContainer: TableDefContainer = new TableDefContainer(Map())
implicit val metricsProvider: MetricsProvider = new MetricsProviderImpl
import BasketModule._

Scenario("Check the creation of the baskets and constituents") {
val omsApi = OmsApi()

Scenario("Check updating trade basket side with no change does not update constituents side") {
withVuuServer(PriceModule(), BasketModule(omsApi)) {
vuuServer =>

vuuServer.login("testUser", "testToken")

GivenBasketTradeExist(vuuServer, ".FTSE", "chris-001")

val vpBasketTrading = vuuServer.createViewPort(BasketModule.NAME, BasketTradingTable)
val vpBasketTradingCons = vuuServer.createViewPort(BasketModule.NAME, BasketTradingConstituentTable)
val basketTradingService = vuuServer.getViewPortRpcServiceProxy[BasketTradingServiceIF](vpBasketTrading)

implicit val clock: Clock = new TestFriendlyClock(10001L)
implicit val lifecycle: LifecycleContainer = new LifecycleContainer()
implicit val tableDefContainer: TableDefContainer = new TableDefContainer(Map())
implicit val metricsProvider: MetricsProvider = new MetricsProviderImpl
When("we edit the side of the parent basket to same side as current value")
basketTradingService.editCellAction().func("chris-001", "side", "Buy", vpBasketTrading, vuuServer.session)
vuuServer.runOnce()

val omsApi = OmsApi()
Then("get all the updates that have occurred for all view ports from the outbound queue")
val updates = combineQs(vpBasketTrading)

import BasketModule._
And("assert the basket trading table has not changed side....")
assertVpEq(filterByVp(vpBasketTrading, updates)) {
Table(
("instanceId", "basketId", "basketName", "status", "units", "filledPct", "fxRateToUsd", "totalNotional", "totalNotionalUsd", "side"),
("chris-001", ".FTSE", "chris-001", "OFF-MARKET", 1, null, null, null, null, "Buy")
)
}

And("assert the basket trading constituent table has not changed sides")
assertVpEq(filterByVp(vpBasketTradingCons, updates)) {
Table(
("quantity", "side", "instanceId", "instanceIdRic", "basketId", "ric", "description", "notionalUsd", "notionalLocal", "venue", "algo", "algoParams", "pctFilled", "weighting", "priceSpread", "limitPrice", "priceStrategyId", "filledQty","orderStatus"),
(10L, "Buy", "chris-001", "chris-001.BP.L", ".FTSE", "BP.L", "Beyond Petroleum", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"),
(10L, "Sell", "chris-001", "chris-001.BT.L", ".FTSE", "BT.L", "British Telecom", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"),
(10L, "Buy", "chris-001", "chris-001.VOD.L", ".FTSE", "VOD.L", "Vodafone", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING")
)
}
}
}

def GivenBasketTradeExist(vuuServer: TestVuuServer, basketId: String, basketTradeName: String): Unit = {
val basketProvider = vuuServer.getProvider(BasketModule.NAME, BasketTable)
basketProvider.tick(".FTSE", Map(B.Id -> ".FTSE", B.Name -> ".FTSE 100", B.NotionalValue -> 1000001, B.NotionalValueUsd -> 1500001))

val constituentProvider = vuuServer.getProvider(BasketModule.NAME, BasketConstituentTable)
constituentProvider.tick("VOD.L.FTSE", Map(BC.RicBasketId -> "VOD.L.FTSE", BC.Ric -> "VOD.L", BC.BasketId -> basketId, BC.Weighting -> 0.1, BC.Side -> "Buy", BC.Description -> "Vodafone"))
constituentProvider.tick("BT.L.FTSE", Map(BC.RicBasketId -> "BT.L.FTSE", BC.Ric -> "BT.L", BC.BasketId -> basketId, BC.Weighting -> 0.1, BC.Side -> "Sell", BC.Description -> "British Telecom"))
constituentProvider.tick("BP.L.FTSE", Map(BC.RicBasketId -> "BP.L.FTSE", BC.Ric -> "BP.L", BC.BasketId -> basketId, BC.Weighting -> 0.1, BC.Side -> "Buy", BC.Description -> "Beyond Petroleum"))

val vpBasket = vuuServer.createViewPort(BasketModule.NAME, BasketTable)
val basketService = vuuServer.getViewPortRpcServiceProxy[BasketServiceIF](vpBasket)
basketService.createBasket(basketId, basketTradeName)(vuuServer.requestContext)
}

Scenario("Check the creation of the baskets and constituents") {

withVuuServer(PriceModule(), BasketModule(omsApi)) {
vuuServer =>
Expand Down Expand Up @@ -119,7 +171,7 @@ class BasketMutateOffMarketTest extends VuuServerTestCase {

//vuuServer.runOnce()
And("assert the basket trading constituent table has flipped sides also")
assertVpEq(filterByVp(vpBasketTradingCons,updates)) {
assertVpEq(filterByVp(vpBasketTradingCons, updates)) {
Table(
("quantity", "side", "instanceId", "instanceIdRic", "basketId", "ric", "description", "notionalUsd", "notionalLocal", "venue", "algo", "algoParams", "pctFilled", "weighting", "priceSpread", "limitPrice", "priceStrategyId", "filledQty", "orderStatus"),
(10L, "Sell", "chris-001", "chris-001.BP.L", ".FTSE", "BP.L", "Beyond Petroleum", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"),
Expand Down

0 comments on commit 436c889

Please sign in to comment.