-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#981 Added first cut of the OmsApi into example code.
- Loading branch information
1 parent
9e30b2c
commit dcea3f7
Showing
12 changed files
with
379 additions
and
72 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
38 changes: 38 additions & 0 deletions
38
...in/scala/org/finos/vuu/core/module/basket/provider/BasketTradingConstituentProvider.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package org.finos.vuu.core.module.basket.provider | ||
|
||
import org.finos.toolbox.lifecycle.LifecycleContainer | ||
import org.finos.toolbox.thread.LifeCycleRunner | ||
import org.finos.toolbox.time.Clock | ||
import org.finos.vuu.core.module.basket.service.OrderStates | ||
import org.finos.vuu.core.table.{DataTable, RowWithData} | ||
import org.finos.vuu.order.oms._ | ||
import org.finos.vuu.provider.DefaultProvider | ||
|
||
class BasketTradingConstituentProvider(val table: DataTable, val omsApi: OmsApi)(implicit lifecycle: LifecycleContainer, clock: Clock) extends DefaultProvider { | ||
|
||
import org.finos.vuu.core.module.basket.BasketModule.{BasketTradingConstituentColumnNames => BTC} | ||
|
||
val runner = new LifeCycleRunner("TradingConsProviderRunner", runOnce, 50L) | ||
|
||
omsApi.addListener(new OmsListener { | ||
override def onAck(ack: Ack): Unit = { | ||
table.processUpdate(ack.clientOrderId, RowWithData(ack.clientOrderId, Map[String, Any](BTC.OrderStatus -> OrderStates.ACKED)),clock.now()) | ||
} | ||
override def onCancelAck(ack: CancelAck): Unit = ??? | ||
override def onReplaceAck(ack: ReplaceAck): Unit = ??? | ||
override def onFill(fill: Fill): Unit = { | ||
val state = if(fill.fillQty == fill.totalFilledQty) OrderStates.FILLED else OrderStates.ACKED | ||
table.processUpdate(fill.clientOrderId, | ||
RowWithData(fill.clientOrderId, Map[String, Any](BTC.InstanceIdRic -> fill.clientOrderId, | ||
BTC.FilledQty -> fill.fillQty, BTC.OrderStatus -> state)) | ||
,clock.now()) | ||
} | ||
}) | ||
|
||
def runOnce(): Unit = { | ||
omsApi.runOnce() | ||
} | ||
|
||
|
||
override val lifecycleId: String = "org.finos.vuu.core.module.basket.provider.BasketTradingConstituentProvider#" + hashCode() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 8 additions & 0 deletions
8
example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/OrderStates.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package org.finos.vuu.core.module.basket.service | ||
|
||
object OrderStates { | ||
final val PENDING = "PENDING" | ||
final val ACKED = "ACKED" | ||
final val CANCELLED = "CANCELLED" | ||
final val FILLED = "FILLED" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
39 changes: 39 additions & 0 deletions
39
example/order/src/main/scala/org/finos/vuu/order/oms/OmsApi.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package org.finos.vuu.order.oms | ||
|
||
import org.finos.toolbox.time.Clock | ||
import org.finos.vuu.order.oms.impl.InMemOmsApi | ||
|
||
object MaxTimes{ | ||
final val MAX_ACK_TIME_MS = 5_000 | ||
final val MAX_FILL_TIME_MS = 8_000 | ||
} | ||
|
||
case class NewOrder(symbol: String, qty: Long, price: Double, clientOrderId: String) | ||
case class ReplaceOrder(orderId: Int, newPrice: Double, newQty: Long) | ||
case class CancelOrder(orderId: Int) | ||
case class Ack(orderId: Int, clientOrderId: String, symbol: String, qty: Long, price: Double) | ||
case class CancelAck(orderId: Int, clientOrderId: String) | ||
case class ReplaceAck(orderId: Int, clientOrderId: String) | ||
case class Fill(orderid: Int, fillQty: Long, fillPrice: Double, clientOrderId: String, totalFilledQty: Long) | ||
|
||
trait OmsApi { | ||
def createOrder(newOrder: NewOrder): Unit | ||
def replaceOrder(replaceOrder: ReplaceOrder): Unit | ||
def cancelOrder(cancelOrder: CancelOrder): Unit | ||
def addListener(omsListener: OmsListener): Unit | ||
def runOnce(): Unit | ||
def containsOrder(clientOrderId: String): Boolean | ||
} | ||
|
||
trait OmsListener{ | ||
def onAck(ack: Ack): Unit | ||
def onCancelAck(ack: CancelAck): Unit | ||
def onReplaceAck(ack: ReplaceAck): Unit | ||
def onFill(fill: Fill): Unit | ||
} | ||
|
||
object OmsApi{ | ||
def apply()(implicit clock: Clock): OmsApi = { | ||
new InMemOmsApi() | ||
} | ||
} |
78 changes: 78 additions & 0 deletions
78
example/order/src/main/scala/org/finos/vuu/order/oms/impl/InMemOmsApi.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package org.finos.vuu.order.oms.impl | ||
|
||
import org.finos.toolbox.time.Clock | ||
import org.finos.vuu.order.oms.impl.States.PENDING_ACK | ||
import org.finos.vuu.order.oms.{Ack, CancelOrder, Fill, NewOrder, OmsApi, OmsListener, ReplaceOrder} | ||
|
||
import java.util.concurrent.atomic.AtomicInteger | ||
import scala.util.Random | ||
|
||
object States { | ||
def ACKED = 'A' | ||
|
||
def PENDING_ACK = '~' | ||
|
||
def CANCELLED = 'X' | ||
|
||
def PENDING_REPLACE = 'R' | ||
|
||
def FILLED = 'F' | ||
} | ||
|
||
case class InMemOrderState(symbol: String, qty: Long, price: Double, clientOrderId: String, state: Char, nextEventTime: Long, orderId: Int, filledQty: Long) | ||
|
||
object OrderId { | ||
private val orderId = new AtomicInteger(0) | ||
def nextOrderId(): Int = orderId.incrementAndGet() | ||
} | ||
|
||
class InMemOmsApi(implicit val clock: Clock) extends OmsApi { | ||
|
||
private final val random = new Random(clock.now()) | ||
|
||
@volatile private var orders = List[InMemOrderState]() | ||
@volatile private var listeners = List[OmsListener]() | ||
|
||
|
||
override def containsOrder(clientOrderId: String): Boolean = orders.exists(_.clientOrderId == clientOrderId) | ||
|
||
override def createOrder(newOrder: NewOrder): Unit = { | ||
orders = orders ++ List(InMemOrderState(newOrder.symbol, newOrder.qty, newOrder.price, | ||
newOrder.clientOrderId, States.PENDING_ACK, clock.now() + random.between(1, 1000), OrderId.nextOrderId(), 0L)) | ||
} | ||
|
||
override def replaceOrder(replaceOrder: ReplaceOrder): Unit = ??? | ||
|
||
override def cancelOrder(cancelOrder: CancelOrder): Unit = ??? | ||
|
||
override def addListener(omsListener: OmsListener): Unit = listeners = listeners ++ List(omsListener) | ||
|
||
override def runOnce(): Unit = { | ||
orders = orders.map(orderstate => { | ||
|
||
if (orderstate.nextEventTime <= clock.now()) { | ||
|
||
orderstate.state match { | ||
case '~' => | ||
val orderId = OrderId.nextOrderId() | ||
listeners.foreach(_.onAck(Ack(orderId, orderstate.clientOrderId, orderstate.symbol, orderstate.qty, orderstate.price))) | ||
orderstate.copy(state = States.ACKED, nextEventTime = clock.now() + random.between(1000, 5000), orderId = orderId) | ||
case 'A' => | ||
val remainingQty = orderstate.qty - orderstate.filledQty | ||
val fillQty = if(remainingQty > 1) random.between(1, orderstate.qty - orderstate.filledQty) else 1 | ||
listeners.foreach(_.onFill(Fill(orderstate.orderId, fillQty, orderstate.price, orderstate.clientOrderId, orderstate.filledQty + fillQty))) | ||
orderstate.copy(filledQty = orderstate.filledQty + fillQty, nextEventTime = clock.now() + random.between(1000, 5000)) | ||
case _ => | ||
orderstate | ||
} | ||
|
||
} else { | ||
orderstate | ||
} | ||
}) | ||
|
||
orders = orders.filter(os => os.filledQty != os.qty) | ||
|
||
} | ||
|
||
} |
Oops, something went wrong.