How this is built — and what it cost me to learn.
This site is the public face of a private trading research stack: a millisecond market tape, a feature engine, a prediction model with a pre-registered gate, and a read-only pipeline that publishes results without ever exposing the trading system. Below is the actual architecture, the real numbers, and the mistakes that shaped it.
EXCHANGES INGEST + RESEARCH BOX PUBLIC BOX BROWSER
───────── ───────────────────── ────────── ───────
Binance ws ──aggTrade──▶ ┌──────────────────────┐ ┌────────────┐
Kraken ws ──trades────▶ │ ingestor → TimescaleDB│ │ candles │
│ ticks · candles │ │ footprint │
│ fut_state · liq │ │ tape │
└──────────┬───────────┘ │ depth │
│ SELECT-only, statement_timeout 20s └─────▲──────┘
▼ │
┌──────────────────────┐ rrsync -wo ┌───────────┐ fetch │
│ feature engine F1-F14│ ──────────────▶│ Caddy │────────┘
│ model → predictions │ one-way push │ static │
│ (DRY-RUN, no orders) │ 185 ──▶ 169 │ + /data │
└──────────────────────┘ └───────────┘
▲
Binance public ws ────────────────────────────────────────────────────────┘
(browser connects DIRECT — the live layer never touches the research box)
The load-bearing decision: the live layer streams from the exchange to the browser, not through our servers. The research box also runs a live trading daemon, so every public request that could reach it is one that could degrade it. Public traffic and trading are physically separate paths.
Read-only by construction
The exporter opens its database session with readonly=True and
statement_timeout='20s'. It can only issue SELECTs, and the database kills anything slow
before it can compete with the trading daemon.
One-way credentials
The push runs research → public, never the reverse, over a key pinned to
rrsync -wo on a single directory. The public box holds no credential that reaches the
trading system.
22× from reading the plan
The volume-delta aggregation took 7,007 ms with a symbol predicate and
date_trunc. Rewritten on Timescale's time_bucket it takes 319 ms.
Same result, same window.
Sign conventions get verified twice
Buy/sell classification was confirmed in two independent code paths before publication. A flipped delta sign would invalidate every order-flow number on this site while still looking plausible.
Freshness is shown, never implied
Every panel carries its own age. If a snapshot is stale or a fetch fails, the page says so and blanks the panel rather than presenting old numbers as current.
Reproducible indicators
EMA, Bollinger, VWAP and RSI are computed in your browser from the same bars we publish at
/data/candles.json. Every line on the chart can be recomputed from public data.
The model commits at a fixed point in each cycle, guarded by a time window. Interpreter startup pushed it to the very edge of that window, so 49.2% of cycles were dropped — and the loss grew with machine load, biasing the sample. Fixed by firing early and sleeping to the exact commitment moment, so every prediction lands on the operating point the model was validated at.
A profile query scanned ~1.4M rows per symbol and was scheduled every minute against the box running the trading daemon. Caught and killed within two minutes, no trading impact. The window was cut and a hard statement timeout added, so the class cannot recur.
Two sibling scripts each declared the same top-level constant. That is a syntax error which silently kills the second file — the chart simply never ran, with an empty console. Now each script is scoped, and a build gate concatenates them to reproduce the shared scope and fail on any collision.
The first version re-rendered once a minute from a file. It was accurate and completely wrong as a product — a market view that does not move is a screenshot. Rebuilt on the same charting engine our internal desk uses, streaming per tick.
Ingest & storage: Python websocket consumers, PostgreSQL + TimescaleDB hypertables.
Research: NumPy/scikit-learn feature engine (F1–F14), logistic model refit per horizon,
walk-forward validation with pre-registered promotion gates.
Publishing: read-only Python exporter, rrsync over SSH, cron with flock.
Serving: Caddy with automatic TLS behind Cloudflare, strict CSP, static assets.
Front end: vanilla JavaScript, no framework, no trackers, no cookies —
TradingView Lightweight Charts
(Apache-2.0) is the only third-party dependency,
vendored locally.
Weight: the whole front end is a few hundred KB and renders without a build step.
Vamsi Venkatesh — Magdeburg, Germany. I build and run the whole stack: ingest, research, modelling, infrastructure and front end. The most useful thing on this site is the prediction ledger, because it shows a model I built failing its own pre-registered test — measured, published, and not quietly retired.