Market Data

Guide for fetching and streaming market data programmatically using the Python SDK.

Prerequisites

Market data endpoints are public — no authentication required:

from turbine_client import TurbineClient, Outcome

client = TurbineClient(
    host="https://api.turbinefi.com",
    chain_id=137,
)

List Markets

Fetch all markets, optionally filtered by chain:

# All markets
markets = client.get_markets()

# Filter by chain
markets = client.get_markets(chain_id=137)

for m in markets:
    status = "RESOLVED" if m.resolved else "ACTIVE"
    print(f"[{status}] {m.question}")
    print(f"  ID: {m.id}")
    print(f"  Contract: {m.contract_address}")
    print(f"  Volume: {m.volume / 1e6:.2f} USDC")
    print()

Each Market object contains the market ID (used for API calls) and the contract address (used for claiming winnings). See Types for all fields.

Orderbook Snapshots

Get the current orderbook for a market:

market_id = "0x..."

# Full orderbook (both outcomes)
ob = client.get_orderbook(market_id)

# YES side only
yes_ob = client.get_orderbook(market_id, outcome=Outcome.YES)

# NO side only
no_ob = client.get_orderbook(market_id, outcome=Outcome.NO)

Parsing the Orderbook

Bids are sorted highest-first (best bid on top). Asks are sorted lowest-first (best ask on top).

ob = client.get_orderbook(market_id, outcome=Outcome.YES)

print("YES Orderbook:")
print(f"{'BIDS':>40} | ASKS")
print("-" * 80)

max_levels = max(len(ob.bids), len(ob.asks))
for i in range(min(max_levels, 5)):
    bid_str = ""
    ask_str = ""

    if i < len(ob.bids):
        b = ob.bids[i]
        bid_str = f"{b.size / 1e6:>8.2f} @ {b.price:>6} (${b.price / 1e6:.4f})"

    if i < len(ob.asks):
        a = ob.asks[i]
        ask_str = f"{a.price:>6} (${a.price / 1e6:.4f}) x {a.size / 1e6:.2f}"

    print(f"{bid_str:>40} | {ask_str}")

Derived Metrics

ob = client.get_orderbook(market_id, outcome=Outcome.YES)

if ob.bids and ob.asks:
    best_bid = ob.bids[0].price
    best_ask = ob.asks[0].price
    mid = (best_bid + best_ask) / 2
    spread = best_ask - best_bid
    spread_pct = spread / mid * 100 if mid > 0 else 0

    print(f"Best bid: {best_bid} (${best_bid / 1e6:.4f})")
    print(f"Best ask: {best_ask} (${best_ask / 1e6:.4f})")
    print(f"Mid: {mid:.0f} (${mid / 1e6:.4f})")
    print(f"Spread: {spread} ({spread_pct:.2f}%)")

    # Total depth
    bid_depth = sum(level.size for level in ob.bids) / 1e6
    ask_depth = sum(level.size for level in ob.asks) / 1e6
    print(f"Bid depth: {bid_depth:.2f} shares")
    print(f"Ask depth: {ask_depth:.2f} shares")

Trade History

Get recent trades for a market:

trades = client.get_trades(market_id, limit=20)

for t in trades:
    outcome = "YES" if t.outcome == 0 else "NO"
    print(
        f"{outcome} {t.size / 1e6:.2f} "
        f"@ {t.price} (${t.price / 1e6:.4f}) | "
        f"tx={t.tx_hash[:16]}..."
    )

Aggregate Trade Data

trades = client.get_trades(market_id, limit=100)

