def __str__(self): r = '\n'.join( str(left) + ' |' + str(right) for left, right in zip_longest( self.bid, self.ask, fillvalue=' ' * 39)) header = Level.bid_header() + "|" + Level.ask_header() return header + '\n' + r
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_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_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_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 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_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_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_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 delete(self, levels, price_level): new_levels = deepcopy(levels) target_level = Level(price_level, 0, 0) level_index = bisect_left(new_levels, target_level) is_found = level_index != len( levels) and new_levels[level_index].price == target_level.price if is_found: new_levels.pop(level_index) return new_levels
def add_or_update(self, levels, update_mbl, find_position): new_levels = deepcopy(levels) target_level = Level(update_mbl.price, update_mbl.count, abs(update_mbl.amount)) price_level = find_position(new_levels, target_level) is_update = price_level != len( levels) and new_levels[price_level].price == target_level.price if is_update: new_levels[price_level] = target_level else: new_levels.insert(price_level, target_level) if len(new_levels) > self.length: new_levels.pop(len(levels)) return new_levels
def execute_top_sell(book, buy_order): sold_amount = 0 trades = [] while sold_amount < buy_order.amount and len(book.ask) != 0: top_sell = book.ask[0] rest = buy_order.amount - sold_amount if rest < top_sell.amount: executed_amount = top_sell.amount - rest book.ask[0] = Level(top_sell.price, min(top_sell.count - 1, 1), executed_amount) trades.append(trade(executed_amount, top_sell.price)) sold_amount += executed_amount else: sold_amount += top_sell.amount trades.append(trade(top_sell.amount, top_sell.price)) book.ask = book.ask[1:] return trades, book
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(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 test_splits_full_snapshot(self): snapshot = [[10.0, 1, 2.5], [11.5, 1, 2], [15.0, 1, -2], [18.2, 1, -6.3]] mbl_snapshot = MBLSnapshot(snapshot) (bid, ask) = mbl_snapshot.split() self.assertEqual([Level(10.0, 1, 2.5), Level(11.5, 1, 2)], bid) self.assertEqual([Level(15.0, 1, 2), Level(18.2, 1, 6.3)], ask)
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_two_copies(self): original = [Level(1, 2, 3), Level(4, 5, 6)] copied_and_changed = copy.deepcopy(original) copied_and_changed[0].price = 0 self.assertNotEqual(original, copied_and_changed)
def to_bid(self, level): return Level(level[0], level[1], level[2])
def to_ask(self, level): return Level(level[0], level[1], -level[2])