quantecho is a self-hosted web platform I built from scratch in 2026: a Next.js front end and Python sidecars behind one gateway, on Docker Compose with encrypted backups. Its centrepiece is a backtest lab: the entry signal is a short Python function typed into the browser; everything else (universes, exits, price adjustment, caching) is fixed, explicit and tested.
- ~84klines, TypeScript + Python
- 1,303symbols: S&P 500 · CSI 300 · CSI 500
- 90tests on the backtest engine
Why
A notebook backtest is easy to write and easy to fool yourself with: the fill rule is implicit, the price series is adjusted differently from the one you looked at, the A-share settlement rule is forgotten. Here the only thing you write is the signal; the questionable decisions are made once, in tested code.
How
A pattern is a Python file with a small META block, which drives the parameter form, and an entries() function returning a boolean series per symbol, written in an embedded Monaco editor. A scan runs it across the S&P 500, CSI 300 (HS300) or CSI 500 and resolves each entry with one of three exit rules: hold N days, target or timeout, stop or target; when one bar touches both, the stop fills first. T+1 for A-shares is applied inside the engine, so pattern code never knows which market it is in. Prices are cached one parquet file per symbol, back-adjusted so ratios are consistent and re-adjusted for display; the sync layer retries through rate limits, trips a circuit breaker on repeated failures and can be cancelled. Every scan is archived as replayable JSON.
What holds it up
- One port, one session. A custom Node server serves Next.js and Socket.IO on one port and reverse-proxies the sidecars after a session check, passing uploads, downloads and SSE through untouched; the Python services carry no auth code.
- Resumable uploads. Chunked, fingerprinted, retried with backoff, persisted in the browser across reloads.
- A data-loss post-mortem. Twice, recent writes vanished after a deploy. Root cause: POSIX file locks do not cross a Docker bind mount, so a host-side SQLite connection could unlink the container's write-ahead log silently. The fix: an owner heartbeat that refuses host connections while the container holds the database, snapshots before every deploy, and a client-side outbox that does not treat a server acknowledgement as durability.
- Backups. Daily SQLite backups, GPG-encrypted.
What I did. Everything: design documents, code, tests, deployment, incident write-ups. The platform is private, with no public demo; the backtest lab is the part I can talk about.
Counts from the repositories, August 2026. Signals, scans and results are not published.