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.
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user