Skip to main content

tpluspy: Client utilities for interacting with tplus

Project description

TPlus Python Client Utilities

Python clients for interacting with tplus.

Install

To install, use either pip or uv pip:

uv pip install -e .

CLI

tpluspy installs a tplus command for interacting with T+ services from the shell — managing local accounts, placing orders, deposits/withdrawals, and on-chain registry/vault operations. Run tplus --help for the full command tree.

For a comprehensive guide covering every subcommand, global options, and the local dev bootstrap flow, see docs/userguides/cli.md.

Usage Example

REST and WebSocket Client (tplus.client)

The tpluspy library also provides an asynchronous client (OrderBookClient) for interacting with the tplus-core REST API and WebSocket streams.

Initialization

To use the client, first initialize it with a User object (for signing requests) and the base URL of your tplus-core instance:

import asyncio
from tplus.client import OrderBookClient
from tplus.utils.user import User

API_BASE_URL = "http://127.0.0.1:8000"  # Replace with your API URL
user = User()

async def run_client():
    # Use async context manager for automatic cleanup
    async with OrderBookClient(API_BASE_URL, default_user=user) as client:
        print("Client initialized.")
        # ... use client methods ...

asyncio.run(run_client())

REST API Usage

The client offers async methods for common REST endpoints:

Fetching Data:

# Get Order Book Snapshot for asset index 200
from tplus.model.asset_identifier import AssetIdentifier

example_asset = AssetIdentifier(Index=200)
orderbook = await client.get_orderbook_snapshot(example_asset)
print(f"Snapshot Sequence: {orderbook.sequence_number}")

# Get Klines for an asset
klines = await client.get_klines(example_asset)
print(f"Klines: {klines}")

# Get Market Details for an asset
market_details = await client.get_market(example_asset)
print(f"Market Details: Price Decimals={market_details.book_price_decimals}, Quantity Decimals={market_details.book_quantity_decimals}")

# Get orders for the user
user_orders, _ = await client.get_user_orders()
print(f"User Orders: {user_orders}")

# Get trades for the user and asset
user_asset_trades = await client.get_user_trades_for_asset(example_asset)
print(f"User Asset Trades: {user_asset_trades}")

# Get user inventory
inventory = await client.get_user_inventory()
print(f"Inventory: {inventory}")

Creating Orders:

# Ensure example_asset is defined (e.g., from "Fetching Data" section)
from tplus.model.asset_identifier import AssetIdentifier
example_asset = AssetIdentifier(200)

# Create a Market for an asset (idempotent)
market_creation_response = await client.create_market(asset_id=example_asset)
print(f"Market Creation Response: {market_creation_response}")

# Create a Market Order for a specific asset
market_response = await client.create_market_order(
    asset_id=example_asset,
    quantity=10,  # integer quantity
    side="Buy",
    fill_or_kill=False,
)
print(f"Market Order Response: {market_response}")

# Create a Limit Order for a specific asset
# Good-Till-Cancelled limit order
from tplus.model.limit_order import GTC
limit_response = await client.create_limit_order(
    asset_id=example_asset,
    quantity=5,
    price=1_000,
    side="Sell",
    time_in_force=GTC(),
)
print(f"Limit Order Response: {limit_response}")

# Cancel an Order
# Order ID should be obtained from an order creation response.
order_id_to_cancel = "actual-order-id-from-api"  # Replace with a real order ID
cancel_response = await client.cancel_order(
    order_id=order_id_to_cancel,
    asset_id=example_asset
)
print(f"Cancel Order Response: {cancel_response}")

# Replace an Order
# Original Order ID should be from an existing, open order.
original_order_id_to_replace = "actual-original-order-id"  # Replace with a real order ID
replace_response = await client.replace_order(
    original_order_id=original_order_id_to_replace,
    asset_id=example_asset,
    new_quantity=6, # Optional: New integer quantity
    new_price=1050   # Optional: New integer price
)
print(f"Replace Order Response: {replace_response}")

See examples/rest_usage.py for a runnable demonstration.

WebSocket Streaming

The client provides async iterators to stream real-time data:

from tplus.model.asset_identifier import AssetIdentifier
from tplus.model.orderbook import OrderBookDiff
from tplus.model.trades import Trade

