def test_cancel_order(self): book = OrderBook() limit_buy_order = Order(ID_GENERATOR, 1, 100, "LIMIT", 100) book.add_order(limit_buy_order) self.assertEqual(limit_buy_order.order_state, 'ACTIVE') book.cancel_order(limit_buy_order.id) self.assertEqual(limit_buy_order.order_state, 'CANCELLED')
def test_has_active_bids(self): book = OrderBook() self.assertEqual(book.has_active_bids(), False) order = Order(ID_GENERATOR, AGENT_ID, PRICE, "LIMIT", 100) book.add_order(order) self.assertEqual(book.has_active_bids(), True) self.assertEqual(book.has_active_asks(), False)
def test_has_both_active(self): book = OrderBook() self.assertEqual(book.has_active_bids(), False) limit_buy_order = Order(ID_GENERATOR, 1, 100, "LIMIT", 100) limit_sell_order = Order(ID_GENERATOR, 2, 105, "LIMIT", -100) book.add_order(limit_buy_order) book.add_order(limit_sell_order) self.assertEqual(book.has_active_asks(), True) self.assertEqual(book.has_active_bids(), True)
def test_cancelled_orders_in_spread_calc(self): book = OrderBook() limit_buy_order = Order(ID_GENERATOR, 1, 195, "LIMIT", 100) limit_sell_order = Order(ID_GENERATOR, 2, 200, "LIMIT", -50) book.add_order(limit_sell_order) book.add_order(limit_buy_order) self.assertEqual(book.current_spread(), 5) limit_sell_order.cancel() self.assertEqual(book.current_spread(), 0)
def test_fill_with_partial_limit_order(self): book = OrderBook() limit_buy_order = Order(ID_GENERATOR, 1, 200, "LIMIT", 100) limit_sell_order = Order(ID_GENERATOR, 2, 200, "LIMIT", -50) book.add_order(limit_buy_order) book.add_order(limit_sell_order) self.assertEqual(book.bids, [limit_buy_order]) self.assertEqual(book.asks, []) self.assertEqual(book.bids[0].order_size, 50) self.assertEqual(limit_sell_order.order_size, 0)
def test_should_not_allow_two_same_agent_orders(self): book = OrderBook() order = Order(ID_GENERATOR, AGENT_ID, PRICE, "LIMIT", -100) order2 = Order(ID_GENERATOR, AGENT_ID, PRICE + 5, "LIMIT", -100) book.add_order(order) self.assertEqual(book.asks, [order]) book.add_order(order2) self.assertEqual(book.asks, [order2]) self.assertEqual(book.agent_orders[AGENT_ID], [order, order2]) self.assertEqual(order.order_state, 'CANCELLED') self.assertEqual(order2.order_state, 'ACTIVE')
def test_partial_fill_of_market_order(self): book = OrderBook() limit_buy_order = Order(ID_GENERATOR, 1, 195, "LIMIT", 50) market_sell_order = Order(ID_GENERATOR, 2, None, "MARKET", -100) book.add_order(limit_buy_order) book.add_order(market_sell_order) self.assertEqual(book.bids, []) self.assertEqual(book.asks, []) self.assertEqual(market_sell_order.order_state, 'CANCEL_PARTIAL_UNFILLED') self.assertEqual(limit_buy_order.order_size, 0)
def test_prevent_market_order_no_orders(self): order = Order(ID_GENERATOR, AGENT_ID, None, "MARKET", 100) book = OrderBook() with self.assertRaises(Exception) as context: book.add_order(order) self.assetEqual(context, "No available liquidity to fill market order") sell_order = Order(ID_GENERATOR, AGENT_ID, None, "MARKET", -100) with self.assertRaises(Exception) as context: book.add_order(order) self.assetEqual(context, "No available liquidity to fill market order")
def test_fill_with_limit_orders(self): book = OrderBook() limit_buy_order = Order(ID_GENERATOR, 1, 200, "LIMIT", 100) limit_sell_order = Order(ID_GENERATOR, 2, 200, "LIMIT", -100) book.add_order(limit_buy_order) self.assertEqual(book.bids, [limit_buy_order]) book.add_order(limit_sell_order) self.assertEqual(book.bids, []) self.assertEqual(book.asks, []) self.assertEqual(limit_sell_order.partial_execution_log, [PartialExecution(100, 200)]) self.assertEqual(limit_buy_order.partial_execution_log, [PartialExecution(100, 200)]) self.assertEqual(limit_buy_order.order_state, 'FILLED')
def test_one_buy_order_book(instrument_identifier, marshaller): simple_order_book = OrderBook(instrument_identifier) buy_order = ServerOrder(Buy(), instrument_identifier, quantity=100.0, price=10.0, counterparty='Trader1') simple_order_book.add_order(buy_order) encoded_order_book = marshaller.encode_order_book(simple_order_book) message_type, body, _ = marshaller.decode_header(encoded_order_book) decoded_order_book = marshaller.decode_order_book(body) assert message_type == MessageTypes.OrderBook.value assert encoded_order_book == marshaller.encode_order_book( decoded_order_book)
def test_lazy_cleanup(self): book = OrderBook() limit_buy_order = Order(ID_GENERATOR, 1, 100, "LIMIT", 100) limit_sell_order = Order(ID_GENERATOR, 2, 105, "LIMIT", -100) book.add_order(limit_buy_order) book.add_order(limit_sell_order) book.cancel_order(limit_buy_order.id) book.cancel_order(limit_sell_order.id) self.assertEqual(limit_buy_order.order_state, 'CANCELLED') self.assertEqual(limit_sell_order.order_state, 'CANCELLED') self.assertEqual(len(book.bids), 1) self.assertEqual(len(book.asks), 1) book._OrderBook__lazy_remove_completed_orders() self.assertEqual(len(book.bids), 0) self.assertEqual(len(book.asks), 0)
def test_add_basic_buy_order(self): order = Order(ID_GENERATOR, AGENT_ID, PRICE, "LIMIT", 100) book = OrderBook() book.add_order(order) self.assertEqual(book.bids, [order]) order1 = Order(ID_GENERATOR, 2, PRICE + 1, "LIMIT", 100) book.add_order(order1) self.assertEqual(book.bids, [order1, order]) all_orders = {} all_orders[order1.id] = order1 all_orders[order.id] = order agent_orders = {} agent_orders[order1.agent_id] = [order1] agent_orders[order.agent_id] = [order] self.assertEqual(book.agent_orders, agent_orders) self.assertEqual(book.all_orders, all_orders)
def test_one_buy_order_book(self): simple_order_book = OrderBook(self.instrument_identifier) buy_order = ServerOrder(Buy(), self.instrument_identifier, quantity=100.0, price=10.0, counterparty='Trader1') simple_order_book.add_order(buy_order) encoded_order_book = self.marshaller.encode_order_book( simple_order_book) message_type, body, _ = self.marshaller.decode_header( encoded_order_book) decoded_order_book = self.marshaller.decode_order_book(body) self.assertEqual(message_type, MessageTypes.OrderBook.value) self.assertEqual(encoded_order_book, self.marshaller.encode_order_book(decoded_order_book))
def decode_order_book(self, encoded_order_book): order_book_message = orderbook_pb2.OrderBook() order_book_message.ParseFromString(encoded_order_book) order_book = OrderBook(order_book_message.instrument_identifier) order_book.last_price = order_book_message.statistics.last_price order_book.high_price = order_book_message.statistics.high_price order_book.low_price = order_book_message.statistics.low_price for decoded_order in order_book_message.orders: order = ServerOrder(identifier=decoded_order.identifier, way=OrderWay(decoded_order.way), instrument_identifier=order_book_message.instrument_identifier, quantity=decoded_order.quantity, canceled_quantity=decoded_order.canceled_quantity, executed_quantity=decoded_order.executed_quantity, price=decoded_order.price, counterparty=decoded_order.counterparty, timestamp=decoded_order.timestamp) order_book.add_order(order) self.logger.debug(order_book) return order_book
def decode_order_book(self, encoded_order_book): tokens = list(filter(None, encoded_order_book.split(self.separator))) instrument_identifier = int(tokens[0]) order_book = OrderBook(instrument_identifier) order_book.last_price = float(tokens[1]) order_book.high_price = float(tokens[2]) order_book.low_price = float(tokens[3]) order_tokens = tokens[4:] for x in range(0, len(order_tokens), 8): order_book.add_order( ServerOrder(instrument_identifier=instrument_identifier, identifier=order_tokens[x], way=OrderWay(int(order_tokens[x + 1])), quantity=float(order_tokens[x + 2]), canceled_quantity=float(order_tokens[x + 3]), executed_quantity=float(order_tokens[x + 4]), price=float(order_tokens[x + 5]), counterparty=order_tokens[x + 6], timestamp=order_tokens[x + 7])) return order_book
def test_two_opposite_orders_in_order_book(self): order_book = OrderBook(self.instrument_identifier) orders = [ ServerOrder(Buy(), self.instrument_identifier, quantity=100.0, price=9.0, counterparty='Trader1'), ServerOrder(Sell(), self.instrument_identifier, quantity=100.0, price=10.0, counterparty='Trader2') ] for order in orders: order_book.add_order(order) encoded_order_book = self.marshaller.encode_order_book(order_book) message_type, body, _ = self.marshaller.decode_header( encoded_order_book) decoded_order_book = self.marshaller.decode_order_book(body) self.assertEqual(message_type, MessageTypes.OrderBook.value) self.assertEqual(encoded_order_book, self.marshaller.encode_order_book(decoded_order_book))
def test_should_give_correct_bid_ask(self): book = OrderBook() self.assertEqual(book.current_spread(), 0) limit_buy_order = Order(ID_GENERATOR, 1, 100, "LIMIT", 100) limit_sell_order = Order(ID_GENERATOR, 2, 105, "LIMIT", -100) book.add_order(limit_buy_order) book.add_order(limit_sell_order) self.assertEqual(book.current_spread(), 5) limit_buy_order2 = Order(ID_GENERATOR, 3, 102, "LIMIT", 100) book.add_order(limit_buy_order2) self.assertEqual(book.current_spread(), 3)
def test_fill_with_partial_limit_order_multiple_and_diff_prices(self): book = OrderBook() limit_buy_order = Order(ID_GENERATOR, 1, 200, "LIMIT", 100) limit_sell_order = Order(ID_GENERATOR, 2, 205, "LIMIT", -50) limit_sell_order2 = Order(ID_GENERATOR, 2, 200, "LIMIT", -25) book.add_order(limit_buy_order) book.add_order(limit_sell_order) book.add_order(limit_sell_order2) self.assertEqual(book.bids, [limit_buy_order]) self.assertEqual(book.asks, []) self.assertEqual(book.bids[0].order_size, 75) self.assertEqual(limit_sell_order.order_size, -50) self.assertEqual(limit_sell_order2.order_size, 0)
def test_partial_fill_of_market_sell_order_existing_unfilled_orders(self): book = OrderBook() limit_buy_order = Order(ID_GENERATOR, 1, 195, "LIMIT", 50) limit_buy_order2 = Order(ID_GENERATOR, 3, 200, "LIMIT", 50) limit_buy_order3 = Order(ID_GENERATOR, 4, 180, "LIMIT", 700) market_sell_order = Order(ID_GENERATOR, 2, None, "MARKET", -100) book.add_order(limit_buy_order) book.add_order(limit_buy_order2) book.add_order(limit_buy_order3) book.add_order(market_sell_order) self.assertEqual(book.bids, [limit_buy_order3]) self.assertEqual(book.asks, []) self.assertEqual(market_sell_order.order_state, 'FILLED') self.assertEqual(limit_buy_order.order_size, 0) self.assertEqual(limit_buy_order2.order_size, 0) self.assertEqual(limit_buy_order3.order_size, 700)
def test_fill_with_partial_limit_order_multiple_and_price_matching_order2( self): book = OrderBook() limit_buy_order = Order(ID_GENERATOR, 1, 200, "LIMIT", 100) limit_sell_order = Order(ID_GENERATOR, 2, 195, "LIMIT", -50) limit_sell_order2 = Order(ID_GENERATOR, 2, 200, "LIMIT", -25) book.add_order(limit_sell_order) book.add_order(limit_buy_order) book.add_order(limit_sell_order2) self.assertEqual(book.bids, [limit_buy_order]) self.assertEqual(book.asks, []) self.assertEqual(book.bids[0].order_size, 25) self.assertEqual(limit_sell_order.order_size, 0) self.assertEqual( limit_buy_order.partial_execution_log, [PartialExecution(50, 195), PartialExecution(25, 200)])