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.1.tar.gz (105.6 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.1-py3-none-any.whl (140.0 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: tpluspy-0.2.1.tar.gz
  • Upload date:
  • Size: 105.6 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.1.tar.gz
Algorithm Hash digest
SHA256 dd24d7b22eaea70e7ee5b0ed369939cec68630ebd50f371ea78169395d60cb1c
MD5 c9d3e5501be59a10839da85d37c1aab2
BLAKE2b-256 ec390837cf074de4c21a9fab6f20df27179d3b952d81e991fff4b737fc82e499

See more details on using hashes here.

Provenance

The following attestation bundles were made for tpluspy-0.2.1.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.1-py3-none-any.whl.

File metadata

  • Download URL: tpluspy-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 140.0 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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 63af3c8c94aff56fb1a1fe4a48d368a41cc93b88eba6f75f0b0487936821e3e6
MD5 8160bd01a363a6001975d0521b3f3967
BLAKE2b-256 1532c08a63fef02e9dae538ff22a44c7db9756b2bdf3e391f9c990ee3110aef1

See more details on using hashes here.

Provenance

The following attestation bundles were made for tpluspy-0.2.1-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