public void CanSubmitBuyLimitOrder()
        {
            ILimitOrderBook lob = new LimitOrderBook.StandardLimitOrderBook();

            Assert.IsNotNull(lob);
            Assert.AreEqual(0, lob.Bids.Count);

            Assert.IsInstanceOfType(lob, typeof(ILimitOrderBook));

            var testOrder = new Order() { Price = 100, Quantity = 10, Side = OrderSide.Buy, Type = OrderType.LimitOrder, UserID = "Test" };
            var testOrderGuid = testOrder.ID.ToString();

            var result = lob.ProcessLimitOrder(testOrder,true);

            Assert.IsNotNull(result);
            Assert.AreEqual(1, result.Count());
            Assert.AreEqual(true, result.First().Placed);
            Assert.AreEqual("Test", result.First().Order.UserID);
            Assert.AreEqual(testOrderGuid, result.First().Order.ID.ToString());
            Assert.AreEqual(OrderSide.Buy, result.First().Order.Side);
            Assert.AreEqual(1, lob.Bids.Count);

            Assert.AreEqual(100, lob.BestBid.Price);
            Assert.AreEqual(10, lob.BestBid.Quantity);
        }
        public virtual Order GetNextAction(LimitOrderBookSnapshot limitOrderBook)
        {
            var size = Math.Ceiling(_maxOrderSize * _rng.GetRandomDouble());
            var priceDiff = _maxPriceDifferential * Math.Abs(_normal.Sample());

            Order order;

            var randomNumber = _rng.GetRandomDouble();
            if (randomNumber > (0.5 + (_doNothingProbability/2)))
            {
                //buylimitorder
                var price = Math.Round(limitOrderBook.BestAskPrice.Value - priceDiff, _decimals);
                order = new Order { Price = price, Quantity = size, Side = OrderSide.Buy,Type = OrderType.LimitOrder, Valid = true};

            }
            else if (randomNumber < (0.5 - (_doNothingProbability/2)))
            {
                //selllimitorder
                var price = Math.Round(limitOrderBook.BestBidPrice.Value + priceDiff, _decimals);
                order = new Order { Price = price, Quantity = size, Side = OrderSide.Sell, Type = OrderType.LimitOrder, Valid = true };
            }
            else
            {
                //donothing
                order = null;
            }

            return order;
        }
        public Order[] GetNextActions(LimitOrderBookSnapshot limitOrderBook)
        {
            var order = base.GetNextAction(limitOrderBook);

            var orders = new List<Order>();

            if (order != null)
            {
                if (_lastOrder != null)
                {
                    //cancel previous
                    var cancelOrder = new Order();
                    cancelOrder.Type = OrderType.Cancel;
                    cancelOrder.ID = _lastOrder.ID;

                    orders.Add(cancelOrder);
                }

                orders.Add(order);

                _lastOrder = order;
            }

            return orders.ToArray();
        }
