Example #1
0
def test_orderbook_init():
    with pytest.raises(TypeError):
        OrderBook('a')

    with pytest.raises(TypeError):
        OrderBook(blah=3)

    with pytest.raises(TypeError):
        OrderBook(max_depth='a')
Example #2
0
def test_kraken_checksum():
    # This checksum is from the kraken docs
    ob = OrderBook(max_depth=10, checksum_format='KRAKEN')
    asks = [["0.05005", "0.00000500", "1582905487.684110"],
            ["0.05010", "0.00000500", "1582905486.187983"],
            ["0.05015", "0.00000500", "1582905484.480241"],
            ["0.05020", "0.00000500", "1582905486.645658"],
            ["0.05025", "0.00000500", "1582905486.859009"],
            ["0.05030", "0.00000500", "1582905488.601486"],
            ["0.05035", "0.00000500", "1582905488.357312"],
            ["0.05040", "0.00000500", "1582905488.785484"],
            ["0.05045", "0.00000500", "1582905485.302661"],
            ["0.05050", "0.00000500", "1582905486.157467"]]

    bids = [["0.05000", "0.00000500", "1582905487.439814"],
            ["0.04995", "0.00000500", "1582905485.119396"],
            ["0.04990", "0.00000500", "1582905486.432052"],
            ["0.04980", "0.00000500", "1582905480.609351"],
            ["0.04975", "0.00000500", "1582905476.793880"],
            ["0.04970", "0.00000500", "1582905486.767461"],
            ["0.04965", "0.00000500", "1582905481.767528"],
            ["0.04960", "0.00000500", "1582905487.378907"],
            ["0.04955", "0.00000500", "1582905483.626664"],
            ["0.04950", "0.00000500", "1582905488.509872"]]

    for a in asks:
        ob.asks[Decimal(a[0])] = Decimal(a[1])

    for b in bids:
        ob.bids[Decimal(b[0])] = Decimal(b[1])

    assert ob.checksum() == 974947235
Example #3
0
 def __init__(self):
     super(ExchangeListener, self).__init__()
     # So I don't love having the public client call here but it seems like a reasonable place to init the book
     # using the level 3 feed to seed the order book
     public_client = PublicClient()
     seed_book = public_client.get_product_order_book('BTC-USD', level=3)
     self.order_book = OrderBook(seed_book=seed_book)
Example #4
0
def test_get_best_bid_price_with_no_ask():
    book = OrderBook()
    order_stream1 = '1568390201|abbb11|a|AAPL|S|209.00000|100'
    order_stream2 = '1568390202|abbb13|a|AAPL|S|220.00000|1000'
    book.process_order(order_stream1)
    book.process_order(order_stream2)

    assert book.best_bid_and_ask('AAPL') == (0, 220)
Example #5
0
def test_get_bid_and_ask_for_missing_ticker():
    book = OrderBook()
    order_stream1 = '1568390201|abbb11|a|AAPL|S|209.00000|100'
    order_stream2 = '1568390202|abbb13|a|AAPL|S|220.00000|1000'
    book.process_order(order_stream1)
    book.process_order(order_stream2)

    assert book.best_bid_and_ask('ZZZZ') == (0, 0)
Example #6
0
def test_ftx_checksum():
    BID = 'bid'
    ASK = 'ask'

    r = requests.get(
        "https://ftx.com/api/markets/BTC-PERP/orderbook?depth=100")
    r.raise_for_status()
    ftx_data = json.loads(r.text, parse_float=Decimal)

    def ftx_checksum(book):
        bid_it = reversed(book[BID])
        ask_it = iter(book[ASK])

        bids = [f"{bid}:{book[BID][bid]}" for bid in bid_it]
        asks = [f"{ask}:{book[ASK][ask]}" for ask in ask_it]

        if len(bids) == len(asks):
            combined = [val for pair in zip(bids, asks) for val in pair]
        elif len(bids) > len(asks):
            combined = [
                val for pair in zip(bids[:len(asks)], asks) for val in pair
            ]
            combined += bids[len(asks):]
        else:
            combined = [
                val for pair in zip(bids, asks[:len(bids)]) for val in pair
            ]
            combined += asks[len(bids):]

        computed = ":".join(combined).encode()
        return zlib.crc32(computed)

    ob = OrderBook(checksum_format='FTX')

    book = {
        BID:
        sd({
            Decimal(update[0]): Decimal(update[1])
            for update in ftx_data['result']['bids']
        }),
        ASK:
        sd({
            Decimal(update[0]): Decimal(update[1])
            for update in ftx_data['result']['asks']
        })
    }
    ob.bids = {
        Decimal(update[0]): Decimal(update[1])
        for update in ftx_data['result']['bids']
    }
    ob.asks = {
        Decimal(update[0]): Decimal(update[1])
        for update in ftx_data['result']['asks']
    }

    ob.checksum() == ftx_checksum(book)
