No description
  • Python 99.8%
  • Dockerfile 0.2%
Find a file
pregno 0acf982651 Run multiple live configurations in parallel (#4)
Closes #3

Co-authored-by: Pi Worker <pi-worker@example.com>
Reviewed-on: #4
Reviewed-by: pippero-bot <pregno+bot@pm.me>
2026-06-22 23:37:38 +02:00
.pippero Run multiple live configurations in parallel (#4) 2026-06-22 23:37:38 +02:00
docs/superpowers docs: implementation plan for quieting transient errors 2026-06-16 00:56:48 +02:00
pivotbot Run multiple live configurations in parallel (#4) 2026-06-22 23:37:38 +02:00
tests Run multiple live configurations in parallel (#4) 2026-06-22 23:37:38 +02:00
.dockerignore feat: add Docker Compose runner (#2) 2026-06-15 09:16:48 +02:00
.env.example feat: load secrets from .env file next to config (env vars take precedence) 2026-06-11 08:05:04 +02:00
.gitignore feat: add Docker Compose runner (#2) 2026-06-15 09:16:48 +02:00
config.btc.yaml Run multiple live configurations in parallel (#4) 2026-06-22 23:37:38 +02:00
config.example.yaml Run multiple live configurations in parallel (#4) 2026-06-22 23:37:38 +02:00
docker-compose.yml feat: add Docker Compose runner (#2) 2026-06-15 09:16:48 +02:00
Dockerfile feat: add Docker Compose runner (#2) 2026-06-15 09:16:48 +02:00
pyproject.toml feat: load secrets from .env file next to config (env vars take precedence) 2026-06-11 08:05:04 +02:00
README.md Run multiple live configurations in parallel (#4) 2026-06-22 23:37:38 +02:00

PivotBot

Single-symbol pivot-bounce trading bot on Alpaca. Spec: docs/superpowers/specs/2026-06-11-pivotbot-design.md.

Setup

python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
cp config.example.yaml config.yaml   # edit symbol etc.
cp .env.example .env                 # fill in your Alpaca keys

Secrets are read from a .env file sitting next to config.yaml (gitignored). Real environment variables, when set, take precedence over .env.

Backtest first

python -m pivotbot backtest --start 2025-01-01 --end 2026-01-01

Do not run the live loop until the backtest shows an edge on YOUR symbol.

Paper trading

python -m pivotbot live          # mode: paper in config.yaml

Stop it any time: touch HALT (checked every tick) or Ctrl-C.

While running, the live loop prints a one-character-per-bar pulse to the console ( quiet · B/S entry · C close · E error · H halt · ! loss-limit · ~ stale feed). Pass --quiet to suppress it. Full tracebacks for any tick error are appended to errors.log (path: error_log_path in config); trade/decision history stays in pivotbot.db.

A steady stream of ~ means the data feed lags more than two bar periods behind. Alpaca's free stock feed (stock_feed: iex) is delayed ~15 minutes, which exceeds the 2-bar staleness window on short timeframes (e.g. 5m → 10m window), so the bot never takes entries. Use timeframe_minutes: 15 (the default — 30m window absorbs the delay) or set stock_feed: sip for real-time data (requires a paid Alpaca market-data subscription).

Real-money live additionally requires I_UNDERSTAND_LIVE_TRADING=yes (in the environment or in .env).

Multiple live bots

Run two or more paper/live configs in one process by repeating --config:

python -m pivotbot live-many --config config.spy.yaml --config config.btc.yaml

live-many is only for paper/live configs, not parallel backtests or sweeps. Each paper/live config must set cash_cap; entries are capped to cash_cap / entry_price before final submission. Runtime artifacts stay in the configured directories and are namespaced by config label (for example, pivotbot.config-spy.db, errors.config-spy.log, HALT.config-spy). The dashboard shows each bot's label, symbol, mode, status, last pulse, consecutive errors, and last update time; pass --quiet to suppress dashboard refreshes. Ctrl-C stops the bot threads gracefully without writing halt files or closing positions.

Docker Compose

Docker Compose runs PivotBot in a local container image so you do not need to install the Python package directly on the host. Secrets stay in your local .env file and config.yaml is bind-mounted at runtime; neither file is baked into the image.

  1. Create local configuration files:

    cp config.example.yaml config.yaml   # edit symbol, mode, risk, paths, etc.
    cp .env.example .env                 # fill in your Alpaca keys
    

    Keep mode: paper in config.yaml until you are ready for real-money trading. Real-money live trading also requires I_UNDERSTAND_LIVE_TRADING=yes in .env or the environment.

  2. Build the image:

    docker compose build
    
  3. Smoke-test the CLI:

    docker compose run --rm pivotbot python -m pivotbot --help
    
  4. Run a backtest with the mounted config.yaml:

    docker compose run --rm pivotbot python -m pivotbot backtest \
      --config /app/config.yaml --start 2025-01-01 --end 2026-01-01
    
  5. Run the live loop (paper by default when mode: paper is in config.yaml):

    docker compose up pivotbot
    

    Stop it with Ctrl-C followed by:

    docker compose down
    

The default Compose command is equivalent to:

python -m pivotbot live --config /app/config.yaml

Because config.yaml is mounted read-only from the repository root, edit the host file to change symbols, trading mode, or runtime artifact paths. By default, relative paths such as pivotbot.db, errors.log, and HALT are inside the container unless you configure absolute or mounted paths.

Tests

python -m pytest