def test_fifo_matching_orders(self): """ Ensure FIFO matching is enforced """ orders = [ ServerOrder(Buy(), self.instrument.identifier, 50, 40.0, 'Trader1', timestamp=1), ServerOrder(Buy(), self.instrument.identifier, 50, 40.0, 'Trader2', timestamp=2), ServerOrder(Sell(), self.instrument.identifier, 50, 40.0, 'Trader3', timestamp=3) ] for order in orders: self.book.on_new_order(order) self.assertEqual(self.book.count_bids(), 1) self.assertEqual(self.book.count_asks(), 0) self.assertEqual(self.book.get_bids()[0].timestamp, 2) self.assertEqual(self.book.get_bids()[0].counterparty, 'Trader2')
def test_four_stacked_orders_no_match(self): orders = [ ServerOrder(Buy(), self.instrument.identifier, 50, 40.0, 'Trader1'), ServerOrder(Buy(), self.instrument.identifier, 50, 40.0, 'Trader1'), ServerOrder(Sell(), self.instrument.identifier, 50, 42.0, 'Trader2'), ServerOrder(Sell(), self.instrument.identifier, 50, 42.0, 'Trader2') ] for order in orders: self.book.on_new_order(order) self.assertEqual(self.book.count_bids(), 2) self.assertEqual(self.book.count_asks(), 2)
def add_order(self, order): """ Do not call add_order directly, use on_new_order instead """ if order.way == Buy(): self.bids.append(order) elif order.way == Sell(): self.asks.append(order) else: raise InvalidWay(order.way)
def test_buy_price_greater_than_sell(self): attacking_order = ServerOrder(Buy(), self.instrument.identifier, 10, 40.0, 'Trader1') attacked_order = ServerOrder(Sell(), self.instrument.identifier, 10, 38.0, 'Trader2') self.validate_one_matching(attacking_order, attacked_order) self.assertEqual(attacking_order.get_remaining_quantity(), 10) self.assertEqual(attacked_order.get_remaining_quantity(), 10)
def test_buy_price_equal_to_sell(self): attacking_order = ServerOrder(Buy(), self.instrument.identifier, 10, 40.0, 'Trader1') attacked_order = ServerOrder(Sell(), self.instrument.identifier, 10, 40.0, 'Trader2') self.book.on_new_order(attacked_order, apply_changes=True) self.book.on_new_order(attacking_order, apply_changes=True) self.assertEqual(attacking_order.get_remaining_quantity(), 0) self.assertEqual(attacked_order.get_remaining_quantity(), 0)
def test_two_orders_no_match(self): buy_order = ServerOrder(Buy(), self.instrument.identifier, 50, 40.0, 'Trader1') sell_order = ServerOrder(Sell(), self.instrument.identifier, 50, 42.0, 'Trader2') self.book.on_new_order(buy_order) self.book.on_new_order(sell_order) self.assertEqual(self.book.count_bids(), 1) self.assertEqual(self.book.count_asks(), 1)
def test_simple_create_order(instrument_identifier, marshaller): create_order = CreateOrder(way=Buy(), price=42.0, quantity=10.0, instrument_identifier=1) encoded_create_order = marshaller.encode_create_order( create_order=create_order) message_type, body, _ = marshaller.decode_header(encoded_create_order) decoded_create_order = marshaller.decode_create_order(body) assert message_type == MessageTypes.CreateOrder.value assert create_order.__dict__ == decoded_create_order.__dict__
def test_two_orders_no_match(self): """ Two orders not matching (different price) """ buy_order = ServerOrder(Buy(), self.instrument.identifier, 50, 40.0, 'Trader1') sell_order = ServerOrder(Sell(), self.instrument.identifier, 50, 42.0, 'Trader2') self.book.on_new_order(buy_order, apply_changes=True) self.book.on_new_order(sell_order, apply_changes=True) self.assertEqual(self.book.count_bids(), 1) self.assertEqual(self.book.count_asks(), 1)
def test_simple_create_order(self): create_order = CreateOrder(way=Buy(), price=42.0, quantity=10.0, instrument_identifier=1) encoded_create_order = self.marshaller.encode_create_order( create_order=create_order) message_type, body, _ = self.marshaller.decode_header( encoded_create_order) decoded_create_order = self.marshaller.decode_create_order(body) self.assertEqual(message_type, MessageTypes.CreateOrder.value) self.assertEqual(create_order.__dict__, decoded_create_order.__dict__)
def test_self_execution(self): """ Ensure you cannot trade with yourself """ orders = [ ServerOrder(Buy(), self.instrument.identifier, 50, 40.0, 'Trader1'), ServerOrder(Sell(), self.instrument.identifier, 50, 40.0, 'Trader1') ] for order in orders: self.book.on_new_order(order) self.assertEqual(self.book.count_bids(), 1) self.assertEqual(self.book.count_asks(), 1)
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_one_full_execution(self): quantity = 10 price = 42.0 attacking_order = ServerOrder(Sell(), self.instrument.identifier, quantity, price, 'Trader1') attacked_order = ServerOrder(Buy(), self.instrument.identifier, quantity, price, 'Trader2') self.book.on_new_order(attacked_order) self.book.on_new_order(attacking_order) self.assertEqual(self.book.count_bids(), 0) self.assertEqual(self.book.count_asks(), 0) self.assertEqual(attacking_order.executed_quantity, quantity) self.assertEqual(attacked_order.executed_quantity, quantity) self.assertEqual(attacking_order.get_remaining_quantity(), 0) self.assertEqual(attacked_order.get_remaining_quantity(), 0)
def main_loop_hook(self): if self.send_one_order: first_instrument = self.feedhandler.referential.get_instruments( )[0] self.ordersender.push_order( way=Buy(), price=42.0, quantity=10.0, instrument_identifier=first_instrument.identifier) self.ordersender.push_order( way=Sell(), price=42.0, quantity=10.0, instrument_identifier=first_instrument.identifier) self.send_one_order = False logger.debug("ORDER SENT")
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 get_matching_orders(self, attacking_order): # TODO: tweak matching rules to increase flexibility if attacking_order.way == Buy(): return sorted([ s for s in self.asks if s.counterparty != attacking_order.counterparty and s.price <= attacking_order.price ], key=lambda o: o.timestamp) if attacking_order.way == Sell(): return sorted([ b for b in self.bids if b.counterparty != attacking_order.counterparty and b.price >= attacking_order.price ], key=lambda o: o.timestamp) raise InvalidWay(attacking_order.way)
def test_one_partial_execution(self): attacking_quantity = 20 attacked_quantity = 10 price = 42.0 attacking_order = ServerOrder(Buy(), self.instrument.identifier, attacking_quantity, price, 'Trader1') attacked_order = ServerOrder(Sell(), self.instrument.identifier, attacked_quantity, price, 'Trader2') self.book.on_new_order(attacked_order, apply_changes=True) self.book.on_new_order(attacking_order, apply_changes=True) self.assertEqual(self.book.count_bids(), 1) self.assertEqual(self.book.count_asks(), 0) self.assertEqual(attacking_order.executed_quantity, attacking_quantity - attacked_quantity) self.assertEqual(attacked_order.executed_quantity, attacked_quantity) self.assertEqual(attacking_order.get_remaining_quantity(), attacking_quantity - attacked_quantity) self.assertEqual(attacked_order.get_remaining_quantity(), 0)
def test_multiple_partial_executions(self): attacking_quantity = 50 attacked_quantity = 10 price = 42.0 attacking_order = ServerOrder(Buy(), self.instrument.identifier, attacking_quantity, price, 'Trader1') attacked_orders = [] for _ in list(range(5)): attacked_order = ServerOrder(Sell(), self.instrument.identifier, attacked_quantity, price, 'Trader2') attacked_orders.append(attacked_order) self.book.on_new_order(attacked_order) self.book.on_new_order(attacking_order) self.assertEqual(self.book.count_bids(), 0) self.assertEqual(self.book.count_asks(), 0) self.assertEqual(attacking_order.executed_quantity, attacking_quantity) self.assertEqual(attacking_order.get_remaining_quantity(), 0) for attacked_order in attacked_orders: self.assertEqual(attacked_order.executed_quantity, attacked_quantity) self.assertEqual(attacked_order.get_remaining_quantity(), 0)
def main_loop_hook(self): # Get all instruments available instruments = self.feedhandler.referential.get_instruments() # Send buy and sell orders on each one (if not empty) for instrument in instruments: if instrument.identifier not in self.feedhandler.order_books: continue order_book = self.feedhandler.order_books[instrument.identifier] if order_book.count_bids() == 0: self.ordersender.push_order( way=Buy(), price=40.0, quantity=10.0, instrument_identifier=instrument.identifier) if order_book.count_asks() == 0: self.ordersender.push_order( way=Sell(), price=42.0, quantity=10.0, instrument_identifier=instrument.identifier)
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_buy_way(self): order_way = Buy() self.assertEqual(order_way.way, WayEnum.BUY) self.assertEqual(order_way.__dict__, Buy().__dict__)
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.way = Buy()
def test_sell_price_equal_to_buy(self): attacking_order = ServerOrder(Sell(), self.instrument.identifier, 10, 40.0, 'Trader1') attacked_order = ServerOrder(Buy(), self.instrument.identifier, 10, 40.0, 'Trader2') self.validate_one_matching(attacking_order, attacked_order)
def get_orders(self, way): if way == Buy(): return self.bids if way == Sell(): return self.asks raise InvalidWay
def test_count_bids(self): buy_order = ServerOrder(Buy(), self.instrument.identifier, 50, 42.0, 'Trader1') self.assertEqual(self.book.count_bids(), 0) self.book.on_new_order(buy_order) self.assertEqual(self.book.count_bids(), 1)