Exchange Liquidity
For exchange traded securities, outside of highly liquid securities like the magnificent 7 tech stocks or G10 FX pairs, many suffer from periodic lack of liquidity. For traders of said products, this can manifest itself in terms of slippage.
This often results in poor execution prices and loss of profit on positions. Sophisticated investors are well aware of this, and seek to minimise slippage losses through Over-The-Counter (OTC) trades, where large orders are negotiated bilaterally between trading parties. The traded securities change hands without ever hitting the market, minimising volatility.
However, in the event that a large order is to be filled, and no suitable counterparty can be located to make the trade, even sophisticated investors themselves have to wade into the murky waters of the exchange’s limit order book and try to make trades at fair prices.
Examining the central limit order book (CLOB), provides useful instantaneous insight into the current market for a given security.
THE CLOB consists of all the various orders in the market at a given moment.
Entities who wish to transact on CLOBs submit either “Bids” (Buy) and “Asks” (Sells), which will be reflected on the CLOB. In the interest of transparency, the exchange is obligated to make them visible for all users.
Order Types
While there are many different order types that take advantage of characteristic of the CLOB, they are all combinations of 2 basic types.
Market Orders and Limit Orders.
Market Orders
Orders which are to be filled immediately regardless of pricing. When you submit a market order to buy 1000 units of a security at $100, is common to find your transaction records showing somethings like the following:
500 units at $100
200 units at $101
300 units at $99
You are tolerating uncertainty in trade execution, in exchange for speed.
Limit orders
orders to be filled only at predetermined prices. Using our previous example of 1000 units of security at $100, if a limit order is placed, our records may look like:
500 units at $100
200 units at $100
300 units at $100
Though keep in mind that for illiquid markets with jarring price swings, it can take a very long time to fill a limit order.
You are exchanging price certainty with time.
Utilizing order book data
A highly liquid market is dependent on having a huge number of bids and asks at most price ranges. In the case of illiquid markets, we can sometimes observe a big imbalance of bids and asks. If the orders are highly lopsided, with an excess of one order type. It likely means that any further buys at the existing price levels will not be fulfilled, and the prices will rise further in the short run.
If there is little urgency, one can simply place a limit order and wait for the prices to drift back to the desired levels.
However, should there be urgency, one would need to examine the order book to ascertain if the current state warrants placing a market order.
Alternatively, this knowledge can also be acted upon to make short term trades to profit from CLOB imbalances.
If imbalances are observed, it suggests that prices will likely move to address these imbalances. Eg If there is a momentary buildup of many bids, a short term price spike likely follows.
A common arbitrage strategy in fact, is comparing order book imbalance against price movements to obtain buying signals for a particular asset class and exchange.
Large amounts of literature have already been written on arbitraging order book imbalances and is beyond the scope of this article.
Extract Binance Order Book data in Python
For the subsequent section, we shall extract the order book of a relatively thinly traded asset from Binance.
While the same analysis can be done from the Graphical Interface, the key benefit of data extraction and plotting the data in Python is greater granularity of analysis.
#run "pip install python-binance" at the command line
from binance import Client
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import math
apikey = '****Your API KEY from Binance******'
secret = '*****Your Secret Key from Binance'
client = Client(apikey, secret)
tickers = pd.DataFrame(client.get_all_tickers())
tickers.set_index("symbol", inplace=True)
#Ticker
ticker = "SOLUSDC"
#Market depth
depth = client.get_order_book(symbol=ticker)
bids = pd.DataFrame(depth["bids"],
columns=["bid price", "bid volume"]).astype(float).round(2).iloc[::-1]
asks = pd.DataFrame(depth["asks"],
columns=["ask price", "ask volume"]).astype(float).round(2)
# print("bids", bids)
# print("asks", asks)
#Mid Price
mid_price = round((bids["bid price"].max()+asks["ask price"].min())/2, 2)
#timestamp
timestamp=depth["lastUpdateId"]
#Order book threshold
threshold = 0.05
floor = math.floor(mid_price*(1-threshold))
ceiling = math.ceil(mid_price*(1+threshold))
#Order Imbalance
ask_vol = asks.loc[asks["ask price"]<ceiling, "ask volume"].sum()
bid_vol = bids.loc[bids["bid price"]>floor, "bid volume"].sum()
order_book_imbalance = round(bid_vol-ask_vol, 2)
plt.title(f"Binance order book for {ticker}; timestamp: {timestamp}")
bid_plot = plt.bar(bids["bid price"], bids["bid volume"], color="lime")
ask_plot = plt.bar(asks["ask price"], asks["ask volume"], color="red")
plt.xticks(np.arange(floor, ceiling, 1))
plt.xlim(floor, ceiling)
plt.xticks(rotation=45)
plt.ylim(0, 150) #arbitrarily chosen upper ylimit, Adjust accordingly for each Ticker
mid_price_plot = plt.axvline(x = mid_price, color = 'b', linestyle = "--", label = 'center price')
plt.grid(True)
plt.legend(handles = [bid_plot, ask_plot, mid_price_plot],
labels = ["bids", "asks", f"mid_price: ${mid_price}"],
title = f"Order Book Imbalance: {order_book_imbalance}",
loc='upper right', prop={"size":10})
plt.show()
We can restrict our analysis to certain ranges from the current price, ignoring many far off limit orders that have little to no bearing on the current state of the CLOB.
In this case, we restrict the analysis to 5% from the mid-price using the variable “threshold”.
As we can see here, the CLOB seems somewhat balanced, with a larger number of bids than asks.
At the current mid price of $98.31, we observe a positive imbalance of 607 units of SOL.
That is approximately $60,000 worth of unfulfilled bids.
Disclaimer
One disclaimer regarding the accuracy of these plots, is that Binance API allows up to 1200 calls/minute. Trading Bots using the exact same API to interact with Binance will long have submitted orders to take advantage of these imbalances by the time this Python plot is displayed.
It is unwise to use these graphs to guide your trading if you are manually inputting trades using the graphical interface.
Hope the explanation and codes have been useful in helping you to understand central limit order books. Thank you and see you in the next article!