Christian CortezPlay the 3D version

Systems project · May 2026

QuantLab

A self-hosted research platform for reproducible portfolio backtesting and risk analytics, with background jobs on Redis/RQ workers.

Role
Sole author
Status
Release candidate for private, self-hosted use
Stack
Python, FastAPI, PostgreSQL, Redis / RQ, Docker, GitHub Actions
Source
OHLCV records indexed
1M+
bundled data is synthetic
Redis/RQ workers
4–8
jobs from 30 seconds to 10 minutes
API endpoints
18
validated with automated tests in CI

The problem

Backtests are easy to write and easy to get quietly wrong: a signal peeks at tomorrow's price, the universe only holds companies that survived, or nobody can regenerate last month's result.

QuantLab treats each of those failures as an engineering requirement with a test, and runs every long computation as a tracked background job.

Architecture

QuantLab request and job flow

The browser talks to a Next.js front end, which proxies API calls to FastAPI. Routes never run simulations: they record a job in PostgreSQL and enqueue only its id on Redis. RQ workers run the domain library, read versioned Parquet datasets through DuckDB, and write results back to PostgreSQL. A reaper redelivers jobs whose worker died.

  • Browser to Next.js web
  • Next.js web to FastAPI (/api/*)
  • FastAPI to PostgreSQL (record job)
  • FastAPI to Redis (enqueue id)
  • Redis to RQ workers (deliver)
  • RQ workers to Parquet versions (read)
  • RQ workers to PostgreSQL (results)
  • Reaper to PostgreSQL (scan)
  • The domain library imports no web or database code, so every numerical routine is testable in isolation.
  • Redis only delivers job ids. Job state lives in PostgreSQL with database-time leases and fencing tokens, so a stale worker cannot overwrite a newer attempt.
  • Every result carries a manifest: dataset version, engine, input hash and output fingerprint.

Decisions and trade-offs

  1. Routes never compute

    HTTP handlers validate, record a job and enqueue its id; workers do the work.

    Trade-off: Every analysis becomes asynchronous, but the API stays responsive and long jobs survive a web restart.

  2. Undefined is reported as undefined

    Ratios that cannot be computed are shown as undefined with a reason, never printed as zero.

    Trade-off: The output is less tidy, and much harder to misread.

  3. Content-addressed datasets

    Market data versions are immutable Parquet files addressed by content.

    Trade-off: Storage grows with each version, and any result can be regenerated exactly from its manifest.

How it is tested

  • An independent reference engine, written from the methodology without importing the engine, must agree to 1e-9 on 50 seeded synthetic universes.
  • Mutation tests inject 36 known defects, such as a one-bar look-ahead or a delisting a day early; the suites must catch each one.
  • Integration tests run against real PostgreSQL and Redis, and Playwright end-to-end tests include an axe accessibility audit.

Outcomes

  • Backtests compute volatility, beta, Sharpe ratio, drawdown, value at risk and expected shortfall, with a research integrity report on each experiment.
  • The release candidate was verified from a fresh clone.

Scope: QuantLab is research infrastructure, not a trading bot. All bundled data is synthetic, results are never investment advice, and it is not publicly deployed.