# 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) ```bash # 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: ```bash # 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: ```bash systemctl --user enable --now alpaclaudia-report.timer ``` It fires Mon–Fri 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 - Mirror: https://git.zeitanker.digital/admin/alpaclaudia