
Published under Quantitative Engineering | This is not investment advice
Intro
If you’ve worked on algorithmic trading projects, you’ve definitely run into this annoying problem: backtests produce great results, but performance falls apart in simulation or live environments. Most of the time, the root cause comes down to how you consume market data.
Many new developers start out using only Level‑1 market data. You get the last trade price, price change, and total volume, which works fine for simple display use‑cases. But Level‑1 cannot capture granular order‑book events such as large orders being added, modified or cancelled. For short‑term and high‑frequency strategies, this missing detail creates a massive gap between simulation and reality.
This post covers Level‑2 depth data, why incremental updates beat full snapshots, WebSocket streaming, common production bugs, and runnable Python sample code for building your local order book.
What data can you get from Level‑2 depth feeds?
Basic public market APIs are easy to integrate and perfect for simple price dashboards. However, they lack granular details needed for short‑term quantitative logic.
Level‑2 depth exposes full order‑book visibility:
- Multi‑level bid and ask prices
- Order volume at each price level
- Market depth metadata
- Event timestamps
Timestamps are frequently overlooked, yet they are essential to keep your local order book synchronized with real‑market state.
Early on, I made a typical mistake: saving a full order‑book snapshot every time new market data arrived. It worked fine with one single symbol. Once I subscribed to multiple stocks, storage pressure and CPU usage shot up, introducing visible latency.
This is where incremental order‑book logic solves the problem. Instead of rewriting the entire book for every incoming payload, you only update price levels that have changed.
Example scenario: A bid price holds 500 lots. An incoming update shows 300 lots remain. Your code only overwrites volume for that exact price point. If volume becomes zero, delete that price entry completely. This reduces redundant computation and makes order‑flow analysis much simpler.
WebSocket over HTTP polling for real‑time depth data
Stock depth data updates constantly at high velocity. With HTTP polling, your client repeatedly sends requests to fetch new data. Under high‑load conditions, polling generates lots of redundant requests plus unpredictable network lag — not ideal for real‑time order‑book tracking.
After connection handshake, WebSocket allows servers to push updates actively without constant client‑side requests. Your application parses incoming messages and updates the local order‑book state incrementally.
Below is a minimal working demo:
import websocket
import json
# Initialize local order‑book structure, separate bids and asks
order_book = {
"bids": {},
"asks": {}
}
def on_message(ws, message):
"""Receive server push and update local order book"""
data = json.loads(message)
symbol = data.get("symbol")
bids = data.get("bids", [])
asks = data.get("asks", [])
# Update bid price tiers
for item in bids:
price = item["price"]
volume = item["volume"]
order_book["bids"][price] = volume
# Update ask price tiers
for item in asks:
price = item["price"]
volume = item["volume"]
order_book["asks"][price] = volume
print(symbol, order_book)
def on_open(ws):
"""Send depth subscription request once WebSocket connects"""
subscribe_req = {
"id": 1,
"cmd": "subscribe",
"symbol": "AAPL",
"type": "depth"
}
ws.send(json.dumps(subscribe_req))
if __name__ == "__main__":
ws = websocket.WebSocketApp(
"wss://api.alltick.co/stock/websocket",
on_open=on_open,
on_message=on_message
)
ws.run_forever()
📝 Note: This snippet is for demonstration only. Adapt field parsing according to your API documentation before deploying to production.
3 common pitfalls building incremental local order books
Getting code running ≠ building a stable system. Watch for these often‑missed issues:
Enforce event ordering with timestamps
Network packets may arrive out‑of‑order. Without validating timestamps, stale data can overwrite newer order‑book state. This corrupts your local book and produces wrong outputs for downstream trading logic.Reconnection logic + full snapshot resync
WebSocket connections can drop due to network instability. Once disconnected, your in‑memory order book is invalid. After reconnecting, do not directly process incremental messages. Fetch a full order‑book snapshot first to align local state, then resume consuming incremental pushes.Handle cross‑market specification differences
Markets use different Level‑2 standards. Tick sizes, field names and returned depth tiers vary. Avoid a one‑size‑fits‑all codebase; adjust your implementation against API docs.
Wrap‑up
Figuring out how to get real‑time stock data is only the very first step of your project. Many quantitative developers spend too much time hunting for data sources while ignoring the importance of solid data‑processing pipelines.
The true value of Level‑2 data is not extra price fields, but giving your program visibility into dynamic order movements. An incrementally maintained local order‑book forms reliable infrastructure for market monitoring, backtesting and strategy simulation. API integration is just the entry point; thoughtful data processing determines overall system reliability.
If you want to skip low‑level market‑data plumbing work, you can leverage AllTick API to ingest Level‑2 depth feeds and focus more of your effort on strategy logic.
Top comments (0)