Exemple #4
0
        void _orderCommunicationsModule_OnOrder(Order order, string userID)
        {
            IEnumerable<OrderUpdate> orderUpdates = null;

            switch (order.Type)
            {
                case OrderType.LimitOrder:
                    orderUpdates =_limitOrderBook.ProcessLimitOrder(order,true);
                    break;
                case OrderType.MarketOrder:
                    orderUpdates = _limitOrderBook.ProcessMarketOrder(order,true);
                    break;
                case OrderType.StopLimitOrder:
                    orderUpdates = _limitOrderBook.ProcessStopOrder(order);
                    break;
                case OrderType.StopMarketOrder:
                    orderUpdates = _limitOrderBook.ProcessStopOrder(order);
                    break;
                case OrderType.Cancel:
                    orderUpdates = _limitOrderBook.CancelOrder(order);
                    break;
                case OrderType.Amend:
                    orderUpdates = _limitOrderBook.AmendLimitOrder(order);
                    break;
                default:
                    throw new Exception("Unknown order type");
            }

            if (orderUpdates != null)
            {
                foreach (var orderUpdate in orderUpdates)
                {
                    _orderCommunicationsModule.PushOrderInstructionUpdate(orderUpdate, orderUpdate.Order.UserID);
                }
            }

            _dataCommunicationsModule.PushUpdate(_limitOrderBook);
        }
        public Order GetNextAction(LimitOrderBookSnapshot limitOrderBook)
        {
            Order order;
            var size = Math.Ceiling(_maxOrderSize * _rng.GetRandomDouble());

            var randomNumber = _rng.GetRandomDouble();

            if (randomNumber < (0.5 - (_doNothingProbability / 2)))
            {
                //buymarketdorder
                order = new Order() {Quantity = size,Type = OrderType.MarketOrder, Side = OrderSide.Buy };
            }
            else if (randomNumber > (0.5 + (_doNothingProbability / 2)))
            {
                order = new Order() { Quantity = size, Type = OrderType.MarketOrder, Side = OrderSide.Sell };
            }
            else
            {
                //do nothing
                order = null;
            }

            return order;
        }
        public IEnumerable<OrderUpdate> ProcessStopOrder(Order order)
        {
            switch (order.Side)
            {
                case OrderSide.Buy:
                    if (BestAsk != null && BestAsk.Price <= order.StopPrice)
                    {
                        switch (order.Type)
                        {
                            case OrderType.StopLimitOrder:
                                return ProcessLimitOrder(order,true);
                            case OrderType.StopMarketOrder:
                                return ProcessMarketOrder(order,true);
                            default:
                                break;
                        }
                    }
                    else
                    {
                        if (!StopBids.ContainsKey(order.StopPrice.Value))
                        {
                            StopBids.Add(order.StopPrice.Value, new Queue<Order>());
                        }
                        StopBids[order.StopPrice.Value].Enqueue(order);
                    }
                    break;
                case OrderSide.Sell:
                    if (BestBid != null && BestBid.Price >= order.StopPrice)
                    {
                        switch (order.Type)
                        {
                            case OrderType.StopLimitOrder:
                                return ProcessLimitOrder(order,true);
                            case OrderType.StopMarketOrder:
                                return ProcessMarketOrder(order,true);
                            default:
                                break;
                        }
                    }
                    else
                    {
                        if (!StopBids.ContainsKey(order.StopPrice.Value))
                        {
                            StopBids.Add(order.StopPrice.Value, new Queue<Order>());
                        }
                        StopBids[order.StopPrice.Value].Enqueue(order);
                    }
                    break;
                default:
                    break;
            }

            return new OrderUpdate[] { new OrderUpdate() {
                Placed = true,
                Order = order,
                Message = "Stop order enqueued"
            }};
        }
        public IEnumerable<OrderUpdate> ProcessMarketOrder(Order order, bool checkStopOrders)
        {
            var results = new List<OrderUpdate>();

            switch (order.Side)
            {
                case OrderSide.Buy:
                    results.AddRange(ProcessBuyMarketOrder(order));
                    break;
                case OrderSide.Sell:
                    results.AddRange(ProcessSellMarketOrder(order));
                    break;
                default:
                    results.Add(new OrderUpdate()
                    {
                        Placed = false,
                        Order = order,
                        Message = "Order side not known"
                    });
                    break;
            }

            if (checkStopOrders)
                results.AddRange(ClearStopOrders());

            return results;
        }
 public IEnumerable<OrderUpdate> CancelOrder(Order order)
 {
     return AmendLimitOrder(order, true);
 }
        public void CanSubmitBuyMarketOrderSimple()
        {
            //ARRANGE
            ILimitOrderBook lob = new LimitOrderBook.StandardLimitOrderBook();

            Assert.IsNotNull(lob);
            Assert.AreEqual(0, lob.Bids.Count);

            Assert.IsInstanceOfType(lob, typeof(ILimitOrderBook));

            var setupOrder = new Order() { Price = 101, Quantity = 20, Side = OrderSide.Sell, Type = OrderType.LimitOrder, UserID = "Test" };
            var result = lob.ProcessLimitOrder(setupOrder,true);
            Assert.AreEqual(1, result.Count());
            Assert.AreEqual(true, result.First().Placed);

            setupOrder = new Order() { Price = 101, Quantity = 10, Side = OrderSide.Sell, Type = OrderType.LimitOrder, UserID = "Test" };
            result = lob.ProcessLimitOrder(setupOrder, true);
            Assert.AreEqual(1, result.Count());
            Assert.AreEqual(true, result.First().Placed);

            setupOrder = new Order() { Price = 103, Quantity = 30, Side = OrderSide.Sell, Type = OrderType.LimitOrder, UserID = "Test" };
            result = lob.ProcessLimitOrder(setupOrder, true);
            Assert.AreEqual(1, result.Count());
            Assert.AreEqual(true, result.First().Placed);

            setupOrder = new Order() { Price = 104, Quantity = 15, Side = OrderSide.Sell, Type = OrderType.LimitOrder, UserID = "Test" };
            result = lob.ProcessLimitOrder(setupOrder, true);
            Assert.AreEqual(1, result.Count());
            Assert.AreEqual(true, result.First().Placed);

            setupOrder = new Order() { Price = 104, Quantity = 5, Side = OrderSide.Sell, Type = OrderType.LimitOrder, UserID = "Test" };
            result = lob.ProcessLimitOrder(setupOrder, true);
            Assert.AreEqual(1, result.Count());
            Assert.AreEqual(true, result.First().Placed);

            setupOrder = new Order() { Price = 105, Quantity = 50, Side = OrderSide.Sell, Type = OrderType.LimitOrder, UserID = "Test" };
            result = lob.ProcessLimitOrder(setupOrder, true);
            Assert.AreEqual(1, result.Count());
            Assert.AreEqual(true, result.First().Placed);

            setupOrder = new Order() { Price = 94, Quantity = 30, Side = OrderSide.Buy, Type = OrderType.LimitOrder, UserID = "Test" };
            result = lob.ProcessLimitOrder(setupOrder, true);
            Assert.AreEqual(1, result.Count());
            Assert.AreEqual(true, result.First().Placed);

            setupOrder = new Order() { Price = 96, Quantity = 50, Side = OrderSide.Buy, Type = OrderType.LimitOrder, UserID = "Test" };
            result = lob.ProcessLimitOrder(setupOrder, true);
            Assert.AreEqual(1, result.Count());
            Assert.AreEqual(true, result.First().Placed);

            setupOrder = new Order() { Price = 97, Quantity = 40, Side = OrderSide.Buy, Type = OrderType.LimitOrder, UserID = "Test" };
            result = lob.ProcessLimitOrder(setupOrder, true);
            Assert.AreEqual(1, result.Count());
            Assert.AreEqual(true, result.First().Placed);

            setupOrder = new Order() { Price = 97, Quantity = 10, Side = OrderSide.Buy, Type = OrderType.LimitOrder, UserID = "Test" };
            result = lob.ProcessLimitOrder(setupOrder, true);
            Assert.AreEqual(1, result.Count());
            Assert.AreEqual(true, result.First().Placed);

            setupOrder = new Order() { Price = 97, Quantity = 10, Side = OrderSide.Buy, Type = OrderType.LimitOrder, UserID = "Test" };
            result = lob.ProcessLimitOrder(setupOrder, true);
            Assert.AreEqual(1, result.Count());
            Assert.AreEqual(true, result.First().Placed);

            //ACT
            var marketOrder = new Order()
            {
                Quantity = 15,
                Side = OrderSide.Buy,
                Type = OrderType.MarketOrder,
                UserID = "Test2"
            };

            var testResult = lob.ProcessMarketOrder(marketOrder, true);

            Assert.AreEqual(1, result.Count());

            //ASSERT

            Assert.AreEqual(2, lob.Asks[101].Count);
            Assert.AreEqual(5,lob.Asks[101].ElementAt(0).Quantity);
            Assert.AreEqual(10, lob.Asks[101].ElementAt(1).Quantity);

            Assert.AreEqual(1, lob.Asks[103].Count);
            Assert.AreEqual(30, lob.Asks[103].ElementAt(0).Quantity);

            Assert.AreEqual(2, lob.Asks[104].Count);
            Assert.AreEqual(15, lob.Asks[104].ElementAt(0).Quantity);
            Assert.AreEqual(5, lob.Asks[104].ElementAt(1).Quantity);

            Assert.AreEqual(1, lob.Asks[105].Count);
            Assert.AreEqual(50, lob.Asks[105].ElementAt(0).Quantity);

            Assert.AreEqual(3, lob.Bids[97].Count);
            Assert.AreEqual(40, lob.Bids[97].ElementAt(0).Quantity);
            Assert.AreEqual(10, lob.Bids[97].ElementAt(1).Quantity);
            Assert.AreEqual(10, lob.Bids[97].ElementAt(2).Quantity);

            Assert.AreEqual(1, lob.Bids[96].Count);
            Assert.AreEqual(50, lob.Bids[96].ElementAt(0).Quantity);

            Assert.AreEqual(1, lob.Bids[94].Count);
            Assert.AreEqual(30, lob.Bids[94].ElementAt(0).Quantity);
        }
 public bool ProcessOrderInstruction(Order order, string userID)
 {
     RegisterUserID(userID, Context.ConnectionId);
     return _commsHandler.ProcessOrderInstruction(order,userID);
 }
 public IEnumerable<OrderUpdate> AmendLimitOrder(Order order)
 {
     return AmendLimitOrder(order, false);
 }
