Skip to main content
OrderBookClient is your primary interface for interacting with the T+ order-management system. It wraps every order lifecycle operation — placing limit and market orders, cancelling and replacing existing orders, batch submissions, and querying your positions, inventory, and trade history — as async Python methods backed by the tplus-core REST API.

Initialization

OrderBookClient is an async context manager. Always use it inside async with to ensure underlying HTTP connections are cleaned up properly.
import asyncio
from tplus.client import OrderBookClient
from tplus.utils.user import load_user

API_BASE_URL = "http://127.0.0.1:8000"  # replace with your tplus-core URL

async def main():
    user = load_user("alice")  # loads a stored, password-encrypted keyfile

    async with OrderBookClient(API_BASE_URL, default_user=user) as client:
        # all client calls go here
        pass

asyncio.run(main())
load_user("name") reads a local keyfile and prompts for the password if required. For ephemeral/test usage, call User() from tplus.utils.user to mint a temporary keypair without storing it.
Every request is Ed25519-signed with the User object you pass. You do not need a separate API key.

Fetching Market and Book Data

Get Market Details

Retrieve the decimal precision for price and quantity on a given asset’s book. This is needed to correctly interpret integer prices and quantities returned by the API.
from tplus.model.asset_identifier import AssetIdentifier

asset = AssetIdentifier(200)
market = await client.get_market(asset)

print(f"Price decimals:    {market.book_price_decimals}")
print(f"Quantity decimals: {market.book_quantity_decimals}")

Get Order Book Snapshot

Fetch the current state of the order book for an asset, including the sequence number, all ask levels, and all bid levels.
snapshot = await client.get_orderbook_snapshot(asset)

print(f"Sequence: {snapshot.sequence_number}")
print(f"Asks: {snapshot.asks}")
print(f"Bids: {snapshot.bids}")

Get User Orders

Returns all orders associated with the authenticated user, along with the raw response payload.
orders, raw = await client.get_user_orders()

for order in orders:
    print(order)
get_user_orders() returns an empty list ([], {}) instead of raising NotFoundError when no orders exist for the user — making it safe to call unconditionally.

Get Open Orders for a Book

Fetch only the currently open orders for a specific asset.
open_orders = await client.get_open_orders_for_book(asset)
print(f"Open orders: {open_orders}")

Get User Inventory

Returns your current inventory holdings across all assets.
inventory = await client.get_user_inventory()
print(f"Inventory: {inventory}")

Get User Margin Info

Returns a breakdown of your margin usage. Pass include_positions=True to include open position details.
margin = await client.get_user_margin_info(include_positions=True)
print(margin)

Placing Orders

All prices and quantities are integers in the book’s native units. Fetch the asset’s book_price_decimals and book_quantity_decimals from get_market() to convert human-readable values into the correct integer representation.

Limit Orders

Use create_limit_order to place a resting limit order. Pass a time_in_force instance to control order lifetime.
from tplus.model.limit_order import GTC

response = await client.create_limit_order(
    asset_id=asset,
    quantity=5,
    price=1_000,
    side="Sell",
    time_in_force=GTC(),
)
print(f"Order ID: {response}")
asset_id
AssetIdentifier
required
The asset to trade. Use AssetIdentifier(index) for registry-index form.
quantity
int
required
Integer quantity in book units.
price
int
required
Integer price in book units.
side
"Buy" | "Sell"
required
Direction of the order.
time_in_force
GTC | GTD | IOC
required
Import from tplus.model.limit_order. Pass an instance, not the class itself.

Market Orders

Use create_market_order to execute immediately at the best available price. Set fill_or_kill=True to reject partial fills.
response = await client.create_market_order(
    asset_id=asset,
    quantity=10,
    side="Buy",
    fill_or_kill=False,
)
print(f"Market order response: {response}")
You can also specify base_quantity instead of quantity for quantity expressed in the base asset:
response = await client.create_market_order(
    asset_id=asset,
    base_quantity=10,
    side="Sell",
    fill_or_kill=True,
)

Batch Orders

Submit multiple orders atomically using send_multiple_orders. Build each request object individually, then pass them as a list.
from tplus.model.limit_order import GTC

# Build order request objects (exact types depend on your order builders)
req1 = await client.create_limit_order(asset_id=asset, quantity=5, price=995, side="Buy", time_in_force=GTC())
req2 = await client.create_limit_order(asset_id=asset, quantity=5, price=1005, side="Sell", time_in_force=GTC())

responses = await client.send_multiple_orders([req1, req2])
print(responses)

Managing Existing Orders

Cancel an Order

Cancel any open order by its ID and asset.
cancel_response = await client.cancel_order(
    order_id="your-order-id",
    asset_id=asset,
)
print(f"Cancelled: {cancel_response}")

Replace an Order

Atomically amend an open order’s price or quantity. You only need to pass the fields you want to change.
replace_response = await client.replace_order(
    original_order_id="your-order-id",
    asset_id=asset,
    new_quantity=8,   # optional
    new_price=1_050,  # optional
)
print(f"Replaced: {replace_response}")

User Trade and Position Data

Get Trades

Retrieve your complete trade history, or filter by a specific asset.
trades = await client.get_user_trades()
print(trades)

Check Solvency

Query your account’s current solvency status.
solvency = await client.get_user_solvency()
print(solvency)

Preview Closing All Positions

Get a preview of what would happen if all positions in a sub-account were closed, without actually submitting any orders.
preview = await client.get_close_all_positions_preview(sub_account_index=1)
print(preview)

Sub-Accounts

Transfer assets between sub-accounts on your user. Specify the source and target by their integer index.
from tplus.model.asset_identifier import AssetIdentifier

result = await client.request_transfer_to_subaccount(
    source_index=0,
    target_index=1,
    asset=AssetIdentifier(200),
    amount=500,
)
print(f"Transfer result: {result}")

Create a Market (Idempotent)

Register a new trading market for an asset. This call is idempotent — it’s safe to call multiple times; it only creates the market if it doesn’t already exist.
await client.create_market(asset_id=asset)

Error Handling

OrderBookClient raises typed exceptions from tplus.exceptions for all error conditions. Catch the most specific exception that applies to your use case.
from tplus import (
    AuthError,
    NotFoundError,
    OmsError,
    OrderRejected,
    RateLimitError,
    ServerError,
)

try:
    await client.create_limit_order(
        asset_id=asset,
        quantity=5,
        price=1_000,
        side="Buy",
        time_in_force=GTC(),
    )
except OrderRejected as err:
    print(f"Order was rejected by the matching engine: {err}")
except AuthError as err:
    print(f"Signature or authentication failure: {err}")
except RateLimitError as err:
    print(f"Rate limited — slow down: {err}")
except OmsError as err:
    print(f"OMS-level error: {err}")
except ServerError as err:
    print(f"Server-side error: {err}")
ExceptionWhen it’s raised
AuthErrorRequest signature is invalid, or the user is not recognised
NotFoundErrorThe requested resource (order, asset, user) does not exist
OmsErrorThe order-management system rejected the operation for a business-logic reason
OrderRejectedThe matching engine explicitly rejected the order (e.g. self-trade, invalid price)
RateLimitErrorToo many requests in a short window; back off and retry
ServerErrorAn unexpected 5xx error occurred on the server
Always catch OrderRejected separately from OmsError. An OmsError indicates a structural problem (wrong asset, missing market), while OrderRejected means the engine received and evaluated the order but declined it. The remediation steps differ.