Alpaca Trade API JS

repository·master·Indexed 20 days ago

https://github.com/alpacahq/alpaca-trade-api-js

A TypeScript SDK for the Alpaca Trading and Market Data APIs. Version 4.0.1 provides a unified client with typed errors, resilience, and real-time streaming capabilities for Node.js and Bun. The SDK includes automated migration helpers (codemods) for upgrading from v3 to v4 and requires Node.js version 20 or higher.

Tokens
62.2K
Snippets
165
Records
232
Agent score
69%

What's inside @alpacahq/alpaca-trade-api

  1. Overview of @alpacahq/alpaca-trade-api

    master

    The @alpacahq/alpaca-trade-api is a TypeScript SDK designed for interacting with both the Alpaca Trading API and Market Data API. It provides a unified Alpaca client and includes several advanced features for production-grade trading applications:

    • Unified Client: A single Alpaca client for both trading and market data.
    • Resilience: Opt-in features including retries with observability, timeouts, rate limiting, and secure-by-default redirects.
    • Data Handling: Pagination helpers, normalized market-data accessors, and typed errors/response metadata.
    • Order Management: Ergonomic order builders.
    • Real-time Data: WebSocket streaming for both trading and market data.
    • Compatibility: Dual ESM + CJS builds; requires Node ≥ 20.
  2. Key features demonstrated in the starter-dashboard

    master

    The starter-dashboard serves as a learning template for the @alpacahq/alpaca-trade-api SDK, demonstrating the following capabilities:

    • Client Usage: Utilizing a single Alpaca client instance.
    • Trading API Reads: Fetching data for accounts, positions, assets, and orders.
    • Market Data API Reads: Fetching latest prices and historical daily bars.
    • Order Helpers: Using ergonomic methods for order placement, specifically alpaca.trading.orders.market() and alpaca.trading.orders.limit().
    • Error Handling: Implementing typed ApiError handling that includes request IDs.
    • Rendering Pattern: Uses REST-only server rendering and server actions (no WebSockets or SSE).
  3. Configure redirect behavior

    master

    By default, the client is configured with redirect: "error". This means any 3xx response will cause the request to fail immediately rather than following the redirect.

    Security Warning: Alpaca APIs do not typically redirect. If you set redirect: "follow" and a redirect occurs to an off-host target, the SDK will not strip the APCA-API-* secret headers. This could expose your credentials to a third party. Only use redirect: "follow" if you are behind a trusted redirecting proxy.

  4. Handle large 64-bit Trade IDs

    master

    Trade IDs (especially in crypto) are 64-bit integers that can exceed JavaScript's safe integer range (2^53). To prevent data loss, canonical Trade records expose two ID fields:

    • id: number: A convenient but potentially lossy representation for values past 2^53.
    • idRaw?: string: The exact, lossless string representation. Use idRaw for comparing, storing, or using IDs as keys.

    Warning on Raw Endpoints: If using raw generated models (e.g., alpaca.marketData.crypto.cryptoTrades(...).trades[sym][i].i), the ID may arrive as a string at runtime even if the type definition says number. It is highly recommended to use the canonical getCryptoTrades accessor instead.

    const trades = await alpaca.marketData.getCryptoTrades({ symbols: "BTC/USD", loc: "us" });
    const t = trades["BTC/USD"][0];
    t.id;    // number — fine to display, lossy past 2^53
    t.idRaw; // e.g. "8857581800245878123" — exact; use this to compare/store/key
  5. How the Trading and Market Data namespaces are organized

    master

    The @alpacahq/alpaca-trade-api package uses a single-package, two-namespace architecture. The Trading API and the Market Data API are exposed via the trading and marketData namespaces respectively.

    This separation is used to prevent naming collisions between the two distinct API specifications, as both specs define a CorporateActionsApi and contain overlapping model names.

  6. Understand Data Feeds and the 15-minute free tier delay

    master

    Data Feeds

    US-equity endpoints accept a feed parameter:

    • iex: Free tier.
    • sip: Paid tier (includes all US exchanges).
    • otc, boats: Other available feeds.

    Note on Defaults: For REST, if you omit feed, Alpaca selects the best feed your subscription allows. For streaming, the SDK defaults to feed: "iex" to ensure free keys work out of the box.

    The 15-minute Rule (Free Plan)

    On the free plan, SIP data for the last 15 minutes is restricted.

    • If you explicitly request feed: "sip" with an end time defaulting to now, you will receive a 403 error.
    • If using iex, the trailing ~15 minutes may be sparse or empty. To ensure data is present on the free tier, set your end parameter to at least 15 minutes in the past.

    Paper vs Live

    The paper flag only affects the trading host (paper-api vs api). It does not affect market data; all market-data REST and stream calls go to data.alpaca.markets regardless of your trading environment.

  7. Unify REST and Streaming data with marketDataShapes

    master

    The marketDataShapes namespace provides a way to use the same data models for both historical REST data and real-time WebSocket streams. This allows you to backfill history and then append live updates to the same array without reconciling different object structures.

    • REST models: Use compact wire keys (e.g., StockBar is { o, h, l, c, v, vw, n, t }).
    • Streaming models: Use readable camelCase keys.
    • marketDataShapes: Bridges these into a single canonical shape (e.g., Bar, Trade, Quote).

    Normalized Accessors

    The Alpaca client provides normalized accessors that return these canonical shapes automatically:

    • getStockBars, getCryptoBars, getOptionBars
    • getStockTrades, getCryptoTrades
    • getStockQuotes, getCryptoQuotes
    • getStockCandles, getCryptoCandles

    For single-symbol requests, use the *For(symbol) variants (e.g., getStockBarsFor) to get the unwrapped value directly instead of a symbol-keyed map.

    import { Alpaca, marketDataShapes, TimeFrame } from "@alpacahq/alpaca-trade-api";
    
    const alpaca = new Alpaca({ keyId, secret });
    
    // 1. Fetch history as canonical Bars: { [symbol]: Bar[] }
    const history = await alpaca.marketData.getStockBars({
      symbols: ["AAPL"], 
      timeframe: TimeFrame.Day, 
      start: new Date("2024-01-01"),
    });
    
    // 2. Live bars arrive in the SAME shape - just append them.
    const stream = alpaca.marketData.stockStream({ feed: "iex" });
    stream.onBar((bar) => history.AAPL?.push(bar)); // bar is a Bar
    stream.onConnect(() => stream.subscribeForBars(["AAPL"]));
    stream.connect();
  8. Handle High-Precision Timestamps and Trade IDs in 4.x

    master

    Version 4.x introduces additive fields to resolve precision issues found in 3.x.

    Nanosecond Timestamps

    To avoid the millisecond truncation issue in 3.x, use the timestampRaw field. This field provides an RFC-3339 string with nanosecond precision. The standard timestamp field remains a millisecond Date for backward compatibility.

    64-bit Trade IDs

    Crypto trade IDs can exceed the JavaScript safe integer range (2^53). To prevent lossy conversion, 4.x provides an idRaw string field alongside the numeric id field.

    Recommendation: Use idRaw when comparing, storing, or using IDs as keys. On raw generated models, an ID exceeding 2^53 will surface as a string rather than a number to ensure losslessness.

  9. Regeneration-safe durability mechanisms

    master

    The project uses three specific mechanisms to handle deviations from standard typescript-fetch output without manual file editing:

    1. Null-safe required arrays: Uses a forked Mustache template (templates/typescript-fetch/modelGeneric.mustache) to add a json['x'] == null ? [] : guard. This prevents runtime errors when a required array is null in a payload.
    2. Undocumented-field passthrough: Uses a vendor extension x-ts-passthrough combined with forked templates to allow certain models (like Account and Order) to keep unknown fields via ...json spread and extends Record<string, unknown>.
    3. Feed enum tightening: Uses a JSON Patch overlay (overlays/market-data.patch.json) to retarget untyped strings (like stock_auction_feed) to existing enum schemas (like StockHistoricalFeed).
  10. Use Order Builders for Trading

    master

    The alpaca.trading.orders namespace provides ergonomic, typed builders for placing various order types. These builders enforce required fields at compile time and require a clientOrderId for audit and recovery. This approach replaces the generic postOrder wrapper with specific methods for each order kind.

    // Place a market order
    const clientOrderId = crypto.randomUUID();
    await alpaca.trading.orders.market({ symbol: "AAPL", side: "buy", qty: 1, clientOrderId });
    
    // Place a bracket order (entry + take-profit + stop-loss)
    const clientOrderId = crypto.randomUUID();
    await alpaca.trading.orders.bracket({
      symbol: "AAPL",
      side: "buy",
      qty: 1,
      takeProfit: { limitPrice: 160 },
      stopLoss: { stopPrice: 140 },
      clientOrderId
    });
  11. Understand retry semantics and order-submission safety

    master

    Retry Semantics

    • Automatic Retries: Enabled by default on the Alpaca client (1 initial + 2 retries). Raw Api classes require manual opt-in.
    • Safe Verbs Only: Retries only occur for idempotent methods (GET, HEAD, OPTIONS, TRACE).
    • Non-idempotent Methods: POST, PUT, PATCH, and DELETE are never auto-retried. This ensures order-placement POST requests are never replayed.
    • Network Failures: Transient failures (DNS, connection reset, TLS) are retried for safe verbs. A deliberate AbortSignal or timeoutMs deadline is not retried.
    • Backoff: Uses exponential backoff (doubling per attempt) starting from retryDelayMs up to maxDelayMs, with ±20% jitter. It honors the Retry-After header if present.

    Order-Submission Safety

    To prevent duplicate orders during ambiguous network failures, always provide a stable, unique clientOrderId.

    Crucial Safety Step: If a FetchError occurs during a POST request, the outcome is ambiguous. Before retrying, call getOrderByClientOrderId({ clientOrderId }) to check if the order was actually accepted. Do not assume a lookup miss means the order failed.

    const clientOrderId = `mean-reversion-${crypto.randomUUID()}`;
    const order = await alpaca.trading.orders.market({
      symbol: "AAPL",
      qty: 1,
      side: "buy",
      clientOrderId,
    });
  12. How the OpenAPI Regeneration Pipeline works

    master

    The pipeline (src/run.ts) follows a strict sequence to ensure the generated code remains a 'frozen' and reproducible output:

    1. Toolchain Setup: Downloads the pinned generator JAR and locates a working JDK.
    2. Fetch & Diff: Fetches latest specs from docs.alpaca.markets, canonicalizes them, and performs a semantic diff against pinned specs. It detects added/removed/modified schemas and operations, as well as moved or renamed operations.
    3. Confirm & Adopt: Prompts the user to overwrite pinned specs. --yes handles additive changes, but removals require --allow-breaking-spec-removals to prevent accidental breaking changes.
    4. Derive: Applies JSON Patch overlays (found in overlays/) to the pinned spec to create the final generator input.
    5. Generate: Executes openapi-generator using forked Mustache templates (found in templates/typescript-fetch/).
    6. Cleanup: Removes stale files from apis/ and models/ that are no longer present in the new generator manifest.
    7. Safety Gate: Runs typecheck, lint, test, and docs:api to ensure the new code is valid.
    8. Orphan Report: Generates a report diffing apis/index.ts and models/index.ts to identify potential broken references in hand-written code (e.g., in src/client.ts, src/orders.ts, etc.).