Market Data¶
The SDK provides two market data streams:
| Stream | Method | Use case |
|---|---|---|
| Live exchange (all assets) | p.market() |
Regular trading |
| Arena stream | p.arena_market() |
Arena bots / training |
Both arrive over the TCP market relay the server advertises at login.
Getting a subscription¶
market = p.market() # live exchange assets
arena_market = p.arena_market() # arena stream (use in 07a/07b)
Both return a Market object that receives data in a background thread.
Reading the latest snapshot¶
md = market.get_latest(asset_id=1)
if md is None:
# No data received yet — wait a moment and retry
pass
else:
bid = md["bid"] # best bid price (raw ticks)
ask = md["ask"] # best ask price (raw ticks)
mid = (bid + ask) // 2
bid_qty = md["bid_qty"]
ask_qty = md["ask_qty"]
# Full book depth — list of (price, qty) tuples
bids = md["bids"] # [( price, qty ), ...] best first
asks = md["asks"]
No mid key
There is no "mid" field. Always compute: mid = (md["bid"] + md["ask"]) // 2.
md.get("mid") always returns None.
All available keys¶
| Key | Type | Description |
|---|---|---|
"bid" |
int |
Best bid price (raw ticks) |
"ask" |
int |
Best ask price (raw ticks) |
"bid_qty" |
int |
Volume at best bid |
"ask_qty" |
int |
Volume at best ask |
"bids" |
list[(int,int)] |
All bid levels (price, qty) |
"asks" |
list[(int,int)] |
All ask levels (price, qty) |
"timestamp" |
int |
Nanosecond publish timestamp |
"seq_id" |
int |
Monotone update counter |
"lifecycle_state" |
int |
Engine state |
"volume_buy" |
int |
Session cumulative buy volume |
"volume_sell" |
int |
Session cumulative sell volume |
"ntb" |
int |
Number of buy trades (session) |
"nts" |
int |
Number of sell trades (session) |
"nlb" |
int |
Live bid order count |
"nls" |
int |
Live ask order count |
In an arena trading loop¶
Use p.arena_market() — not conn.lob():
arena_market = p.arena_market()
while RUNNING:
md = arena_market.get_latest(asset_id)
if md is None:
time.sleep(0.1)
continue
bid = md["bid"]
ask = md["ask"]
mid = (bid + ask) // 2
# your signal logic here...
time.sleep(0.3)
conn.lob() in arena context
conn.lob(asset_id) is always empty in arena trader connections
(best_bid=None, best_ask=None). Book data comes from p.arena_market(),
not through the trading connection.
Polars export¶
# All snapshots as DataFrame
df = market.to_polars(asset_id=1)
# Public trade tape
trades_df = market.trades_to_polars(asset_id=1)
# Tick event history
ticks_df = market.ticks_to_polars(asset_id=1)
Status check¶
market.is_connected() # True if data received in the last 2s
market.history_len() # number of stored snapshots
Price conventions reminder¶
All prices in the market data dict are raw ticks (u64 integers):