[Sources]

Built-in historical data sources: venue REST, mock walk, CSV upload — contracts, config, and fallbacks.

Sources

Abstract

A source loads a finite window of OHLCV bars for the chart and engine. Sources live in frontend/src/sources/catalog.ts and register into the unified registry via ensureSourcesRegistered().

Conceptual model

Built-in catalog

idNameNetworkNotes
binance-restBinance RESTyesPublic klines; synthetic walk fallback when fallback: true (default)
okx-restOKX RESTyesCandles; symbol BTCUSDTBTC-USDT; max 300 bars
bybit-restBybit RESTyesSpot v5 klines; newest-first reversed
coinbase-restCoinbase RESTyesExchange candles; USDT pair rewritten to USD product
mock-walkMock WalknoOffline random walk; optional Mulberry-like seed
csv-uploadCSV / JSON UploadnoReads last upload from upload-store

UI order is BUILTIN_SOURCES array order (Binance first).

Interface surface

Every source implements SourcePlugin (contracts):

fetchHistorical({ symbol, interval, limit?, config? }): Promise<Bar[]>

Config highlights

binance-rest

KeyDefaultMeaning
baseUrlhttps://api.binance.comOverride for mirrors/proxies
limit50050–1000
fallbacktrueOn network error, synthesizeWalk

mock-walk

KeyDefaultMeaning
seed00 = non-deterministic; non-zero = deterministic PRNG
startPrice100Walk origin
limit500Bar count

csv-upload

  • No schema fields. User must Upload a CSV (time,open,high,low,close[,volume]) or JSON array first; otherwise throws a clear error.

Internals

PathRole
frontend/src/sources/catalog.tsDefinitions + register/list/get
frontend/src/sources/upload-store.tsIn-memory last upload for csv-upload
frontend/src/data/load-symbol.tsApp pipeline that calls active source
frontend/src/data/parse-bars.tsCSV/JSON normalization

Interval → venue codes

Helpers map AXIS intervals (1m, 5m, 15m, 1h, 4h, 1d, 1w) to OKX bar, Bybit interval codes, Coinbase granularity seconds. Unmapped intervals fall back to daily-ish defaults — check venue docs if you add exotic TFs.

Dynamic registration

registerDynamicSource(plugin)  // from catalog / loader
unregisterDynamicSource(id)
listDynamicSourceIds()

Loader path: kind === 'source' + fetchHistorical required.

Invariants & edge cases

  1. Time unit — always seconds unix (Binance ms ÷ 1000).
  2. Binance fallback — offline demos “work” but are not real prices; disable fallback for strict desk research.
  3. CORS — browser → public venue APIs must allow CORS; corporate proxies may require a Worker /api/proxy (not shipped as a general proxy today — plan carefully).
  4. Newest-first venues (OKX, Bybit, Coinbase) — catalog reverses/sorts ascending by time for the chart.

Worked example

// Minimal custom source (ES module for loader)
export default {
  id: 'static-two',
  name: 'Two Bars',
  kind: 'source',
  async fetchHistorical() {
    return [
      { time: 1_700_000_000, open: 1, high: 2, low: 0.5, close: 1.5, volume: 10 },
      { time: 1_700_000_060, open: 1.5, high: 2, low: 1, close: 1.2, volume: 12 },
    ];
  },
};

Failure modes

Error / symptomFix
No uploaded file…Use Upload before selecting csv-upload
Empty chart + Binance downExpected synthetic walk if fallback on
OKX code !== '0'Symbol format / region block
CORS blockedProxy or different source

See also