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 .
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(user=user, base_url=API_BASE_URL) 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+ specific EIP-712 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'
EIP-712
Sign EIP-712 messages, such as settlements, using the eip712 library.
from ape import accounts, convert, chain
from tplus.evm.eip712 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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tpluspy-0.1.0a0.tar.gz.
File metadata
- Download URL: tpluspy-0.1.0a0.tar.gz
- Upload date:
- Size: 51.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c1b5a4f3c43b04113bb25d5cbaa1fd3bcb63ba111b237d7ae0485fd7cd783847
|
|
| MD5 |
0704dcf29c18c4243fc8c71be5fa54a2
|
|
| BLAKE2b-256 |
7b66c71f23c9f25a8a20098a4edc2c55366167bcbaa9e22f39c4056c28b4d9a7
|
File details
Details for the file tpluspy-0.1.0a0-py3-none-any.whl.
File metadata
- Download URL: tpluspy-0.1.0a0-py3-none-any.whl
- Upload date:
- Size: 51.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
376a3de9c87422d423654e427ac37774fead7aab685eeebf256fa4ff17bbdf97
|
|
| MD5 |
2df0b1d247d8fd0ede87bdc32166e661
|
|
| BLAKE2b-256 |
31176b6ddba98c9c5c739ed8fa49c218000e0cae24198c09a95a24fc59ebc194
|