Overnight Local-LLM Paper-Trading Agent

Every night the Mac wakes itself, runs 3 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 a stock thesis, 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.

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 :8090 with a model downloaded (default gpt-oss-20b; toggle qwen35_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 (3 personas → 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 sequentially (one model, time-sliced with rollover budgets). Each agent researches with tools (run_python for all math, web search/fetch, Alpaca/Finnhub/yfinance market data, get_portfolio for continuity) and its output is checkpointed incrementally to state/output/<date>/. A min-steps nudge keeps agents researching broadly instead of stopping early.

Each persona trades its own Alpaca paper account (Nova→agent1, Warren-lite→agent2, Atlas→agent3), so the three 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) and places GTC bracket orders (marketable-limit entry so stop/take legs survive multi-day holds).

Automate it (America/Chicago)

  • 00:00–07:00 research (~2.3 hr/agent), 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).
  • run_python executes model-generated code locally — kept math-only, sandboxed, no network.
S
Description
Recovered from Google Drive GitHub backup
Readme
6.3 MiB
0 Stars 1 Watchers 0 Forks
Languages
Python 98.7%
Shell 1.3%