Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

tria-trade (Python)

Python port of @tria-sdk/api-trading — programmatic access to Hyperliquid and Decibel perpetuals through Tria, with builder-fee attribution. Fully async, mirrors the TypeScript SDK's surface 1:1.

Install

pip install tria-trade

Requires Python 3.11+.

Quickstart

import asyncio
from tria_trade import (
    TriaClient,
    TriaClientConfig,
    HlConfig,
    DecibelConfig,
    generate_client_order_id,
)


async def main():
    client = TriaClient(
        TriaClientConfig(
            hl=HlConfig(agent_private_key="0x…", account_address="0x…"),
            decibel=DecibelConfig(
                delegate_private_key="0x…",  # omit for a read-only Decibel client
                aptos_owner_address="0x…",  # SDK derives the primary subaccount
                node_api_key="<geomi-node-key>",  # required (Decibel rejects anonymous reads)
                gas_station="<geomi-gs-key>",  # optional — sponsored (no-APT) writes
            ),
        )
    )

    # Market data
    print(await client.ticker(venue="hl", market="BTC"))
    print(await client.markets(venue="decibel"))

    # Trade
    status = await client.place_order(
        {
            "venue": "hl",
            "market": "BTC",
            "side": "buy",
            "size": "0.001",
            "price": "50000",
            "tif": "gtc",
            "clientOrderId": generate_client_order_id(),
        }
    )
    await client.cancel_order(venue="hl", order_id=status["orderId"])


asyncio.run(main())

Build the config from a generated .env with os.environ (see examples/), or generate one with the provisioning CLI below.

Surface

Every method is async and routed through non-blocking telemetry. venue is "hl" or "decibel".

  • Orders — place_order, place_batch, modify_order, cancel_order, cancel_all_orders, order_status, open_orders, attach_tp_sl
  • Positions / account — positions, balances, margin_state, account, close_position
  • Market data — markets, ticker, orderbook, candles, recent_trades, fills
  • Risk — scheduled_cancel (HL native; Decibel raises)
  • Streams — subscribe_fills, subscribe_positions, subscribe_orders, subscribe_account, and on_connection for lifecycle events
  • Lifecycle — await client.close() releases the venue WebSocket(s), REST/HTTP clients, and the telemetry sink so the event loop can shut down. Idempotent and a no-op for REST-only callers. async with TriaClient(...) as client: calls it for you.

All amounts are decimal strings (full precision; never float). Errors raise TriaError with a .code of VENUE_REJECTED / VENUE_RATE_LIMIT / VENUE_UNREACHABLE / INVALID_ARGUMENT / MISSING_BUILDER / CONFIG.

clientOrderId is optional — omit it and the SDK mints one; provide your own to use it as a dedup key (re-using a live one is rejected). On HL, price is rounded to the venue rule (≤5 sig figs and ≤ 6 - szDecimals decimals) before signing, a fill populates OrderStatus["avgFillPrice"], and account() reads Unified Account collateral from spotClearinghouseState (account()["mode"] is "unified" / "legacy_cross").

Tiers

development=False (default) uses Tria's production builder; development=True uses the staging builder. Both trade on real mainnet venues — only the builder/treasury address differs.

Decibel: acknowledged at submit

place_order on Decibel returns state="submitted" as soon as Aptos accepts the transaction — it does not wait for the commit, and makes no indexer reads unless you supplied your own clientOrderId (one read, to reject a cloid that is already live). orderId is "" and filled / remaining are placeholders in that state; look the order up later with order_status(venue="decibel", client_order_id=...).

The commit is verified in the background. If it aborts, the SDK logs a warning on the tria_trade.decibel logger and order_status reports order_not_found. Pass "resolve": "confirmed" to await the commit (an abort then raises) and read the resolved state from the indexer. A reader failure after a successful submit (e.g. a rate limit) returns the submitted status rather than an error — the order is live either way. modify_order and close_position take the same resolve= keyword.

Cancel with market (cancel_order(venue="decibel", client_order_id=..., market="BTC/USD")) whenever you know it: the cancel then goes straight to the chain with no open-orders lookup against the venue's rate limit. Without it the SDK looks the order up (at most two reads). Indexer reads count against a per-organization rate limit shared with other Tria traffic, so prefer the default unless you need the outcome inline.

Your fee is your Tria fee

Every order carries Tria's builder address and fee in the venue payload (HL: the action's builder; Decibel: builder_addr + fee on place_order). The standard builder fee is 5 bps on both venues, and each order is charged the same fee you pay in the Tria app: your VIP trading-badge discount, your staking-badge discount and any fee offer on your account apply exactly as in the app, with the same math.

