Permalink
Browse files

Added trading package

  • Loading branch information...
1 parent d832998 commit b5f4e18a8dff70b556095c5f13d8d178ab0b8926 @dcaoyuan committed Feb 24, 2012
@@ -0,0 +1,22 @@
+OrderSide_Buy=Buy
+OrderSide_BuyCover=Buy Cover
+OrderSide_Sell=Sell
+OrderSide_SellShort=Sell Short
+OrderStatus_Canceled=Canceled
+OrderStatus_Expired=Expired
+OrderStatus_Filled=Filled
+OrderStatus_New=New
+OrderStatus_Partial=Partial
+OrderStatus_PendingCancel=Pending Cancel
+OrderStatus_PendingNew=Pending New
+OrderStatus_Rejected=Rejected
+OrderType_Limit=Limit
+OrderType_Market=Market
+OrderType_Stop=Stop
+OrderType_StopLimit=Stop Limit
+OrderValidity_AtClosing=At Closing
+OrderValidity_AtOpening=At Opening
+OrderValidity_Day=Day
+OrderValidity_GoodTillCancel=Good Till Cancel
+OrderValidity_GoodTillDate=Good Till Date
+OrderValidity_ImmediateOrCancel=Imm. or Cancel
@@ -0,0 +1,64 @@
+package org.aiotrade.lib.trading
+
+import org.aiotrade.lib.collection.ArrayList
+import org.aiotrade.lib.util.actors.Publisher
+import java.util.Currency
+import java.util.Locale
+import java.util.UUID
+
+class Account(var description: String, val currency: Currency = Currency.getInstance(Locale.getDefault)) extends Publisher {
+ val id: Long = UUID.randomUUID.getMostSignificantBits
+
+ private var _balance = 0.0
+ private var _transactions = new ArrayList[Transaction]()
+ private var _positions = new ArrayList[Position]()
+ private var _expenseScheme: ExpenseScheme = _
+
+ def balance: Double = _balance
+ def balance_=(balance: Double) {
+ _balance = balance
+ }
+
+ def expenseScheme = _expenseScheme
+ def expenseScheme_=(expenseScheme: ExpenseScheme) {
+ _expenseScheme = expenseScheme
+ }
+
+ def transactions = _transactions.toArray
+ def positions = _positions.toArray
+
+ def processCompletedOrder(order: Order) {
+ val expenses = if (expenseScheme != null) {
+ order.side match {
+ case OrderSide.Buy => expenseScheme.getBuyExpenses(order.filledQuantity, order.averagePrice)
+ case OrderSide.Sell => expenseScheme.getSellExpenses(order.filledQuantity, order.averagePrice)
+ case _ => Double.NaN
+ }
+ } else Double.NaN
+
+ val transaction = new TradeTransaction(order, order.transactions, if (expenses != Double.NaN) new ExpenseTransaction(expenses) else null)
+ _transactions += transaction
+
+ _balance -= transaction.amount
+
+ val quantity = if (order.side == OrderSide.Sell) -order.filledQuantity else order.filledQuantity
+ val averagePrice = transaction.amount / order.filledQuantity
+
+ _positions find (_.sec == order.sec) match {
+ case None =>
+ val position = new Position(order.sec, quantity, averagePrice)
+ _positions += position
+ publish(PositionOpened(this, position))
+
+ case Some(position) =>
+ position.add(quantity, averagePrice)
+ if (position.quantity == 0) {
+ _positions -= position
+ publish(PositionClosed(this, position))
+ } else {
+ publish(PositionChanged(this, position))
+ }
+ }
+ }
+}
+
@@ -0,0 +1,42 @@
+package org.aiotrade.lib.trading
+
+
+import org.aiotrade.lib.securities.model.Sec
+import org.aiotrade.lib.util.actors.Publisher
+
+/**
+ * Brokers that managed accounts and receive trade to fill orders
+ *
+ */
+trait Broker extends Publisher {
+ def id: Long
+ def name: String
+ def connect: Unit
+ def disconnect: Unit
+ def allowedTypes: Array[OrderType]
+ def allowedSides: Array[OrderSide]
+ def allowedValidity: Array[OrderValidity]
+ def allowedRoutes: Array[OrderRoute]
+ def canTrade(sec: Sec): Boolean
+ def getSecurityFromSymbol(symbol: String): Sec
+ def getSymbolFromSecurity(sec: Sec)
+ def accounts: Array[Account]
+ def orderExecutors: Array[OrderExecutor]
+
+ @throws(classOf[BrokerException])
+ def prepareOrder(order: Order): OrderExecutor
+}
+
+
+case class BrokerException(message: String, cause: Throwable) extends Exception(message, cause)
+
+trait OrderDelta {
+ def order: OrderExecutor
+}
+object OrderDelta {
+ case class Added(order: OrderExecutor) extends OrderDelta
+ case class Removed(order: OrderExecutor) extends OrderDelta
+ case class Updated(order: OrderExecutor) extends OrderDelta
+}
+
+case class OrderDeltasEvent(broker: Broker, deltas: Array[OrderDelta])
@@ -0,0 +1,85 @@
+package org.aiotrade.lib.trading
+
+trait ExpenseScheme {
+ def getBuyExpenses(quantity: Double, averagePrice: Double): Double
+ def getSellExpenses(quantity: Double, averagePrice: Double): Double
+}
+
+object ExpenseScheme {
+ val LimitedProportional1Scheme = LimitedProportionalScheme(0.05, 5, 100)
+ val LimitedProportional2Scheme = LimitedProportionalScheme(0.05, 5, Double.PositiveInfinity) // no maximum limit
+}
+
+object NoExpensesScheme extends ExpenseScheme {
+ def getBuyExpenses(quantity: Double, averagePrice: Double) = 0.0
+ def getSellExpenses(quantity: Double, averagePrice: Double) = 0.0
+
+ override
+ def hashCode = 11 * toString.hashCode
+
+ override
+ def toString = "None expenses scheme"
+}
+
+case class SimpleFixedScheme(expenses: Double = 9.95) extends ExpenseScheme {
+ def getBuyExpenses(quantity: Double, averagePrice: Double) = expenses
+ def getSellExpenses(quantity: Double, averagePrice: Double) = expenses
+}
+
+
+case class LimitedProportionalScheme(percentage: Double, minimum: Double, maximum: Double) extends ExpenseScheme {
+
+ def getBuyExpenses(quantity: Double, averagePrice: Double): Double = {
+ var expenses = quantity * averagePrice / 100.0 * percentage
+ if (expenses < minimum) {
+ expenses = minimum
+ }
+ if (expenses > maximum) {
+ expenses = maximum
+ }
+ expenses
+ }
+
+ def getSellExpenses(quantity: Double, averagePrice: Double): Double = {
+ var expenses = quantity * averagePrice / 100.0 * percentage
+ if (expenses < minimum) {
+ expenses = minimum
+ }
+ if (expenses > maximum) {
+ expenses = maximum
+ }
+ expenses
+ }
+}
+
+/**
+ * Sample params:
+ * @param level1 = 0.01
+ * @param level1quantity = 500
+ * @param level2 = 0.005
+ * @param minimum = 1.0
+ */
+case class TwoLevelsPerShareScheme(level1: Double, level1quantity: Double, level2: Double, minimum: Double) extends ExpenseScheme {
+
+ def getBuyExpenses(quantity: Double, averagePrice: Double): Double = {
+ var expenses = level1 * (if (quantity > level1quantity) level1quantity else quantity)
+ if (quantity > level1quantity) {
+ expenses += level2 * (quantity - level1quantity)
+ }
+ if (expenses < minimum) {
+ expenses = minimum
+ }
+ expenses
+ }
+
+ def getSellExpenses(quantity: Double, averagePrice: Double): Double = {
+ var expenses = level1 * (if (quantity > level1quantity) level1quantity else quantity)
+ if (quantity > level1quantity) {
+ expenses += level2 * (quantity - level1quantity)
+ }
+ if (expenses < minimum) {
+ expenses = minimum
+ }
+ expenses
+ }
+}
Oops, something went wrong.

0 comments on commit b5f4e18

Please sign in to comment.