@luxalgo/broker-sdk
Connect code, apps, and AI agents to real brokerage and exchange accounts — with the user's own API keys, running wherever the user's code runs.
Point it at Alpaca, Binance, Bybit, Kraken, Tradier, Hyperliquid, Interactive Brokers and more, and get the same clean, normalized picture from every one of them: accounts, balances, positions, trade history, and computed performance stats.
No hosted service. No per-connection fees. No keys ever leaving your environment.
npm install @luxalgo/broker-sdk
Your portfolio in five lines
import { connect } from "@luxalgo/broker-sdk";
const kraken = connect({ broker: "kraken", credentials: { apiKey, apiSecret } });
const snapshot = await kraken.fetchSnapshot();
console.log(snapshot.accounts);
Every broker returns the same shape. Learn it once:
type Account = {
id: string;
name: string;
currency: string;
equity: number;
cash?: number;
environment?: "live" | "paper";
positions: { symbol: string; quantity: number; marketValue?: number }[];
trades: { symbol: string; side: "buy" | "sell"; quantity: number; price: number; fee?: number; executedAt?: string }[];
};
Your whole portfolio, every broker at once
import { createPortfolio } from "@luxalgo/broker-sdk";
import { computeStats } from "@luxalgo/broker-sdk/stats";
const portfolio = createPortfolio();
portfolio.add({ broker: "alpaca", credentials: { apiKey, apiSecret } });
portfolio.add({ broker: "binance", credentials: { apiKey, apiSecret } });
portfolio.add({ broker: "hyperliquid", credentials: { walletAddress } });
const { snapshots, failures } = await portfolio.fetchAll();
const stats = computeStats(
snapshots.flatMap((s) => s.accounts.map((a) => ({ ...a, broker: s.broker }))),
);
console.log(stats.totalEquity, stats.trades?.winRate, stats.topPositions);
The stats engine does FIFO round-trip matching, win rate, average win/loss, and per-symbol activity — a sell with no recorded buy is ignored, never guessed at.
Import any broker statement
No API? Any account at any institution is importable from a trade-history CSV. The parser is tolerant on headers (brokers disagree on column names) and strict on rows (anything unreadable is skipped and counted, never guessed):
import { parseStatementCsv, positionsFromTrades } from "@luxalgo/broker-sdk/csv";
const { trades, skippedRows, contentHash } = parseStatementCsv(csvText);
const positions = positionsFromTrades(trades);
Supported brokers
| Alpaca (live + paper) | API key + secret | ✅ |
| Binance | API key + secret (read-only) | — |
| Bybit | API key + secret (read-only) | — |
| Coinbase | your own OAuth2 app (read scope) | — |
| Crypto.com Exchange | API key + secret (read-only) | — |
| E*TRADE | your own OAuth 1.0a app | ✅ |
| Hyperliquid | wallet address only | ✅ |
| Interactive Brokers (Flex) | Flex token + query ID | ✅ |
| Kraken | API key + secret ("Query Funds") | — |
| OKX | API key + secret + passphrase (read) | — |
| Public.com | API secret key | ✅ |
| Questrade | API refresh token | ✅ |
| Topstep (ProjectX) | username + API key | ✅ |
| Tradier | access token | ✅ |
| Trading212 | API key | — |
| Webull (OpenAPI) | App key + secret | — |
| Any broker via CSV import | a statement file | ✅ |
listBrokers() returns every adapter with its exact credential fields and a one-line guide to creating the key with read-only scope — which is all this SDK ever needs.
Sanctioned APIs only. If a broker does not officially support programmatic access for its users, it is not in this repo — no scraping, no reverse-engineered private APIs, ever. That's why you won't find Robinhood here. Brokers reachable only through credentialed aggregators (Plaid-style: Fidelity, Schwab, Chase…) can't ship in an open-source library and are out of scope. OAuth brokers where you register your own free developer app (E*TRADE, Coinbase) are supported bring-your-own-app style — the flow helpers and setup guide are in docs/byo-oauth.md.
Read-only, local-only, by design
- Your keys stay yours. The SDK runs where your code runs. There is no LuxAlgo server in the path, no telemetry, no phoning home. We don't want your keys.
- Read-only by default. The root export reads accounts, balances, positions, and history — nothing in it can place an order. Every adapter documents the minimal read-only scope its key needs.
- Credential rotation is first-class. Brokers with single-use tokens (Questrade) hand the rotated credentials back through
onCredentialsRotated so you can persist them before the old ones die.
- Fail-soft, never fabricate. A position the broker can't price has no
marketValue rather than a made-up one. A history row that can't be read is skipped and counted, not guessed.
Place orders (experimental)
The write layer lives in a deliberately separate module — importing the SDK never gives code trading capability by accident:
import { connectTrading } from "@luxalgo/broker-sdk/orders";
const trading = connectTrading({ broker: "alpaca", credentials: { apiKey, apiSecret } });
const order = await trading.placeOrder({ symbol: "AAPL", side: "buy", type: "limit", quantity: 5, limitPrice: 180.5 });
await trading.cancelOrder(order.id);
Supported: Alpaca (paper by default; a live account additionally requires acknowledgeLiveTrading set to the exact LIVE_TRADING_ACKNOWLEDGEMENT sentence — never a boolean, never a default) and Tradier (sandbox only, pinned to the sandbox host so live orders are impossible by construction). Roadmap and full safety posture: docs/orders-rfc.md.
The conformance kit
The schema plus golden test vectors live in conformance/vectors/ — one per adapter, pairing a raw provider payload with the exact normalized output. Every adapter splits into an IO-only fetchRaw and a pure normalize, so the mapping of every broker is tested without a network or credentials, and every community adapter must pass the gate before merge. The same vectors keep the Python SDK provably identical in behavior.
Runtime
Node ≥ 18.17 (built-in fetch; node:crypto for request signing). Zero runtime dependencies. ESM and CJS. Bring your own persistence — snapshots are plain JSON.
The suite
broker-sdk (this repo) — the TypeScript SDK and reference implementation.
brokers-py — the Python SDK, built against the same conformance vectors after the 1.0 freeze.
brokers-mcp — a local MCP server wrapping this SDK, giving AI agents read access to your real portfolio with keys that never leave your machine.
Contributing
Recipes live in docs/recipes.md; the bring-your-own-app OAuth plan (E*TRADE, Coinbase) in docs/byo-oauth.md. Adapter #15 is yours to add — see CONTRIBUTING.md. The short version: sanctioned user-key APIs only, split fetch/normalize, ship a conformance vector, pass the gate.
Disclaimer
This software reports what your broker reports. It is not investment advice, and nothing in it recommends any trade. Use at your own risk; verify important numbers against your broker's own statements.
License
MIT © LuxAlgo