def test_market_data_check_max_ask_print_size_limiter(self): order_book = OrderBook(DEFAULT_TRADING_PAIR, 2, 2) orders = [generate_order_obj(type=OrderType.ASK) for _ in range(5)] for ord in orders: order_book.add_order(ord) old_market_data = order_book.market_data orders = sorted(orders, key=lambda i: i.price) delete_order = orders[0] order_book.remove_order(delete_order.id) assert order_book.market_data != old_market_data expected_data = self.expected_market_data( asks=self.aggregate_orders(orders[1:3])) assert order_book.market_data == expected_data
class Engine(object): def __init__(self): self.order_book = OrderBook() self.ts = 0 def execute(self, message): self.ts += 1 try: order_action = parse_input_message(message, self.ts) if order_action.action_type == ACTION_TYPE_ADD_ORDER: trades = self.order_book.add_order(order_action.order) for trade in trades: output_trade(trade) elif order_action.action_type == ACTION_TYPE_CANCEL_ORDER: self.order_book.cancel_order(order_action.order_id) except WrongInputFormatException: sys.stderr.write('Wrong input format: {}\n'.format(message)) except WrongMessageTypeException: sys.stderr.write('Wrong message type: {}\n'.format(message)) except UnknownOrderException: sys.stderr.write('Unknown order: {}\n'.format(message)) except DuplicateOrderException: sys.stderr.write('Duplicate order: {}\n'.format(message))
class OrderBookTest(unittest.TestCase): def setUp(self): self.events = queue.Queue() self.order_book = OrderBook(self.events) def test_sell_order_is_added(self): order = OrderBookOrder(1, 'sell', Decimal('500'), Decimal('5')) self.order_book.add_order(order) self.assertEqual(self.order_book.sell_orders(), [order]) self.assertEqual(self.order_book.buy_orders(), []) def test_buy_order_is_added(self): order = OrderBookOrder(1, 'buy', Decimal('500'), Decimal('5')) self.order_book.add_order(order) self.assertEqual(self.order_book.buy_orders(), [order]) self.assertEqual(self.order_book.sell_orders(), []) def test_sell_and_buy_orders_are_matched(self): sell_order = OrderBookOrder(1, 'sell', Decimal('500'), Decimal('5')) self.order_book.add_order(sell_order) buy_order = OrderBookOrder(2, 'buy', Decimal('500'), Decimal('5')) self.order_book.add_order(buy_order) self.assertEqual(self.order_book.buy_orders(), []) self.assertEqual(self.order_book.sell_orders(), []) self.assertEqual({ 'name': 'match', 'amount': Decimal('500'), 'order_id': 2, 'matched_order_id': 1, }, self.events.get(block=False)) self.assertEqual({ 'name': 'complete', 'order_id': 1, }, self.events.get(block=False)) self.assertEqual({ 'name': 'complete', 'order_id': 2, }, self.events.get(block=False)) def test_cancelled_order_is_removed_from_the_order_book(self): self.order_book.add_order(OrderBookOrder(1, 'sell', Decimal('500'), Decimal('5'))) self.order_book.cancel_order_by_id(1) self.assertEqual(self.order_book.buy_orders(), []) self.assertEqual(self.order_book.sell_orders(), []) self.assertEqual({ 'name': 'cancelled', 'order_id': 1, 'remaining_amount': Decimal('500'), }, self.events.get(block=False)) def test_cancelled_partially_matched_order_has_a_correct_remaining_amount(self): self.order_book.add_order(OrderBookOrder(1, 'sell', Decimal('500'), Decimal('5'))) self.order_book.add_order(OrderBookOrder(2, 'buy', Decimal('300'), Decimal('5'))) self.order_book.cancel_order_by_id(1) self.assertEqual(self.order_book.buy_orders(), []) self.assertEqual(self.order_book.sell_orders(), []) self.expect_event('match') self.expect_event('complete') self.assertEqual({ 'name': 'cancelled', 'order_id': 1, 'remaining_amount': Decimal('200'), }, self.events.get(block=False)) def test_sell_and_buy_orders_are_matched_incompletely(self): self.order_book.add_order(OrderBookOrder(1, 'sell', Decimal('500'), Decimal('5'))) self.order_book.add_order(OrderBookOrder(2, 'buy', Decimal('300'), Decimal('5'))) self.assertEqual(self.order_book.buy_orders(), []) self.assertEqual(self.order_book.sell_orders(), [ self.with_matched_amount(OrderBookOrder(1, 'sell', Decimal('500'), Decimal('5')), Decimal('300'))]) self.assertEqual({ 'name': 'match', 'amount': Decimal('300'), 'order_id': 2, 'matched_order_id': 1, }, self.events.get(block=False)) self.order_book.add_order(OrderBookOrder(3, 'buy', Decimal('500'), Decimal('5'))) self.assertEqual([self.with_matched_amount(OrderBookOrder(3, 'buy', Decimal('500'), Decimal('5')), Decimal('200'))], self.order_book.buy_orders()) self.assertEqual(self.order_book.sell_orders(), []) self.assertEqual({ 'name': 'complete', 'order_id': 2, }, self.events.get(block=False)) self.assertEqual({ 'name': 'match', 'amount': Decimal('200'), 'order_id': 3, 'matched_order_id': 1, }, self.events.get(block=False)) def test_orders_are_matched_in_fifo_order(self): self.order_book.add_order(OrderBookOrder(1, 'sell', Decimal('10'), Decimal('3.5'))) self.order_book.add_order(OrderBookOrder(2, 'sell', Decimal('30'), Decimal('3.5'))) self.order_book.add_order(OrderBookOrder(3, 'buy', Decimal('15'), Decimal('3.5'))) self.assertEqual([], self.order_book.buy_orders()) self.assertEqual([self.with_matched_amount(OrderBookOrder(2, 'sell', Decimal('30'), Decimal('3.5')), Decimal('5'))], self.order_book.sell_orders()) def test_sell_orders_are_matched_until_they_are_filled_up_to_the_price_level(self): self.order_book.add_order(OrderBookOrder(1, 'sell', Decimal('10'), Decimal('3.6'))) self.order_book.add_order(OrderBookOrder(2, 'sell', Decimal('30'), Decimal('3.5'))) self.order_book.add_order(OrderBookOrder(3, 'sell', Decimal('15'), Decimal('3.5'))) self.order_book.add_order(OrderBookOrder(4, 'sell', Decimal('5'), Decimal('3.4'))) self.order_book.add_order(OrderBookOrder(5, 'buy', Decimal('60'), Decimal('3.5'))) self.assertEqual([self.with_matched_amount(OrderBookOrder(5, 'buy', Decimal('60'), Decimal('3.5')), Decimal('50'))], self.order_book.buy_orders()) self.assertEqual([self.with_matched_amount(OrderBookOrder(1, 'sell', Decimal('10'), Decimal('3.6')), Decimal('0'))], self.order_book.sell_orders()) def test_buy_orders_are_matched_until_they_are_filled_up_to_the_price_level(self): self.order_book.add_order(OrderBookOrder(1, 'buy', Decimal('10'), Decimal('3.6'))) self.order_book.add_order(OrderBookOrder(2, 'buy', Decimal('30'), Decimal('3.5'))) self.order_book.add_order(OrderBookOrder(3, 'buy', Decimal('15'), Decimal('3.5'))) self.order_book.add_order(OrderBookOrder(4, 'buy', Decimal('5'), Decimal('3.4'))) self.order_book.add_order(OrderBookOrder(5, 'sell', Decimal('60'), Decimal('3.5'))) self.assertEqual([self.with_matched_amount(OrderBookOrder(4, 'buy', Decimal('5'), Decimal('3.4')), Decimal('0'))], self.order_book.buy_orders()) self.assertEqual([self.with_matched_amount(OrderBookOrder(5, 'sell', Decimal('60'), Decimal('3.5')), Decimal('55'))], self.order_book.sell_orders()) def test_unmatched_buy_and_sell_orders_are_added(self): self.order_book.add_order(OrderBookOrder(1, 'buy', Decimal('10'), Decimal('1.0'))) self.order_book.add_order(OrderBookOrder(2, 'sell', Decimal('20'), Decimal('1.1'))) self.order_book.add_order(OrderBookOrder(3, 'buy', Decimal('30'), Decimal('0.9'))) self.order_book.add_order(OrderBookOrder(4, 'sell', Decimal('40'), Decimal('1.2'))) self.assertEqual([OrderBookOrder(3, 'buy', Decimal('30'), Decimal('0.9')), OrderBookOrder(1, 'buy', Decimal('10'), Decimal('1.0'))], self.order_book.buy_orders()) self.assertEqual([OrderBookOrder(2, 'sell', Decimal('20'), Decimal('1.1')), OrderBookOrder(4, 'sell', Decimal('40'), Decimal('1.2'))], self.order_book.sell_orders()) def expect_event(self, event_name): self.assertEqual(event_name, self.events.get(block=False)['name']) @staticmethod def with_matched_amount(order, matcher_amount): order.matched_amount = matcher_amount return order
def test_order_book(): order_book = OrderBook() assert len(order_book.sell_orders) == 0 assert len(order_book.buy_orders) == 0 trades = order_book.add_order(Order(100000, ORDER_SELL_SIDE, 1, 1075, 1)) assert len(trades) == 0 assert len(order_book.sell_orders) == 1 assert len(order_book.buy_orders) == 0 assert order_book.sell_orders[0].order_id == 100000 trades = order_book.add_order(Order(100001, ORDER_BUY_SIDE, 9, 1000, 2)) assert len(trades) == 0 assert len(order_book.sell_orders) == 1 assert len(order_book.buy_orders) == 1 assert order_book.sell_orders[0].order_id == 100000 assert order_book.buy_orders[0].order_id == 100001 trades = order_book.add_order(Order(100002, ORDER_BUY_SIDE, 30, 975, 3)) assert len(trades) == 0 assert len(order_book.sell_orders) == 1 assert len(order_book.buy_orders) == 2 assert order_book.sell_orders[0].order_id == 100000 assert order_book.buy_orders[0].order_id == 100001 assert order_book.buy_orders[1].order_id == 100002 trades = order_book.add_order(Order(100003, ORDER_SELL_SIDE, 10, 1050, 3)) assert len(trades) == 0 assert len(order_book.sell_orders) == 2 assert len(order_book.buy_orders) == 2 assert order_book.sell_orders[0].order_id == 100003 assert order_book.sell_orders[1].order_id == 100000 assert order_book.buy_orders[0].order_id == 100001 assert order_book.buy_orders[1].order_id == 100002 trades = order_book.add_order(Order(100004, ORDER_BUY_SIDE, 10, 950, 4)) assert len(trades) == 0 assert len(order_book.sell_orders) == 2 assert len(order_book.buy_orders) == 3 assert order_book.sell_orders[0].order_id == 100003 assert order_book.sell_orders[1].order_id == 100000 assert order_book.buy_orders[0].order_id == 100001 assert order_book.buy_orders[1].order_id == 100002 assert order_book.buy_orders[2].order_id == 100004 trades = order_book.add_order(Order(100005, ORDER_SELL_SIDE, 2, 1025, 5)) assert len(trades) == 0 assert len(order_book.sell_orders) == 3 assert len(order_book.buy_orders) == 3 assert order_book.sell_orders[0].order_id == 100005 assert order_book.sell_orders[1].order_id == 100003 assert order_book.sell_orders[2].order_id == 100000 assert order_book.buy_orders[0].order_id == 100001 assert order_book.buy_orders[1].order_id == 100002 assert order_book.buy_orders[2].order_id == 100004 trades = order_book.add_order(Order(100006, ORDER_BUY_SIDE, 1, 1000, 6)) assert len(trades) == 0 assert len(order_book.sell_orders) == 3 assert len(order_book.buy_orders) == 4 assert order_book.sell_orders[0].order_id == 100005 assert order_book.sell_orders[1].order_id == 100003 assert order_book.sell_orders[2].order_id == 100000 assert order_book.buy_orders[0].order_id == 100001 assert order_book.buy_orders[1].order_id == 100006 assert order_book.buy_orders[2].order_id == 100002 assert order_book.buy_orders[3].order_id == 100004 order_book.cancel_order(100004) assert len(order_book.sell_orders) == 3 assert len(order_book.buy_orders) == 3 assert order_book.sell_orders[0].order_id == 100005 assert order_book.sell_orders[1].order_id == 100003 assert order_book.sell_orders[2].order_id == 100000 assert order_book.buy_orders[0].order_id == 100001 assert order_book.buy_orders[1].order_id == 100006 assert order_book.buy_orders[2].order_id == 100002 trades = order_book.add_order(Order(100007, ORDER_SELL_SIDE, 5, 1025, 8)) assert len(trades) == 0 assert order_book.sell_orders[0].order_id == 100005 assert order_book.sell_orders[1].order_id == 100007 assert order_book.sell_orders[2].order_id == 100003 assert order_book.sell_orders[3].order_id == 100000 assert order_book.buy_orders[0].order_id == 100001 assert order_book.buy_orders[1].order_id == 100006 assert order_book.buy_orders[2].order_id == 100002 trades = order_book.add_order(Order(100008, ORDER_BUY_SIDE, 3, 1050, 9)) assert len(trades) == 2 assert trades[0].quantity == 2 assert trades[0].price == 1025 assert trades[0].aggressive_fill == FILL_TYPE_PARTIAL assert trades[0].aggressive_quantity == 1 assert trades[0].aggressive_id == 100008 assert trades[0].resting_fill == FILL_TYPE_FULL assert trades[0].resting_id == 100005 assert trades[1].quantity == 1 assert trades[1].price == 1025 assert trades[1].aggressive_fill == FILL_TYPE_FULL assert trades[1].aggressive_id == 100008 assert trades[1].resting_fill == FILL_TYPE_PARTIAL assert trades[1].resting_id == 100007 assert trades[1].resting_quantity == 4 assert order_book.sell_orders[0].order_id == 100007 assert order_book.sell_orders[1].order_id == 100003 assert order_book.sell_orders[2].order_id == 100000 assert order_book.buy_orders[0].order_id == 100001 assert order_book.buy_orders[1].order_id == 100006 assert order_book.buy_orders[2].order_id == 100002 with pytest.raises(UnknownOrderException): order_book.cancel_order(1000004) with pytest.raises(DuplicateOrderException): order_book.add_order(Order(100007, ORDER_SELL_SIDE, 5, 1025, 11))