Install and initialize Lean CLI
Prerequisites
Local backtests and reports run in Docker. Install Docker and verify that your user can access it. Lean CLI initialization also requires a QuantConnect organization on a paid tier.
This repository manages Lean CLI in its uv environment:
cd /home/hi/qrt
uv add lean
uv run lean --versionThe tested version is lean 1.0.227. uv run lean ... is equivalent when the virtual environment is not activated.
Lean CLI and the LEAN engine are different versioned components. The Python package supplies the CLI; local backtests run a Docker image such as quantconnect/lean:latest.
Configure Docker access
LEAN must reach Docker without sudo from the same Linux user that starts Python or Jupyter. With a system Docker daemon, add that user to the socket’s group:
sudo usermod -aG docker <username>
getent group dockerGroup membership is captured when a login session starts. End every existing SSH, VS Code Remote SSH, terminal, and Jupyter session for that user, then reconnect. Verify the new session before opening the notebook:
id
stat -c 'owner=%U group=%G mode=%A' /var/run/docker.sock
docker versionid must include the socket group (normally docker), and docker version must print both Client and Server sections. Rootless Docker is also supported when it is configured for the Jupyter user.
Membership in the docker group is effectively root-level access to the host. Grant it only to trusted users. Never run the notebook as root, invoke the backtest with sudo, or pass a sudo password to q.bt.lean.
Closing a local VS Code window may leave its remote server and Jupyter kernels running. After changing groups, use Remote-SSH: Kill VS Code Server on Host…, close all connections to that host, and reconnect. See Docker permission denied.
Initialize a workspace
The tracked Sweden demo contains algorithms and generators but intentionally does not commit the organization-bound lean.json. Initialize it once per checkout:
cd /home/hi/qrt/lean/demo-generated-data
uv run lean init --organization <organization-name-or-id> --language pythonInitialization creates:
demo-generated-data/
├── lean.json
└── data/
lean.jsonconfigures the engine and pointsdata-folderatdata.data/contains sample native LEAN data, market hours, and symbol properties.
Create ordinary projects with lean create-project NAME. The tested fixture instead keeps demo.py, universe_demo.py, and demo_sma.py at the workspace root and always passes the desired file explicitly.
Run commands through uv
Run commands from the repository environment, even after changing into a LEAN workspace:
cd /home/hi/qrt
uv run lean --version
uv run python lean/demo-generated-data/source/generate_data.py
uv run lean backtest lean/demo-generated-data/demo.py --no-updateuv run resolves Python and Lean CLI from /home/hi/qrt/.venv without depending on shell activation state.
Protect custom metadata
Lean CLI periodically replaces the public market-hours and symbol-properties databases. Disable the global refresh while maintaining custom entries:
uv run lean config set database-update-frequency _
uv run lean config listThe fixture also sets this workspace value in lean.json:
"file-database-last-update": "12/31/2099 00:00:00"Keep the loose CSV providers when custom map and factor files are not packaged in LEAN’s bulk ZIP format:
"map-file-provider": "QuantConnect.Data.Auxiliary.LocalDiskMapFileProvider",
"factor-file-provider": "QuantConnect.Data.Auxiliary.LocalDiskFactorFileProvider"Pin the engine for reproducibility
lean backtest ... --no-update uses the Docker image already present locally instead of pulling the latest tag. It does not disable database refreshes or pin an immutable image digest.
For durable production reproducibility, configure a versioned image tag or digest and record it with each run.