if trades:
    prices = [t.price for t in trades]
    sizes = [t.size for t in trades]
    total_volume = sum(t.price * t.size // 1_000_000 for t in trades)

    print(f"Trades: {len(trades)}")
    print(f"Price range: {min(prices)} (${min(prices) / 1e6:.4f}) — {max(prices)} (${max(prices) / 1e6:.4f})")
    print(f"Volume: {total_volume / 1e6:.2f} USDC")

Market Statistics

Single Market

stats = client.get_market(market_id)

print(f"Last price: {stats.last_price} (${stats.last_price / 1e6:.4f})")
print(f"24h volume: {stats.volume_24h / 1e6:.2f} USDC")
print(f"Total volume: {stats.total_volume / 1e6:.2f} USDC")

Platform-Wide

platform = client.get_platform_stats()

print(f"Total volume: {platform.total_volume / 1e6:.2f} USDC")
print(f"Total trades: {platform.total_trades}")

for chain in platform.chains:
    print(f"  Chain {chain.chain_id}: {chain.total_volume / 1e6:.2f} USDC, {chain.total_trades} trades")

Top Holders

holders = client.get_holders(market_id, limit=10)

for i, h in enumerate(holders, 1):
    print(
        f"#{i} {h.user_address[:10]}... | "
        f"YES={h.yes_shares / 1e6:.2f} | "
        f"NO={h.no_shares / 1e6:.2f} | "
        f"Invested={h.total_invested / 1e6:.2f} USDC"
    )

Quick Market Data

Active Quick Market

qm = client.get_quick_market("BTC")

print(f"Question: Will BTC be above ${qm.start_price / 1e8:,.2f}?")
print(f"Market ID: {qm.market_id}")
print(f"Contract: {qm.contract_address}")
print(f"Starts: {qm.start_time}")
print(f"Ends: {qm.end_time}")
print(f"Resolved: {qm.resolved}")

Current Price

price = client.get_quick_market_price("BTC")
print(f"BTC: ${price.price / 1e8:,.2f}")

Price History

history = client.get_quick_market_price_history("BTC", limit=60)

for p in history:
    print(f"  {p.timestamp}: ${p.price / 1e8:,.2f}")

Quick Market History

past_markets = client.get_quick_market_history("BTC", limit=10)

for qm in past_markets:
    if qm.resolved:
        outcome = "YES" if qm.outcome == 0 else "NO"
        print(f"  Strike: ${qm.start_price / 1e8:,.2f} → End: ${qm.end_price / 1e8:,.2f} = {outcome}")
    else:
        print(f"  Strike: ${qm.start_price / 1e8:,.2f} (active)")

Real-Time Streaming via WebSocket

import asyncio
from turbine_client.ws import TurbineWSClient

async def stream_market(market_id: str):
    ws = TurbineWSClient(host="https://api.turbinefi.com")

    async with ws.connect() as stream:
        await stream.subscribe(market_id)
        print(f"Subscribed to {market_id}")

        async for msg in stream:
            if msg.type == "orderbook":
                ob = msg.orderbook
                if ob and ob.bids and ob.asks:
                    mid = (ob.bids[0].price + ob.asks[0].price) / 2
                    spread = ob.asks[0].price - ob.bids[0].price
                    print(f"Book: {ob.bids[0].price}/{ob.asks[0].price} mid={mid:.0f} spread={spread}")

            elif msg.type == "trade":
                trade = msg.trade
                if trade:
                    outcome = "YES" if trade.outcome == 0 else "NO"
                    print(f"Trade: {trade.size / 1e6:.2f} {outcome} @ {trade.price} (${trade.price / 1e6:.4f})")

asyncio.run(stream_market("0x..."))

Market Transition Detection

Quick markets rotate every 15 minutes. Detect transitions via WebSocket:

async def stream_with_transitions():
    client = TurbineClient(host="https://api.turbinefi.com", chain_id=137)
    ws = TurbineWSClient(host="https://api.turbinefi.com")

    qm = client.get_quick_market("BTC")
    current_market_id = qm.market_id

    async with ws.connect() as stream:
        await stream.subscribe(current_market_id)

        async for msg in stream:
            if msg.type == "quick_market":
                new_qm = msg.quick_market
                if new_qm and new_qm.market_id != current_market_id:
                    # Switch to new market
                    await stream.unsubscribe(current_market_id)
                    current_market_id = new_qm.market_id
                    await stream.subscribe(current_market_id)
                    print(f"New market: {current_market_id} (strike: ${new_qm.start_price / 1e8:,.2f})")

            elif msg.type == "orderbook":
                ob = msg.orderbook
                if ob and ob.bids and ob.asks:
                    print(f"  {ob.bids[0].price}/{ob.asks[0].price}")

asyncio.run(stream_with_transitions())