def test_order_book_can_cancel_sell_other_than_best_ask(): instrument_id = "AAPL" quantity = 100 price = 10 limit_orders = [ LimitOrder(instrument_id=instrument_id, order_direction=OrderDirection.buy if i % 2 else OrderDirection.sell, quantity=quantity - 10 * i, price=price + (i if i % 2 else -i)) for i in range(10) ] for i, l in enumerate(limit_orders): l.order_id = i limit_orders[i] = l order_book = OrderBook() for order in limit_orders: order_book.add_order(order) cancel_order = CancelOrder(instrument_id=instrument_id, order_id=2, order_direction=OrderDirection.sell) order_book.add_order(cancel_order) assert len(order_book.bids) > len( order_book.asks), "Test Failed: should be more buys than sells" assert cancel_order.cancel_success, "Test Failed: cancel should succeed" pass
def test_cancel_order_init_(): instrument_id = "AAPL" order_id = 1 cancel_order = CancelOrder(instrument_id=instrument_id, order_id=order_id, order_direction=OrderDirection.buy) assert not cancel_order.cancel_success, "Test Failed: cancel_success should be false unless an order can be cancelled" pass
def test_order_book_cannot_cancel_nothing(): instrument_id = "AAPL" order_book = OrderBook() cancel_order = CancelOrder(instrument_id=instrument_id, order_id=2, order_direction=OrderDirection.sell) order_book.add_order(cancel_order) assert not cancel_order.cancel_success, "Test Failed: cancel should fail" pass
def test_cannot_cancel_filled_order(): instrument_id = "AAPL" order_direction = OrderDirection.buy quantity = 100 price = 10 limit_order = LimitOrder(instrument_id=instrument_id, order_direction=order_direction, quantity=quantity, price=price) limit_order.order_id = 1 limit_order.status = OrderStatus.filled instrument_id = "AAPL" order_id = 1 cancel_order = CancelOrder(instrument_id=instrument_id, order_id=order_id, order_direction=order_direction) cancel_order.cancel_order(order=limit_order) assert limit_order.status == OrderStatus.filled, "Test failed: order cancelled" assert not cancel_order.cancel_success, "Test Failed: order cancelled" pass
def add_cancel(self, order: CancelOrder) -> None: """ Cancelling an existing order Check all orders to find the first matching order_id and cancel it if possible. """ if order.order_direction == OrderDirection.buy and self.best_bid is not None: best_bid = self.best_bid bids = self.bids if order.order_id == best_bid.order_id: order.cancel_order(best_bid) self.complete_orders.append(best_bid) if bids: self.best_bid = bids.pop(0) self.attempt_match = True else: self.best_bid = None elif bids: matched_order = self.find_in_list(bids, order.order_id) if matched_order: bids.remove(matched_order) self.complete_orders.append(matched_order) order.cancel_order(matched_order) elif order.order_direction == OrderDirection.sell and self.best_ask is not None: best_ask = self.best_ask asks = self.asks if order.order_id == best_ask.order_id: order.cancel_order(best_ask) self.complete_orders.append(best_ask) if self.asks: self.best_ask = self.asks.pop(0) self.attempt_match = True else: self.best_ask = None elif asks: matched_order = self.find_in_list(asks, order.order_id) if matched_order: asks.remove(matched_order) self.complete_orders.append(matched_order) order.cancel_order(matched_order) return None
def test_order_book_can_cancel_sell(): """ Here there are more asks than bids, so the bids will fill""" instrument_id = "AAPL" quantity = 100 price = 10 limit_orders = [ LimitOrder(instrument_id=instrument_id, order_direction=OrderDirection.buy if i % 2 else OrderDirection.sell, quantity=quantity - 10 * i, price=price + (i if i % 2 else -i)) for i in range(10) ] for i, l in enumerate(limit_orders): l.order_id = i limit_orders[i] = l order_book = OrderBook() for order in limit_orders: order_book.add_order(order) cancel_order = CancelOrder(instrument_id=instrument_id, order_id=0, order_direction=OrderDirection.sell) order_book.match() order_book.add_order(cancel_order) assert not order_book.asks, "Test Failed: There should be no asks after this matching" assert order_book.best_ask is None, "Test Failed: best_ask should be empty" assert not order_book.bids, "Test Failed: There should be no bids after this matching" assert order_book.best_bid is None, "Test Failed: best_bid should be empty" assert len( order_book.trades) > 5, "Test Failed: trades should more than 5 trades" assert len(order_book.complete_orders ) == 10, "Test Failed: complete_orders should have 10 orders" assert cancel_order.cancel_success, "Test Failed: cancel should succeed" pass
# matching_engine.match() # profile cProfile.run("matching_engine.match()", "prof_file") p = pstats.Stats("prof_file") p.strip_dirs().sort_stats(-1).print_stats(10) matches = sum( len(o.complete_orders) for o in matching_engine.order_books.values()) matches / num_orders # Test cancels orders = get_data(num_orders) cancels = [ CancelOrder(instrument_id=o.instrument_id, order_id=o.order_id, order_direction=o.order_direction) for o in orders ] orders = orders + cancels random.shuffle(orders) matching_engine = MatchingEngine() for order in orders: matching_engine.add_order(order) # matching_engine.match() # Profile cProfile.run("matching_engine.match()", "prof_file") p = pstats.Stats("prof_file") p.strip_dirs().sort_stats(-1).print_stats(10)