def test_OrderBookBids(self): book = OrderBook() book.process_order(Order('B', 100322, 5103, 7500)) book.process_order(Order('B', 100345, 5103, 10000, 100000)) book.process_order(Order('B', 1, 5100, 10)) self.assertTrue(len(book.bids.price_map.keys()) == 2) self.assertTrue(len(book.bids.order_map.keys()) == 3) self.assertTrue(book.bids.min == 5100)
def test_LimitNewOrderPartial(self): book = OrderBook() book.process_order(Order('B', 1, 101, 10)) book.process_order(Order('B', 2, 101, 10)) trades = book.process_order(Order('S', 5, 101, 25)) self.assertTrue(len(trades) == 2) self.assertTrue(len(book.bids.price_map) == 0) self.assertTrue(len(book.asks.price_map) == 1) self.assertTrue(trades[0].id == 1) self.assertTrue(trades[1].id == 2) self.assertTrue(book.asks.order_map[5].peak_size == 5)
def test_LimitOrderSimple(self): book = OrderBook() book.process_order(Order('B', 1, 101, 10)) book.process_order(Order('B', 2, 101, 10)) trades = book.process_order(Order('S', 3, 103, 10)) self.assertTrue(len(trades) == 0) # Marching first B order trades = book.process_order(Order('S', 4, 101, 10)) self.assertTrue(len(trades) == 1) self.assertTrue(len(book.bids.price_map) == 1) self.assertTrue(len(book.asks.price_map) == 1) self.assertTrue(trades[0].id == 1)
def test_LimitOrdersAdvanced(self): book = OrderBook() book.process_order(Order('B', 1, 101, 10)) book.process_order(Order('B', 2, 101, 10)) trades = book.process_order(Order('S', 3, 103, 10)) self.assertTrue(len(trades) == 0) # Fill both B orders trades = book.process_order(Order('S', 5, 101, 20)) self.assertTrue(len(trades) == 2) self.assertTrue(len(book.bids.price_map) == 0) self.assertTrue(len(book.asks.price_map) == 1) self.assertTrue(trades[0].id == 1) self.assertTrue(trades[1].id == 2)
def test_PassiveIcebergOder(self): book = OrderBook() book.process_order(Order('B', 1, 100, 82500, 10000)) book.process_order(Order('B', 2, 99, 50000)) book.process_order(Order('B', 3, 98, 25500)) book.process_order(Order('S', 4, 101, 20000)) trades = book.process_order(Order('S', 5, 100, 10000)) self.assertTrue(len(trades) == 1) self.assertTrue(len(book.bids.price_map) == 3) self.assertTrue(len(book.asks.price_map) == 1) self.assertTrue(trades[0].id == 1) self.assertTrue(book.bids.order_map[1].left_peak_size == 62500) self.assertTrue(book.bids.order_map[1].peak_size == 10000)
def test_passiveIcebergTwoOrders(self): book = OrderBook() book.process_order(Order('B', 1, 100, 72500, 10000)) book.process_order(Order('B', 2, 99, 50000)) book.process_order(Order('B', 3, 98, 25500)) book.process_order(Order('S', 4, 101, 20000)) trades = book.process_order(Order('S', 5, 99, 35000)) # Match the max - 35k from 1 self.assertTrue(len(trades) == 1) self.assertTrue(len(book.bids.price_map) == 3) self.assertTrue(len(book.asks.price_map) == 1) self.assertTrue(trades[0].id == 1) self.assertTrue(book.bids.order_map[1].left_peak_size == 32500) self.assertTrue(book.bids.order_map[1].peak_size == 5000)
def test_PassiveIcebergPeak(self): book = OrderBook() book.process_order(Order('B', 1, 100, 72500, 10000)) book.process_order(Order('B', 2, 99, 50000)) book.process_order(Order('B', 3, 98, 25500)) book.process_order(Order('S', 4, 101, 20000)) trades = book.process_order(Order('S', 5, 99, 11000)) self.assertTrue(len(trades) == 1) self.assertTrue(len(book.bids.price_map) == 3) self.assertTrue(len(book.asks.price_map) == 1) self.assertTrue(trades[0].id == 1) # Leftovers should be peak - 1k self.assertTrue(book.bids.order_map[1].left_peak_size == 52500) self.assertTrue(book.bids.order_map[1].peak_size == 9000)
def main(): book = OrderBook() start = timer() count = 0 while True: try: line = sys.stdin.readline() order_fields = line.split(",") # Probably reached end of file if not line or len(order_fields) < 4 or len(order_fields) > 5: sys.stderr.write("Unrecognized message: {0}\n".format(line)) break order_type = order_fields[0] # 'B' or 'S' order_id = order_fields[1] order_price = int(order_fields[2]) # in pence > 0 order_size = int(order_fields[3]) # quantity > 0 new_order = Order( order_type, order_id, order_price, order_size, int(order_fields[4]) if len(order_fields) == 5 else None) book.process_order(new_order) except KeyboardInterrupt: break count += 1 total = timer() - start print("Done processing {0} lines of input".format(count)) print("Processed {} orders in {:.2f} sec - avg: {} orders/second".format( count, total, int(count / total)))
def test_LimitOrderSimple(self): # B, 100322, 5103, 7500 # Limit order id 100322: Buy 7,500 at 5,103p, order_type = 'B' order_id = 100322 order_price = 5103 order_size = 7500 order = Order(order_type, order_id, order_price, order_size) self.assertTrue(order.is_bid) self.assertEqual(order.type, 'B') self.assertEqual(order.id, order_id) self.assertEqual(order.price, order_price) self.assertEqual(order.peak_size, order_size) self.assertEqual(order.size, order_size) self.assertTrue(order.left_peak_size == 0) self.assertEqual( order.__str__(), "Order: type: {} id: {} price: {} size {}".format( order_type, order_id, order_price, order_size))
def test_OrderBookAdd(self): book = OrderBook() # Simple Limit order example (as defined in spec) # B,100322,5103,7500 book.process_order(Order('B', 100322, 5103, 7500)) self.assertTrue(len(book.bids.order_map) == 1) self.assertTrue(100322 in book.bids.order_map) self.assertTrue(5103 is book.bids.max) self.assertTrue(5103 in book.bids.price_map) # Simple Iceberg order example (as defined in spec) # S,100345,5103,100000,10000 book.process_order(Order('S', 100345, 5103, 100000, 10000)) self.assertTrue(len(book.asks.order_map) == 1) self.assertTrue(100345 in book.asks.order_map) # Trade should have matched the bid self.assertTrue(5103 is book.asks.min) self.assertTrue(5103 not in book.bids.price_map)
def populateList(num_elements): order_type = 'S' order_id = 1 order_price = 5000 order_size = 7500 order_list = OrderList() # Adding num_elements for i in range(0, num_elements): order = Order(order_type, order_id, order_price, order_size) order_list.add(order) order_id += 1 return order_list
def test_OrderListAdd(self): num_elements = 1000 order_type = 'B' order_id = 1 order_price = 5000 order_size = 7500 order_list = OrderList() for i in range(0, num_elements): order = Order(order_type, order_id, order_price, order_size, order_size) if order_list.tail is not None: self.assertTrue(order_list.tail.id < order.id) order_list.add(order) order_id += 1 self.assertTrue(order_list.size == num_elements)
def test_IcebergOrderSimple(self): # S, 100345, 5103, 100000, 10000 # Iceberg order id 100345: Sell 100,000 at 5103p, with a peak size of 10,000 order_type = 'S' order_id = 100345 order_price = 5103 order_size = 100000 order_peak = 10000 order = Order(order_type, order_id, order_price, order_size, order_peak) self.assertTrue(not order.is_bid) self.assertEqual(order.type, 'S') self.assertEqual(order.id, order_id) self.assertEqual(order.price, order_price) self.assertEqual(order.peak_size, order_peak) self.assertEqual(order.size, order_peak) self.assertTrue(order.left_peak_size == 90000)
def test_AggessiveIcebergOrder(self): book = OrderBook() book.process_order(Order('B', 1, 99, 50, 50000)) book.process_order(Order('B', 2, 98, 25, 25500)) book.process_order(Order('S', 3, 100, 25, 10000)) book.process_order(Order('S', 4, 100, 25, 7500)) trades = book.process_order(Order('S', 5, 101, 25, 20000)) self.assertTrue(len(trades) == 0) # Fill twp sell orders with an iceberg trades = book.process_order(Order('B', 6, 100, 100000, 10000)) self.assertTrue(len(trades) == 2) self.assertTrue(len(book.bids.price_map) == 3) self.assertTrue(len(book.asks.price_map) == 1) self.assertTrue(trades[0].id == 3) self.assertTrue(trades[1].id == 4) self.assertTrue(book.bids.order_map[6].left_peak_size == 72500) self.assertTrue(book.bids.order_map[6].peak_size == 10000)
def test_OrberBookComplexOrders(self): book = OrderBook() book.process_order(Order('B', 1138, 31502, 7500)) book.process_order(Order('B', 1139, 31502, 7500)) trades = book.process_order(Order('S', 1, 31501, 20000, 800)) self.assertTrue(len(trades) == 2) self.assertTrue(trades[0].id == 1138) self.assertTrue(trades[1].id == 1139) self.assertTrue(1138 not in book.bids.order_map) self.assertTrue(1139 not in book.bids.order_map) book.process_order(Order('S', 2, 30501, 1000, 800)) book.process_order(Order('S', 3, 30501, 200)) trades = book.process_order(Order('B', 1003, 30501, 1000)) self.assertTrue(3 not in book.bids.order_map) self.assertTrue(len(trades) == 2) self.assertTrue(trades[0].id == 3) self.assertTrue(trades[1].id == 2)
def test_makeTrade(self): order_type = 'S' order_id = 100345 order_price = 5103 order_size = 100000 order_peak = 10000 ice_order = Order(order_type, order_id, order_price, order_size, order_peak) # Remaining public size ice_order.make_trade(5000) self.assertTrue(ice_order.peak_size == 5000) self.assertTrue(ice_order.left_peak_size == 90000) self.assertTrue(ice_order.trade_size == 5000) ice_order = Order(order_type, order_id, order_price, order_size, order_peak) # No remaining public size - should deduct from leftpeak ice_order.make_trade(10000) self.assertTrue(ice_order.peak_size == 10000) self.assertTrue(ice_order.left_peak_size == 80000) self.assertTrue(ice_order.trade_size == 10000) # To empty final Order ice_order = Order(order_type, order_id, order_price, 5000) ice_order.make_trade(5000) self.assertTrue(ice_order.peak_size == 0) self.assertTrue(ice_order.left_peak_size == 0) self.assertTrue(ice_order.trade_size == 5000) # TODO Trades above peak should never happen - check? ice_order = Order(order_type, order_id, order_price, 5000) ice_order.make_trade(10000)