Overnight Local-LLM Paper-Trading Agent
▶ Dashboard tour — portfolio & option positions, each persona's overnight theses, the AI Investment Committee verdicts, and the orders that got placed. Click for the full-quality MP4 (with sound).
Every night the Mac wakes itself, runs 4 trader personas one at a time against one local LLM
(gpt-oss-20b via oMLX, an Apple-MLX inference server). Each persona researches the
web + live market data, forms up to 4 trade theses — at least one of them an options trade —
and writes JSON. In the morning at market open a separate job reads that JSON and places
Alpaca paper trades with programmatic risk guardrails. Everything is visible in a local
Streamlit dashboard, including an Agents tab that manages the roster (add/edit/disable agents,
per-agent research budgets) via state/agents.json — no code edits needed.
Paper trading only. Fake money, real prices. "The build works" ≠ "it's profitable" — the quality of a local model's theses is the open question you tune over time.
Requirements
- Apple Silicon Mac (built/tested on M4 Pro, 24 GB), plugged in, lid open, logged in overnight.
- oMLX (Apple-MLX server) auto-running on
:8090with a model downloaded (defaultgpt-oss-20b; toggleqwen35_27b). Enforces an API key, auto-read from~/.omlx/settings.json. - uv for Python env management.
- Alpaca paper account + Finnhub free key.
Setup
# 1. Python env + deps
uv sync
# 2. Secrets
cp .env.example .env # then paste your Alpaca paper + Finnhub keys
# 3. Model host — oMLX auto-starts on login; if not, bring it up + verify tool-calling
omlx start # OpenAI-compatible API on http://127.0.0.1:8090
uv run python scripts/smoke_toolcalling.py # GATE: multi-turn tool calls must PASS
# 4. Phase-0 gate
uv run pytest
Switch models any time with one line in .env: MODEL_PROFILE=gpt_oss or qwen35_27b.
Entry points
| Command | What it does |
|---|---|
uv run python -m orchestration.run_nightly |
Nightly research run (all enabled agents → JSON). --compressed for a fast test |
uv run python -m execution.run_market_open |
Morning: JSON → guardrails → Alpaca paper orders. --force to test while closed |
uv run streamlit run web/dashboard.py |
Dashboard: positions, PnL, theses, orders, logs |
uv run python -m reporting.report |
CLI summary |
How it works
run_nightly starts oMLX, then runs Nova → Warren-lite → Atlas → Maverick sequentially (one
model, time-sliced with rollover budgets; per-agent budgets are dashboard-editable). The roster
comes from config/agent_registry.py (built-ins merged with state/agents.json). Each agent
researches with tools (run_python for math, run_analysis for data/charts, web search/fetch,
Alpaca/Finnhub/yfinance market data, options chains, get_portfolio for continuity) and its
output is checkpointed incrementally to state/output/<date>/. Nudges keep agents researching
broadly, steer them to the options mandate (each night's picks must include a researched
single-leg option), and converge them near the end of their budget.
Each persona trades its own Alpaca paper account (Nova→agent1, Warren-lite→agent2,
Atlas→agent3, Maverick→agent4 — Maverick is the deliberately aggressive options/shorts book),
so the books — and their PnL — stay separate and comparable. run_market_open gates on
Alpaca's clock, then per account applies execution/guardrails.py (position/day caps, sizing,
buying-power, an options conviction floor + premium cap, and a reserved slot so the mandated
option trade isn't trimmed) and places GTC bracket orders (marketable-limit entry so
stop/take legs survive multi-day holds).
Adding an agent: use the dashboard's 🤖 Agents tab (clone a template, tweak knobs), create a fresh Alpaca paper account for it, enable options trading (level 2) on that account, and add
ALPACA_<ID>_KEY/ALPACA_<ID>_SECRETto.env. Maverick ships built-in but still needs its own account keys the same way.
The differentiating layer
- Market regime snapshot — SPY trend / VIX / sector momentum computed in code each night and injected into every agent's kickoff (shared ground truth).
- Self-learning journal — each agent sees its own past picks marked-to-market before researching; losses and wins become explicit lessons.
- AI Investment Committee — a Chief-Risk-Officer LLM pass reviews the whole book after research and issues per-pick verdicts (APPROVE / REDUCE / VETO with reasons). The memo lands in the Reports tab and the morning executor enforces the verdicts.
Automate it (America/Chicago)
- 00:00–07:00 research (fair-share time-slicing: ~105 min/agent with 4 agents; tune per-agent budgets from the dashboard), machine woken at 23:55.
- 08:30 execution (= 09:30 ET open; gated on Alpaca's clock, never local time).
scripts/install_launchd.sh # loads the 3 launchd jobs
sudo pmset repeat wakeorpoweron MTWRFSU 23:55:00 # one-time: wake the Mac nightly (needs sudo)
Overnight requirements: plugged in, lid open, logged in (lock screen OK), oMLX running, .env filled.
Remove with scripts/uninstall_launchd.sh + sudo pmset repeat cancel.
Instruments & safety
- Trades stocks (long or short) and single-leg long options (buy calls/puts). Per-trade
- per-day caps; stops/takes enforced in code, not trusted from the LLM. Shorts use inverted
brackets; options are sized by premium×100 (max loss = premium; see
docs/options-phase.md).
- per-day caps; stops/takes enforced in code, not trusted from the LLM. Shorts use inverted
brackets; options are sized by premium×100 (max loss = premium; see
run_pythonexecutes model-generated code locally — kept math-only, sandboxed, no network.