def test_market_order_cancelled(self): contract = 'IBM' ba_table = LOBTable(contract=contract) for i, order in enumerate(self.orders['market_cancellation_accepted']): notification = ba_table.handle_order(order, order.creation_time) # First order is canceled self.assertEquals(len(notification.canceled), 1) self.assertEquals(len(notification.completed), 1)
def test_expired_order(self): contract = 'IBM' ba_table = LOBTable(contract=contract) order = self.orders['basic'][0] notification = ba_table.handle_order(order, order.expiration_time + 1) self.assertEquals(len(notification.rejected), 1) self.assertEquals(notification.rejected[0].m_orderId, order.m_orderId) self.assertEquals(notification.rejected[0].get_status(), OrderStatus.Rejected)
def test_limit_vs_market_multiple_order(self): ba_table = LOBTable(contract='IBM') for i, order in enumerate(self.orders['market_vs_limit_multiple']): notification = ba_table.handle_order(order, order.creation_time) if i == 2: self.assertEquals(len(notification.completed), 2) if i == 3: self.assertEquals(len(notification.completed), 2)
def test_stop_to_market(self): ba_table = LOBTable(contract='IBM') for i, order in enumerate(self.orders['stop_mutates_to_market']): notification = ba_table.handle_order(order, order.creation_time) if i == 2: self.assertEqual(len(notification.completed), 2) self.assertEqual(len(ba_table.stop), 0) self.assertEqual(len(ba_table.market_bid), 1)
def test_bid_ordering_1(self): contract = 'AAPL' ba_table = LOBTable(contract=contract) for i, order in enumerate(self.orders['bid_ordering_1']): ba_table.handle_order(order, order.creation_time) # Asserts self.assertEquals([order.m_orderId for order in heapq.nsmallest(5, ba_table.bid)], [13, 14, 15]) self.assertEquals([order.m_orderId for order in heapq.nsmallest(5, ba_table.ask)], [16, 17, 18])
def test_market_vs_limit_order(self): ba_table = LOBTable(contract='IBM') order1 = self.orders['market_vs_limit'][0] notification1 = ba_table.handle_order(order1, order1.creation_time) self.assertEquals(len(notification1.accepted), 1) self.assertEquals(ba_table.queue_observer.market_bid_size(), 1) order2 = self.orders['market_vs_limit'][1] notification2 = ba_table.handle_order(order2, order2.creation_time) self.assertEquals(len(notification2.completed), 2)
def test_expiration_before_match(self): contract = 'IBM' ba_table = LOBTable(contract=contract) order1 = self.orders['expiration_before_match'][0] ba_table.handle_order(order1, order1.creation_time) order2 = self.orders['expiration_before_match'][1] notification_order2 = ba_table.handle_order(order2, order2.creation_time) self.assertEquals(len(notification_order2.accepted), 1) self.assertEquals(len(notification_order2.expired), 1)
def test_bat_reject_unordered_expired_order(self): contract = 'IBM' b = LOBTable(contract=contract) notification1 = b.handle_order( self.orders['unordered'][0], self.orders['unordered'][0].creation_time) self.assertEquals(len(notification1.accepted), 1) self.assertRaises(Exception, b.handle_order, self.orders['unordered'][1], self.orders['unordered'][1].creation_time)
def test_accepted_and_canceled(self): contract = 'IBM' ba_table = LOBTable(contract=contract) for i, order in enumerate(self.orders['single_canceled_accepted']): notification = ba_table.handle_order(order, order.creation_time) # First order is canceled self.assertEquals(len(notification.canceled), 1) self.assertEquals(len(notification.completed), 1) self.assertEquals(ba_table.queue_observer.bid_size(), 0) self.assertEquals(ba_table.queue_observer.ask_size(), 0)
def test_multiple_expiration_before_match(self): contract = 'IBM' ba_table = LOBTable(contract=contract) for i, order in enumerate(self.orders['multiple_expiration_before_match']): notification = ba_table.handle_order(order, order.creation_time) if i <= 2: self.assertEqual(len(notification.accepted), 1) elif i == 3: self.assertEqual(len(notification.expired), 3) self.assertEqual(len(notification.accepted), 1)
def test_partial_direct_buy(self): current_time = 90 contract = 'IBM' ba_table = LOBTable(contract=contract) buy_order_1 = self.orders['partial_buy'][0] notification_buy_1 = ba_table.handle_order(buy_order_1, buy_order_1.creation_time) self.assertEquals(len(notification_buy_1.accepted), 1) sell_order = self.orders['partial_buy'][1] notification_sell = ba_table.handle_order(sell_order, sell_order.creation_time) self.assertEquals(len(notification_sell.partial_completed), 1) self.assertEquals(len(notification_sell.completed), 1)
def test_completed_order(self): contract = 'IBM' ba_table = LOBTable(contract=contract) buy_order_1 = self.orders['basic_2'][0] notification_buy_1 = ba_table.handle_order(buy_order_1, buy_order_1.creation_time) self.assertEquals(len(notification_buy_1.accepted), 1) sell_order = self.orders['basic_2'][1] notfication_sell = ba_table.handle_order(sell_order, sell_order.creation_time) self.assertEquals(len(notfication_sell.completed), 2) self.assertTrue(ba_table.queue_observer.bid_empty(), True) self.assertTrue(ba_table.queue_observer.ask_empty(), True)
def test_expired_vs_cancelled(self): contract = 'IBM' ba_table = LOBTable(contract=contract) for i, order in enumerate(self.orders['expired_vs_cancelled']): notification = ba_table.handle_order(order, order.creation_time) if i == 1: self.assertEqual(len(notification.canceled), 1) self.assertEqual(len(notification.completed), 1) if i == 3: self.assertEquals(len(notification.expired), 1) self.assertEqual(len(notification.rejected), 1)
def test_price_execution_two_limit_orders(self): contract = 'IBM' ba_table = LOBTable(contract=contract) ba_table.handle_order(self.orders['limit'][0], self.orders['limit'][0].creation_time) sell_notification = ba_table.handle_order( self.orders['limit'][1], self.orders['limit'][1].creation_time) self.assertEqual(len(sell_notification.completed), 2) for order in sell_notification.completed: self.assertEqual(len(order.trades), 1) self.assertEqual(order.trades[0][0], 0.233423432) self.assertEqual(order.trades[0][1], 15)
def test_rejected_new_order_expired(self): current_time = 100 contract = 'IBM' ba_table = LOBTable(contract=contract) buy_order_1 = self.orders['with_expiration'][0] notification_buy_1 = ba_table.handle_order(buy_order_1, buy_order_1.creation_time) self.assertEquals(len(notification_buy_1.accepted), 1) sell_order = self.orders['with_expiration'][1] notification_sell = ba_table.handle_order(sell_order, current_time) self.assertEquals(len(notification_sell.rejected), 1) self.assertEquals(ba_table.queue_observer.bid_size(), 1) self.assertEquals(ba_table.queue_observer.ask_size(), 0)
def test_partial_direct_sell(self): current_time = 90 contract = 'IBM' ba_table = LOBTable(contract=contract) sell_order = self.orders['partial_sell'][0] notification_sell = ba_table.handle_order(sell_order, sell_order.creation_time) self.assertEquals(len(notification_sell.accepted), 1) buy_order = self.orders['partial_sell'][1] notification_buy = ba_table.handle_order(buy_order, buy_order.creation_time) self.assertEquals(len(notification_buy.partial_completed), 1) self.assertEquals(len(notification_buy.completed), 1) self.assertEquals(notification_buy.completed[0].direction, Direction.Buy) self.assertEquals(notification_buy.partial_completed[0].direction, Direction.Sell)
def test_accepted_and_canceled_with_noise(self): contract = 'IBM' ba_table = LOBTable(contract=contract) for i, order in enumerate( self.orders['single_canceled_accepted_with_noise']): notification = ba_table.handle_order(order, order.creation_time) # First order is canceled self.assertEquals(len(notification.canceled), 1) self.assertEquals(len(notification.completed), 1) self.assertEquals(ba_table.queue_observer.bid_size(), 3) # Check that the queue keeps in order self.assertEquals(ba_table.queue_observer.best_bid().price, 50) self.assertEquals( [order.price for order in heapq.nsmallest(3, ba_table.bid)], [50, 10, 1])
def test_price_execution_multiple(self): contract = 'IBM' ba_table = LOBTable(contract=contract) for i, order in enumerate(self.orders['limit_multiple']): notification = ba_table.handle_order(order, order.creation_time) if i == 0: self.assertEqual(len(notification.accepted), 1) elif i == 1: self.assertEqual(len(notification.accepted), 1) elif i == 2: self.assertEqual(len(notification.completed), 2) elif i == 3: self.assertEqual(len(notification.accepted), 1) self.assertEqual(len(notification.partial_completed), 0) self.assertEqual(len(notification.completed), 0)
def test_handle_order_expired_raises_exception(self): contract = 'IBM' ba_table = LOBTable(contract=contract) ls = self.data_with_errors['single_canceled_rejected'][0] d = {self.colnames[j]: ls[j] for j, _ in enumerate(ls)} d['creator_id'] = 'false_agent' order1 = OrderCreator.create_order_from_dict(d) ba_table.handle_order(order1, order1.creation_time) # Second ls2 = self.data_with_errors['single_canceled_rejected'][1] d2 = {self.colnames[j]: ls2[j] for j, _ in enumerate(ls2)} d2['creation_time'] = ba_table.current_time - 1 d2['creator_id'] = 'false_agent' order2 = OrderCreator.create_order_from_dict(d2) self.assertRaises(Exception, ba_table.handle_order, order2, order2.creation_time)
def __init__(self, agent, identifier, contract, delay_order, delay_notification, output_ports_map): self.agent = agent self.identifier = identifier + '_strategy' self.last_message_id = 0 self.output_ports_map = output_ports_map self.contract = contract self.bid_ask_table = LOBTable(contract=contract) # Priority queue of orders to process self.delay_order = delay_order self.delay_notification = delay_notification self.ready = [] self.next_order_status_delivery = {contract: []} self.next_notification_delivery = {contract: []}
def test_handle_expired_order_raise_exception(self): ls = self.data_ok['ordered'][0] d = {self.colnames[j]: ls[j] for j, _ in enumerate(ls)} d['creator_id'] = 'false_agent' order = OrderCreator.create_order_from_dict(d) order.creation_time = order.expiration_time + 1 contract = 'IBM' ba_table = LOBTable(contract=contract) self.assertRaises(Exception, ba_table.handle_order, order)
def test_bid_ordering_4(self): contract = 'AAPL' b = LOBTable(contract=contract) notification1 = b.handle_order(self.orders['bid_ordering_4'][0], self.orders['bid_ordering_4'][0].creation_time) notification2 = b.handle_order(self.orders['bid_ordering_4'][1], self.orders['bid_ordering_4'][1].creation_time) notification3 = b.handle_order(self.orders['bid_ordering_4'][2], self.orders['bid_ordering_4'][2].creation_time) notification4 = b.handle_order(self.orders['bid_ordering_4'][3], self.orders['bid_ordering_4'][3].creation_time) notification5 = b.handle_order(self.orders['bid_ordering_4'][4], self.orders['bid_ordering_4'][4].creation_time) notification6 = b.handle_order(self.orders['bid_ordering_4'][5], self.orders['bid_ordering_4'][5].creation_time) # Checks self.assertEquals(len(notification1.accepted), 1) self.assertEquals(len(notification2.accepted), 1) self.assertEquals(len(notification3.accepted), 1) self.assertEquals(len(notification4.partial_completed), 0) self.assertEquals(len(notification4.completed), 2) self.assertEquals(len(notification5.partial_completed), 0) self.assertEquals(len(notification5.completed), 2) self.assertEquals(len(notification6.completed), 2)
def test_three_market_orders(self): ba_table = LOBTable(contract='IBM') order1 = self.orders['three_market'][0] notification1 = ba_table.handle_order(order1, order1.creation_time) self.assertEquals(len(notification1.accepted), 1) order2 = self.orders['three_market'][1] notification2 = ba_table.handle_order(order2, order2.creation_time) self.assertEquals(len(notification2.accepted), 1) order3 = self.orders['three_market'][2] ba_table.handle_order(order3, order3.creation_time) # Final state of bid ask tables self.assertEqual(ba_table.queue_observer.market_bid_size(), 2) self.assertEqual(ba_table.queue_observer.market_ask_size(), 1)
def test_bid_ordering_3(self): contract = 'AAPL' ba_table = LOBTable(contract=contract) for i, order in enumerate(self.orders['bid_ordering_3']): ba_table.handle_order(order, order.creation_time) self.assertEquals([order.m_orderId for order in heapq.nsmallest(6, ba_table.bid)], [10, 11, 12, 13, 14, 15])
def test_stop_accepted(self): ba_table = LOBTable(contract='IBM') order1 = self.orders['single_stop_market'][0] notification = ba_table.handle_order(order1, order1.creation_time) self.assertEquals(len(notification.accepted), 1)
class OrderbookStrategy(Debug): def __init__(self, agent, identifier, contract, delay_order, delay_notification, output_ports_map): self.agent = agent self.identifier = identifier + '_strategy' self.last_message_id = 0 self.output_ports_map = output_ports_map self.contract = contract self.bid_ask_table = LOBTable(contract=contract) # Priority queue of orders to process self.delay_order = delay_order self.delay_notification = delay_notification self.ready = [] self.next_order_status_delivery = {contract: []} self.next_notification_delivery = {contract: []} def get_identifier(self): return self.identifier def get_next_message_id(self): self.last_message_id += 1 return self.last_message_id def set_initial_orders(self, initial_orders): return self.bid_ask_table.set_initial_orders(initial_orders) def set_tick_size(self, tick_size): self.bid_ask_table.set_tick_size(tick_size) return 0 def output_function(self, current_time, elapsed): output = {} for out_port in ['out_journal']: # Look for a notification for each LOB table messages = self.next_notification_delivery[self.contract] if len(messages) > 0: next_message = heapq.heappop(messages) assert (current_time + elapsed <= next_message.wakeup_time) self.debug('Check notification: %f %f %f' % (current_time, elapsed, next_message.wakeup_time)) self.debug(str(next_message)) if eq_rounded(current_time + elapsed, next_message.wakeup_time): self.debug("Notification ready") bat_notification = next_message.notification ob_information = OBInformation( contract=self.contract, best_ask=self.bid_ask_table.queue_observer.best_ask(), best_bid=self.bid_ask_table.queue_observer.best_bid()) ob_notification = OBNotificationCreator.create_from_batable_notification( bat_notification, ob_information) output[out_port] = MessageForJournal( current_time + elapsed, ob_notification) else: self.debug( "Notification not ready: %f %f %f" % (current_time, elapsed, next_message.wakeup_time)) heapq.heappush( self.next_notification_delivery[self.contract], next_message) self.debug("Emit output = %s" % str(output)) return output def get_smallest_wakeup_time_orders_and_notifications(self): smallest_wakeup_time = float('inf') messages = self.next_notification_delivery[self.contract] if len(messages) > 0: wakeup_time = heapq.nsmallest(1, messages)[0].wakeup_time if wakeup_time < smallest_wakeup_time: smallest_wakeup_time = wakeup_time # 2. messages = self.next_order_status_delivery[self.contract] if len(messages) > 0: wakeup_time = heapq.nsmallest(1, messages)[0].wakeup_time if wakeup_time < smallest_wakeup_time: smallest_wakeup_time = wakeup_time return smallest_wakeup_time def process_internal(self, current_time, elapsed): self.debug("process_internal") if len(self.next_order_status_delivery[self.contract]) == 0: self.debug("No orders missing processing") next_wakeup_time = self.get_smallest_wakeup_time_orders_and_notifications( ) self.debug("Next wakeup time = %f" % next_wakeup_time) self.debug("Next waiting time = %f" % (next_wakeup_time - current_time - elapsed)) return next_wakeup_time - current_time - elapsed else: self.debug("Processing orders") top_order = heapq.heappop( self.next_order_status_delivery[self.contract]) assert (current_time + elapsed <= top_order.wakeup_time) if lt_rounded(current_time + elapsed, top_order.wakeup_time): # Re-enqueue in order queue heapq.heappush(self.next_order_status_delivery[self.contract], top_order) else: # Process and enqueue in notifications queue notification = self.bid_ask_table.handle_order( top_order.order, current_time + elapsed) notification_wake_up = current_time + elapsed + self.delay_notification heapq.heappush( self.next_notification_delivery[self.contract], PendingNotification(self.get_next_message_id(), notification, notification_wake_up)) next_wakeup_time = self.get_smallest_wakeup_time_orders_and_notifications( ) self.debug("Next wakeup time = %f" % next_wakeup_time) self.debug("Next waiting time = %f" % (next_wakeup_time - current_time - elapsed)) return next_wakeup_time - current_time - elapsed def process_in_order(self, current_time, elapsed, message): self.debug("process_in_order") wakeup_time = current_time + elapsed + self.delay_order self.debug("execution_time=%f, current_time=%f, elapsed=%f, delay=%f" % (wakeup_time, current_time, elapsed, self.delay_order)) heapq.heappush( self.next_order_status_delivery[message.value.contract], PendingOrder(self.get_next_message_id(), message.value, wakeup_time)) next_wakeup_time = self.get_smallest_wakeup_time_orders_and_notifications( ) self.debug("Next wakeup time = %f" % next_wakeup_time) self.debug("Next waiting time = %f" % (next_wakeup_time - current_time - elapsed)) return next_wakeup_time - current_time - elapsed