f2caca9175
ARCHITECTURE.md: system overview, data flow, SQLite schema, guard rails, risk gates, wheel flow, guide for adding new strategies. RUNBOOK.md: day-to-day ops, config reference, troubleshooting, safe shutdown, upgrade procedure. CHANGELOG.md: v0.1.0 + v0.1.1 (limit_price fix). .env.example: credentials removed, URL /v2 suffix stripped.
140 lines
4.5 KiB
Markdown
140 lines
4.5 KiB
Markdown
# Runbook
|
||
|
||
## Day-to-day
|
||
|
||
### Check if the bot is alive
|
||
```bash
|
||
systemctl --user status alpaclaudia-loop.service
|
||
journalctl --user -u alpaclaudia-loop.service -n 30
|
||
```
|
||
|
||
### Manual tick (one-shot, uses current BOT_MODE)
|
||
```bash
|
||
cd ~/finhacks && bot/.venv/bin/python -m alpaclaudia tick
|
||
```
|
||
|
||
### Account + position snapshot (CLI)
|
||
```bash
|
||
cd ~/finhacks && bot/.venv/bin/python -m alpaclaudia status
|
||
```
|
||
|
||
### Post Discord report manually
|
||
```bash
|
||
cd ~/finhacks && bot/.venv/bin/python -m alpaclaudia report
|
||
```
|
||
|
||
### Dump SQLite state (JSON, last 50 ticks/intents)
|
||
```bash
|
||
cd ~/finhacks && bot/.venv/bin/python -m alpaclaudia dump-state
|
||
```
|
||
|
||
### Dashboard
|
||
```
|
||
http://192.168.0.93:3030/ (browser)
|
||
http://192.168.0.93:3030/api/refresh (raw JSON)
|
||
```
|
||
|
||
---
|
||
|
||
## Config changes (~/finhacks/.env)
|
||
|
||
| Change | Key | Action after |
|
||
|---|---|---|
|
||
| Add symbol to universe | `WHEEL_UNIVERSE` | Service auto-picks up on next tick (no restart needed — env file is reloaded each run) |
|
||
| Change DTE window | `WHEEL_PUT_DTE_MIN/MAX` | next tick |
|
||
| Change trail % | `TRAILING_STOP_PCT` | next tick |
|
||
| Disable trailing stops | `TRAILING_STOP_ENABLED=false` | next tick |
|
||
| Go live on paper | `BOT_MODE=live` | `systemctl --user restart alpaclaudia-loop` |
|
||
| Switch to real account | `ALPACA_ENV=live` + live key/secret | **Careful.** Restart service. |
|
||
|
||
Note: the bot reloads `.env` on every process start, but the systemd service runs as a single long-lived process. Config changes only apply after a restart unless the service is in loop mode and you run a manual tick with the new env.
|
||
|
||
To force an env reload: `systemctl --user restart alpaclaudia-loop.service`
|
||
|
||
---
|
||
|
||
## Troubleshooting
|
||
|
||
### "limit price must be limited to 2 decimal places"
|
||
Fixed in `executor.py`. Should not recur. If it does: check if a new order type path is missing `round(..., 2)`.
|
||
|
||
### "insufficient cash" block
|
||
The CSP collateral exceeds `cash − equity * MIN_CASH_BUFFER_PCT`. Either:
|
||
- The underlying's spot moved up and the closest strike now requires more cash.
|
||
- Other positions consumed cash (assignments).
|
||
- Increase `MIN_CASH_BUFFER_PCT` or reduce `MAX_POSITION_PCT` or pick cheaper underlyings.
|
||
|
||
### "collateral exceeds per-symbol cap"
|
||
Strike * 100 > `equity * MAX_POSITION_PCT`. Default is 25%. TSLA at ~$370 = $37k collateral; needs `MAX_POSITION_PCT >= 0.37`.
|
||
|
||
### "no long stock to cover"
|
||
Phase 2 (covered call) triggered but position was closed / not assigned yet. Normal — next tick it resolves.
|
||
|
||
### Options chain returns empty
|
||
Alpaca may not have an active options chain for that symbol, or DTE window yields no contracts. Check:
|
||
```bash
|
||
cd ~/finhacks && bot/.venv/bin/python -c "
|
||
from alpaclaudia.config import load_config
|
||
from alpaclaudia.client import build_clients, list_option_contracts
|
||
cfg = load_config()
|
||
from alpaclaudia.client import Clients
|
||
import os; from dotenv import load_dotenv; load_dotenv()
|
||
from alpaca.trading.client import TradingClient
|
||
from alpaca.data.historical.stock import StockHistoricalDataClient
|
||
from alpaca.data.historical.option import OptionHistoricalDataClient
|
||
tc = TradingClient(cfg.alpaca.key, cfg.alpaca.secret, paper=True)
|
||
sd = StockHistoricalDataClient(cfg.alpaca.key, cfg.alpaca.secret)
|
||
od = OptionHistoricalDataClient(cfg.alpaca.key, cfg.alpaca.secret)
|
||
clients = Clients(trading=tc, stock_data=sd, option_data=od)
|
||
contracts = list_option_contracts(clients, 'SOFI', option_type='put', dte_min=7, dte_max=45)
|
||
print(len(contracts), 'contracts')
|
||
"
|
||
```
|
||
|
||
### Service fails to start
|
||
```bash
|
||
journalctl --user -u alpaclaudia-loop.service -n 50 --no-pager
|
||
```
|
||
Common cause: `.env` missing or Alpaca credentials empty.
|
||
|
||
---
|
||
|
||
## Stopping the loop safely
|
||
|
||
```bash
|
||
systemctl --user stop alpaclaudia-loop.service
|
||
```
|
||
|
||
Open orders in Alpaca are **not** cancelled — they remain until filled or expire (DAY orders expire at market close). To cancel all open orders manually:
|
||
```bash
|
||
cd ~/finhacks && bot/.venv/bin/python -c "
|
||
from alpaclaudia.config import load_config
|
||
from alpaclaudia.client import build_clients
|
||
cfg = load_config()
|
||
clients = build_clients(cfg.alpaca)
|
||
clients.trading.cancel_orders()
|
||
print('all open orders cancelled')
|
||
"
|
||
```
|
||
|
||
---
|
||
|
||
## Extending the universe
|
||
|
||
Edit `WHEEL_UNIVERSE` in `~/finhacks/.env`:
|
||
```
|
||
WHEEL_UNIVERSE=TSLA,SOFI,PLTR,NIO,BAC,F,HOOD,RIVN,LCID
|
||
```
|
||
Good candidates: liquid, optionable, strike < $50 to stay within $5k collateral per lot at the default 25% cap on a $100k account.
|
||
|
||
---
|
||
|
||
## Upgrading the bot
|
||
|
||
```bash
|
||
cd ~/finhacks
|
||
git pull
|
||
cd bot && .venv/bin/pip install -e ".[dev]"
|
||
systemctl --user restart alpaclaudia-loop.service
|
||
```
|