Exemple #12
0
 public virtual Order FilterLimitOrders(Order order)
 {
     return order;
 }
        public Order GetAction(int timeStep, double[] spotPrice, double[] fundamentalValue, double[] noise, double? bestBid, double? bestAsk)
        {
            var fundamentalTimeHorizon = _agentTimeHorizon;
            var lookBackTime = Math.Min(_agentTimeHorizon, timeStep)-1;

            var normalisationTerm = _fundamentalistWeighting + _chartistWeighting + _noiseWeighting;

            var fundamentalistTerm = (_fundamentalistWeighting * (decimal)Math.Log(fundamentalValue[timeStep - 1] / spotPrice[timeStep - 1])) / fundamentalTimeHorizon; //should the fundamental TH be added??

            var averageReturn = CalculateAverageReturn(timeStep, spotPrice, lookBackTime);
            var chartistTerm = _chartistWeighting * averageReturn;

            var noiseTerm = _noiseWeighting * (decimal) noise[timeStep];

            var expectedReturn = (fundamentalistTerm + chartistTerm + noiseTerm) / normalisationTerm;

            var expectedPrice = Math.Round(spotPrice[timeStep-1] * Math.Exp((double)(expectedReturn * _agentTimeHorizon)),4);

            var varianceOfPastReturns = CalculateVarianceOfPastReturns(timeStep, spotPrice, lookBackTime, averageReturn);

            var comfortPriceAtCurrentHolding = Math.Round(FindRoot(p => GetStocksToHold(p, expectedPrice, (double)_agentRiskAversionLevel, (double)varianceOfPastReturns) - StockHeld, expectedPrice, 0.0000001,0.01,expectedPrice), 4);

            var maxPrice = expectedPrice;
            var minPrice = FindRoot(p => p * (GetStocksToHold(p, expectedPrice, (double)_agentRiskAversionLevel, (double)varianceOfPastReturns) - StockHeld) - CashHeld, comfortPriceAtCurrentHolding, 0.0000001,0.1,expectedPrice);

            var drawnPrice = Math.Round(Math.Min(minPrice,maxPrice) + (Math.Abs(maxPrice-minPrice) * _randomGenerator.NextDouble()),4);

            var order = new Order();

            if (drawnPrice < comfortPriceAtCurrentHolding)
            {
                //buy
                order.Side = OrderSide.Buy;

                if (bestAsk.HasValue && drawnPrice > bestAsk.Value)
                {
                    //buy market order
                    order.Quantity = GetStocksToHold(bestAsk.Value, expectedPrice, (double)_agentRiskAversionLevel, (double)varianceOfPastReturns) - StockHeld;
                    order.Type = OrderType.MarketOrder;
                    order.Price = bestAsk.Value;
                    StockHeld += (int)order.Quantity;
                    CashHeld -= order.Quantity * order.Price;
                }
                else
                {
                    //buy limit order at drawnPrice
                    order.Quantity = GetStocksToHold(drawnPrice, expectedPrice, (double)_agentRiskAversionLevel, (double)varianceOfPastReturns) - StockHeld;
                    order.Type = OrderType.LimitOrder;
                    order.Price = drawnPrice;
                }
            }
            else if (drawnPrice > comfortPriceAtCurrentHolding)
            {
                //sell
                order.Side = OrderSide.Sell;

                if (bestBid.HasValue && drawnPrice < bestBid.Value)
                {
                    //sell market order
                    order.Quantity = StockHeld - GetStocksToHold(bestBid.Value, expectedPrice, (double)_agentRiskAversionLevel, (double)varianceOfPastReturns);
                    order.Type = OrderType.MarketOrder;
                    order.Price = bestBid.Value;
                    StockHeld -= (int)order.Quantity;
                    CashHeld += order.Quantity * order.Price;
                }

                else
                {
                    //sell limit order at drawnProce
                    order.Quantity = StockHeld - GetStocksToHold(drawnPrice, expectedPrice, (double)_agentRiskAversionLevel, (double)varianceOfPastReturns);
                    order.Type = OrderType.LimitOrder;
                    order.Price = drawnPrice;
                }

            }
            else
            {
                //do nothing
                order = null;
            }

            return order;
        }
        private IEnumerable<OrderUpdate> ProcessSellLimitOrder(Order order)
        {
            if (Bids.Any() && order.Price < Bids.Last().Key)
            {
                //cross order
                return new [] {new OrderUpdate() { Message = "Cross order", Order = order }};
            }
            if (!Asks.Keys.Contains(order.Price))
            {
                Asks.Add(order.Price, new Queue<Order>());
            }

            Asks[order.Price].Enqueue(order);

            return new[] {new OrderUpdate()
            {
                Placed = true,
                Order = order
            }};
        }
