Skip to main content
T+ does not use ticker symbols like "BTC" or "ETH-PERP" to refer to assets. Instead, it uses an AssetIdentifier — a T+-specific value that uniquely identifies a tradeable asset on the exchange. Every order, market query, and inventory lookup requires a valid AssetIdentifier. Understanding the two accepted forms, and how to construct them correctly, is essential before placing any trades.

The Two Accepted Forms

Registry Index

An integer (or its string representation) that maps to an asset’s position in the T+ registry. This is the simplest form when you already know the index.

address@chain_id

An EVM token contract address paired with the T+ 9-byte chain ID. Used when you have an on-chain address and need to construct the identifier without knowing the registry index.

Registry Index

from tplus.model.asset_identifier import AssetIdentifier

# Both forms are equivalent
asset = AssetIdentifier(200)
asset = AssetIdentifier("200")
The index comes from the T+ asset registry. You can retrieve the full asset list with tplus assets list (see the CLI guide) or by querying the clearing engine. When the backend sends an asset identifier over the wire, it serialises both forms as plain strings ("200" or "<address>@<chain>").

address@chain_id

from tplus.model.asset_identifier import AssetIdentifier, AssetAddress
from tplus.model.types import ChainID

# Build the AssetAddress from an EVM contract address and EVM chain ID.
# The helper converts the raw EVM chain ID to the T+ 9-byte chain ID for you.
addr = AssetAddress.from_evm_address("0xYourTokenAddress", chain_id=42161)

# Construct the AssetIdentifier from the AssetAddress
asset = AssetIdentifier(str(addr))
AssetIdentifier("BTC-PERP") or any ticker-style string will not work. T+ has no symbol namespace — always use an index or an address@chain_id string.

Chain IDs: T+ 9-byte Format vs. Raw EVM Chain IDs

This is the most common source of errors when constructing asset identifiers manually. T+ uses its own 9-byte chain ID format (18 hex characters), not the raw integer chain ID you see in MetaMask or EVM tooling.
Do not pass a raw EVM chain ID (e.g. 42161) directly into the address@chain_id string. T+ will reject it. Always convert with the helpers below.

Converting an EVM Chain ID

from tplus.model.types import ChainID

# Arbitrum One: EVM chain ID 42161 → T+ chain ID
chain = ChainID.evm(42161)
print(chain)  # ChainID('00000000000000a4b1')
The 9-byte format is <routing_id:1B><vm_id:8B>. Hand-encoding this is error-prone — always use ChainID.evm() for EVM-compatible chains.

Advanced: from_parts

For non-EVM chains or custom routing configurations, use ChainID.from_parts:
chain = ChainID.from_parts(routing_id=1, vm_id=101)
The simplest path for EVM assets is to let AssetAddress.from_evm_address handle the chain ID conversion entirely:
from tplus.model.asset_identifier import AssetAddress

# Pass the EVM chain ID as an integer — the conversion is automatic.
addr = AssetAddress.from_evm_address(
    "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9",  # USDT on Arbitrum
    chain_id=42161,
)
# addr is now "0xFd086b...@00000000000000a4b1"

AssetAddress vs. ChainAddress

Both names refer to the same underlying type, but the choice of name signals semantic role at the call site:

AssetAddress

Use when the address refers to a tradeable asset — constructing an AssetIdentifier, identifying tokens in settlement requests, or looking up decimals.
from tplus.model.asset_identifier import AssetAddress

addr = AssetAddress.from_evm_address("0x...", chain_id=42161)
asset = AssetIdentifier(str(addr))

ChainAddress

Use when the address refers to a non-asset chain-scoped entity — deposit vaults, the asset registry, the credential manager, or market-maker EOAs.
from tplus.model.types import ChainAddress

# e.g. a vault address returned by the clearing engine
vaults: list[ChainAddress] = await ce_client.vaults.get()
Ask yourself: “Is this thing tradable?” If yes, use AssetAddress. If no (vault, registry, EOA), use ChainAddress.

Common Mistakes

Using a raw EVM chain ID in a string literal

# ❌ Wrong — 42161 is the EVM integer chain ID, not the T+ chain ID
asset = AssetIdentifier("0xToken@42161")

# ✅ Correct — use the helper to get the 18-hex-char T+ chain ID
addr = AssetAddress.from_evm_address("0xToken", chain_id=42161)
asset = AssetIdentifier(str(addr))

Using a ticker symbol

# ❌ Wrong — T+ has no ticker/symbol namespace
asset = AssetIdentifier("ETH-PERP")

# ✅ Correct — use the registry index
asset = AssetIdentifier(200)

Passing Asset Identifiers to Client Methods

Most OrderBookClient and MarketDataClient methods accept AssetIdentifier | str. Build the identifier once and pass the object through — don’t re-stringify it on every call:
from tplus.model.asset_identifier import AssetIdentifier
from tplus.client import OrderBookClient
from tplus.utils.user import load_user

asset = AssetIdentifier(200)

async with OrderBookClient(user=load_user("alice"), base_url="http://127.0.0.1:8000") as client:
    market = await client.get_market(asset)
    orders, _ = await client.get_user_orders()
    snapshot = await client.get_orderbook_snapshot(asset)