admin 39875112a0 initial: alpaclaudia paper-trading bot + dashboard
Python bot (bot/alpaclaudia): alpaca-py client, wheel strategy (CSP + covered
calls) plus equity trailing stops, risk gates (cash buffer, cost-basis guard,
per-symbol concentration cap), SQLite state log, Typer CLI (tick/loop/status/
report/dump-state), Discord daily report, pytest suite.

Next.js 14 dashboard (dashboard/): read-only — reads the bot's SQLite directly
and pulls live account/positions/orders from Alpaca. KPIs, equity chart,
positions, bot-intents audit table, and orders table. Dark UI with Tailwind.

systemd/: user-unit templates for the polling loop and the post-close report
timer.

docs/STRATEGY.md: wheel mechanics, risk invariants, later candidates.

Defaults to BOT_MODE=dry — nothing is submitted to Alpaca until explicitly
enabled in .env. ALPACA_ENV=paper by default; flipping to live requires an
explicit second guard.
2026-04-16 21:38:25 +02:00

alpaclaudia

Automated Alpaca paper-trading bot with a Next.js dashboard.

Strategy coverage today:

  • Wheel — sells cash-secured puts on a configurable universe, rolls into covered calls after assignment.
  • Trailing stops — on every long equity position (opt-in).

Safety first: by default BOT_MODE=dry — the bot plans and logs intents but submits nothing to Alpaca. Flip to live only after you've reviewed the intent log.

finhacks/
├── bot/         # Python 3.11+ trading bot (alpaca-py, SQLite state)
├── dashboard/   # Next.js 14 dashboard (read-only view of bot + Alpaca)
├── systemd/     # user-unit templates for loop + daily report
├── data/        # SQLite DB lives here (gitignored)
├── logs/        # bot logs (gitignored)
└── docs/        # extra docs

Quick start (paper)

# 0. prerequisites: Python 3.11+, Node 20+, a paper Alpaca account

# 1. credentials
cp .env.example .env
# edit .env and set ALPACA_API_KEY, ALPACA_API_SECRET
# leave BOT_MODE=dry for the first few runs

# 2. bot
cd bot
python -m venv .venv
.venv/bin/pip install -e ".[dev]"
.venv/bin/python -m alpaclaudia status   # smoke test
.venv/bin/python -m alpaclaudia tick     # one dry iteration

# 3. dashboard
cd ../dashboard
cp .env.example .env.local
# set ALPACA_API_KEY + ALPACA_API_SECRET (same paper creds)
npm install
npm run dev                              # http://localhost:3030

# 4. schedule (optional, systemd user units)
#    see systemd/README.md

How a tick runs

 scheduler.tick()
   ├─ snapshot account / positions / orders (Alpaca)
   ├─ record_tick() → SQLite
   ├─ plan_wheel()             ── produces OrderIntent[]
   ├─ plan_trailing_stops()    ── produces OrderIntent[]
   ├─ risk.check_*()           ── per intent; blocked → logged, never submitted
   └─ executor.submit_intent() ── no-op in dry-run; else Alpaca REST

Everything the bot considers ends up in data/alpaclaudia.db::order_intents, whether submitted, blocked, or dry-run. The dashboard reads this table verbatim, so you can audit the bot's reasoning independently of Alpaca.

Going live (on paper — still "paper" at Alpaca)

After reviewing a couple of dry runs:

# in .env
BOT_MODE=live
ALPACA_ENV=paper   # still paper account — don't touch this unless you mean it

ALPACA_ENV=live is a separate, explicit guard that flips the SDK to the production endpoint. Don't set it unless you really want real money at stake.

Daily Discord report

Set DISCORD_WEBHOOK_URL in .env and enable the timer:

systemctl --user enable --now alpaclaudia-report.timer

It fires MonFri at 22:30 local time (≈30 min after NYSE close if you're in Europe).

Risk invariants (code in bot/alpaclaudia/risk.py)

  • CSPs require strike * 100 * qty ≤ cash equity * MIN_CASH_BUFFER_PCT.
  • CSP collateral per symbol capped at MAX_POSITION_PCT of equity.
  • Covered calls only sell above cost basis — never locking in a loss.
  • Covered calls require ≥ qty*100 underlying shares already held.
  • Trailing stops only on long equity positions we own.

Tests: cd bot && .venv/bin/pytest.

Repo

S
Description
Alpaca Paper-Trading Bot (Wheel + Trailing-Stops) + Dashboard
Readme 95 KiB
Languages
Python 67.8%
TypeScript 30.9%
CSS 1%
JavaScript 0.3%