Exemple #15
0
        public MarketSimulator.Contracts.Order GetNextAction(MarketSimulator.Contracts.LimitOrderBookSnapshot limitOrderBookSnapshot, int day, int tradingPeriod)
        {
            if (!WillTradeInThisPeriod(day, tradingPeriod))
            {
                return null;
            }

            var randomDraw = (ExpectedAssetLiquidationValue - ExpectedAssetLiquidationValueOrderRange) + (_random.NextDouble() * ExpectedAssetLiquidationValueOrderRange * 2);

            var orderQuantity = Math.Round(_random.NextDouble() * _maxOrderQuantity,0);

            Order order = new Order();
            order.Price = randomDraw;
            order.Quantity = orderQuantity;
            order.UserID = _name;

            if (randomDraw > ExpectedAssetLiquidationValue)
            {
                //sell
                order.Side = OrderSide.Sell;
                if (limitOrderBookSnapshot != null && limitOrderBookSnapshot.BestBidPrice != null && randomDraw < limitOrderBookSnapshot.BestBidPrice)
                {
                    //sell market order
                    order.Type = OrderType.MarketOrder;
                }
                else
                {
                    //sell limit order
                    order.Type = OrderType.LimitOrder;
                }
            }
            else
            {
                //buy
                order.Side = OrderSide.Buy;
                if (limitOrderBookSnapshot != null && limitOrderBookSnapshot.BestAskPrice != null && randomDraw > limitOrderBookSnapshot.BestAskPrice)
                {
                    //buy market order
                    order.Type = OrderType.MarketOrder;
                }
                else
                {
                    //buy limit order
                    order.Type = OrderType.LimitOrder;
                }
            }

            order = FilterLimitOrders(order);

            return order;
        }
        private IEnumerable<OrderUpdate> ProcessSellMarketOrder(Order order)
        {
            if (order.ExecutionValidity == OrderExecutionValidity.ForceOrKill)
            {
                if (order.Quantity > Bids.Sum(a => a.Value.Sum(l => l.Quantity)))
                {
                    return new[] {new OrderUpdate()
                    {
                        Placed = false,
                        Order = order,
                        Message = "FOK validity and not enough depth"
                    }};
                }
            }

            var quantity = order.Quantity;

            var matches = new List<Match>();
            var orderUpdates = new List<OrderUpdate>();

            while (quantity > 0 && Bids.Count != 0)
            {
                var prices = Bids.Keys;
                for (int i = prices.Count - 1; i >= 0; i--)
                {
                    var price = prices[i];
                    var orders = Bids[price];

                    while (orders.Any() && quantity > 0)
                    {
                        var nextOrder = orders.Peek();
                        if (!nextOrder.Valid)
                        {
                            orders.Dequeue();
                            continue;
                        }

                        if (nextOrder.Quantity > quantity)
                        {
                            nextOrder.Quantity -= quantity;
                            matches.Add(new Match() { Price = price, Quantity = quantity });
                            orderUpdates.Add(new OrderUpdate()
                            {
                                Order = nextOrder,
                                Matches = new List<Match> { new Match() { Price = price, Quantity = quantity } }
                            });
                            quantity = 0;
                        }
                        if (nextOrder.Quantity <= quantity)
                        {
                            quantity -= nextOrder.Quantity;
                            matches.Add(new Match() { Price = price, Quantity = nextOrder.Quantity });
                            orderUpdates.Add(new OrderUpdate()
                            {
                                Order = nextOrder,
                                Matches = new List<Match> { new Match() { Price = price, Quantity = nextOrder.Quantity } }
                            });
                            orders.Dequeue();
                        }
                    }

                    if (!orders.Any()) Bids.Remove(price);
                }
            }

            orderUpdates.Add(new OrderUpdate()
            {
                Placed = true,
                Order = order,
                Matches = matches
            });

            return orderUpdates;
        }
