상속: IDisposable, ILimitOrder
        public void ShouldIgnoreOrderWithDifferentPriceOnAdd()
        {
            IPriceSlot priceSlot = new PriceSlot(90, new LimitOrderMatchingAlgorithm(new DateService()), new MarketOrderMatchingAlgorithm(new DateService()));
            var buyOrder = new LimitOrder("ABC", 10, 91, WayEnum.Buy, 9);
            priceSlot.AddOrder(buyOrder);

            Assert.AreEqual(0, priceSlot.BuyOrders.Count);
        }
 public void ShouldRegisterDeleteHandlerAndRaiseDeleteEvent()
 {
     var receivedDeletedOrders = new List<ILimitOrder>();
     var newOrder = new LimitOrder("ABC", 10, 99.22d, WayEnum.Buy, 3);
     newOrder.RegisterDeleteNotificationHandler(receivedDeletedOrders.Add);
     newOrder.Delete();
     Assert.AreEqual(1, receivedDeletedOrders.Count);
 }
        public void ShouldAddSellOrder()
        {
            IPriceSlot priceSlot = new PriceSlot(90, new LimitOrderMatchingAlgorithm(new DateService()), new MarketOrderMatchingAlgorithm(new DateService()));
            var sellOrder = new LimitOrder("ABC", 10, 90, WayEnum.Sell, 9);
            priceSlot.AddOrder(sellOrder);

            Assert.AreEqual(1, priceSlot.SellOrders.Count);
            Assert.AreEqual(sellOrder, priceSlot.SellOrders[0]);
        }
        public void ShouldInstantiateWithValues()
        {
            var newOrder = new LimitOrder("ABC", 10, 99.22d, WayEnum.Buy, 3);

            Assert.AreEqual("ABC", newOrder.Symbol);
            Assert.AreEqual(10, newOrder.Quantity);
            Assert.AreEqual(99.22d, newOrder.Price);
            Assert.AreEqual(WayEnum.Buy, newOrder.Way);
            Assert.AreEqual(3, newOrder.ClientId);
        }
        public void BookShouldSetBestAskAndNullBidOnOneSellOrder()
        {
            var orderBookBestBidAsk = new OrderBookBestBidAsk("ABC");
            var book = new OrderBook("ABC", limitOrderMatchingAlgorithmMock, marketOrderMatchingAlgorithmMock, orderBookBestBidAsk);

            var sellOrder = new LimitOrder("ABC", 10, 90, WayEnum.Sell, 9);
            book.AddLimitOrder(sellOrder);

            Assert.AreEqual(90, orderBookBestBidAsk.BestAskPrice);
            Assert.IsNull(orderBookBestBidAsk.BestBidPrice);
        }
        public void ShouldRegisterFilledHandlerAndReceiveFilledEvent()
        {
            var filledOrders = new List<ILimitOrder>();
            var newOrder = new LimitOrder("ABC", 10, 99.22d, WayEnum.Buy, 3);
            newOrder.RegisterFilledNotification(filledOrders.Add);

            newOrder.Modify(0, 88.44d);

            Assert.AreEqual(1, filledOrders.Count);
            Assert.AreEqual(newOrder, filledOrders[0]);
        }
        public void BookShouldRemoveSlotWhenOrderIsFilled()
        {
            var orderBookBestBidAsk = new OrderBookBestBidAsk("ABC");
            var book = new OrderBook("ABC", limitOrderMatchingAlgorithmMock, marketOrderMatchingAlgorithmMock, orderBookBestBidAsk);

            var buyOrder = new LimitOrder("ABC", 10, 90, WayEnum.Buy, 9);
            book.AddLimitOrder(buyOrder);

            Assert.IsTrue(book.PriceSlots.ContainsKey(90));
            Assert.AreEqual(buyOrder, book.PriceSlots[90].BuyOrders[0]);

            buyOrder.Modify(0);

            Assert.IsFalse(book.PriceSlots.ContainsKey(90));
        }
        public void ShouldRegisterModifyEventHandlerAndReceiveModifyEvent()
        {
            var newOrder = new LimitOrder("ABC", 10, 99.22d, WayEnum.Buy, 3);
            newOrder.RegisterModifyNotificationHandler((order, oldQuantity, oldPrice) =>
            {
                Assert.AreEqual(newOrder, order);
                Assert.AreEqual(11, order.Quantity);
                Assert.AreEqual(88.44d, order.Price);

                Assert.AreEqual(10, oldQuantity);
                Assert.AreEqual(99.22d, oldPrice);
            });

            newOrder.Modify(11, 88.44d);
        }
        public void ShouldExecuteOnLowestQuantity()
        {
            var staticDatetimeOffset = DateTimeOffset.UtcNow;
            dateServiceMock.Stub(a => a.UtcNow()).Return(staticDatetimeOffset);

            var generatedExecutions = new List<INewExecution>();
            var algo = new LimitOrderMatchingAlgorithm(dateServiceMock);
            algo.AddExecutionsHandler(generatedExecutions.Add);

            ILimitOrder sellOrder = new LimitOrder("ABC", 40, 90, WayEnum.Sell, 13);
            ILimitOrder buyOrder = new LimitOrder("ABC", 100, 90, WayEnum.Buy, 12);

            algo.TryMatch(buyOrder, sellOrder);
            Assert.AreEqual(1, generatedExecutions.Count);
            Assert.AreEqual(40, generatedExecutions[0].MatchedQuantity);
        }
        public void OrdersShouldNotHaveModifiedQuantitiesAfterNoMatch()
        {
            var staticDatetimeOffset = DateTimeOffset.UtcNow;
            dateServiceMock.Stub(a => a.UtcNow()).Return(staticDatetimeOffset);

            var generatedExecutions = new List<INewExecution>();
            var algo = new LimitOrderMatchingAlgorithm(dateServiceMock);
            algo.AddExecutionsHandler(generatedExecutions.Add);

            ILimitOrder sellOrder = new LimitOrder("ABC", 40, 91, WayEnum.Sell, 13);
            ILimitOrder buyOrder = new LimitOrder("ABC", 100, 90, WayEnum.Buy, 12);

            algo.TryMatch(buyOrder, sellOrder);
            Assert.AreEqual(40, sellOrder.Quantity);
            Assert.AreEqual(100, buyOrder.Quantity);
        }
        public void PublisherShouldReceiveOrderModifiedData()
        {
            var limitOrder = new LimitOrder("ABC", 21, 20d, WayEnum.Buy, 90);

            outgoingQueue.EnqueueUpdatedLimitOrder(limitOrder, 21, 20d);

            Thread.Sleep(100);
            messagePublisherMock.AssertWasCalled(a => a.OnNext(Arg<ServerToClientMessage>.Matches(b =>
                b.MessageType == ServerToClientMessageTypeEnum.LimitOrderChanged
                && b.LimitOrder.ClientId == 90
                && b.LimitOrder.Price == 20d
                && b.LimitOrder.Quantity == 21
                && b.LimitOrder.Symbol == "ABC"
                && b.LimitOrder.Way == WayEnum.Buy),
                Arg<long>.Is.Anything,
                Arg<bool>.Is.Anything), options => options.Repeat.Once());
        }
        public void ShouldRegisterModifyEventHandlerAndUnregister()
        {
            var receivedModifedOrders = new List<ILimitOrder>();
            var newOrder = new LimitOrder("ABC", 10, 99.22d, WayEnum.Buy, 3);

            Action<ILimitOrder, int, double> eventHandler;
            eventHandler = (order, oldQuantity, oldPrice) =>
            {
                receivedModifedOrders.Add(order);
            };

            newOrder.RegisterModifyNotificationHandler(eventHandler);

            newOrder.Modify(11, 88.44d);
            newOrder.UnRegisterModifyNotificationHandler(eventHandler);
            newOrder.Modify(13, 12.44d);
            Assert.AreEqual(1, receivedModifedOrders.Count);
        }
        public void ShouldMatchBuyOrderCompletely()
        {
            var executions = new List<INewExecution>();
            var executionalgo = new LimitOrderMatchingAlgorithm(new DateService());
            executionalgo.AddExecutionsHandler(executions.Add);

            var priceSlot = new PriceSlot(90, executionalgo, new MarketOrderMatchingAlgorithm(new DateService()));

            var sellOrder = new LimitOrder("ABC", 100, 90, WayEnum.Sell, 90);
            var buyOrder = new LimitOrder("ABC", 10, 90, WayEnum.Buy, 80);

            priceSlot.AddOrder(sellOrder);
            priceSlot.TryMatchLimitOrder(buyOrder);

            Assert.AreEqual(1, executions.Count);
            Assert.AreEqual(0, priceSlot.BuyOrders.Count);
            Assert.AreEqual(1, priceSlot.SellOrders.Count);
            Assert.AreEqual(90, priceSlot.SellOrders[0].Quantity);
        }
        public void ShouldMatchMultipleSellOrdersToSameBuyOrder()
        {
            var executions = new List<INewExecution>();
            var executionalgo = new LimitOrderMatchingAlgorithm(new DateService());
            executionalgo.AddExecutionsHandler(executions.Add);

            var priceSlot = new PriceSlot(90, executionalgo, new MarketOrderMatchingAlgorithm(new DateService()));

            var sellOrder1 = new LimitOrder("ABC", 10, 90, WayEnum.Sell, 90);
            var sellOrder2 = new LimitOrder("ABC", 40, 90, WayEnum.Sell, 90);
            var buyOrder = new LimitOrder("ABC", 50, 90, WayEnum.Buy, 80);

            priceSlot.AddOrder(sellOrder1);
            priceSlot.AddOrder(sellOrder2);
            priceSlot.TryMatchLimitOrder(buyOrder);

            Assert.AreEqual(2, executions.Count);
            Assert.AreEqual(0, priceSlot.BuyOrders.Count);
            Assert.AreEqual(0, priceSlot.SellOrders.Count);
        }
        public void BookShouldSetBestBidOnHigherBuyOrders()
        {
            var orderBookBestBidAsk = new OrderBookBestBidAsk("ABC");
            var book = new OrderBook("ABC", limitOrderMatchingAlgorithmMock, marketOrderMatchingAlgorithmMock, orderBookBestBidAsk);

            Assert.IsNull(orderBookBestBidAsk.BestBidPrice);

            var buyOrder1 = new LimitOrder("ABC", 10, 90.1d, WayEnum.Buy, 1);
            book.AddLimitOrder(buyOrder1);

            Assert.AreEqual(90.1d, orderBookBestBidAsk.BestBidPrice);

            var buyOrder2 = new LimitOrder("ABC", 10, 90.2d, WayEnum.Buy, 1);
            book.AddLimitOrder(buyOrder2);

            Assert.AreEqual(90.2d, orderBookBestBidAsk.BestBidPrice);

            var buyOrder3 = new LimitOrder("ABC", 10, 80.0d, WayEnum.Buy, 1);
            book.AddLimitOrder(buyOrder3);

            Assert.AreEqual(90.2d, orderBookBestBidAsk.BestBidPrice);
        }
        public void ShouldNotMatchOrdersWithZeroQuantity()
        {
            var generatedExecutions = new List<INewExecution>();
            var algo = new LimitOrderMatchingAlgorithm(dateServiceMock);
            algo.AddExecutionsHandler(generatedExecutions.Add);

            ILimitOrder sellOrder = new LimitOrder("ABC", 0, 90, WayEnum.Sell, 13);
            ILimitOrder buyOrder = new LimitOrder("ABC", 10, 90, WayEnum.Buy, 12);

            algo.TryMatch(buyOrder, sellOrder);
            Assert.AreEqual(0, generatedExecutions.Count);

            sellOrder.Modify(90);
            buyOrder.Modify(0);

            algo.TryMatch(buyOrder, sellOrder);
            Assert.AreEqual(0, generatedExecutions.Count);
        }
        public void ShouldNotMatchHigherSellOrderWithLowerBuyOrder()
        {
            var generatedExecutions = new List<INewExecution>();
            var algo = new LimitOrderMatchingAlgorithm(dateServiceMock);
            algo.AddExecutionsHandler(generatedExecutions.Add);

            ILimitOrder sellOrder = new LimitOrder("ABC", 10, 100, WayEnum.Sell, 13);
            ILimitOrder buyOrder = new LimitOrder("ABC", 10, 90, WayEnum.Buy, 12);

            algo.TryMatch(buyOrder, sellOrder);
            Assert.AreEqual(0, generatedExecutions.Count);
        }
        public void ShouldGenerateExecutionWithSamePriceAsBuyAndSell()
        {
            var staticDatetimeOffset = DateTimeOffset.UtcNow;
            dateServiceMock.Stub(a => a.UtcNow()).Return(staticDatetimeOffset);

            var generatedExecutions = new List<INewExecution>();
            var algo = new LimitOrderMatchingAlgorithm(dateServiceMock);
            algo.AddExecutionsHandler(generatedExecutions.Add);

            ILimitOrder sellOrder = new LimitOrder("ABC", 10, 90, WayEnum.Sell, 13);
            ILimitOrder buyOrder = new LimitOrder("ABC", 10, 90, WayEnum.Buy, 12);

            algo.TryMatch(buyOrder, sellOrder);
            Assert.AreEqual(1, generatedExecutions.Count);

            Assert.AreEqual(10, generatedExecutions[0].MatchedQuantity);
            Assert.AreEqual(90, generatedExecutions[0].MatchedPrice);
            Assert.AreEqual(buyOrder, generatedExecutions[0].BuySideOrder);
            Assert.AreEqual(sellOrder, generatedExecutions[0].SellSideOrder);
            Assert.AreEqual(staticDatetimeOffset, generatedExecutions[0].ExecutionTime);
        }
        public void BookShouldSetBestAskOnLowerSellOrders()
        {
            var orderBookBestBidAsk = new OrderBookBestBidAsk("ABC");
            var book = new OrderBook("ABC", limitOrderMatchingAlgorithmMock, marketOrderMatchingAlgorithmMock, orderBookBestBidAsk);

            Assert.IsNull(orderBookBestBidAsk.BestAskPrice);

            var order1 = new LimitOrder("ABC", 10, 90.1d, WayEnum.Sell, 1);
            book.AddLimitOrder(order1);

            Assert.AreEqual(90.1d, orderBookBestBidAsk.BestAskPrice);

            var order2 = new LimitOrder("ABC", 10, 90.0d, WayEnum.Sell, 1);
            book.AddLimitOrder(order2);

            Assert.AreEqual(90.0d, orderBookBestBidAsk.BestAskPrice);

            var order3 = new LimitOrder("ABC", 10, 99.0d, WayEnum.Sell, 1);
            book.AddLimitOrder(order3);

            Assert.AreEqual(90.0d, orderBookBestBidAsk.BestAskPrice);
        }
        public void ShouldUnregisterAllHandlersOnDelete()
        {
            var receivedDeletedOrders = new List<ILimitOrder>();
            var receivedModifyOrders = new List<ILimitOrder>();
            var newOrder = new LimitOrder("ABC", 10, 99.22d, WayEnum.Buy, 3);

            Action<ILimitOrder, int, double> modifyEventHandler;
            modifyEventHandler = (order, oldQuantity, oldPrice) =>
            {
                receivedModifyOrders.Add(order);
            };

            newOrder.RegisterDeleteNotificationHandler(receivedDeletedOrders.Add);
            newOrder.RegisterModifyNotificationHandler(modifyEventHandler);
            newOrder.Delete();
            newOrder.Modify(90,20);
            newOrder.Delete();
            Assert.AreEqual(1, receivedDeletedOrders.Count);
            Assert.AreEqual(0, receivedModifyOrders.Count);
        }
        public void ShouldNotMatchSellStopLimitOrderLowerThanMarket()
        {
            var executions = new List<INewExecution>();

            var orderBookBestBidAsk = new OrderBookBestBidAsk("ABC");
            var matchAlgo = new LimitOrderMatchingAlgorithm(new DateService());
            matchAlgo.AddExecutionsHandler(executions.Add);

            var book = new OrderBook("ABC", matchAlgo, marketOrderMatchingAlgorithmMock, orderBookBestBidAsk);

            var sellOrder1 = new LimitOrder("ABC", 10, 1161.8d, WayEnum.Sell, 9);
            book.AddLimitOrder(sellOrder1);

            var buyOrder1 = new LimitOrder("ABC", 10, 1161.7d, WayEnum.Buy, 9);
            book.AddLimitOrder(buyOrder1);

            var trigger = new BestPriceTrigger("ABC", 1160, WayEnum.Sell);
            trigger.SetTriggerAction(() =>
            {
                Console.WriteLine("Boom!");
                int i = 0;

            });

            var sellStopLimit = new StopLimitOrder("ABC", 1, 1160,1160, WayEnum.Sell, 5, trigger);

            book.AddStopLimitOrder(sellStopLimit);

            Assert.AreEqual(0, executions.Count);
        }
        public void ShouldNotMatchOrderWhenMatchingIsSuspendedButMatchWhenSuspensionsIsCancelled()
        {
            var executions = new List<INewExecution>();

            var orderBookBestBidAsk = new OrderBookBestBidAsk("ABC");
            var matchAlgo = new LimitOrderMatchingAlgorithm(new DateService());
            matchAlgo.AddExecutionsHandler(executions.Add);

            var book = new OrderBook("ABC", matchAlgo, marketOrderMatchingAlgorithmMock, orderBookBestBidAsk);

            var sellOrder1 = new LimitOrder("ABC", 10, 90, WayEnum.Sell, 9);
            var buyOrder1 = new LimitOrder("ABC", 10, 80, WayEnum.Buy, 9);

            sellOrder1.RegisterModifyNotificationHandler(book.HandleLimitOrderModify);
            buyOrder1.RegisterModifyNotificationHandler(book.HandleLimitOrderModify);

            book.AddLimitOrder(sellOrder1);
            book.AddLimitOrder(buyOrder1);

            Assert.AreEqual(0, executions.Count);
            book.SetSuspendLimitOrderMatchingStatus(true);

            sellOrder1.Modify(10,70);
            Assert.AreEqual(0, executions.Count);

            book.SetSuspendLimitOrderMatchingStatus(true);

            book.TryMatchLimitOrder(sellOrder1);
            book.TryMatchLimitOrder(buyOrder1);

            Assert.AreEqual(1, executions.Count);
        }
        public void IncomingBuyOrderShouldBeMatchedCompletelyAndNotBooked()
        {
            var orderBookBestBidAsk = new OrderBookBestBidAsk("ABC");
            var book = new OrderBook("ABC", new LimitOrderMatchingAlgorithm(new DateService()), new MarketOrderMatchingAlgorithm(new DateService()),  orderBookBestBidAsk);

            var sellOrder1 = new LimitOrder("ABC", 100, 90, WayEnum.Sell, 9);
            book.AddLimitOrder(sellOrder1);

            var buyOrder1 = new LimitOrder("ABC", 10, 90, WayEnum.Buy, 9);
            book.AddLimitOrder(buyOrder1);

            Assert.AreEqual(0, buyOrder1.Quantity);
            Assert.AreEqual(90, sellOrder1.Quantity);

            Assert.AreEqual(0, book.PriceSlots[90].BuyOrders.Count);
            Assert.AreEqual(1, book.PriceSlots[90].SellOrders.Count);
        }
        public void HigherBuyOrderShouldMatchLowerSellOrdersAndPlaceBuyOrderInBookOnRestQuantity()
        {
            var executions = new List<INewExecution>();

            var orderBookBestBidAsk = new OrderBookBestBidAsk("ABC");
            var matchAlgo = new LimitOrderMatchingAlgorithm(new DateService());
            matchAlgo.AddExecutionsHandler(executions.Add);

            var book = new OrderBook("ABC", matchAlgo, marketOrderMatchingAlgorithmMock, orderBookBestBidAsk);

            var sellOrder1 = new LimitOrder("ABC", 10, 90, WayEnum.Sell, 9);
            var sellOrder2 = new LimitOrder("ABC", 10, 91, WayEnum.Sell, 9);
            var sellOrder3 = new LimitOrder("ABC", 10, 92, WayEnum.Sell, 9);
            var sellOrder4 = new LimitOrder("ABC", 10, 93, WayEnum.Sell, 9);
            var sellOrder5 = new LimitOrder("ABC", 10, 94, WayEnum.Sell, 9);

            book.AddLimitOrder(sellOrder1);
            book.AddLimitOrder(sellOrder2);
            book.AddLimitOrder(sellOrder3);
            book.AddLimitOrder(sellOrder4);
            book.AddLimitOrder(sellOrder5);

            Assert.AreEqual(90, orderBookBestBidAsk.BestAskPrice);
            Assert.AreEqual(10, orderBookBestBidAsk.BestAskQuantity);

            var buyOrder1 = new LimitOrder("ABC", 100, 93, WayEnum.Buy, 9);
            book.AddLimitOrder(buyOrder1);

            Assert.AreEqual(4, executions.Count);
            Assert.AreEqual(60, buyOrder1.Quantity);

            Assert.AreEqual(94, orderBookBestBidAsk.BestAskPrice);
            Assert.AreEqual(10, orderBookBestBidAsk.BestAskQuantity);

            Assert.AreEqual(93, orderBookBestBidAsk.BestBidPrice);
            Assert.AreEqual(60, orderBookBestBidAsk.BestBidQuantity);
        }
        public void BookShouldUpdateBestBidWhenBetterBuyPriceComesIn()
        {
            var orderBookBestBidAsk = new OrderBookBestBidAsk("ABC");
            var book = new OrderBook("ABC", limitOrderMatchingAlgorithmMock, marketOrderMatchingAlgorithmMock, orderBookBestBidAsk);

            var buyOrder1 = new LimitOrder("ABC", 10, 90, WayEnum.Buy, 9);
            book.AddLimitOrder(buyOrder1);

            Assert.AreEqual(90, orderBookBestBidAsk.BestBidPrice);

            var buyOrder2 = new LimitOrder("ABC", 10, 91, WayEnum.Buy, 9);
            book.AddLimitOrder(buyOrder2);

            Assert.AreEqual(91, orderBookBestBidAsk.BestBidPrice);
        }
        public void ShouldReturnTrueWhenSellOrdersArePresent()
        {
            var slot = new PriceSlot(90, new LimitOrderMatchingAlgorithm(new DateService()), new MarketOrderMatchingAlgorithm(new DateService()));

            var sellOrder = new LimitOrder("ABC", 50, 90, WayEnum.Sell, 80);
            slot.AddOrder(sellOrder);

            Assert.IsTrue(slot.HasOrders);
            Assert.IsTrue(slot.HasAsks);
            Assert.IsFalse(slot.HasBids);
        }
        public void ShouldRemoveBuyOrder()
        {
            IPriceSlot priceSlot = new PriceSlot(90, new LimitOrderMatchingAlgorithm(new DateService()), new MarketOrderMatchingAlgorithm(new DateService()));
            var buyOrder = new LimitOrder("ABC", 10, 90, WayEnum.Buy, 9);
            priceSlot.AddOrder(buyOrder);

            Assert.AreEqual(1, priceSlot.BuyOrders.Count);
            Assert.AreEqual(buyOrder, priceSlot.BuyOrders[0]);

            priceSlot.RemoveOrder(buyOrder);
            Assert.AreEqual(0, priceSlot.BuyOrders.Count);
        }
        public ILimitOrder NewLimitOrder(string symbol, int clientId, double price, int quantity, WayEnum way)
        {
            if (!ClientOrders.ContainsKey(clientId))
                ClientOrders.Add(clientId, new EditableList<ILimitOrder>());

            ILimitOrder toReturn = new LimitOrder(symbol, quantity, price, way, clientId);
            toReturn.SetExchangeOrderId(globalItemCounter);

            LimitOrders.Add(toReturn.ExchangeOrderId, toReturn);
            ClientOrders[clientId].Add(toReturn);
            toReturn.RegisterDeleteNotificationHandler(HandleDeletedLimitOrder);
            toReturn.RegisterFilledNotification(HandleDeletedLimitOrder);

            globalItemCounter++;
            return toReturn;
        }
        public void BookShouldUpdateBestAskWhenBetterSellPriceComesIn()
        {
            var orderBookBestBidAsk = new OrderBookBestBidAsk("ABC");
            var book = new OrderBook("ABC", limitOrderMatchingAlgorithmMock, marketOrderMatchingAlgorithmMock, orderBookBestBidAsk);

            var sellOrder1 = new LimitOrder("ABC", 10, 90, WayEnum.Sell, 9);
            book.AddLimitOrder(sellOrder1);

            Assert.AreEqual(90, orderBookBestBidAsk.BestAskPrice);

            var sellOrder2 = new LimitOrder("ABC", 10, 89, WayEnum.Sell, 9);
            book.AddLimitOrder(sellOrder2);

            Assert.AreEqual(89, orderBookBestBidAsk.BestAskPrice);
        }