Limeint Trade API — Python SDK
Limeint's Python SDK for the gRPC Trade API. It wraps the generated stubs with:
- a single
TradeAPIClient/AsyncTradeAPICliententry point, - automatic JWT issuance and background refresh (via
AuthService.SubscribeJwtRenewal), - a
from_rpc_error()helper for typed errors, - exponential-backoff retries for
UNAVAILABLEand server-approved rate-limit retries.
Service methods are invoked directly on the generated stubs, without an extra request or response translation layer.
Installation
Python 3.10 or newer is required.
This checkout currently targets 2.18.2, which is on PyPI. Create and activate
a virtual environment, then install it:
python3 -m venv .venv
source .venv/bin/activate
python -m pip install limeint-sdk==2.18.2
The PyPI distribution is
limeint-sdk; the Python import name istrade_api.
Quick start
The first program authenticates and prints the account IDs visible to the secret. It is bounded and does not place an order.
Save this as quickstart.py:
import os
from trade_api import TradeAPIClient
from trade_api.auth_messages import TokenDetailsRequest
secret = os.environ["TRADE_API_SECRET"]
with TradeAPIClient(secret=secret) as client:
token = client.get_token()
if token is None:
raise RuntimeError("Authentication did not return a token")
details = client.auth.TokenDetails(TokenDetailsRequest(token=token))
print("Available account IDs:", list(details.account_ids))
Run it inside the activated virtual environment:
TRADE_API_SECRET=... python quickstart.py
If authentication fails, confirm that the secret is active. An empty account list means the token does not expose a trading account; it may still be usable for market data if it has the required entitlement.
To fetch one of the discovered accounts, extend the program like this:
import os
from trade_api import TradeAPIClient
from trade_api.accounts import GetAccountRequest
from trade_api.auth_messages import TokenDetailsRequest
with TradeAPIClient(secret=os.environ["TRADE_API_SECRET"]) as client:
token = client.get_token()
if token is None:
raise RuntimeError("Authentication did not return a token")
details = client.auth.TokenDetails(TokenDetailsRequest(token=token))
if not details.account_ids:
raise RuntimeError("This secret exposes no accounts")
account_id = details.account_ids[0]
account = client.accounts.GetAccount(GetAccountRequest(account_id=account_id))
print(account)
Asyncio quick start
import asyncio
import os
from trade_api import AsyncTradeAPIClient
from trade_api.auth_messages import TokenDetailsRequest
async def main() -> None:
async with AsyncTradeAPIClient(secret=os.environ["TRADE_API_SECRET"]) as client:
token = client.get_token()
if token is None:
raise RuntimeError("Authentication did not return a token")
details = await client.auth.TokenDetails(TokenDetailsRequest(token=token))
print("Available account IDs:", list(details.account_ids))
asyncio.run(main())
Subscribe to market data
Streaming RPCs return iterators. This synchronous example runs until Ctrl-C; leaving the context manager closes the channel and token-renewal stream:
import os
from trade_api import TradeAPIClient
from trade_api.market_data import SubscribeQuoteRequest
with TradeAPIClient(secret=os.environ["TRADE_API_SECRET"]) as client:
for tick in client.market_data.SubscribeQuote(
SubscribeQuoteRequest(symbols=["AAPL@XNAS"])
):
print(tick)
The repository also includes focused examples for authentication and accounts, async quote streaming, and real order placement with cancellation. They live in a standalone consumer project that installs the published package by default.
Available services
The client currently exposes these Trade API services as sub-clients:
| Attribute | gRPC service | What it does |
|---|---|---|
client.auth |
AuthService |
Token issuance + details (usually automatic). |
client.accounts |
AccountsService |
Accounts, positions, trades, transactions. |
client.assets |
AssetsService |
Instruments, exchanges, schedules, options. |
client.market_data |
MarketDataService |
Bars, quotes, order book, trade streams. |
client.orders |
OrdersService |
Place / cancel orders, order + trade streams. |
client.metrics |
UsageMetricsService |
API usage / quota metrics. |
The protobuf contracts also contain CorporateActionsService, but the current
Python client does not yet expose it as a sub-client. The Node.js SDK does.
API reference
Every RPC belonging to the services listed below is exposed directly on its sub-client. Request and response message types are re-exported from short, per-service modules:
| Module | Use with |
|---|---|
trade_api.accounts |
client.accounts.* |
trade_api.assets |
client.assets.* |
trade_api.market_data |
client.market_data.* |
trade_api.orders |
client.orders.* (includes Side) |
trade_api.metrics |
client.metrics.* |
trade_api.auth_messages |
client.auth.* (rarely needed — JWT handled automatically) |
The original deeply-nested paths
(trade_api.proto.grpc.tradeapi.v1.<service>.<service>_service_pb2)
still work and remain the source of truth.
Legend: ▶ unary · ⇉ server-stream · ⇄ bidi-stream
client.auth — AuthService
| Method | Kind | Purpose |
|---|---|---|
Auth(AuthRequest) |
▶ | Exchange API secret for a JWT. Called for you on construction. |
TokenDetails(TokenDetailsRequest) |
▶ | Inspect a JWT — expiry, market-data permissions, visible account IDs. |
SubscribeJwtRenewal(SubscribeJwtRenewalRequest) |
⇉ | Stream of refreshed JWTs. Consumed for you in the background. |
client.accounts — AccountsService
| Method | Kind | Purpose |
|---|---|---|
GetAccount(GetAccountRequest) |
▶ | Account info: equity, cash, positions, margin. |
Trades(TradesRequest) |
▶ | Historical trades for an account. |
Transactions(TransactionsRequest) |
▶ | Cash movements and other non-trade transactions. |
SubscribeAccount(GetAccountRequest) |
⇉ | Streaming account updates. |
client.assets — AssetsService
| Method | Kind | Purpose |
|---|---|---|
Exchanges(ExchangesRequest) |
▶ | List of supported exchanges. |
Assets(AssetsRequest) |
▶ | Tradable instruments (filtered). |
AllAssets(AllAssetsRequest) |
▶ | Full instrument catalog. |
GetAsset(GetAssetRequest) |
▶ | Single instrument by symbol. |
GetAssetParams(GetAssetParamsRequest) |
▶ | Trading parameters for an instrument. |
OptionsChain(OptionsChainRequest) |
▶ | Options chain for an underlying. |
Schedule(ScheduleRequest) |
▶ | Trading session schedule. |
Clock(ClockRequest) |
▶ | Server clock (use for time-aligned operations). |
GetConstituents(GetConstituentsRequest) |
▶ | Index constituents. |
client.market_data — MarketDataService
| Method | Kind | Purpose |
|---|---|---|
Bars(BarsRequest) |
▶ | OHLC candles (any timeframe via TimeFrame enum). |
LastQuote(QuoteRequest) |
▶ | Most recent quote snapshot. |
OrderBook(OrderBookRequest) |
▶ | Order book snapshot. |
LatestTrades(LatestTradesRequest) |
▶ | Most recent trades for a symbol. |
SubscribeQuote(SubscribeQuoteRequest) |
⇉ | Live quote stream. |
SubscribeOrderBook(SubscribeOrderBookRequest) |
⇉ | Live order-book updates. |
SubscribeLatestTrades(SubscribeLatestTradesRequest) |
⇉ | Live trades stream. |
SubscribeBars(SubscribeBarsRequest) |
⇉ | Live candle stream. |
client.orders — OrdersService
| Method | Kind | Purpose |
|---|---|---|
PlaceOrder(Order) |
▶ | Place market / limit / stop / stop-limit / multi-leg order. |
PlaceSLTPOrder(SLTPOrder) |
▶ | Place an SL/TP (stop-loss + take-profit) order. |
CancelOrder(CancelOrderRequest) |
▶ | Cancel an active order. |
GetOrders(OrdersRequest) |
▶ | List active orders for an account. |
GetOrder(GetOrderRequest) |
▶ | Single order by ID. |
SubscribeOrders(SubscribeOrdersRequest) |
⇉ | Live order-state updates. |
SubscribeTrades(SubscribeTradesRequest) |
⇉ | Live execution / fill stream. |
SubscribeOrderTrade(stream OrderTradeRequest) |
⇄ | Bidi stream — order + trade events, request-driven. |
client.metrics — UsageMetricsService
| Method | Kind | Purpose |
|---|---|---|
GetUsageMetrics(GetUsageMetricsRequest) |
▶ | API usage / quota stats for the current token. |
Client lifecycle
| Operation | Sync | Async |
|---|---|---|
| Construct | TradeAPIClient(secret, *, endpoint=DEFAULT_ENDPOINT, retry_policy=DEFAULT_POLICY, channel_options=None) |
AsyncTradeAPIClient(secret, ...) — same args |
| Start | immediate, blocks for initial JWT | await client.start() — or use async with |
| Current JWT | client.get_token() → str | None |
client.get_token() → str | None (sync read of cached snapshot) |
| Close | client.close() |
await client.close() |
| Context manager | with TradeAPIClient(...) as client: |
async with AsyncTradeAPIClient(...) as client: |
| Testing (no TLS) | TradeAPIClient.for_testing(secret, endpoint="localhost:50051") |
AsyncTradeAPIClient.for_testing(secret, endpoint="localhost:50051") |
for_testing(...)opens an insecure (plaintext) channel against an in-process fake server. Never use againstapi.limeint.eu— it sends your JWT in clear.
Error handling
SDK calls raise raw grpc.RpcError instances. Use from_rpc_error() when your
application benefits from the SDK's typed TradeAPIError hierarchy:
import grpc
from trade_api import TradeAPIClient, RateLimitError, from_rpc_error
with TradeAPIClient(secret="...") as client:
try:
client.accounts.GetAccount(GetAccountRequest(account_id="A12345"))
except grpc.RpcError as raw:
err = from_rpc_error(raw)
if isinstance(err, RateLimitError):
...
raise err
Exception classes: AuthError (401), PermissionDeniedError (403),
InvalidArgumentError (400), NotFoundError (404), RateLimitError (429),
InternalError (500), ServiceUnavailableError (503), DeadlineExceededError (504).
All inherit from TradeAPIError.
Retries
Unary RPCs retry UNAVAILABLE automatically with exponential backoff and
jitter. RESOURCE_EXHAUSTED is retried only when the server supplies
grpc-retry-pushback-ms; otherwise the SDK returns the rate-limit error instead
of amplifying the throttle. Streaming RPCs are not retried — the caller is
expected to reconnect at a meaningful boundary, such as the last received bar.
Override the policy:
from trade_api import TradeAPIClient, RetryPolicy
policy = RetryPolicy(max_attempts=6, initial_backoff=0.5, max_backoff=10.0)
client = TradeAPIClient(secret="...", retry_policy=policy)
Local build
From the repository root:
cd sdk/python
uv sync --locked
uv run ./scripts/generate_proto.sh
uv run ruff check trade_api tests
uv run mypy trade_api
uv run pytest
scripts/generate_proto.sh compiles the .proto files in ../../proto/ into
trade_api/proto/. Re-run it whenever the protos change.
Layout
sdk/python/
├── pyproject.toml
├── uv.lock
├── README.md
├── LICENSE
├── scripts/
│ └── generate_proto.sh # protoc invocation (contributors only)
└── trade_api/
├── __init__.py
├── client.py # TradeAPIClient (sync)
├── aio.py # AsyncTradeAPIClient
├── auth.py # JWT lifecycle
├── retry.py # retry policy + interceptors
├── exceptions.py # typed errors
├── _insecure_auth.py # plaintext test-channel authentication
├── _metadata.py # Authorization header plumbing
├── _services.py # lazy generated-service registry
├── accounts.py # message re-exports (per-service)
├── assets.py
├── auth_messages.py
├── market_data.py
├── orders.py
├── metrics.py
└── proto/ # generated by CI; ships in wheel and sdist
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 limeint_sdk-2.19.0.tar.gz.
File metadata
- Download URL: limeint_sdk-2.19.0.tar.gz
- Upload date:
- Size: 108.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
99ef2b2fe686059f35e576a1fd1718236f8c560db85a1f8876637ee5b6ccee7e
|
|
| MD5 |
70e99d32e57a896cbc7b1d870eebaad5
|
|
| BLAKE2b-256 |
f31b38795c1927c28db34aad6c4a5d919b52e6463b976da28fa3c67e0e0042ac
|
Provenance
The following attestation bundles were made for limeint_sdk-2.19.0.tar.gz:
Publisher:
publish_python.yml on limeint/tradingapi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
limeint_sdk-2.19.0.tar.gz -
Subject digest:
99ef2b2fe686059f35e576a1fd1718236f8c560db85a1f8876637ee5b6ccee7e - Sigstore transparency entry: 2504604858
- Sigstore integration time:
-
Permalink:
limeint/tradingapi@9baf1b036fb2ad944889aaa400cb514df58b1936 -
Branch / Tag:
refs/tags/2.19.0 - Owner: https://github.com/limeint
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish_python.yml@9baf1b036fb2ad944889aaa400cb514df58b1936 -
Trigger Event:
release
-
Statement type:
File details
Details for the file limeint_sdk-2.19.0-py3-none-any.whl.
File metadata
- Download URL: limeint_sdk-2.19.0-py3-none-any.whl
- Upload date:
- Size: 127.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7b6a4dcbad1102cd6275656d67b8c2a0f8db6f94a15594824245b36a8f0138a4
|
|
| MD5 |
060b969b91974ee2a9ed960407022d4f
|
|
| BLAKE2b-256 |
94567ca391d2ea32acae4e50c6527a9f111aadd2f57cfdaa50f8f74f6642e852
|
Provenance
The following attestation bundles were made for limeint_sdk-2.19.0-py3-none-any.whl:
Publisher:
publish_python.yml on limeint/tradingapi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
limeint_sdk-2.19.0-py3-none-any.whl -
Subject digest:
7b6a4dcbad1102cd6275656d67b8c2a0f8db6f94a15594824245b36a8f0138a4 - Sigstore transparency entry: 2504606002
- Sigstore integration time:
-
Permalink:
limeint/tradingapi@9baf1b036fb2ad944889aaa400cb514df58b1936 -
Branch / Tag:
refs/tags/2.19.0 - Owner: https://github.com/limeint
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish_python.yml@9baf1b036fb2ad944889aaa400cb514df58b1936 -
Trigger Event:
release
-
Statement type: