public MockOrderBook HandleOrder(ExchangeOrder incomingOrder) { switch (incomingOrder.Status) { case ExchangeOrderStatus.Canceled: return(CancelOrder(incomingOrder)); case ExchangeOrderStatus.Pending: return(PlaceOrder(incomingOrder)); default: throw new Exception(string.Format("Unhandled incoming order status {0}", incomingOrder.Status)); } }
//if the bid > ask or one and only of the orders is a market order, return the price of the transaction //else return -1 //two birds one stone: //allows me to know IF there was a transaction and if so, tells me what the price is private decimal GetTransactionPrice(ExchangeOrder incomingOrder, ExchangeOrder targetOrder) { if (incomingOrder.OSide == targetOrder.OSide) { throw new ArgumentException("Cannot compute transaction price for two same-side orders"); } if (incomingOrder.Status != ExchangeOrderStatus.Open || targetOrder.Status != ExchangeOrderStatus.Open) { throw new Exception("A transaction price can only be evaluated between two Open orders"); } decimal price = -1; if (!((incomingOrder.OType == OrderType.Market) && (targetOrder.OType == OrderType.Market)))//there is no transaction if they are two market orders { if (incomingOrder.OType == OrderType.Market) { //at this point we are sure the target order is a limit order price = targetOrder.Price; } else if (targetOrder.OType == OrderType.Market) { //at this point we are sure the incoming order is a limit order price = incomingOrder.Price; } else { //they are both limit orders //we choose the price that favors the target order because it arrived first (first come best served) if (((incomingOrder.OSide == OrderSide.Buy) && (incomingOrder.Price >= targetOrder.Price)) || ((incomingOrder.OSide == OrderSide.Sell) && (incomingOrder.Price <= targetOrder.Price)) ) { price = incomingOrder.Price; } } } return(price); }
public MockOrderBook PlaceOrder(ExchangeOrder pendingOrder) { if (pendingOrder == null) { throw new ArgumentNullException("pendingOrder"); } if (pendingOrder.Status != ExchangeOrderStatus.Pending) { throw new Exception(string.Format("Cannot insert order with '{0}' status in the OrderBook", pendingOrder.Status)); } //Now the order is opened var openOrder = pendingOrder.WithUpdatedStatus(ExchangeOrderStatus.Open); var orders = this.Orders; var bids = this.Bids; var asks = this.Asks; ImmutableSortedSet <ExchangeOrder> oppositeSideOrders = null; ImmutableSortedSet <ExchangeOrder> sameSideOrders = null; if (openOrder.OSide == OrderSide.Buy) { oppositeSideOrders = asks; sameSideOrders = bids; } else { oppositeSideOrders = bids; sameSideOrders = asks; } var matchOuput = MatchOrder(Tuple.Create(openOrder, oppositeSideOrders)); ExchangeOrder resultingOrder = matchOuput.Item1; ImmutableSortedSet <ExchangeOrder> resultingSameSideOrders = null; if (resultingOrder.RemainingVolume > 0) { resultingSameSideOrders = sameSideOrders.Add(resultingOrder); } else { resultingSameSideOrders = sameSideOrders; } ImmutableSortedSet <ExchangeOrder> resultingOppositeSideOrders = matchOuput.Item2; #region update orders var ordersBuilder = orders.ToBuilder(); ordersBuilder[resultingOrder.ID] = resultingOrder; var oppositeSideOrdersDiff = resultingOppositeSideOrders.SymmetricExcept(oppositeSideOrders). //contains all the elements which are NOT PRESENT IN BOTH sets. for updated orders, both the old and new one will be returned GroupBy(o => o.ID, (_, g) => g.OrderBy(o => o.RemainingVolume).FirstOrDefault()). //for changed orders, take only the latest one ToList(); foreach (var item in oppositeSideOrdersDiff) { //add or update the value in dictionary ordersBuilder[item.ID] = item; } #endregion #region reconstruct bids and asks ImmutableSortedSet <ExchangeOrder> resultingBids = null; ImmutableSortedSet <ExchangeOrder> resultingAsks = null; if (openOrder.OSide == OrderSide.Buy) { resultingBids = resultingSameSideOrders; resultingAsks = resultingOppositeSideOrders; } else { resultingBids = resultingOppositeSideOrders; resultingAsks = resultingSameSideOrders; } resultingBids = resultingBids.Where(o => o.Status == ExchangeOrderStatus.Open).ToImmutableSortedSet(OrderComparer.DescBidComparer()); resultingAsks = resultingAsks.Where(o => o.Status == ExchangeOrderStatus.Open).ToImmutableSortedSet(OrderComparer.DescAskComparer()); #endregion //return all orders + bids and asks from which completed orders are removed return(new MockOrderBook(this.ExchangeID, ordersBuilder.ToImmutable(), resultingBids, resultingAsks)); }