Crypto-toolbox/HFT-Orderbook

Better documentation

kjgd opened this issue · 6 comments

kjgd commented

The documentation is currently a little thin.

From the tests I see how to add and remove orders.

And I see there is a top_level() function to get the best bid/ask.

But if all I needed was the best bid/ask then I would just use a ticker :)

How do I query the book to find the market depth, for example? Is there any way to return a list of bids and asks (price/size)?

Hey @kjgd ,
The only documentation available is indeed only provided as doc strings.
As for the query method, you will have to implement this yourself (or submit a PR to add this!) - the implementation itself is just meant as a means to store, update and remove orders.

The project isn't done yet, of course, so I may add this later on. However, the C implementation takes precedence for me.

best,
Nils

kjgd commented

Yes, I can appreciate that the C implementation takes precedence, but I don't know C so I will have to hope you (or someone else) end up implementing the query method there :)

Regarding the Python version, I have to admit I am entirely unsure how to even begin querying a binary tree in order to implement a GetVolumeAtLimit type method.

Hey @kjgd,
If you look at the implementation, you can see that all limits are stored in a dictionary. You would just have to turn it's keys into a sorted list, and then iterate over the dictionary to get each limits size and price. You can, in theory, even allow level 3 order books this way, by simply iterating over the limit's orders attribute.

Best,

Nils

kjgd commented

Maybe I'm confused by the existence of a LimitLevel class which is marked as being a BST.

What is stored in the binary tree then, if not for the limits?

The LimitLevels are stored in a balanced binary tree (AVL tree).
Additionally, a reference to all orders is kept in a separated dictionary, as well as to all limit levels.
This ensures that accessing any limit and any order is O(1), as well as deleting and updating. Only inserting a new limit level will take longer.

Take a look at the blog post by WK Selph, upon which this implementation is based.

kjgd commented

Ok, let's consider the following book:

import lob as LOB
lob = LOB.LimitOrderBook()
orders = [
    LOB.Order(uid=1, is_bid=True, size=5, price=100),
    LOB.Order(uid=2, is_bid=True, size=5, price=95),
    LOB.Order(uid=3, is_bid=True, size=5, price=90),
    LOB.Order(uid=4, is_bid=False, size=5, price=200),
    LOB.Order(uid=5, is_bid=False, size=5, price=205),
    LOB.Order(uid=6, is_bid=False, size=5, price=210),
    ]
for order in orders:
     lob.process(order)

I'm looking at the limit level dictionary:
lob._price_levels
Since no limit level is aware of whether it is a bid or an ask level, it looks like determining this means querying:
lob._price_levels[100].orders.head.is_bid
(for an order book containing a price level of 100)

And therefore it looks like the only way to separate out bids and asks is:

bids = []
asks = []
for k, level in lob._price_levels.items():
    if level.orders.head.is_bid:
        bids.append(level)
    else:
        asks.append(level)

Now, since the query function should also be O(1), I would like to avoid iterating through every price level in the book where this is not necessary -- a book may have 1000 levels but only the first 100 may be relevant.

Is there any way to do this?