Example #7
0
 def __init__(self, name, addr, balance, base_cur, desired_cur):
     self.name = name
     self.exchange = Exchange(name, addr, balance)
     self.book = OrderBook(base_cur, desired_cur)
     self.exchange.book = self.book
     self.graph = Graph(self.exchange)
     self.traders = {}
     self.html = ''
     self.display_graph = False
     self.clearing_price = np.random.uniform(20, 50)
     self.first_time = True
Example #8
0
def test_add_order_missing_details():
    order_stream = '1568390243|abbb11|a|AAPL|B|209.00000'
    book = OrderBook()
    book.process_order(order_stream)

    assert book.exception_queue == [[
        'Invalid order string', '1568390243', 'abbb11', 'a', 'AAPL', 'B',
        '209.00000'
    ]]
    with pytest.raises(KeyError):
        book.orders['abbb11']
Example #9
0
def setup(json_file='demo.json'):
    '''
    '''
    with open(json_file) as json_data:
        data = json.load(json_data)

    bids = TradeObject(data['bids'])
    asks = TradeObject(data['asks'], 'asks')

    order_book = OrderBook(bids, asks)
    return order_book
Example #10
0
    def __init__(self, accounts, products):
        self.accounts = accounts
        self.products = products

        self.order_books = {
            product: OrderBook(product)
            for product in products
        }
        self.orders_dict = {}  # key = (account, product, side), value = price

        self.transaction_history = []
def profile_orderbook():
    ob = OrderBook()

    for side, d in data.items():
        if side == 'bids':
            for price, size, _ in d:
                ob.bids[Decimal(price)] = size
        elif side == 'asks':
            for price, size, _ in d:
                ob.asks[Decimal(price)] = size
    ob.to_dict()
Example #12
0
def test_get_best_bid_and_ask_prices():
    book = OrderBook()
    order_stream1 = '1568390201|abbb11|a|AAPL|B|209.00000|100'
    order_stream2 = '1568390202|abbb12|a|AAPL|S|210.00000|10'
    order_stream3 = '1568390202|abbb13|a|AAPL|B|220.00000|1000'
    order_stream4 = '1568390202|abbb14|a|AAPL|S|230.00000|500'
    book.process_order(order_stream1)
    book.process_order(order_stream2)
    book.process_order(order_stream3)
    book.process_order(order_stream4)

    assert book.best_bid_and_ask('AAPL') == (209, 230)
 def test_market_data_check_max_ask_print_size_limiter(self):
     order_book = OrderBook(DEFAULT_TRADING_PAIR, 2, 2)
     orders = [generate_order_obj(type=OrderType.ASK) for _ in range(5)]
     for ord in orders:
         order_book.add_order(ord)
     old_market_data = order_book.market_data
     orders = sorted(orders, key=lambda i: i.price)
     delete_order = orders[0]
     order_book.remove_order(delete_order.id)
     assert order_book.market_data != old_market_data
     expected_data = self.expected_market_data(
         asks=self.aggregate_orders(orders[1:3]))
     assert order_book.market_data == expected_data
Example #14
0
def test_orderbook_setitem():
    ob = OrderBook()

    data = requests.get(
        "https://api.pro.coinbase.com/products/BTC-USD/book?level=2").json()
    ob.bids = {Decimal(price): size for price, size, _ in data['bids']}
    ob.asks = {Decimal(price): size for price, size, _ in data['asks']}

    assert ob.bids.index(0)[0] < ob.asks.index(0)[0]
    assert ob.bids.index(-1)[0] < ob.asks.index(-1)[0]

    assert ob.bids.index(-1)[0] < ob.bids.index(0)[0]
    assert ob.asks.index(-1)[0] > ob.asks.index(0)[0]
