New:Microsoft Teams Notifications Are Now Available in Socket.Learn more
Get Started

@luxalgo/broker-sdk

Package Overview
Dependencies
Maintainers
3
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@luxalgo/broker-sdk

Open-source broker connectivity for code, apps, and AI agents. 22 brokers, one normalized schema, zero dependencies. Your keys never leave your machine.

latest
Source
npmnpm
Version
0.5.0
Version published
Weekly downloads
933
95.6%
Maintainers
3
Weekly downloads
 
Created
Source

Broker SDK. Every broker. One schema. Your keys never leave your machine.

npm version CI Canary MIT license

Recipes  ·  Schema  ·  OAuth setup  ·  npm  ·  MCP server

Broker SDK is a LuxAlgo open-source project. Official repository: github.com/LuxAlgo/broker-sdk

Connect code, apps, and AI agents to real brokerage and exchange accounts. Point it at Charles Schwab, Alpaca, Robinhood Crypto, Binance, Kraken, Interactive Brokers and more. Get back the same clean picture from every one of them: accounts, balances, positions, trade history, and computed performance stats.

It runs where your code runs: no hosted service, no telemetry, and your keys never touch anyone else's servers.

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); // normalized: equity, positions, trades

Every broker returns the same shape. Learn it once:

type Account = {
  id: string;          // broker-side stable id, safe as an upsert key
  name: string;
  currency: string;    // ISO 4217
  equity: number;      // total account value
  cash?: number;       // when the broker reports it separately
  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);

One broker failing never takes down the sweep: failures come back alongside the snapshots that succeeded. The stats engine does FIFO round-trip matching, win rate, average win and loss, and per-symbol activity. A sell with no recorded buy is ignored, never guessed at.

Bars

Brokers that publish their own market-data endpoints can serve historical OHLCV bars with the same read-only credentials, normalized to one shape (time is the bar open in epoch ms, oldest-first):

const alpaca = connect({ broker: "alpaca", credentials: { apiKey, apiSecret } });
const from = Date.now() - 24 * 60 * 60 * 1000;
const bars = await alpaca.fetchBars("AAPL", { timeframe: "1m", from, to: Date.now() });
// [{ time, open, high, low, close, volume }, ...]
await alpaca.fetchBars("BTC/USD", { timeframe: "1h", limit: 500 }); // crypto pairs carry a slash

Supported: Alpaca (stocks on the IEX feed, crypto pairs; 1m, 5m, 15m, 1h, 1d) and Tradier (1m, 5m, 15m via timesales, 1d via history). Other brokers have no market-data endpoint, so fetchBars rejects with UnsupportedCapabilityError; check ahead with supportsBars(brokerId) or the supportsBars flag on listBrokers().

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

BrokerCredentialsTrades historyBars
Alpaca (live + paper)API key + secret
BinanceAPI key + secret (read-only)
BybitAPI key + secret (read-only)
Charles Schwabyour own OAuth2 app
Coinbaseyour own OAuth2 app (read scope)
Crypto.com ExchangeAPI key + secret (read-only)
E*TRADEyour own OAuth 1.0a app
GeminiAPI key + secret (auditor role)
Hyperliquidwallet address only
Interactive Brokers (Flex)Flex token + query ID
KrakenAPI key + secret ("Query Funds")
KuCoinAPI key + secret + passphrase (read)
OKXAPI key + secret + passphrase (read)
Public.comAPI secret key
QuestradeAPI refresh token
Robinhood CryptoAPI key + Ed25519 private key
tastytradelogin (rotating remember token)
Topstep (ProjectX)username + API key
TradeStationyour own OAuth2 app
Tradieraccess token
Trading212API key
Webull (OpenAPI)App key + secret
Any broker via CSV importa 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. Brokers reachable only through credentialed aggregators (Plaid-style: Fidelity, Chase, Vanguard) can't ship in an open-source library and are out of scope. The moment a broker opens an official retail API it becomes eligible, which is exactly how Charles Schwab and Robinhood Crypto earned their rows above. OAuth brokers where you register your own free developer app (Charles Schwab, TradeStation, E*TRADE, Coinbase) are supported bring-your-own-app style; the flow helpers and setup guide live 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.
  • 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.

Give your AI agent portfolio access

Run the LuxAlgo MCP server locally and its broker_* tools give Claude, Cursor, or any MCP client read-only access to your real accounts through this SDK. Keys go in your own MCP client config as env vars; the agent can ask "how is my portfolio doing?" but can never trade.

Drop-in connect UI

One React component renders the full "connect your broker" flow: a filterable broker picker, guided credential entry with the right fields per broker, and secret masking.

import { BrokerConnect } from "@luxalgo/broker-sdk/connect";

<BrokerConnect
  onComplete={(brokerId, credentials) => myVault.store(brokerId, credentials)}
/>;

The security contract in one sentence: credentials go only to your onComplete callback, never to LuxAlgo, and the kit never stores, transmits, or logs them itself. Not using React? The headless state machine behind the component is at @luxalgo/broker-sdk/connect/core. React is an optional peer dependency, so installs without React stay warning-free and the rest of the SDK never touches it.

Sync daemon and webhooks

Run npx broker-sync with your keys in BROKERS_* env vars (e.g. BROKERS_ALPACA_API_KEY, BROKERS_ALPACA_API_SECRET, the same convention as the MCP server) and it polls your brokers on an interval, diffs each snapshot against the last, and emits only what changed.

npx broker-sync --interval 300 --webhook-url https://example.com/hooks/portfolio --webhook-secret change-me

Events are trade_executed, balance_changed, position_opened, position_closed, position_changed, broker_error, and sync_completed, delivered per sweep as one JSON batch. When a secret is configured, every webhook request carries X-BrokerSync-Signature, the lowercase hex HMAC-SHA256 of the raw body. State persists to a local JSON file before delivery, so a crash can drop a batch but never replay one. Programmatic use lives at @luxalgo/broker-sdk/sync.

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 } }); // paper keys only
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), Tradier (sandbox only, pinned to the sandbox host so live orders are impossible by construction), and Binance Spot Testnet (pinned to testnet.binance.vision, live orders impossible by construction). Roadmap and full safety posture: docs/orders-rfc.md.

The conformance kit

Adapter architecture: fetchRaw does IO only, normalize is pure, golden vectors gate every adapter

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.

Two workflows keep the adapters honest in production:

  • Canary: a scheduled run against real read-only accounts, per broker, so a silent API change surfaces as a red badge instead of a user bug report.
  • API watch: hash-diffs each broker's public API docs and changelogs and files an issue the day something moves.

Runtime

Node ≥ 18.17 (built-in fetch; node:crypto for request signing). Zero runtime dependencies. ESM and CJS. TypeScript strict, exactOptionalPropertyTypes on. Bring your own persistence: snapshots are plain JSON.

The suite

PackageWhat it is
@luxalgo/broker-sdk (this repo)The TypeScript SDK and reference implementation
@luxalgo/mcpThe LuxAlgo MCP server; its local broker_* tools give AI agents read-only portfolio access through this SDK

Contributing

Copy-paste starting points live in docs/recipes.md; the bring-your-own-app OAuth guide (Charles Schwab, TradeStation, E*TRADE, Coinbase) in docs/byo-oauth.md. Adapter #23 is yours to add, and CONTRIBUTING.md walks you through it. 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 Global, LLC. The "Broker SDK" and "LuxAlgo" names and the LuxAlgo logo are trademarks of LuxAlgo Global, LLC; see TRADEMARKS.md. Security reports: SECURITY.md.

Keywords

broker

FAQs

Package last updated on 03 Sep 2026

Related posts