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 (a Decibel modify_order is one atomic update and always waits for its commit; "confirmed" also reads the replacement's state). A Decibel order modified this way gets a new orderId and no client order id: track and cancel it by the returned orderId, because a cancel by the old client_order_id returns not_found while the modified order stays open. Indexer reads count against a per-organization rate limit shared with other Tria traffic, so prefer the default unless you need the outcome inline.

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, usually with no open-orders lookup against the venue's rate limit (one still happens if a gas station refuses the direct cancel, or for a client order id with capitals). Without it the SDK looks the order up (at most two reads). Pass the order's OWN market: an unknown market raises INVALID_ARGUMENT, and a different valid market returns not_found while the order stays open.

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.2b0

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.2b0
File Size Uploaded
tria_trade-8.6.2b0.tar.gz 152.2 kB Details

Built distribution (wheel)

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

Total release size: 279.4 kB

Release files / tria_trade-8.6.2b0.tar.gz

Download URL tria_trade-8.6.2b0.tar.gz
Size 152.2 kB
Tags Source
SHA-256 checksum
How to use checksums
a05f7c6f655d27a31fd20e1b5d49cbbc22694fda49e0d58a7aab0f98a3542289
BLAKE2b-256 checksum
How to use checksums
59bf5b32c8c4bafb8090ef8277f6d9054d2292279214c1930068675f87de2a4c
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.2b0-py3-none-any.whl

Download URL tria_trade-8.6.2b0-py3-none-any.whl
Size 127.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
89c87176e441ca0782f50fb9e1e869b4a43e54e673520e791db8fc62dc3eaf2a
BLAKE2b-256 checksum
How to use checksums
c10267ddfc7e4fb4c0dde2ba52ce59c1d780b9f11a0f25307d8588c79c35a17a
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