example_asset = AssetIdentifier(200)

# Stream Order Book Diffs
async for diff_update in client.stream_depth(example_asset):
    if isinstance(diff_update, OrderBookDiff):
        print(f"[Depth] Seq={diff_update.sequence_number}, Asks={len(diff_update.asks)}, Bids={len(diff_update.bids)}")
    # Add logic to handle the update, e.g., update a local order book

# Stream Finalized Trades
async for trade in client.stream_finalized_trades():
     if isinstance(trade, Trade):
        print(f"[Trade] ID: {trade.trade_id}, Price: {trade.price}, Qty: {trade.quantity}")
    # Add logic to handle the trade

# Other available streams:
# client.stream_orders() -> OrderEvent
# client.stream_all_trades() -> TradeEvent
# client.stream_klines(asset_id) -> KlineUpdate

See examples/websocket_usage.py for a runnable demonstration using asyncio.gather to run multiple streams concurrently.

Contracts

To interact with the contracts or sign T+ settlement messages, ensure you have installed the evm extra:

pip install tpluspy[evm]

Use the tplusp.contracts module to read data from t+ contracts. For example, launch a Sepolia-connected Ape console:

ape console --network ethereum:sepolia:alchemy

Note: You can use any provider you want or a RPC directly, it doesn't have to be Alchemy.

Then, once in the console, you will already have access to contracts that you can call methods on:

In [1]: registry.getAssets()
Out[1]: [getAssets_return(assetAddress=HexBytes('0x000000000000000000000000f08a50178dfcde18524640ea6618a1f965821715'), chainId=11155111, maxDeposits=100)]
In [2]: registry.admin()
Out[2]: '0x467a95fC5359edE5d5dDc4f10A1F4B680694858E'

Settlement signatures

Sign settlement messages using the structured Order type from tplus.utils.domain.

from ape import accounts, convert, chain
from tplus.utils.domain import Order
from tplus.evm.contracts import vault
from tplus.utils.user import UserManager

# Load your Ethereum account for t+.
tplus_user = accounts.load("tplus-account")

# Load your t+ user (public key).
user_id = UserManager.load("my_user").public_key

# Get the nonce from t+ or the contracts directly.
nonce = vault.getDepositNonce(tplus_user)

order = Order(
    tokenOut="0x62622E77D1349Face943C6e7D5c01C61465FE1dc",
    amountOut=convert("1 ether", int),
    tokenIn="0x58372ab62269A52fA636aD7F200d93999595DCAF",
    amountIn=convert("1 ether", int),
    userId=user_id,
    nonce=nonce,
    validUntil=chain.pending_timestamp,
)

# Use this signature for the settlement.
signature = tplus_user.sign_message(order).encode_rsv()
print(signature)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tpluspy-0.2.0.tar.gz (105.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tpluspy-0.2.0-py3-none-any.whl (139.4 kB view details)

Uploaded Python 3

File details

Details for the file tpluspy-0.2.0.tar.gz.

File metadata

  • Download URL: tpluspy-0.2.0.tar.gz
  • Upload date:
  • Size: 105.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for tpluspy-0.2.0.tar.gz
Algorithm Hash digest
SHA256 fe3e83da7ed06907650dd77572c48e50e8dc5657a60f103f501731fcc532f66f
MD5 71ca67bd1b4b7dc6ba1ab42283ac6e4f
BLAKE2b-256 889ecce8d91dac5f0d084fce9b156d98186eeb7df003fc926e615767183e5b06

See more details on using hashes here.

Provenance

The following attestation bundles were made for tpluspy-0.2.0.tar.gz:

Publisher: publish.yml on tpluslabs/tpluspy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file tpluspy-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: tpluspy-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 139.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for tpluspy-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 05b81f1d914ca6fbb0000e6716c57867c09749da2abd2c3403c652be02d81141
MD5 71dbb9efec505ccc1e28308904feccef
BLAKE2b-256 747c23b455226081560e37b8b517e2de81ec33cc53d4e84a8b2a5b1c98029481

See more details on using hashes here.

Provenance

The following attestation bundles were made for tpluspy-0.2.0-py3-none-any.whl:

Publisher: publish.yml on tpluslabs/tpluspy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page