73 stable releases (9 major)
| new 10.0.0 | May 9, 2026 |
|---|---|
| 9.1.0 | May 9, 2026 |
| 8.0.37 | May 7, 2026 |
| 7.3.1 | Apr 17, 2026 |
| 1.2.4 | Mar 26, 2026 |
#51 in Finance
134 downloads per month
2MB
39K
SLoC
ThetaDataDx
Rust SDK for ThetaData market data — single Rust core, four language surfaces (Rust, Python, TypeScript, C++).
thetadatadx is a native Rust SDK for ThetaData market data. It connects directly to ThetaData's three public surfaces — MDDS (historical request/response over gRPC), FPSS (real-time streaming over TCP), and FLATFILES (whole-universe daily blobs over the legacy MDDS port) — decodes ticks in-process, and exposes a typed API across Rust, Python, TypeScript, and C++ from a single Rust core. No JVM, no subprocess, no IPC serialization. Third-party C consumers can integrate against the unchanged C ABI in ffi/ — header at sdks/cpp/include/thetadx.h, all FFI types and free functions exported as tdx_* symbols.
Important
A valid ThetaData subscription is required. The SDK authenticates against ThetaData's Nexus API using your account credentials.
Requirements
- Rust 1.88 or newer. Declared as
rust-version = "1.88"on every workspace[package]; the Linux Lint job in CI is pinned to this floor so dependency bumps that raise the rustc requirement surface before release. - A valid ThetaData subscription for the live endpoints.
Highlights
- Typed everywhere. 61 ThetaData endpoints exposed as typed methods across all four SDKs; no raw JSON or protobuf on the public surface.
- Arrow-backed DataFrames. Python
to_arrow()/to_pandas()/to_polars()pipe through shared Arrow buffers. - SPKI-pinned FPSS TLS. Public-key pinning on the FPSS streaming handshake.
- FIT decoder + SPSC ring buffer on the FPSS path. Decode cost is measured in the benchmarks under
crates/thetadatadx/benches/. - Shared FFI layer. C++ and Node.js go through the same
extern "C"layer; the Python wheel uses PyO3 ABI3 directly. The C ABI is also the supported integration path for any third-party C / C++ consumer. - Covers all three public surfaces. MDDS gRPC endpoints, FPSS wire format with reconnect semantics, and the FLATFILES daily-blob protocol — every transport speaks directly to ThetaData's production servers from a single client. See the vendor flat-file reference.
- FLATFILES daily blobs. Pull whole-universe
(sec_type, req_type, date)blobs over the legacy MDDS port; decode to vendor-byte CSV, JSONL, or a typedVec<FlatFileRow>in memory. Cross-language coverage is tracked under the binding issues; the Rust core is shipped today.
Quick start
Tip
Credentials can be supplied as a creds.txt file (email on line 1, password on line 2), inline via Credentials::new("email", "password"), or through the THETADATA_EMAIL / THETADATA_PASSWORD environment variables.
Rust
[dependencies]
thetadatadx = "9"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
use thetadatadx::{ThetaDataDxClient, Credentials, DirectConfig};
#[tokio::main]
async fn main() -> Result<(), thetadatadx::Error> {
let creds = Credentials::from_file("creds.txt")?;
let tdx = ThetaDataDxClient::connect(&creds, DirectConfig::production()).await?;
let eod = tdx.stock_history_eod("AAPL", "20240101", "20240301").await?;
for tick in &eod {
println!("{}: O={} H={} L={} C={} V={}",
tick.date, tick.open, tick.high, tick.low, tick.close, tick.volume);
}
Ok(())
}
Opt into chainable DataFrame ergonomics by enabling the polars and/or arrow features. Both stay out of the default dep graph:
[dependencies]
thetadatadx = { version = "9", features = ["polars"] }
use thetadatadx::frames::TicksPolarsExt;
let eod = tdx.stock_history_eod("AAPL", "20240101", "20240301").await?;
let df = eod.as_slice().to_polars()?;
The arrow feature exposes a TicksArrowExt::to_arrow that materialises an arrow_array::RecordBatch with the same schema the Python .to_polars() / .to_arrow() terminal produces. features = ["frames"] pulls both in.
Python
pip install thetadatadx
from thetadatadx import Credentials, Config, ThetaDataDxClient
tdx = ThetaDataDxClient(Credentials.from_file("creds.txt"), Config.production())
for tick in tdx.stock_history_eod("AAPL", "20240101", "20240301"):
print(f"{tick.date}: O={tick.open:.2f} H={tick.high:.2f} "
f"L={tick.low:.2f} C={tick.close:.2f} V={tick.volume}")
TypeScript / Node.js
npm install thetadatadx
import { ThetaDataDxClient } from 'thetadatadx';
const tdx = await ThetaDataDxClient.connectFromFile('creds.txt');
for (const t of tdx.stockHistoryEOD('AAPL', '20240101', '20240301')) {
console.log(`${t.date}: O=${t.open} H=${t.high} L=${t.low} C=${t.close} V=${t.volume}`);
}
C++
#include <thetadx.hpp>
#include <cstdio>
int main() {
auto tdx = thetadatadx::ThetaDataDxClient::connect_from_file("creds.txt");
for (const auto& t : tdx.stock_history_eod("AAPL", "20240101", "20240301")) {
std::printf("%d: O=%.2f H=%.2f L=%.2f C=%.2f V=%lld\n",
t.date, t.open, t.high, t.low, t.close, (long long)t.volume);
}
}
Streaming
One connection, one auth. Historical queries are available immediately; streaming connects lazily on first subscription. The client auto-reconnects and re-subscribes all active contracts on involuntary disconnect.
The primary streaming surface is the fluent contract-first API —
Contract::stock("AAPL").quote() returns a typed Subscription value
that the polymorphic client.subscribe(...) accepts directly:
use thetadatadx::fpss::{FpssData, FpssEvent};
use thetadatadx::prelude::*;
tdx.start_streaming(|event: &FpssEvent| {
match event {
FpssEvent::Data(FpssData::Quote { contract, bid, ask, .. }) => {
println!("Quote: {} bid={bid} ask={ask}", contract.symbol);
}
FpssEvent::Data(FpssData::Trade { contract, price, size, .. }) => {
println!("Trade: {} @ {price} x {size}", contract.symbol);
}
_ => {}
}
})?;
let stock = Contract::stock("AAPL");
let option = Contract::option("SPY", "20260620", "550", "C")?;
tdx.subscribe(stock.quote())?;
tdx.subscribe(option.trade())?;
tdx.subscribe(SecType::Option.full_open_interest())?;
// Bulk install:
tdx.subscribe_many(vec![stock.quote(), option.quote()])?;
All prices (bid, ask, price, open, high, low, close) are f64, decoded during parsing.
All prices (bid, ask, price, open, high, low, close) are f64, decoded during parsing.
API coverage
61 registry/REST endpoints plus 4 SDK-only historical stream variants, FPSS real-time streaming, and a full Black-Scholes Greeks calculator.
| Category | Endpoints | Examples |
|---|---|---|
| Stock | 14 | EOD, OHLC, trades, quotes, snapshots, at-time |
| Option | 34 | Same as stock + 5 Greeks tiers, open interest, contracts |
| Index | 9 | EOD, OHLC, price, snapshots |
| Calendar | 3 | Market open/close, holiday schedule |
| Interest Rate | 1 | EOD rate history |
All endpoints return fully typed data in every language. See the API Reference for the complete method list.
Additional surfaces (not REST/gRPC endpoints): FPSS real-time streaming (7 subscribe/unsubscribe methods per contract and per full-stream type) and a local Greeks calculator (22 Black-Scholes Greeks plus an IV solver, callable individually or batched).
Architecture
flowchart TB
subgraph core["Rust core"]
direction TB
thetadatadx["<b>thetadatadx</b><br/>auth · MDDS gRPC · FPSS TCP · decode"]
tdbe["<b>tdbe</b><br/>types · FIT / FIE codec · Greeks · Price"]
thetadatadx --> tdbe
end
ffi["<b>ffi</b><br/>stable C ABI · panic boundary"]
core --> ffi
core -->|PyO3 / maturin| python["Python SDK<br/>(pyo3 · Arrow)"]
ffi -->|napi-rs| ts["TypeScript SDK<br/>(N-API · BigInt)"]
ffi -->|extern C| cpp["C++ SDK<br/>(RAII header-only)"]
core -->|tonic| rust["Rust consumer<br/>(direct crate)"]
classDef coreStyle fill:#1e3a8a,stroke:#0c1e5c,color:#fff
classDef ffiStyle fill:#7c2d12,stroke:#450a0a,color:#fff
classDef sdkStyle fill:#14532d,stroke:#052e16,color:#fff
class thetadatadx,tdbe coreStyle
class ffi ffiStyle
class python,ts,cpp,rust sdkStyle
| Layer | Crate / package | Purpose |
|---|---|---|
| Encoding / types | crates/tdbe |
Tick structs, FIT/FIE codecs, Greeks, Price |
| Core SDK | crates/thetadatadx |
MDDS gRPC client, FPSS streaming, auth |
| C FFI | ffi/ |
Stable extern "C" layer consumed by C++, Node.js, and any third-party C / C++ consumer |
| Python | sdks/python |
PyO3 / maturin wheel with Arrow DataFrame adapter |
| TypeScript | sdks/typescript |
napi-rs prebuilt binary |
| C++ | sdks/cpp |
RAII header-only wrapper |
| CLI | tools/cli |
tdx CLI — every generated historical endpoint from the command line |
| MCP | tools/mcp |
MCP server - gives clients access to every generated historical endpoint plus offline tools over JSON-RPC |
| Server | tools/server |
REST + WebSocket server exposing the /v3/* route surface |
| Docs | docs/ |
API reference, architecture, attribution |
| Website | docs-site/ |
VitePress documentation site (deployed to GitHub Pages) |
| Notebooks | notebooks/ |
7 Jupyter notebooks (101-107) |
Documentation
| Document | Description |
|---|---|
| API Reference | All typed methods, streaming builders, generated tick types, and configuration options |
| Architecture | System design, wire protocols, TOML codegen pipeline |
| Endpoint Schema | TOML codegen format for adding new types/columns |
| Proto Maintenance | Guide for updating proto files |
| Roadmap | Per-binding coverage status |
| Changelog | Release notes with breaking changes, features, and fixes |
Contributing
Contributions are welcome. See CONTRIBUTING.md for development setup, pre-commit checks, and pull-request process. Community discussion happens on the ThetaData Discord.
License
Licensed under the Apache License, Version 2.0. See LICENSE.
Dependencies
~36–60MB
~1M SLoC