Skip to content

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):

from fastboxex.price import to_display, from_float

raw     = from_float(100.00)   # 1_000_000
display = to_display(raw)      # 100.0

mid_display = to_display((md["bid"] + md["ask"]) // 2)