Example #15
0
def test_add_order():
    order_stream = '1568390243|abbb11|a|AAPL|B|209.00000|100'
    book = OrderBook()
    book.process_order(order_stream)

    assert book.orders['abbb11'] == {
        'timestamp': 1568390243,
        'id': 'abbb11',
        'action': 'a',
        'ticker': 'AAPL',
        'side': 'B',
        'price': 209,
        'size': 100
    }
Example #16
0
def test_orderbook_setitem_invalid():
    ob = OrderBook()

    with pytest.raises(ValueError):
        ob[123] = {}

    with pytest.raises(ValueError):
        ob['invalid'] = {}

    with pytest.raises(ValueError):
        del ob['bids']

    with pytest.raises(ValueError):
        ob['bids'] = 'a'
def retrieve_order_data(book_data, pair, agg_data):
    """
    Get spread, midpoint, and liquidity from book data. The information represents the status of the OrderBook at
    specific time. Time of retrieving is the last moment in each minute defined in aggregated market data (agg_data).

    :param book_data: order book data containing all limit order arrivals
    :type book_data: pandas.DataFrame
    :param pair: pair name of two currencies
    :type pair: str
    :param agg_data: minute level aggregated market information data
    :type agg_data: pandas.DataFrame
    :return: a minute level aggregated market information data with spread, midpoint, and liquidity added
    :rtype: pandas.DataFrame
    """
    # filter order data based on pair
    book_data_sub = book_data.loc[book_data["pair"] == pair]
    book_data_sub.reset_index(drop=True, inplace=True)
    # print(book_data_sub.head())
    order_book = OrderBook()
    agg_index = 0
    for i in range(len(book_data_sub)):
        # update order book
        order_book.update_order(book_data_sub["price"][i],
                                book_data_sub["amount"][i])
        # get the time of next order
        if i + 1 < len(book_data_sub):
            next_time = book_data_sub["servert"][i + 1]
        # book data reached to the end, set next time as last time
        else:
            next_time = book_data_sub["servert"][i]
        curr_end_time = agg_data["period_end_time"][agg_index]
        # record data to agg_data when (1) next time surpasses the end time of current period and agg_data has at least
        # two rows unfilled. (2) agg_data reaches to the last row.
        # In case (2) the last row of agg_data will keep updating until book data depletes
        if ((next_time > curr_end_time) and
            (agg_index < len(agg_data))) or (agg_index == len(agg_data) - 1):
            # get info from order book
            curr_spread = order_book.get_spread()
            curr_midpoint = order_book.get_midpoint()
            curr_bid_liquidity, curr_ask_liquidity = order_book.get_liquidity()
            # fill in values into agg data
            agg_data["spread"][agg_index] = curr_spread
            agg_data["midpoint"][agg_index] = curr_midpoint
            agg_data["liquidity_bid"][agg_index] = curr_bid_liquidity
            agg_data["liquidity_ask"][agg_index] = curr_ask_liquidity
            # when agg_data reaches to the last row, index stop moving forward
            if agg_index < len(agg_data) - 1:
                agg_index += 1

    return agg_data
Example #18
0
def test_okcoin_checksum():
    ob = OrderBook(checksum_format='OKCOIN')

    asks = {
        Decimal("3366.8"): Decimal("9"),
        Decimal("3368"): Decimal("8"),
        Decimal("3372"): Decimal("8")
    }
    bids = {Decimal("3366.1"): Decimal("7")}
    expected = 831078360

    ob.bids = bids
    ob.asks = asks

    assert ob.checksum() == expected
