Developers

SDK Docs

Official client libraries for the Data Captain US ETF API. Same API key as the REST docs — typed helpers for list, screener, backtest, and portfolio.

Install

npm / yarn / pnpm
npm install datacaptain
# yarn add datacaptain
# pnpm add datacaptain
pip
pip install datacaptain
# python -m pip install datacaptain

Requires Node.js 18+ (native fetch) or Python 3.9+.

Authentication

Create a key in Dashboard → API Keys. The SDK sends it as the x-api-key header. Default API origin is https://datacaptain.up.railway.app (override with baseUrl / base_url — origin only, no /api suffix).

TypeScript / JavaScript

Package: datacaptain on npm

Quick start

TypeScript
import { DataCaptain, DataCaptainError } from "datacaptain";

const dc = new DataCaptain({
  apiKey: process.env.DATACAPTAIN_API_KEY!,
  // baseUrl: "https://datacaptain.up.railway.app", // optional
});

try {
  const usage = await dc.developer.usage();
  const list = await dc.etf.list({ search: "SPY", limit: 10 });
  const prices = await dc.prices.batch(["SPY", "QQQ", "VOO"]);
  const status = await dc.market.status();

  const rankings = await dc.etf.rankings({
    category: "return",
    period: "1y",
    limit: 20,
  });

  const screen = await dc.etf.screener({
    returnMin: 10,
    period: "1y",
    sort: "return",
  });

  const heatmap = await dc.etf.heatmap({ basket: "broad", period: "1y" });

  const backtest = await dc.backtest.buyAndHold({
    symbol: "SPY",
    investment: 10_000,
    startDate: "2020-01-01",
    endDate: "2024-12-31",
  });

  const compare = await dc.backtest.compare({
    symbols: ["SPY", "QQQ", "VOO"],
    investment: 10_000,
    startDate: "2018-01-01",
    endDate: "2024-12-31",
  });

  const rebalance = await dc.portfolio.rebalance({
    holdings: [
      { symbol: "SPY", value: 6000 },
      { symbol: "BND", value: 4000 },
    ],
    target: [
      { symbol: "SPY", weight: 0.6 },
      { symbol: "BND", weight: 0.4 },
    ],
    driftThreshold: 0.02,
  });

  console.log({ usage, list, prices, status, rankings, screen, heatmap, backtest, compare, rebalance });
} catch (err) {
  if (err instanceof DataCaptainError) {
    console.error(err.message, err.statusCode, err.code);
  }
  throw err;
}

Namespaces

  • dc.developer.usage() — plan & daily quota
  • dc.market.status() — US market open/closed
  • dc.prices.batch(symbols) — latest prices
  • dc.etf.* — list, get, screener, rankings, heatmap
  • dc.backtest.* — buyAndHold, compare
  • dc.portfolio.rebalance() — target weights

Python

Package: datacaptain on PyPI (stdlib HTTP — no extra deps)

Quick start

Python
import os
from datacaptain import DataCaptain, DataCaptainError

dc = DataCaptain(
    api_key=os.environ["DATACAPTAIN_API_KEY"],
    # base_url="https://datacaptain.up.railway.app",  # optional
)

try:
    usage = dc.developer_usage()
    etfs = dc.etf_list(search="SPY", limit=10)
    detail = dc.etf_get("SPY")

    screen = dc.etf_screener(
        return_min=10,
        dividend_yield_min=2,
        period="1y",
        sort="return",
    )

    heatmap = dc.etf_heatmap(basket="broad", period="1y")

    prices = dc.batch_prices(["SPY", "QQQ", "VOO"])
    status = dc.market_status()

    bt = dc.backtest_buy_and_hold(
        symbol="SPY",
        start_date="2020-01-01",
        end_date="2024-12-31",
        investment=10000,
    )

    compare = dc.backtest_compare(
        symbols=["SPY", "QQQ", "VOO"],
        start_date="2018-01-01",
        end_date="2024-12-31",
        investment=10000,
    )

    rebalance = dc.portfolio_rebalance(
        holdings=[
            {"symbol": "VOO", "shares": 63},
            {"symbol": "QQQ", "shares": 37},
        ],
        target=[
            {"symbol": "VOO", "weight": 60},
            {"symbol": "QQQ", "weight": 40},
        ],
        drift_threshold=2,
    )

    print(usage, etfs["total"], bt.get("totalReturn"))
except DataCaptainError as e:
    print(str(e), e.status_code, e.code)

Method map

CapabilityTypeScriptPython
Usagedc.developer.usage()dc.developer_usage()
Market statusdc.market.status()dc.market_status()
Batch pricesdc.prices.batch([...])dc.batch_prices([...])
ETF listdc.etf.list({...})dc.etf_list(...)
ETF detaildc.etf.get('SPY')dc.etf_get('SPY')
Screenerdc.etf.screener({...})dc.etf_screener(...)
Rankingsdc.etf.rankings({...})— (use REST /etf/rankings)
Heatmapdc.etf.heatmap({...})dc.etf_heatmap(...)
Backtestdc.backtest.buyAndHold({...})dc.backtest_buy_and_hold(...)
Comparedc.backtest.compare({...})dc.backtest_compare(...)
Rebalancedc.portfolio.rebalance({...})dc.portfolio_rebalance(...)

Errors

Both SDKs throw DataCaptainError with statusCode / status_code and optional code (plan limits, not found, etc.).