def testOrderbook(red): '''Returns an OrderBook populated with 20 test non crossing bids/asks''' #FIXME or use ob fixture? ob = OrderBook('XBT', 'XLT', red) #ob. some bids #ob. some asks return ob
def test_update_invalid(self): """ check: invalid size and update missing order""" obj = OrderBook() # invalid size self.assertRaises(AssertionError, obj.process_order, "1568390243|abbb11|u|0") # update missing order self.assertRaises(KeyError, obj.process_order, "1|abbb11|u|1")
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_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 __init__(self, order_arrival_lambda=2, initial_price=100., price_sigma=.2, quantity_mu=2, quantity_sigma=1, periods=None, traders=50, tick_size=.0001, purge_after_vol=100, open_time=dt.datetime(2017, 1, 1, 8, 0, 0), close_time=dt.datetime(2017, 1, 1, 15, 0, 0)): self.p0 = initial_price self.p = initial_price self.tick_size = tick_size self.purge_after_vol = purge_after_vol self.order_arrival_lambda = order_arrival_lambda self.price_sigma = price_sigma self.quantity_mu = quantity_mu self.quantity_sigma = quantity_sigma if periods: self.periods = periods else: self.periods = (close_time-open_time).total_seconds() if type(traders) == int: traders = range(traders) self.traders = traders self.orderbook = OrderBook() self.total_orders_submitted = 0 self.sides = np.array(['ask', 'bid']) self.sign = np.array([1., -1.]) self.time = 0 self.orders_by_vol = deque(maxlen=None)
def test_empty_order_book(instrument_identifier, marshaller): empty_order_book = OrderBook(instrument_identifier) encoded_order_book = marshaller.encode_order_book(empty_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 empty_order_book.__dict__ == decoded_order_book.__dict__
def initialize_order_books(self, referential): logger.trace("Initializing order books") # TODO: use generator for instrument in referential.instruments: self.order_books[instrument.identifier] = OrderBook( instrument.identifier) logger.trace(f"[{len(referential)}] order books are initialized")
def ob(red, request): '''Returns an empty OrderBook''' def fin(): red.flushdb() request.addfinalizer(fin) return OrderBook('XBT', 'XLT', red)
def initialize_order_books(self): self.logger.debug('Initializing order books') # TODO: use generator for instrument in self.referential.instruments: self.order_books[instrument.identifier] = OrderBook( instrument.identifier) self.logger.debug('[{}] order books are initialized'.format( len(self.referential)))
def test_to_json(): asks = [Ask(quantity=1, rate=2)] bids = [Bid(quantity=3, rate=4)] o = OrderBook(asks=asks, bids=bids) j = orderbook_to_json(o) assert j == '{"Asks": [{"Quantity": 1, "Rate": 2}], "Bids": [{"Quantity": 3, "Rate": 4}]}'
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_empty_order_book(self): empty_order_book = OrderBook(StaticData.get_instrument(1).identifier) encoded_order_book = self.marshaller.encode_order_book( empty_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(empty_order_book.__dict__, decoded_order_book.__dict__)
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 setup(self): self.book = OrderBook(9999, 3, 'TEST') self.book.change(3, 'Offer', 8, 8, 8) self.book.change(2, 'Offer', 7, 7, 7) self.book.change(1, 'Offer', 6, 6, 6) self.book.change(1, 'Bid', 3, 3, 3) self.book.change(2, 'Bid', 2, 2, 2) self.book.change(3, 'Bid', 1, 1, 1) self.book.instrument_sequence = 0
def test_sequence1(self): """ test sequence 1: add, update, cancel """ obj = OrderBook() self.assertEqual(obj.get_best_bid_and_ask('AAPL'), (0, 0)) obj.process_order("1568390243|abbb11|a|AAPL|B|209.00000|100") self.assertEqual(obj.get_best_bid_and_ask('AAPL'), (209.0, 0.0)) obj.process_order("1568390244|abbb11|u|101") self.assertEqual(obj.get_best_bid_and_ask('AAPL'), (209.0, 0.0)) obj.process_order("1568390245|abbb11|c") self.assertEqual(obj.get_best_bid_and_ask('AAPL'), (0.0, 0.0))
def _setup_orderbook(): [redis.delete(key) for key in redis.keys()] orderbook_store = db.orderbook.find({'orderbook_id': 1}).limit(1) if path.isfile(ORDERBOOK_FILE): with open(ORDERBOOK_FILE, 'rb') as f: orderbook = pickle.load(f) elif orderbook_store.count() > 0: orderbook = pickle.loads(orderbook_store[0]["orderbook"]) else: orderbook = OrderBook(STOCK_SYMBOL) return orderbook
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_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_add_invalid(self): """ check: invalid type , order size, order price""" obj = OrderBook() # invalid type self.assertRaises(AttributeError, obj.process_order, 11) # invalid order size self.assertRaises(AssertionError, obj.process_order, "1568390243|abbb11|a|AAPL|B|209.00000|0") # invalid order price self.assertRaises(AssertionError, obj.process_order, "1568390243|abbb11|a|AAPL|B|-209.00000|2")
def setUp(self): self.order_book = OrderBook() self.limit_orders = [ { 'type': 'limit', 'side': 'ask', 'quantity': 5, 'price': 101 }, { 'type': 'limit', 'side': 'ask', 'quantity': 5, 'price': 103 }, { 'type': 'limit', 'side': 'ask', 'quantity': 5, 'price': 101 }, { 'type': 'limit', 'side': 'ask', 'quantity': 5, 'price': 101 }, { 'type': 'limit', 'side': 'bid', 'quantity': 5, 'price': 99 }, { 'type': 'limit', 'side': 'bid', 'quantity': 5, 'price': 98 }, { 'type': 'limit', 'side': 'bid', 'quantity': 5, 'price': 99 }, { 'type': 'limit', 'side': 'bid', 'quantity': 5, 'price': 97 }, ] for order in self.limit_orders: trades, order_id = self.order_book.process_order(order)
def test_process_order(self): """ check: order,add,update,missing parameters; unsupported action""" obj = OrderBook() # missing parameters self.assertRaises(IndexError, obj.process_order, "1568390243|abbb11") # add missing parameters self.assertRaises(AssertionError, obj.process_order, "1568390243|abbb11|a") # update missing parameters self.assertRaises(AssertionError, obj.process_order, "1568390243|abbb11|u") # unsupported action self.assertRaises(PermissionError, obj.process_order, "1568390243|abbb11|x")
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_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_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 main(): # TODO: Create three agents: order_book = OrderBook() agents = [101, 102, 103] # TODO: Agents send in buy/sell orders randomly with some probablility for i in range(30): print '\nTimestep# {}: '.format(i) for a in agents: if (random.random() > 0.5): # make an order # buy or sell? # TO BE REPLACED WITH TRADING STRATEGIES tradedir = random.choice(['bid', 'ask']) # how many? ordqty = random.randint(1, 20) # market or limit? tradetype = random.choice(['market', 'limit']) # if limit, what is your bid/ask price if tradetype == 'limit': # TO BE REPLACED WITH TRADING STRATEGIES limitprice = random.uniform(90, 100) # send in the order if tradetype == 'market': agent_order = { 'type': 'market', 'side': tradedir, 'quantity': ordqty, 'trade_id': a } print 'agent {} made a market order to {} {} shares'.format( a, tradedir, ordqty) else: agent_order = { 'type': 'limit', 'side': tradedir, 'quantity': ordqty, 'price': limitprice, 'trade_id': a } print 'agent {} made a limit order at {} to {} {} shares'.format( a, limitprice, tradedir, ordqty) trades, order_in_book = order_book.process_order( agent_order, False, False) else: print 'agent {} did not trade'.format(a) # plot how the stock changes print order_book
def orderbook_demo(): import time, random ITERS = 100000 max_price = 10 ob = OrderBook("FOOBAR", max_price=max_price) start = time.clock() for i in range(ITERS): os.system("clear") buysell, qty, price, trader = random.choice([0,1]), random.randrange(1,50), \ random.randrange(1,max_price), 'trader %s' % random.randrange(1000) print "NEW ORDER: %s %s %s @ %s" % (trader, "BUY" if buysell == 0 else "SELL", qty, price) ob.limit_order(buysell, qty, price, trader) print ob.render() raw_input()
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)