Markets represent tradeable assets on T+. Learn how to query market details, order book snapshots, klines, and public trade history.
A market on T+ is a tradeable asset — each asset listed in the T+ registry has a corresponding market with its own order book, price and quantity decimal precision, and real-time data feeds. You interact with markets through two clients: OrderBookClient for authenticated operations (including market creation and user-specific data) and MarketDataClient for read-only public market data such as order book snapshots, klines, and public trades.
Before placing any order, fetch the Market object for the asset you want to trade. It contains the decimal precision you need to convert human-readable amounts to book-native integers.
book_price_decimals and book_quantity_decimals define the scale of integer values on the book. For example, if book_price_decimals is 6, a book price of 1_500_000 represents a human-readable price of 1.50.
Cache the Market object for each asset rather than re-fetching it on every order. The decimal precision for a given market does not change during normal operations.
Use MarketDataClient to fetch a point-in-time snapshot of the order book. The snapshot includes all current bids and asks along with a sequence_number that you can use to synchronise with the real-time depth stream.
import asynciofrom tplus.client import MarketDataClientfrom tplus.model.asset_identifier import AssetIdentifierasset = AssetIdentifier(200)async def main(): async with MarketDataClient(base_url="http://localhost:8011") as md_client: snapshot = await md_client.get_orderbook_snapshot(asset) print(f"Sequence number: {snapshot.sequence_number}") print(f"Best bid: {snapshot.bids[0] if snapshot.bids else 'empty'}") print(f"Best ask: {snapshot.asks[0] if snapshot.asks else 'empty'}")asyncio.run(main())
MarketDataClient is a read-only, unauthenticated client. Its default base URL is http://localhost:8011, matching the local market-data-service.
For real-time order book maintenance, stream incremental depth diffs and apply them on top of a snapshot:
from tplus.model.orderbook import OrderBookDiffasync for diff in md_client.stream_depth(asset): if isinstance(diff, OrderBookDiff): print(f"Seq={diff.sequence_number}, asks={len(diff.asks)}, bids={len(diff.bids)}")
Fetch recent public trades (all participants, no authentication required):
# All recent public trades across all marketstrades = await md_client.get_trades()# Trades for a specific assetasset_trades = await md_client.get_trades_for_asset(asset)for trade in asset_trades: print(f"Price: {trade.price}, Qty: {trade.quantity}")
Stream finalized trades in real time:
from tplus.model.trades import Tradeasync 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}")
CLI equivalent:
tplus trades listtplus trades list --asset 200tplus stream trades
Market data queries raise specific exceptions from tplus.exceptions:
from tplus import NotFoundError, RateLimitError, ServerErrorfrom tplus.model.asset_identifier import AssetIdentifierasset = AssetIdentifier(99999) # non-existent markettry: market = await client.get_market(asset)except NotFoundError: print("Market not found for this asset ID")except RateLimitError: print("Rate limited — back off and retry")except ServerError as err: print(f"Server error: {err}")
Some methods return empty results rather than raising NotFoundError when a resource is absent. For example, get_user_orders() returns ([], {}) for an unknown user. Check the method’s return type before assuming an exception will be raised.