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 #1060

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
436c889
#966 when updating basket trade cell value, only update if different …
naleeha Nov 27, 2023
c4c6afb
#982 initial implementation of editing basket trade constituent side
naleeha Nov 27, 2023
6463da7
#979 using unique instanceId for the basket trade separate from baske…
naleeha Nov 27, 2023
e0d905d
#980 adding basket trading constituent row - using menu for testing
naleeha Nov 24, 2023
9d23e74
#980 removed the add row menu that was for testing, clean up and erro…
naleeha Nov 24, 2023
79fd6a2
#980 returning no action for menu calls and rcp success or failure fo…
naleeha Nov 24, 2023
a6d3173
#1010 registring ViewPortRpcSuccess
naleeha Nov 27, 2023
2441862
#979 updated test to use basket trade instance id seperate from baske…
naleeha Nov 27, 2023
351a5b2
#1010 re-naming to VP_EDIT_FAILURE and VP_RCP_FAILURE for consistency
naleeha Nov 27, 2023
f5a41e6
#1019 converting weighting and limit price field to a double as json …
naleeha Nov 27, 2023
b2cae8a
#979 moved logic for generating unique basket id to the static class,…
naleeha Dec 1, 2023
90eaa31
#980 making basket trade add constituent take in single ric as parsin…
naleeha Dec 5, 2023
6390950
#1025 updating internal order state's state when processing fill
naleeha Nov 28, 2023
5bf65d0
#1025 implementing taking basket trade off the market
naleeha Nov 28, 2023
b898042
#1025 using MAX_FILL_TIME_MS when generating random next event time
naleeha Nov 28, 2023
dc35263
#1025 updated basket send to market test to include taking off the ma…
naleeha Dec 1, 2023
b83cfbb
#1027 fix for where basket constituent is not sorting
naleeha Nov 28, 2023
ec58b40
#1036 adding equals and hashcode override methods to be able to comp…
naleeha Dec 5, 2023
c57daf3
#1010 correcting name of RPC response message
naleeha Dec 6, 2023
f6de416
#980 adding description to the new constituent on basket trading
naleeha Dec 6, 2023
71cf561
#1059 removed the redundant sides constants and made buy and sell all…
naleeha Dec 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
@@ -0,0 +1,3 @@
package org.finos.vuu.core.module.basket.result

case class ErrorReason(reason: String)
Original file line number Diff line number Diff line change
Expand Up @@ -2,98 +2,102 @@ 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, PriceStrategy, Sides}
import org.finos.vuu.core.module.basket.service.BasketService.counter
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.{EditRpcHandler, RpcHandler}
import org.finos.vuu.net.rpc.RpcHandler
import org.finos.vuu.net.{ClientSessionId, RequestContext}
import org.finos.vuu.order.oms.{NewOrder, OmsApi}
import org.finos.vuu.order.oms.OmsApi
import org.finos.vuu.viewport._

import java.util.concurrent.atomic.AtomicInteger