Exemple #17
0
        static void Main(string[] args)
        {
            System.IO.File.WriteAllLines(@"c:\temp\test.csv", new string[] {"Time,BestBid,BestAsk"});
            var providers = new List<LiquidityProvider>();

            var rng = new CSharpRandomNumberGenerator() as IRandomNumberGenerator;
            var normalDist = new Normal(0, 0.01);

            var numLiquidityProviders = 10;
            var numLiquidityTakers = 10;

            for (int i = 0; i < numLiquidityProviders; i++)
            {
                providers.Add(new LiquidityProvider(rng,50,1,0.3,normalDist,4));
            }

            var takers = new List<RandomLiquidityTaker>();

            for (int i = 0; i < numLiquidityTakers; i++)
            {
                takers.Add(new RandomLiquidityTaker(rng, 5, 0.6));
            }

            var connection = new HubConnection(@"http://localhost:8080/signalr");
            var hub = connection.CreateHubProxy("market");
            connection.Start().Wait();

            System.Console.WriteLine("Connected");

            hub.On<LimitOrderBookSnapshot>("Update", data =>
                UpdateLimitOrderBook(data)
            );

            var subscribeResult = hub.Invoke("SubscribeToDataFeed", "TestDriver");
            subscribeResult.Wait();

            var orders = new List<Order>();

            orders.Add(new Order() { Price = 100, Quantity = 10, Side = OrderSide.Buy, Type = OrderType.LimitOrder, UserID = "TestDriver" });
            orders.Add(new Order() { Price = 99, Quantity = 10, Side = OrderSide.Buy, Type = OrderType.LimitOrder, UserID = "TestDriver" });
            orders.Add(new Order() { Price = 98, Quantity = 20, Side = OrderSide.Buy, Type = OrderType.LimitOrder, UserID = "TestDriver" });
            orders.Add(new Order() { Price = 99.5, Quantity = 3, Side = OrderSide.Buy, Type = OrderType.LimitOrder, UserID = "TestDriver" });
            orders.Add(new Order() { Price = 102, Quantity = 10, Side = OrderSide.Sell, Type = OrderType.LimitOrder, UserID = "TestDriver" });
            orders.Add(new Order() { Price = 103, Quantity = 8, Side = OrderSide.Sell, Type = OrderType.LimitOrder, UserID = "TestDriver" });
            orders.Add(new Order() { Price = 102.5, Quantity = 19, Side = OrderSide.Sell, Type = OrderType.LimitOrder, UserID = "TestDriver" });

            foreach (var order in orders)
            {
                var r = hub.Invoke<bool>("ProcessOrderInstruction", order, "TestDriver");
                r.Wait();
            }

            while (true)
            {
                Thread.Sleep(10);

                var rndLT = rng.GetRandomInt(0, numLiquidityTakers - 1);
                var rndLP = rng.GetRandomInt(0, numLiquidityProviders - 1);

                var rnd = rng.GetRandomInt(1, 100);

                Order[] orders2;

                if (rnd % 2 == 0)
                {
                    orders2 = providers[rndLP].GetNextActions(_lob);
                }
                else
                {
                    orders2 = new Order[] { takers[rndLT].GetNextAction(_lob) };
                }

                foreach (var item in orders2)
                {
                    if (item != null)
                    {
                        item.UserID = "TestDriver";
                        var r = hub.Invoke<bool>("ProcessOrderInstruction", item, "TestDriver");
                        r.Wait();
                    }
                }
            }
        }
        public IEnumerable<OrderUpdate> AmendLimitOrder(Order order,bool cancel)
        {
            var amended = false;
            var remove = false;

            foreach (var bidGroup in Bids.Values)
            {
                foreach (var bid in bidGroup)
                {
                    if (bid.ID == order.ID)
                    {
                        if (cancel)
                        {
                            bid.Valid = false;

                            if (bidGroup.Count() <= 1)
                            {
                                remove = true;
                                Bids.Remove(bid.Price);
                            }

                            return new[] {new OrderUpdate() {
                            Amended = false,Message = "Order Canceled",Order = bid,Placed=false}
                            };
                        }

                        if (bid.Price != order.Price)
                        {
                            bid.Valid = false;

                            if (bidGroup.Count() <= 1)
                            {
                                remove = true;
                                Bids.Remove(bid.Price);
                            }

                            return ProcessLimitOrder(order,true);
                        }
                        else
                        {
                            bid.Quantity = order.Quantity;
                        }
                        return new[] {new OrderUpdate() {
                            Amended = true,Message = "Order amended",Order = bid,Placed=true}
                        };
                    }
                }
            }

            foreach (var askGroup in Asks.Values)
            {
                foreach (var ask in askGroup)
                {
                    if (ask.ID == order.ID)
                    {
                        if (cancel)
                        {
                            ask.Valid = false;

                            if (askGroup.Count() <= 1)
                            {
                                remove = true;
                                Asks.Remove(ask.Price);
                            }

                            return new[] {new OrderUpdate() {
                            Amended = false,Message = "Order Canceled",Order = ask,Placed=false}
                            };
                        }

                        if (ask.Price != order.Price)
                        {
                            ask.Valid = false;
                            if (askGroup.Count() <= 1)
                            {
                                remove = true;
                                Asks.Remove(ask.Price);
                            }
                            return ProcessLimitOrder(order,true);
                        }
                        else
                        {
                            ask.Quantity = order.Quantity;
                        }
                        return new[] {new OrderUpdate() {
                            Amended = true,Message = "Order amended",Order = ask,Placed=true}
                        };
                    }
                }
            }

            return new[] {new OrderUpdate() {
                Message = "Order not found",
                Order = order
            }};
        }
 public bool ProcessOrderInstruction(Order order, string userID)
 {
     OnOrder(order, userID);
     return true;
 }