Install
openclaw skills install backtest-pollerBackground daemon that monitors QuantConnect backtests with adaptive polling, real-time equity tracking, drawdown early-stop, auto-download, and auto-diagnosis — survives terminal disconnection.
openclaw skills install backtest-pollerNever babysit a 3-hour backtest again. This skill runs a background daemon that monitors your QuantConnect backtests, auto-stops on excessive drawdown, downloads results when done, runs forensic diagnosis, and sends you a system notification.
The poller runs as a nohup background process that survives terminal disconnection. All state is persisted to state.json with file-locking to prevent CLI/poller race conditions.
User submits backtest
|
v
[Poller Daemon] (nohup, runs independently)
|
|-- Every 30-180s: check QC API
|-- Track equity & peak equity
|-- Calculate live drawdown
|
|-- If DD > threshold at 20%+ progress:
| |-- Delete backtest (early stop)
| |-- Record result
| \-- Send notification
|
|-- If completed:
| |-- Download orders.csv + result.json
| |-- Run OrderForensics diagnosis
| |-- Generate diagnosis.txt
| |-- Update state.json
| \-- Send macOS notification
|
\-- If no active backtests: exit gracefully
Instead of a fixed 30s interval (360 API calls for a 3-hour backtest), the poller adapts based on progress:
| Phase | Progress | Interval | Rationale |
|---|---|---|---|
| Startup | 0%, < 2min elapsed | 30s | Confirm backtest actually started |
| Normal | 0-30% | 120s | Steady tracking |
| Midgame | 30-80% | 180s | Low frequency, save API quota |
| Endgame | > 80% | 60s | Nearly done, check frequently |
Result: ~50 API calls instead of ~360 for a 3-hour backtest.
python3 cli.py submit \
--main-file strategy.py \
--name "MyStrategy_v1" \
--max-dd 40
python3 cli.py status
Shows a table with: name, status, progress %, current equity, live drawdown, elapsed time.
python3 cli.py logs --lines 30
python3 cli.py results --name "MyStrategy_v1" --full
python3 cli.py start-poller
python3 cli.py stop-poller
python3 cli.py clear
All state is stored in state.json:
{
"poller_pid": 12345,
"poller_running": true,
"poller_started": "2026-03-17T10:00:00",
"backtests": [
{
"backtest_id": "abc123",
"name": "MyStrategy_v1",
"status": "running",
"progress": 0.45,
"peak_equity": 12500,
"current_equity": 11200,
"live_drawdown": 0.104,
"max_dd_threshold": 0.40,
"auto_download": true,
"auto_diagnose": true
}
]
}
File-locking (fcntl.flock) prevents race conditions between the CLI and the poller daemon writing to the same file.
When a backtest completes, the poller automatically:
orders.csv and result.json to results/<name>/OrderForensics.full_diagnosis() to generate diagnosis.txtOn macOS, the poller sends a system notification via osascript when a backtest finishes.
The daemon handles SIGTERM and SIGINT for clean exit. It clears its PID from state.json only if the PID still matches (prevents stale cleanup from a different process).
state.json while the poller is running. Use the CLI commands (submit, clear) to modify state. The file uses fcntl.flock locking — manual edits bypass the lock and can corrupt state.results/ while the poller is actively downloading. Wait for the "completed" status.QC_USER_ID, QC_API_TOKEN, and QC_PROJECT_ID must be set before running any command. The skill will fail with a clear error if they are missing.