Skip to main content
Every request sent to T+ is authenticated by an Ed25519 digital signature — there are no API keys, bearer tokens, or passwords involved in signing. Your signing identity is a User object that holds a keypair; the private key never leaves your machine. tpluspy signs each order, cancel, replace, and transfer request automatically via User.sign() before it is sent over the wire.

Creating a User

You have two options: an ephemeral user (keypair lives in memory only) or a stored user (keypair is saved to disk and reloaded between sessions).
from tplus.utils.user import User

# Generates a fresh Ed25519 keypair in memory.
# The private key is discarded when the process exits.
user = User()
Use an ephemeral user for quick experiments or automated test runs. For production workflows where you want a stable identity across sessions, use a stored user.

Managing Stored Users

Stored users live under ~/.tplus/users/ as password-encrypted keyfiles. You can manage them with the UserManager class or the tplus accounts CLI commands.

Python API

from tplus.utils.user import UserManager

# List all stored user aliases
manager = UserManager()
aliases = manager.list()
print(aliases)  # e.g. ["alice", "bob"]

CLI Commands

1

Generate a new keypair

tplus accounts generate alice
Creates a fresh Ed25519 keypair and saves it to ~/.tplus/users/alice (prompts for an encryption password).
2

Import an existing private key

tplus accounts add alice --private-key <hex>
Pass your existing Ed25519 private key as a hex string. Omit --private-key to be prompted securely.
3

List stored accounts

tplus accounts list
4

Inspect a specific account

tplus accounts show alice
Displays the public key and metadata for the alice keyfile.

Keyfile Storage

All keyfiles are stored at ~/.tplus/users/<alias>. The directory is created automatically on first use. Each file contains the Ed25519 private key encrypted with a password you supply at generation time.
Back up your ~/.tplus/users/ directory to avoid losing access to your T+ identity. The private key cannot be recovered if the keyfile is lost.

Signing Model

T+ uses its own signing scheme across all request types: Ed25519 over compact JSON (no spaces, sorted keys). Every order, cancel, replace, transfer, and settlement request carries this signature. tpluspy handles all of this automatically — you never call User.sign() directly during normal order flow; just pass the User object to OrderBookClient and the client takes care of signing.
import asyncio
from tplus.client import OrderBookClient
from tplus.utils.user import load_user

async def main():
    user = load_user("alice")
    async with OrderBookClient(user=user, base_url="http://127.0.0.1:8000") as client:
        # All requests made through `client` are automatically signed by `user`.
        orders, _ = await client.get_user_orders()
        print(orders)

asyncio.run(main())

Sub-accounts

T+ supports sub-accounts for inventory isolation within a single signing identity. Sub-accounts are identified by an integer index (starting at 0 for the default account). They are useful when you want to segregate positions or run multiple strategies under one keypair without creating separate users. You specify the sub-account index when placing orders or querying state:
from tplus.model.asset_identifier import AssetIdentifier

asset = AssetIdentifier(200)

# Place a limit order in sub-account 1
from tplus.model.limit_order import GTC

response = await client.create_limit_order(
    asset_id=asset,
    quantity=5,
    price=1_000,
    side="Buy",
    time_in_force=GTC(),
    sub_account_index=1,
)
You can also transfer inventory between sub-accounts:
# Transfer 100 units of `asset` from sub-account 0 to sub-account 1
await client.request_transfer_to_subaccount(
    source_index=0,
    target_index=1,
    asset=asset,
    amount=100,
)
Or use the CLI:
tplus orders transfer --source 0 --target 1 --asset 200 --amount 100

Automation: the TPLUS_PASSWORD Environment Variable

When running tpluspy in CI or unattended scripts, set the TPLUS_PASSWORD environment variable to supply the keyfile decryption password without an interactive prompt:
export TPLUS_PASSWORD="my-secure-password"
python my_bot.py
TPLUS_PASSWORD bypasses the getpass prompt. Avoid setting it in shared shell sessions or committing it to source control. Use a secrets manager or environment injection in CI instead.