39875112a0
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.
98 lines
3.2 KiB
Markdown
98 lines
3.2 KiB
Markdown
# 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
|