Skip to content

Install with Docker (recommended)

The supported way to run Holdout Lab is the Docker Compose bundle from holdoutlab.com/download: three commands, no toolchain, everything on your machine. (Developers who want to hack on the source use the from-source install instead.)

  • macOSDocker Desktop for Mac; Apple Silicon runs natively.
  • Windows 10/11Docker Desktop for Windows with its default WSL 2 backend (Docker Desktop sets this up itself — no extra steps).
  • LinuxDocker Desktop, or plain Docker Engine plus the compose plugin (every command below uses docker compose, the v2 plugin — not the old docker-compose binary). On Engine, add your user to the docker group or prefix the commands with sudo.
  • ~2 GB free disk to start; market data grows with what you ingest.

Install Docker and open it once so the daemon is running before you continue.

Download SHA256SUMS into the same folder as the zip, then:

Terminal window
shasum -a 256 -c SHA256SUMS --ignore-missing # macOS
sha256sum -c SHA256SUMS --ignore-missing # Linux

On Windows (PowerShell): Get-FileHash .\holdout-lab-vX.Y.Z.zip and compare the hash against the matching line in SHA256SUMS.

Download and unzip the bundle, then open a terminal in the unzipped folder.

macOS / Linux (also WSL or Git Bash on Windows):

Terminal window
./setup.sh # once: creates .env with a fresh session secret
docker compose up -d # pulls the images and starts the stack

Windows (PowerShell)setup.sh is a shell script, so create .env with these lines instead (they do exactly what the script does: copy .env.template to .env with a fresh random session secret), then start the stack:

Terminal window
$bytes = [byte[]]::new(32)
[System.Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($bytes)
$secret = -join ($bytes | ForEach-Object { $_.ToString('x2') })
(Get-Content .env.template) -replace '__GENERATE__', $secret | Set-Content .env
docker compose up -d

Open http://localhost:8080 and register — the first account becomes the owner and registration closes after it. Everything binds to 127.0.0.1; nothing is reachable from other machines, and nothing phones home.

The stack: web (the UI, the only published port), api, worker, postgres, redis — plus an optional IB gateway (below). Your database, market data, artifacts, and saved keys live on named Docker volumes, so they survive restarts and updates.

Continue with First run — register, add keys in Settings, ingest data, run the gauntlet. Two container-edition notes:

  • Zero keys needed to start: the Getting started checklist (Learn tab) can ingest the crypto starter basket from free public data, and crypto paper trading runs against live Kraken market data with no exchange account.
  • Keys you save in Settings are stored on the shared config volume — both the api and the worker read them, and they survive image updates. After saving a data key, use the in-app Restart worker button as prompted (in this edition it triggers a clean self-restart via compose).

The bundle includes an IB Gateway service (profile ib) so the app can paper-trade your own Interactive Brokers account:

  1. Put your IBKR credentials in the bundle’s .env (uncomment TWS_USERID / TWS_PASSWORD). The gateway’s headless login can’t complete app-based 2FA — see paper trading for account setup options.

  2. Start it alongside the app:

    Terminal window
    docker compose --profile ib up -d
  3. Enter your paper account id (DU…) in Settings → Interactive Brokers.

The app reaches the gateway inside the compose network (service name ib-gateway-paper); its API port is never published to the host. Gateways are compose-managed in this edition — the in-app gateway buttons show you the matching docker compose commands instead of starting containers themselves. To watch the gateway GUI (rescue an unexpected dialog), set VNC_SERVER_PASSWORD in .env and VNC to localhost:5900.

  1. Download the latest bundle from holdoutlab.com/download and replace docker-compose.yml (keep your .env).
  2. Terminal window
    docker compose pull
    docker compose up -d

Volumes are untouched: login, keys, data, and runs all persist. The running version shows in Settings → System.

Back up the database (runs, sessions, settings) any time:

Terminal window
docker compose exec -T postgres pg_dump -U ats ats > holdout-backup.sql

Restore into a fresh stack:

Terminal window
docker compose exec -T postgres psql -U ats ats < holdout-backup.sql

Market data isn’t in the dump — it re-ingests from the vendors on demand. To snapshot everything including market data, back up the Docker volumes (pgdata, appdata, artifacts, config).

  • docker compose ps — every service should be running (api and the gateway report health).
  • docker compose logs api --tail 50 (or worker, web) — startup errors land here. A missing .env means the setup step hasn’t been run (./setup.sh, or the PowerShell lines above on Windows).
  • The UI is served at http://localhost:8080 only — :5173 and :8000 belong to the developer install.
Terminal window
docker compose down # stop (data volumes are kept)
docker compose down -v # stop AND delete all data — irreversible