Example #19
0
def test_update_order():
    order_stream1 = '1568390243|abbb11|a|AAPL|B|209.00000|100'
    order_stream2 = '1568390244|abbb11|u|101'
    book = OrderBook()
    book.process_order(order_stream1)
    book.process_order(order_stream2)

    assert book.orders['abbb11'] == {
        'timestamp': 1568390244,
        'id': 'abbb11',
        'action': 'u',
        'ticker': 'AAPL',
        'side': 'B',
        'price': 209,
        'size': 101
    }
    def setUp(self):
        self.lp_2_gateway = deque()
        self.ob_2_ts = deque()
        self.ts_2_om = deque()
        self.ms_2_om = deque()
        self.om_2_ts = deque()
        self.gw_2_om = deque()
        self.om_2_gw = deque()

        self.liquidityProvider = LiquidityProvider(self.lp_2_gateway)
        self.bookBuilder = OrderBook(self.lp_2_gateway, self.ob_2_ts)
        self.tradingStrategy = TradingStrategy(self.ob_2_ts, self.ts_2_om,
                                               self.om_2_ts)
        self.marketSimulator = MarketSimulator(self.om_2_gw, self.gw_2_om)
        self.orderManager = OrderManager(self.ts_2_om, self.om_2_ts,
                                         self.om_2_gw, self.gw_2_om)
Example #21
0
def books_from_lines_v1(lines, debug=False, end=None, drop_out_of_order=False):
    currBook = None
    # keep track of which side the book starts on,
    # if that side repeats we've reached a new book
    startSide = None
    nLine = 0
    nBooks = 0

    keep_out_of_order = not drop_out_of_order
    maxTimestamp = None
    book_list = []
    for line in lines:
        if end and nBooks > end:
            break
        nLine += 1
        if line[0:9] == "ORDERBOOK":
            nBooks += 1
            if currBook is not None:
                if keep_out_of_order or currBook.last_update_time == maxTimestamp:
                    book_list.append(currBook)
            timestr = line[10:]
            lastUpdateTime = parse_datetime_opt(timestr)
            if maxTimestamp is None or lastUpdateTime > maxTimestamp:
                maxTimestamp = lastUpdateTime

            currBook = OrderBook(day=None,
                                 last_update_time=lastUpdateTime,
                                 last_update_monotonic=None,
                                 bids=[],
                                 offers=[],
                                 actions=[])
        else:
            row = line.split(',')
            side = row[obc.SIDE]
            entry = Order(
                timestamp=parse_datetime_opt(row[obc.TIMESTAMP]),
                side=side,
                level=int(row[obc.LEVEL]),
                price=float(row[obc.PRICE]),
                size=long(row[obc.SIZE]),
                #orderdepthcount = int(row[obc.ORDERDEPTHCOUNT])
                #ccy = row[obc.CURRENCY]
            )
            if (side == obc.BID): currBook.bids.append(entry)
            elif (side == obc.OFFER): currBook.offers.append(entry)
    return book_list
Example #22
0
def test_orderbook_keys():
    ob = OrderBook()

    ob['bids'][1] = 1
    ob['BIDS'][1] = 2
    ob['bid'][1] = 3
    ob['BID'][1] = 4

    assert ob.bids.to_dict() == {1: 4}
    assert ob.bid.to_dict() == {1: 4}

    ob['asks'][1] = 1
    ob['ASKS'][1] = 2
    ob['ask'][1] = 3
    ob['ASK'][1] = 4

    assert ob.asks.to_dict() == {1: 4}
    assert ob.ask.to_dict() == {1: 4}
Example #23
0
def test_orderbook_getitem():
    ob = OrderBook()

    data = requests.get(
        "https://api.pro.coinbase.com/products/BTC-USD/book?level=2").json()
    for side, d in data.items():
        if side in {'bids', 'asks'}:
            for price, size, _ in d:
                ob[side][Decimal(price)] = size

    assert ob.bids.index(0)[0] < ob.asks.index(0)[0]
    assert ob.bids.index(-1)[0] < ob.asks.index(-1)[0]

    assert ob.bids.index(-1)[0] < ob.bids.index(0)[0]
    assert ob.asks.index(-1)[0] > ob.asks.index(0)[0]

    with pytest.raises(KeyError):
        # legal keys are BID, bid, BIDS, bids, ASK, ask, ASKS, asks
        ob['invalid'][1] = 3
