Skip to content

gordon-data

Purpose

gordon-data is the sole writer of the market_data.* schema. It ingests live market feeds from Binance (REST + WebSocket), Deribit, alternative.me, DefiLlama, and FRED; precomputes higher-timeframe candles (5m through 1w) from the canonical 1m source via pure SQL; and publishes KlineEvent payloads to the NATS JetStream bus via an atomic dual-write outbox. Every downstream consumer — bots, manager, risk, executor, console, lab — reads market data through either the REST surface or, in the case of gordon-risk and gordon-manager, named Postgres views. There is no consumer-facing WebSocket; that path was deleted in Wave 2 of the event-bus migration (2026-05-08).

Version + port + env var

FieldValue
Version3.6.0
Port8081
Env overrideGORDON_DATA_BIND_ADDR
DB rolegordon_data_writer
Imageghcr.io/dlepaux/gordon-data

HTTP endpoints

Health / ops

MethodPathPurpose
GET/healthzLiveness probe
GET/readyzReadiness probe (DB + role probe must pass)
GET/metricsPrometheus metrics
GET/configRedacted config dump
GET/openapi.jsonOpenAPI spec

Business endpoints

GroupExample pathsPurpose
KlinesGET /klines, GET /perp_klinesSpot and perp OHLCV with timeframe + symbol params
DerivativesGET /funding, GET /open_interest, GET /long_short_ratioDerivatives data by symbol + range
SentimentGET /fear_greed, GET /stablecoin_supply, GET /metrics_dataMacro + sentiment indicators
GEXGET /gexGamma exposure (Deribit)
LiquidationsGET /liquidationsBinance liquidation feed
MacroGET /macroFRED macro data
WarmupPOST /warmupBot warmup — returns strict-completeness candle slice
InventoryGET /inventorySymbol + timeframe availability
Sources healthGET /sources/healthPer-source freshness rows (source_freshness table)
Sources scheduleGET /sources/scheduleScheduler run log
Backfill triggersPOST /backfill/{source}Trigger backfill job per source (spot_klines, perp_klines, funding_rates, fear_greed, stablecoin_supply, gamma_exposure, metrics, precompute_klines, open_interest)
Backfill jobsGET /backfill/jobs, GET /backfill/jobs/{job_id}, DELETE /backfill/jobs/{job_id}List, inspect, cancel backfill jobs
Backfill reportsGET /backfill/{source}/reportCoverage report per source

NATS subjects

PatternRoleDirection
market.klines.binance.spot.{symbol_lc}.{tf}Publishes KlineEvent via leader-elected outboxPublisher
market.klines.binance.perp.{symbol_lc}.{tf}Perp klines (if wired)Publisher

Stream: gordon-bus, 168h retention. Dual-write: KlineEvent is written atomically inside the same sqlx transaction as the spot_klines INSERT via gordon_bus::nats::outbox_publisher. No durable consumers owned by gordon-data.

Database access

ActionDetail
Writermarket_data.* — sole writer, enforced via gordon_data_writer role
Role probeStartup verifies positive + negative privileges before binding HTTP; connecting as gordon superuser aborts
Views usedNone — data service owns the tables, others read via views

Prometheus metrics

  • data_fetch_total
  • data_fetch_duration_seconds
  • data_rows_written_total
  • gordon_data_source_quarantined_total
  • gordon_data_source_unquarantined_total
  • gordon_data_source_command_unknown_variant_total
  • gordon_data_source_gap_seconds
  • gordon_data_source_gap_seconds_by_symbol
  • gordon_errors_total

Key env vars

VariablePurpose
GORDON_DATA_BIND_ADDRHTTP bind address (default :8081)
GORDON_DATABASE_URLPostgres connection string (must use gordon_data_writer role)
GORDON_BUS_NATS_URLNATS JetStream URL for outbox publisher
BINANCE_API_KEY / BINANCE_API_SECRETRead-only Binance keys (startup probe rejects trading-capable keys)
FRED_API_KEY / FRED_API_KEY_ALIASFRED macro data fetch

Invariants

  • Sole writer. market_data.* writes enforced at the DB layer. No other service may INSERT into this schema.
  • Read-only Binance keys only. Startup probe queries /sapi/v1/account/apiRestrictions; aborts if any enable_* flag other than enable_reading is true. Key identity is separate from gordon-executor's trading keys.
  • Fail loud on missing precomputed timeframe. Never returns silent empty arrays for an unmaterialized timeframe.
  • Aggregation rules are a workspace contract. Rust and Python (lab) must produce bit-identical candles. See workspace CLAUDE.md klines pipeline section.
  • Outbox atomicity. KlineEvent is dual-written (DB row + bus outbox) inside one transaction. A partial write is a bug.
  • No /ws endpoint. The consumer-facing WebSocket was deleted in Wave 2 (2026-05-08). The live tail for bots runs via NATS JetStream.

Status

Phase 2 (Data): 16/16 complete (2026-04-19). Backend close-out audit passed (2026-04-22) — zero #[allow], clippy pedantic + nursery clean. Stable.

OBS-6 (2026-05-17): WS sources (BinanceKlines, BinancePerpKlines, BinanceLiquidations) now write source_freshness rows via a 1 Hz health-metrics-refresh task, closing the console blind spot for WS-continuous sources.

Gordon — keep compounding without blowing up