Skip to main content
MarketDataClient is the read-only client for the T+ market-data-service. It requires no user authentication — you only need the base URL of a running market-data instance. Use it to fetch order book snapshots, candlestick (kline) data, 24-hour tickers, and the public trade history, or to subscribe to live WebSocket streams for any of those feeds.

Initialization

Because MarketDataClient is unauthenticated, you only need to supply the service URL. The default base URL is http://localhost:8011.
import asyncio
from tplus.client import MarketDataClient

async def main():
    # uses the default http://localhost:8011 base URL
    async with MarketDataClient() as md_client:
        pass

    # or specify a custom URL
    async with MarketDataClient(base_url="http://market-data.example.com:8011") as md_client:
        pass

asyncio.run(main())
MarketDataClient does not require a User object or any signing — all endpoints are publicly accessible. If you need to place orders or query user-specific data, use OrderBookClient instead.

REST Methods

Get Order Book Snapshot

Fetch the current state of the order book for an asset. Returns the sequence number, the list of ask price levels, and the list of bid price levels.
from tplus.model.asset_identifier import AssetIdentifier

asset = AssetIdentifier(200)

snapshot = await md_client.get_orderbook_snapshot(asset)

print(f"Sequence:  {snapshot.sequence_number}")
print(f"Top ask:   {snapshot.asks[0] if snapshot.asks else 'empty'}")
print(f"Top bid:   {snapshot.bids[0] if snapshot.bids else 'empty'}")

Get Klines (Candlestick Data)

Retrieve candlestick data for charting and analysis.
klines = await md_client.get_klines(asset)

for candle in klines:
    print(candle)

Get 24-Hour Ticker

Fetch a 24-hour rolling price and volume summary for an asset.
ticker = await md_client.get_ticker(asset)
print(ticker)

Get Public Trades

Retrieve the public trade history — all finalized trades visible on the exchange, not filtered by user.
trades = await md_client.get_trades()

for trade in trades:
    print(trade)

WebSocket Streaming

MarketDataClient exposes three real-time streams as async generators. Use async for to consume each stream. For guidance on running multiple streams concurrently, see the WebSocket Streaming page.

Stream Finalized Trades

Subscribe to all finalized (matched and settled) trades in real time.
from tplus.model.trades import Trade

async for trade in md_client.stream_finalized_trades():
    if isinstance(trade, Trade):
        print(f"Trade  id={trade.trade_id}  price={trade.price}  qty={trade.quantity}")

Stream Order Book Depth Diffs

Subscribe to incremental updates to the order book. Each message is an OrderBookDiff containing the sequence number and the changed price levels on the ask and bid sides. Apply diffs sequentially to a local snapshot to maintain a live view of the book.
from tplus.model.orderbook import OrderBookDiff

async for diff in md_client.stream_depth(asset):
    if isinstance(diff, OrderBookDiff):
        print(
            f"Depth update  seq={diff.sequence_number}"
            f"  asks_changed={len(diff.asks)}"
            f"  bids_changed={len(diff.bids)}"
        )
To bootstrap a local order book, first call get_orderbook_snapshot() to get the current state and note the sequence_number. Then start consuming stream_depth(). Discard any diffs whose sequence number is ≤ the snapshot’s sequence number, then apply the rest in order.

Stream Klines

Subscribe to live candlestick updates as trades are matched.
async for update in md_client.stream_klines(asset):
    print(f"Kline update: {update}")

Complete Streaming Example

The following example runs all three MarketDataClient streams concurrently using asyncio.gather:
import asyncio
from tplus.client import MarketDataClient
from tplus.model.asset_identifier import AssetIdentifier
from tplus.model.orderbook import OrderBookDiff
from tplus.model.trades import Trade

asset = AssetIdentifier(200)

async def watch_trades(md_client):
    async for trade in md_client.stream_finalized_trades():
        if isinstance(trade, Trade):
            print(f"[Trade]  {trade.trade_id}  px={trade.price}  qty={trade.quantity}")

async def watch_depth(md_client):
    async for diff in md_client.stream_depth(asset):
        if isinstance(diff, OrderBookDiff):
            print(f"[Depth]  seq={diff.sequence_number}")

async def watch_klines(md_client):
    async for update in md_client.stream_klines(asset):
        print(f"[Kline]  {update}")

async def main():
    async with MarketDataClient() as md_client:
        await asyncio.gather(
            watch_trades(md_client),
            watch_depth(md_client),
            watch_klines(md_client),
        )

asyncio.run(main())
Each coroutine passed to asyncio.gather runs indefinitely. Press Ctrl-C to interrupt the program in interactive use. In production, wrap your gather in a try/except to handle asyncio.CancelledError cleanly.