Example #24
0
def test_cancel_for_invalid_order():
    order_stream1 = '1568390243|abbb11|a|AAPL|B|209.00000|100'
    order_stream2 = '1568390244|ZZZZZZ|c'
    book = OrderBook()
    book.process_order(order_stream1)
    book.process_order(order_stream2)

    assert book.orders['abbb11'] == {
        'timestamp': 1568390243,
        'id': 'abbb11',
        'action': 'a',
        'ticker': 'AAPL',
        'side': 'B',
        'price': 209,
        'size': 100
    }
    assert book.exception_queue == [[
        'Cancel for non existent order', '1568390244', 'ZZZZZZ', 'c'
    ]]
Example #25
0
def populate_orderbook():
    ob = OrderBook()

    data = requests.get(
        "https://api.pro.coinbase.com/products/BTC-USD/book?level=2").json()
    for side, d in data.items():
        if side == 'bids':
            for price, size, _ in d:
                ob.bids[Decimal(price)] = size
        elif side == 'asks':
            for price, size, _ in d:
                ob.asks[Decimal(price)] = size

    assert ob.bids.index(0)[0] < ob.asks.index(0)[0]
    assert ob.bids.index(-1)[0] < ob.asks.index(-1)[0]

    assert ob.bids.index(-1)[0] < ob.bids.index(0)[0]
    assert ob.asks.index(-1)[0] > ob.asks.index(0)[0]

    return ob
Example #26
0
def test_orderbook_len():
    random.seed()
    bids = []
    asks = []

    for _ in range(500):
        bids.append(random.uniform(0.0, 100000.0))
    bids = list(set(bids))

    for _ in range(500):
        asks.append(random.uniform(0.0, 100000.0))
    asks = list(set(asks))

    ob = OrderBook()

    for b in bids:
        ob['BIDS'][b] = str(b)
    for a in asks:
        ob['ASKS'][a] = str(a)

    assert len(ob) == len(asks) + len(bids)
Example #27
0
    def start_new_orderbook(self, line):
        self.at_start_of_file = False
        # periodically clear the order cache so it doesn't eat all the memory
        if len(self.order_cache) > 5000:
            self.order_cache.clear()

        if self.currBook:
            self.books.append(self.currBook)
        _, _, monotonic_time, exchange_time = line.split(',')
        monotonic_seconds, _, monotonic_nanoseconds = monotonic_time.partition(
            ':')
        epoch_seconds, _, exchange_nanoseconds = exchange_time.partition(':')
        epoch_seconds = long(epoch_seconds)
        exchange_seconds = epoch_seconds % self.SECONDS_PER_DAY
        exchange_day = epoch_seconds / self.SECONDS_PER_DAY
        update_time = exchange_seconds * 1000 + long(exchange_nanoseconds) / (
            10**6)
        monotonic_time = long(monotonic_seconds) * 1000 + long(
            monotonic_nanoseconds) / (10**6)
        self.currBook = OrderBook(exchange_day, update_time, monotonic_time,
                                  [], [], self.actions)
        self.actions = []
Example #28
0
def main():
    lp_2_gateway = deque()
    ob_2_ts = deque()
    ts_2_om = deque()
    om_2_ts = deque()
    gw_2_om = deque()
    om_2_gw = deque()

    lp = LiquidityProvider(lp_2_gateway)
    ob = OrderBook(lp_2_gateway, ob_2_ts)
    ts = TradingStrategy(ob_2_ts, ts_2_om, om_2_ts)
    ms = MarketSimulator(om_2_gw, gw_2_om)
    om = OrderManager(ts_2_om, om_2_ts, om_2_gw, gw_2_om)

    lp.read_tick_data_from_data_source()

    while len(lp_2_gateway) > 0:
        ob.handle_order_from_gateway()
        ts.handle_input_from_bb()
        om.handle_input_from_ts()
        ms.handle_order_from_gw()
        om.handle_input_from_market()
        ts.handle_response_from_om()
        lp.read_tick_data_from_data_source()
Example #29
0
 def setUp(self):
     self.reforderbook = OrderBook()
Example #30
0
def test_minimum_depth_kraken():
    ob = OrderBook(max_depth=9, checksum_format='KRAKEN')
    with pytest.raises(ValueError):
        ob.checksum()