def test_keeps_book_intact_when_delete_on_empty_book(self): empty_book = Book() delete_bid = MBLUpdate.create_delete_bid_level(18.1) mbl = MBL(5) updated_book = mbl.update(empty_book, delete_bid) expected_book = Book() self.assertEqual(expected_book, updated_book)
def test_adds_bid_to_empty_book_when_update_on_bid(self): book = Book() bid_update = MBLUpdate(13.1, 4, 126) mbl = MBL(5) updated_book = mbl.update(book, bid_update) expected_book = Book() expected_book.add_bid(Level(13.1, 4, 126)) self.assertEqual(expected_book, updated_book)
def test_keeps_book_intact_when_delete_missing_level(self): book = Book() book.add_bid(Level(13.1, 1, 2)) book.add_bid(Level(15.1, 1, 2)) delete_bid = MBLUpdate.create_delete_bid_level(18.1) mbl = MBL(5) updated_book = mbl.update(book, delete_bid) expected_book = Book([Level(13.1, 1, 2), Level(15.1, 1, 2)], []) self.assertEqual(expected_book, updated_book)
def test_deletes_existing_level_when_update_on_bid(self): book = Book() book.add_bid(Level(13.1, 1, 2)) book.add_bid(Level(15.1, 1, 2)) delete_bid = MBLUpdate.create_delete_bid_level(13.1) mbl = MBL(5) updated_book = mbl.update(book, delete_bid) expected_book = Book([Level(15.1, 1, 2)], []) self.assertEqual(expected_book, updated_book)
def test_cut_extra_levels_when_update_on_full_bid(self): book = Book() book.add_bid(Level(15.1, 1, 2)) book.add_bid(Level(13.1, 1, 2)) bid_update = MBLUpdate(17.1, 1, 2) mbl = MBL(length=2) updated_book = mbl.update(book, bid_update) expected_book = Book([Level(17.1, 1, 2), Level(15.1, 1, 2)], []) self.assertEqual(expected_book, updated_book)
def test_buy_market_removes_top_ask(self): simulation = Simulation() buy_at_market_price = actions.buy('BTC-USD', 2) simulation.on_action(buy_at_market_price) mbl = Book(bids=[Level(90, 1, 1)], asks=[Level(100, 1, 1), Level(105, 2, 2)]) events = simulation.on_event({'event_name': 'on_mbl', 'data': mbl}) trade_event = events[0] mbl_event = events[1] self.assertEqual({'event_name': 'on_trade', 'data': Trades([(0, 0, 1, 100), (0, 0, 1, 105)])}, trade_event) self.assertEqual({'event_name': 'on_mbl', 'data': Book(bids=[Level(90, 1, 1)], asks=[Level(105, 1, 1)])}, mbl_event)
def test_new_top_ask_after_buy_market_keeps_it(self): simulation = Simulation() buy_at_market_price = actions.buy('BTC-USD', 1) simulation.on_action(buy_at_market_price) mbl = Book(bids=[Level(90, 1, 1)], asks=[Level(105, 2, 2)]) simulation.on_event({'event_name': 'on_mbl', 'data': mbl}) mbl_new_top = Book(bids=[Level(90, 1, 1)], asks=[Level(100, 1, 1), Level(105, 2, 2)]) events = simulation.on_event({'event_name': 'on_mbl', 'data': mbl_new_top}) mbl_event = events[0] self.assertEqual(1, len(events)) self.assertEqual({'event_name': 'on_mbl', 'data': Book(bids=[Level(90, 1, 1)], asks=[Level(100, 1, 1), Level(105, 1, 1)])}, mbl_event)
def test_updates_existing_bid_level_when_update_on_bid(self): book = Book() book.add_bid(Level(13.1, 2, 7)) bid_update = MBLUpdate(13.1, 4, 126) mbl = MBL(5) updated_book = mbl.update(book, bid_update) expected_book = Book() expected_book.add_bid(Level(13.1, 4, 126)) self.assertEqual(expected_book, updated_book)
def btfxwss(): log = logging.getLogger(__name__) fh = logging.FileHandler('test.log') fh.setLevel(logging.DEBUG) sh = logging.StreamHandler(sys.stdout) sh.setLevel(logging.DEBUG) log.addHandler(sh) log.addHandler(fh) logging.basicConfig(level=logging.DEBUG, handlers=[fh, sh]) wss = BtfxWss() wss.start() while not wss.conn.connected.is_set(): time.sleep(1) # Subscribe to some channels wss.subscribe_to_ticker('BTCUSD') wss.subscribe_to_order_book('BTCUSD') wss.subscribe_to_order_book('ETHUSD') # Wait for subscription... time.sleep(2) mbl = MBL() book = Book() recorder = Recorder(open("output.txt", mode='w')) # Accessing data stored in BtfxWss: books_queue = wss.books('ETHUSD') # returns a Queue object for the pair. while True: book_update = books_queue.get()[0][0] if len(book_update) > 3: print("snapshot") mbl_snapshot = MBLSnapshot(book_update) book = mbl.from_snapshot(mbl_snapshot) recorder.on_mbl(book) elif len(book_update) == 3: print("update: " + str(book_update)) update = MBLUpdate(book_update[0], book_update[1], book_update[2]) book = mbl.update(book, update) recorder.on_mbl(book) # Unsubscribing from channels: wss.unsubscribe_from_ticker('BTCUSD') wss.unsubscribe_from_order_book('BTCUSD') # Shutting down the client: wss.stop()
def update(self, book, update_mbl): updated_book = Book() if update_mbl.is_add_or_update_level(): if update_mbl.is_add_or_update_bid(): updated_book = self.add_or_update_bid(book, update_mbl) else: updated_book = self.add_or_update_ask(book, update_mbl) else: if update_mbl.is_delete_bid(): updated_book = self.delete_bid(book, update_mbl.price) elif update_mbl.is_delete_ask(): updated_book = self.delete_ask(book, update_mbl.price) return updated_book
def test_on_mbl(self): os = TestRecorder.TestOutputStream() book = Book(bids=[Level(10.0, 1, 2.5), Level(11.5, 1, 2)], asks=[Level(15.0, 1, 2), Level(18.2, 1, 6.3)]) recorder = Recorder(os) recorder.on_mbl(book) self.assertEqual( json.dumps({ 'event_name': 'on_mbl', 'data': { 'bid': [[10.0, 1, 2.5], [11.5, 1, 2]], 'ask': [[15.0, 1, 2], [18.2, 1, 6.3]] } }) + "\n", os.dump)
def test_decode_book(self): record_entry = json.dumps({ 'event_name': 'on_mbl', 'data': { 'bid': [[10.0, 1, 2.5], [11.5, 1, 2]], 'ask': [[15.0, 1, 2], [18.2, 1, 6.3]] } }) entry = decode(record_entry) self.assertEqual( { 'event_name': 'on_mbl', 'data': Book( [Level(10.0, 1, 2.5), Level(11.5, 1, 2)], [Level(15.0, 1, 2), Level(18.2, 1, 6.3)]) }, entry)
def test_default_book_is_empty(self): book = Book() self.assertTrue(book.is_empty())
def test_displays_nicely_a_MBL(self): book = Book() book.add_bid(Level(6.3, 4, 80)) book.add_bid(Level(4, 1, 5)) book.add_ask(Level(7, 1, 1)) book.add_ask(Level(10, 26, 150)) book.add_ask(Level(16, 17, 42)) expected_str = " BID | ASK \n" \ " +6.300000 x 80.000000 @ 4 | +7.000000 x 1.000000 @ 1\n" \ " +4.000000 x 5.000000 @ 1 | +10.000000 x 150.000000 @ 26\n" \ " | +16.000000 x 42.000000 @ 17" self.assertEqual(expected_str, str(book))
def test_displays_nicely_an_unaligned_book(self): book = Book() book.add_bid(Order(6.3, 80)) book.add_bid(Order(4, 5)) book.add_ask(Order(7, 1)) book.add_ask(Order(10, 150)) book.add_ask(Order(16, 42)) expected_str = " BID | ASK \n" \ " +6.300000 x 80.000000 | +7.000000 x 1.000000\n" \ " +4.000000 x 5.000000 | +10.000000 x 150.000000\n" \ " | +16.000000 x 42.000000" self.assertEqual(expected_str, str(book))
def test_a_book_with_three_ask_lines_has_a_ask_depth_of_three(self): book = Book() book.add_ask(Level(4, 10, 2)) book.add_ask(Level(5, 10, 2)) book.add_ask(Level(7, 10, 2)) self.assertEqual(3, book.ask_depth())
def test_best_ask_is_the_smallest_price(self): book = Book() book.add_ask(Order(5, 10)) book.add_ask(Order(7, 10)) self.assertEqual(Order(5, 10), book.best_ask())
def test_best_bid_is_the_greatest_price(self): book = Book() book.add_bid(Order(7, 10)) book.add_bid(Order(5, 10)) self.assertEqual(Order(7, 10), book.best_bid())
async def home_made_websocket(in_queue): async with websockets.connect("wss://api.bitfinex.com/ws/2") as ws: result = await ws.recv() result = json.loads(result) print("Connection established to Bitfinex api version %s " % result['version']) # Subscribe await ws.send( json.dumps({ "event": "subscribe", "channel": "book", "symbol": "tBTCUSD", "prec": "P0", "freq": "F0", "len": "25" })) # Subscribe await ws.send( json.dumps({ "event": "subscribe", "channel": "trades", "symbol": "tBTCUSD" })) mbl = MBL() book = Book() trades = Trades() channel_ids = {} try: while True: result = await ws.recv() result = json.loads(result) fct_to_call = None decoded_msg = Book() if 'event' in result and result['event'] == 'subscribed': print("Subscribed to %s channel for %s" % (result['channel'], result['pair'])) if result['channel'] == 'book': channel_ids[result['chanId']] = 'b' elif result['channel'] == 'trades': channel_ids[result['chanId']] = 't' elif result[0] in channel_ids and channel_ids[ result[0]] == 't': if result[1] == 'tu': pass elif result[1] == 'hb': pass elif len(result[1]) > 3: trades = Trades(result[1], length=3) decoded_msg = trades fct_to_call = 'on_trade' elif result[1] == 'te': trades.add_trade( Trade(result[2][1], result[2][2], result[2][3])) decoded_msg = trades fct_to_call = 'on_trade' elif result[0] in channel_ids and channel_ids[ result[0]] == 'b': if len(result[1]) > 3: mbl_snapshot = MBLSnapshot(result[1]) book = mbl.from_snapshot(mbl_snapshot) decoded_msg = book fct_to_call = 'on_mbl' elif result[1] == 'hb': pass elif len(result[1]) == 3: # print("update: " + str(result[1])) update = MBLUpdate(result[1][0], result[1][1], result[1][2]) book = mbl.update(book, update) decoded_msg = book fct_to_call = 'on_mbl' if fct_to_call is not None: in_queue.put({ 'event_name': fct_to_call, 'data': decoded_msg }) except KeyboardInterrupt: print("Keyboard interruption in websocket") finally: print("Cleaning websocket")
def delete_ask(self, book, up_price): ask = self.delete(book.ask, up_price) return Book(book.bid, ask)
def delete_bid(self, book, up_price): bid = self.delete(book.bid, up_price) return Book(bid, book.ask)
def add_or_update_ask(self, book, update_mbl): ask = self.add_or_update(book.ask, update_mbl, bisect_left) return Book(book.bid, ask)
def add_or_update_bid(self, book, update_mbl): bid = self.add_or_update( book.bid, update_mbl, lambda l, level: max(len(l) - 1 - bisect_left(l[::-1], level), 0)) return Book(bid, book.ask)
def from_snapshot(self, snapshot): (bid, ask) = snapshot.split() return Book(bid[:self.length], ask[:self.length])
def test_updates_existing_bid(self): book = Book() book.add_bid(Level(11705.0, 1, 0.381988)) book.add_bid(Level(11704.0, 4, 0.955999)) book.add_bid(Level(11703.0, 1, 0.165141)) print(book) mbl = MBL(3) bid_update = MBLUpdate(11704.0, 3, 0.94745498) updated_book = mbl.update(book, bid_update) print(updated_book) expected_book = Book() expected_book.add_bid(Level(11705.0, 1, 0.381988)) expected_book.add_bid(Level(11704.0, 3, 0.94745498)) expected_book.add_bid(Level(11703.0, 1, 0.165141)) self.assertEqual(expected_book, updated_book)
def __init__(self, strategy): self.book = Book() self.trades = Trades() self.daily_info = DailyInfo() self.living_orders = [] self.strategy = strategy
def test_len_is_zero_for_default_book(self): book = Book() self.assertEqual(0, len(book))