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. Go consumers can build a thin cgo wrapper against the unchanged C ABI in ffi/ — header at sdks/cpp/include/thetadx.h, all FFI types and free fns exported as tdx_* symbols.
Important
A valid ThetaData subscription is required. The SDK authenticates against ThetaData's Nexus API using your account credentials.
- 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.
- 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 Go/C/other-language consumer that wants to roll their own wrapper. - 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 parity checklist and 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.
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.
[dependencies]
thetadatadx = "8"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }use thetadatadx::{ThetaDataDx, Credentials, DirectConfig};
#[tokio::main]
async fn main() -> Result<(), thetadatadx::Error> {
let creds = Credentials::from_file("creds.txt")?;
let tdx = ThetaDataDx::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 = "8", 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.
pip install thetadatadxfrom thetadatadx import Credentials, Config, ThetaDataDx
tdx = ThetaDataDx(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}")npm install thetadatadximport { ThetaDataDx } from 'thetadatadx';
const tdx = await ThetaDataDx.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}`);
}#include <thetadx.hpp>
#include <cstdio>
int main() {
auto tdx = thetadatadx::ThetaDataDx::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);
}
}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.
use thetadatadx::fpss::{FpssData, FpssEvent};
use thetadatadx::fpss::protocol::Contract;
tdx.start_streaming(|event: &FpssEvent| {
match event {
FpssEvent::Data(FpssData::Quote { contract_id, bid, ask, .. }) => {
println!("Quote: {contract_id} bid={bid} ask={ask}");
}
FpssEvent::Data(FpssData::Trade { contract_id, price, size, .. }) => {
println!("Trade: {contract_id} @ {price} x {size}");
}
FpssEvent::Data(FpssData::Ohlcvc { contract_id, open, high, low, close, volume, .. }) => {
println!("OHLCVC: {contract_id} O={open} H={high} L={low} C={close} V={volume}");
}
_ => {}
}
})?;
tdx.subscribe_quotes(&Contract::stock("AAPL"))?;
tdx.subscribe_trades(&Contract::stock("AAPL"))?;All prices (bid, ask, price, open, high, low, close) are f64, decoded during parsing.
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).
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/Go 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, Java parity checklist |
| Website | docs-site/ |
VitePress documentation site (deployed to GitHub Pages) |
| Notebooks | notebooks/ |
7 Jupyter notebooks (101-107) |
thetadatadx implements the ThetaData MDDS and FPSS wire protocols and covers the terminal endpoint surface. Feature-by-feature parity and intentional deviations are tracked in docs/java-parity-checklist.md.
| Document | Description |
|---|---|
| API Reference | All typed methods, streaming builders, generated tick types, and configuration options |
| Architecture | System design, wire protocols, TOML codegen pipeline |
| Parity Checklist | Feature-by-feature protocol and endpoint parity notes |
| Endpoint Schema | TOML codegen format for adding new types/columns |
| Proto Maintenance | Guide for updating proto files |
| Changelog | Release notes with breaking changes, features, and fixes |
Contributions are welcome. See CONTRIBUTING.md for development setup, pre-commit checks, and pull-request process. Community discussion happens on the ThetaData Discord.
Licensed under the Apache License, Version 2.0. See LICENSE.