object BasketService{
val counter = new AtomicInteger(0)
object BasketTradeId {

private val counter: AtomicInteger = new AtomicInteger(0)
var current:String = "NoneInitalised" //this is for testing but only works if tests that use this doesnt run in parallel
def oneNew(user:String): String = {
val counterValue = counter.incrementAndGet()
current = user + "-" + "".padTo(5 - counterValue.toString.length, "0").mkString + counterValue
current
}
}

trait BasketServiceIF{
def createBasket(basketKey: String, name: String)(ctx: RequestContext): ViewPortAction
def createBasket(basketId: String, name: String)(ctx: RequestContext): ViewPortAction
}

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

import org.finos.vuu.core.module.basket.BasketModule.{BasketConstituentColumnNames => BC, BasketTradingColumnNames => BT, 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] = {
private def getConstituentsForSourceBasket(basketId: 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)
keys.map( key => table.pullRow(key) ).filter(_.get(BC.BasketId).toString == basketId)
}

private def mkTradingConstituentRow(side: String, basketKey: String, instanceKey: String,
constituentKey: String, quantity: Long, weighting: Double, basketConsRow: RowData): RowWithData = {
RowWithData(constituentKey, Map(BTC.BasketId -> basketKey,
BTC.Ric -> basketConsRow.get(BC.Ric),
BTC.InstanceId -> instanceKey,
BTC.Quantity -> quantity,
BTC.InstanceIdRic -> constituentKey,
BTC.Description -> basketConsRow.get(BC.Description),
BTC.Side -> side,
BTC.Weighting -> weighting,
BTC.PriceStrategyId -> 2,
BTC.Algo -> -1,
BTC.OrderStatus -> OrderStates.PENDING,
BTC.FilledQty -> 0
))
private def mkTradingConstituentRow(side: String, sourceBasketId: String, basketTradeInstanceId: String, constituentKey: String,
quantity: Long, weighting: Double, basketConsRow: RowData): RowWithData = {
RowWithData(
constituentKey,
Map(
BTC.Ric -> basketConsRow.get(BC.Ric),
BTC.BasketId -> sourceBasketId,
BTC.InstanceId -> basketTradeInstanceId,
BTC.InstanceIdRic -> constituentKey,
BTC.Quantity -> quantity,
BTC.Description -> basketConsRow.get(BC.Description),
BTC.Side -> side,
BTC.Weighting -> weighting,
BTC.PriceStrategyId -> 2,
BTC.Algo -> -1,
BTC.OrderStatus -> OrderStates.PENDING,
BTC.FilledQty -> 0
))
}

private def mkTradingBasketRow(instanceKey: String, basketKey: String): RowWithData = {
RowWithData(instanceKey, Map(BT.InstanceId -> instanceKey, BT.Status -> "OFF-MARKET", BT.BasketId -> basketKey, BT.BasketName -> instanceKey, BT.Side -> Sides.Buy, BT.Units -> 1))
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 -> Side.Buy, BT.Units -> 1))
}

def createBasketFromRpc(basketKey: String, name: String)(ctx: RequestContext): ViewPortAction = {
createBasket(basketKey, name)(ctx)
def createBasketFromRpc(basketId: String, name: String)(ctx: RequestContext): ViewPortAction = {
createBasket(basketId, name)(ctx)
}

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

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

val instanceKey = getAndPadCounter(session)
val instanceKey = BasketTradeId.oneNew(session.user)

createBasketInternal(basketKey, instanceKey, session)
createBasketInternal(basketId, instanceKey, instanceKey, session)
}

def createBasket(basketKey: String, name: String)(ctx: RequestContext): ViewPortAction = {
createBasketInternal(basketKey, name, ctx.session)
def createBasket(basketId: String, name: String)(ctx: RequestContext): ViewPortAction = {
val basketTradeId = BasketTradeId.oneNew(ctx.session.user)
createBasketInternal(basketId, name, basketTradeId, ctx.session)
}

private def createBasketInternal(sourceBasketId: String, basketTradeName: String, basketTradeId: String, sessionId: ClientSessionId) = {

private def createBasketInternal(basketKey: String, name: String, sessionId: ClientSessionId): ViewPortAction = {

val constituents = getConstituentsForBasketKey(basketKey)
val constituents = getConstituentsForSourceBasket(sourceBasketId)

tableContainer.getTable(BasketModule.BasketTradingTable) match {
case table: DataTable =>
table.processUpdate(name, mkTradingBasketRow(name, basketKey), clock.now())
table.processUpdate(basketTradeId, mkTradingBasketRow(sourceBasketId, basketTradeName, basketTradeId), clock.now())
case null =>
logger.error("Cannot find the Basket Trading table.")
}

tableContainer.getTable(BasketModule.BasketTradingConstituentTable) match {
case table: DataTable =>
constituents.foreach( rowData => {
val constituentKey = name + "." + rowData.get(BTC.Ric)
val constituentKey = basketTradeId + "." + rowData.get(BTC.Ric)
val weighting = rowData.get(BTC.Weighting).asInstanceOf[Double]
val quantity = (weighting * 100).asInstanceOf[Long]
val side = rowData.get(BTC.Side).toString
table.processUpdate(constituentKey, mkTradingConstituentRow(side, basketKey, name, constituentKey, quantity, weighting, rowData), clock.now())
table.processUpdate(constituentKey, mkTradingConstituentRow(side, sourceBasketId, basketTradeId, constituentKey, quantity, weighting, rowData), clock.now())
})
case null =>
logger.error("Cannot find the Basket Trading Constituent.")
Expand Down