Level2 Data Fetch
Fetch and process streaming Level 2 order book data from exchange WebSocket feeds, maintaining a local high-fidelity order book reconstruction with incremental update application for latency-sensitive real-time microstructure analysis and trading signal generation.
Understanding Level 2 Order Book Data
This notebook provides a structured introduction to Level 2 order book data, a crucial concept in financial markets, especially for high-frequency trading and market analysis.
What is Level 2 Order Book Data?
Level 2 order book data provides a detailed, real-time view of all outstanding buy (bid) and sell (ask) orders for a specific financial instrument (like a stock, cryptocurrency, or commodity) at various price levels. Unlike Level 1 data, which only shows the best bid and ask prices (the top of the book), Level 2 data exposes the full depth of the market.
Key Components:
- Bid Side: Represents orders from buyers indicating the maximum price they are willing to pay. These orders are sorted in descending order by price.
- Ask Side: Represents orders from sellers indicating the minimum price they are willing to accept. These orders are sorted in ascending order by price.
- Price Level: The specific price at which an order is placed.
- Quantity (Size): The number of units (e.g., shares, contracts) available at a given price level.
Importance:
Level 2 data is vital for:
- Market Depth Analysis: Understanding the liquidity and potential price impact of large orders.
- Price Discovery: Gaining insights into where supply and demand are concentrated.
- Identifying Support/Resistance: Large clusters of bids/asks can indicate potential price barriers.
- Order Flow Analysis: Observing how orders are placed, modified, and executed to infer market sentiment and potential future price movements.
Setting up the Environment
First, let's import the necessary libraries.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import randomMock Data Generation
To demonstrate the concepts, we will generate a realistic-looking mock Level 2 order book. In a real-world scenario, this data would be fetched from a trading API (e.g., Binance, Coinbase, LMAX, Interactive Brokers).
def generate_mock_order_book_data(
mid_price: float = 100.0,
spread: float = 0.05,
depth: int = 10,
qty_range: tuple = (10, 100)
) -> dict:
"""
Generates mock Level 2 order book data for demonstration.
Args:
mid_price (float): The central price around which bids and asks are generated.
spread (float): The difference between the best ask and best bid.
depth (int): The number of price levels to generate for bids and asks.
qty_range (tuple): A tuple (min_qty, max_qty) for random quantities.
Returns:
dict: A dictionary containing 'bids' and 'asks' DataFrames.
Each DataFrame has 'Price' and 'Quantity' columns.
"""
best_ask = mid_price + spread / 2
best_bid = mid_price - spread / 2
# Generate Ask orders
ask_prices = [best_ask + i * 0.01 for i in range(depth)]
ask_quantities = [random.randint(qty_range[0], qty_range[1]) for _ in range(depth)]
asks_df = pd.DataFrame({'Price': ask_prices, 'Quantity': ask_quantities})
# Generate Bid orders
bid_prices = [best_bid - i * 0.01 for i in range(depth)]
bid_quantities = [random.randint(qty_range[0], qty_range[1]) for _ in range(depth)]
bids_df = pd.DataFrame({'Price': bid_prices, 'Quantity': bid_quantities})
return {"bids": bids_df, "asks": asks_df}
# Generate and display mock data
order_book = generate_mock_order_book_data(mid_price=1500.00, spread=0.10, depth=15)
print("### Mock Bid Orders (Buyers wanting to buy) ###")
display(order_book['bids'].head())
print("\n### Mock Ask Orders (Sellers wanting to sell) ###")
display(order_book['asks'].head())### Mock Bid Orders (Buyers wanting to buy) ###
| Price | Quantity | |
|---|---|---|
| 0 | 1499.95 | 44 |
| 1 | 1499.94 | 28 |
| 2 | 1499.93 | 58 |
| 3 | 1499.92 | 58 |
| 4 | 1499.91 | 29 |
### Mock Ask Orders (Sellers wanting to sell) ###
| Price | Quantity | |
|---|---|---|
| 0 | 1500.05 | 49 |
| 1 | 1500.06 | 59 |
| 2 | 1500.07 | 28 |
| 3 | 1500.08 | 30 |
| 4 | 1500.09 | 53 |
Core Metrics from Level 2 Data
From the Level 2 order book, we can derive several important metrics that help in understanding market dynamics.
1. Bid-Ask Spread
Definition: The difference between the best (highest) bid price and the best (lowest) ask price.
Formula: Spread = Best Ask Price - Best Bid Price
Importance: A narrower spread generally indicates higher liquidity and lower transaction costs, while a wider spread suggests lower liquidity or higher volatility.
2. Mid-Price
Definition: The average of the best bid and best ask prices.
Formula: Mid-Price = (Best Bid Price + Best Ask Price) / 2
Importance: Often used as a proxy for the true market price of an asset, especially when the last traded price might be stale.
def calculate_spread(order_book: dict) -> float:
"""
Calculates the bid-ask spread from the order book.
Args:
order_book (dict): A dictionary containing 'bids' and 'asks' DataFrames.
Returns:
float: The bid-ask spread.
"""
best_bid = order_book['bids']['Price'].max()
best_ask = order_book['asks']['Price'].min()
spread = best_ask - best_bid
return spread
def calculate_mid_price(order_book: dict) -> float:
"""
Calculates the mid-price from the order book.
Args:
order_book (dict): A dictionary containing 'bids' and 'asks' DataFrames.
Returns:
float: The mid-price.
"""
best_bid = order_book['bids']['Price'].max()
best_ask = order_book['asks']['Price'].min()
mid_price = (best_bid + best_ask) / 2
return mid_price
# Demonstrate calculations with mock data
mock_spread = calculate_spread(order_book)
mock_mid_price = calculate_mid_price(order_book)
print(f"Best Bid Price: {order_book['bids']['Price'].max():.2f}")
print(f"Best Ask Price: {order_book['asks']['Price'].min():.2f}")
print(f"Calculated Bid-Ask Spread: {mock_spread:.2f}")
print(f"Calculated Mid-Price: {mock_mid_price:.2f}")Best Bid Price: 1499.95 Best Ask Price: 1500.05 Calculated Bid-Ask Spread: 0.10 Calculated Mid-Price: 1500.00
3. Order Book Depth (Cumulative Quantity)
Definition: The total quantity of orders available at or up to a certain price level (or a certain number of levels away from the best bid/ask).
Importance: Provides insight into the liquidity available at different price points. A high depth on one side (e.g., many bids) might indicate strong buying interest (support), while high depth on the other side (e.g., many asks) might indicate strong selling pressure (resistance).
def calculate_order_book_depth(df: pd.DataFrame) -> pd.DataFrame:
"""
Calculates the cumulative quantity for an order book side (bids or asks).
Args:
df (pd.DataFrame): DataFrame representing either bids or asks, with 'Price' and 'Quantity' columns.
Returns:
pd.DataFrame: A DataFrame with 'Price', 'Quantity', and 'Cumulative Quantity' columns,
sorted appropriately for the order book side.
"""
df_sorted = df.sort_values(by='Price', ascending=True if 'asks' in df.columns else False)
df_sorted['Cumulative Quantity'] = df_sorted['Quantity'].cumsum()
return df_sorted
# Calculate and display depth for bids and asks
bids_with_depth = calculate_order_book_depth(order_book['bids'].sort_values(by='Price', ascending=False).reset_index(drop=True))
asks_with_depth = calculate_order_book_depth(order_book['asks'].sort_values(by='Price', ascending=True).reset_index(drop=True))
print("### Bid Orders with Cumulative Depth ###")
display(bids_with_depth.head())
print("\n### Ask Orders with Cumulative Depth ###")
display(asks_with_depth.head())### Bid Orders with Cumulative Depth ###
| Price | Quantity | Cumulative Quantity | |
|---|---|---|---|
| 0 | 1499.95 | 44 | 44 |
| 1 | 1499.94 | 28 | 72 |
| 2 | 1499.93 | 58 | 130 |
| 3 | 1499.92 | 58 | 188 |
| 4 | 1499.91 | 29 | 217 |
### Ask Orders with Cumulative Depth ###
| Price | Quantity | Cumulative Quantity | |
|---|---|---|---|
| 14 | 1500.19 | 32 | 32 |
| 13 | 1500.18 | 54 | 86 |
| 12 | 1500.17 | 35 | 121 |
| 11 | 1500.16 | 72 | 193 |
| 10 | 1500.15 | 58 | 251 |
Visualizing Level 2 Order Book Data
Visualizations help to quickly grasp the distribution of orders and market depth. We will create two types of plots:
- Order Book Profile: A multi-panel plot showing the individual bid and ask levels.
- Cumulative Order Book Depth: A plot illustrating the cumulative quantity at various price levels.
1. Order Book Profile Visualization
This plot shows the quantity at each price level for both bids and asks, providing a snapshot of the current market structure. The best bid and ask prices are highlighted to indicate the current spread.
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6), sharey=True)
# Plot Bids
ax1.barh(order_book['bids']['Price'], order_book['bids']['Quantity'], color='green', alpha=0.7)
ax1.set_title('Bid Orders (Buyers)', fontsize=14)
ax1.set_xlabel('Quantity', fontsize=12)
ax1.set_ylabel('Price', fontsize=12)
ax1.invert_xaxis() # Bids typically shown decreasing quantity from best price
ax1.tick_params(axis='x', rotation=45)
ax1.grid(axis='x', linestyle='--', alpha=0.6)
# Highlight Best Bid
best_bid_price = order_book['bids']['Price'].max()
ax1.axhline(best_bid_price, color='darkgreen', linestyle='--', linewidth=1.5, label=f'Best Bid: {best_bid_price:.2f}')
ax1.legend()
# Plot Asks
ax2.barh(order_book['asks']['Price'], order_book['asks']['Quantity'], color='red', alpha=0.7)
ax2.set_title('Ask Orders (Sellers)', fontsize=14)
ax2.set_xlabel('Quantity', fontsize=12)
ax2.tick_params(axis='x', rotation=45)
ax2.grid(axis='x', linestyle='--', alpha=0.6)
# Highlight Best Ask
best_ask_price = order_book['asks']['Price'].min()
ax2.axhline(best_ask_price, color='darkred', linestyle='--', linewidth=1.5, label=f'Best Ask: {best_ask_price:.2f}')
ax2.legend()
fig.suptitle(f'Level 2 Order Book Profile (Mid-Price: {mock_mid_price:.2f}, Spread: {mock_spread:.2f})', fontsize=16)
plt.tight_layout(rect=[0, 0.03, 1, 0.95])
plt.show()2. Cumulative Order Book Depth Visualization
This plot aggregates the quantity of orders at each price level, showing the total liquidity available as you move away from the current mid-price. This helps in understanding market resilience to large orders.
plt.figure(figsize=(12, 7))
# Plot Cumulative Bids
plt.plot(bids_with_depth['Price'], bids_with_depth['Cumulative Quantity'], drawstyle='steps-post', color='green', label='Cumulative Bids')
# Plot Cumulative Asks
plt.plot(asks_with_depth['Price'], asks_with_depth['Cumulative Quantity'], drawstyle='steps-post', color='red', label='Cumulative Asks')
plt.axvline(mock_mid_price, color='purple', linestyle=':', label=f'Mid-Price: {mock_mid_price:.2f}')
plt.axvline(order_book['bids']['Price'].max(), color='darkgreen', linestyle='--', label=f'Best Bid: {order_book['bids']['Price'].max():.2f}')
plt.axvline(order_book['asks']['Price'].min(), color='darkred', linestyle='--', label=f'Best Ask: {order_book['asks']['Price'].min():.2f}')
plt.title('Cumulative Order Book Depth', fontsize=16)
plt.xlabel('Price', fontsize=12)
plt.ylabel('Cumulative Quantity', fontsize=12)
plt.legend(fontsize=10)
plt.grid(True, linestyle='--', alpha=0.6)
plt.tight_layout()
plt.show()Conclusion
This notebook has introduced the fundamental concepts of Level 2 order book data, including its structure, key metrics like bid-ask spread, mid-price, and cumulative depth, and methods for visualizing this data. Analyzing Level 2 data is essential for understanding market microstructure, liquidity, and potential price movements in dynamic financial markets.