How the SDK knows your fee, without any extra credential:

  • It signs a short request with the trading key it already has (HL agent / Decibel delegate) and asks Tria which discounts apply to that account. The request carries your account address, a timestamp and that signature — never a private key.
  • Tria verifies the signature, checks with the venue that the key trades for the account, and answers with your discounts.
  • The answer is cached for the whole process (shared by every client you create) and refreshed in the background.

It never gets in the way of an order:

  • If the fee can't be determined (backend unreachable, key not yet recognised, account not linked to Tria), the order goes out at the standard fee — never higher.
  • The first order in a process waits at most ~1 second for the answer; every later order uses the cached one.
  • An offer stops applying at its end date even between refreshes.

The fee is paid by the venue out of the fill, not added on top.

Telemetry

The SDK emits anonymous usage telemetry (trade actions, latencies, error categories) to a Tria-owned proxy so the team can monitor SDK health on the same "Trade Health" dashboard the apps feed. It is non-blocking and fire-and-forget — a hung or unreachable endpoint is indistinguishable from telemetry-off and never delays or fails a trade.

  • What's collected: trade action, venue, outcome, latency, error category/ severity, size bucket, a truncated wallet (first6…last4), an optional client_id. Free-text is scrubbed of hex/base58/email runs.
  • What's never collected: private keys, full addresses, or order-level PII — the redaction pass makes leaking signing material structurally impossible.
  • Always on: telemetry is part of the SDK's operating contract and has no disable switch. TRIA_TRADE_TELEMETRY_QUIET=1 silences the one-time first-run notice (telemetry itself stays on).

Provisioning CLI

tria-trade provision sets up an operator's HL + Decibel accounts (mint the HL agent, register the Decibel delegate, approve builders, fund the venues) and writes a ready-to-use .env. All actions are signed on-chain with the operator's own master key — the wizard never calls a Tria backend.

export HL_MASTER_PRIVATE_KEY=0x…          # or TRIA_MNEMONIC="word1 word2 …"
export APTOS_MASTER_PRIVATE_KEY=0x…        # for Decibel (or derived from TRIA_MNEMONIC)
export DECIBEL_NODE_API_KEY=<geomi-key>

tria-trade provision --dry-run             # print the plan, no chain writes
tria-trade provision --hl-amount 50 --decibel-amount 50 --output .env

Flags: --hl-amount / --decibel-amount (target USDC), --output, --dry-run, --skip-hl / --skip-decibel, --development, --gas-station-key, --force-new-agent / --force-new-decibel-delegate.

Examples

See examples/: place_order.py, cancel_order.py, subscribe_fills.py, multi_venue.py. Each reads credentials from the environment — source a generated .env first.

Development

cd packages/trade-sdk-py
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"

pytest                 # unit tests (telemetry forced off)
ruff check src tests && ruff format --check src tests
mypy

Live e2e (tests/test_live_e2e.py) is skipped unless funded credentials are present at ~/.config/tria/sdk-test.env. It runs reads + far-below-market place/cancel round-trips on both venues (real signed mainnet txns; no fills; it cancels only the orders it placed). Run with TRIA_RUN_LIVE_E2E=1 pytest tests/test_live_e2e.py.

Reference

The TypeScript SDK (@tria-sdk/api-trading at packages/trade-sdk/) is the canonical implementation; this port mirrors it 1:1. The OpenAPI schema at packages/trade-sdk/openapi.yaml is the cross-language source of truth for shapes.

Metadata

Release files for tria-trade 8.6.0b0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for tria-trade 8.6.0b0
File Size Uploaded
tria_trade-8.6.0b0.tar.gz 146.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for tria-trade 8.6.0b0
File Interpreter ABI Platform
tria_trade-8.6.0b0-py3-none-any.whl Python 3 none any Details

Total release size: 271.2 kB

Release files / tria_trade-8.6.0b0.tar.gz

Download URL tria_trade-8.6.0b0.tar.gz
Size 146.9 kB
Tags Source
SHA-256 checksum
How to use checksums
b77ef92963512ff5ad587f181c9c9424926bf381bc7ede5dbd97b55ddc115d33
BLAKE2b-256 checksum
How to use checksums
84ed2aecadd3ab86ed40f8cd198bcf93b635fec5d23abac4a4eab9472a51f131
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.15

Release files / tria_trade-8.6.0b0-py3-none-any.whl

Download URL tria_trade-8.6.0b0-py3-none-any.whl
Size 124.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4b82c629ce26d96e0389fec6cd8378a707e1cc34e231aa18f98f7ecd434158d1
BLAKE2b-256 checksum
How to use checksums
8cee0f9dccaba3ebb1018d02f6c2f4f2b430e2bcd96a808a46a9f7255ad373f3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.15
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page