{"slug": "trader-llm-agent-for-robinhood-with-a-rust-safety-layer-and-paper-trading", "title": "Trader – LLM agent for Robinhood with a Rust safety layer and paper trading", "summary": "A new open-source trading agent called \"Trader\" connects large language models to Robinhood's official agentic trading API through a Rust-based safety layer that enforces hard risk limits on every order. The agent operates as an MCP bridge, allowing LLMs from OpenAI, Anthropic, Groq, or Ollama to read portfolios, fetch quotes, and place orders while a typed `SafetyValidator` intercepts and validates all transactions against user-defined thresholds for stop-losses, position caps, and buy filters. The system supports paper trading against live market data with a virtual portfolio, full audit logging to JSONL, and a TUI dashboard for monitoring multiple strategies running in parallel.", "body_md": "A Rust agent that connects an LLM to Robinhood's official agentic trading API, enforces hard risk limits in a typed safety layer, and paper-trades against live market data before you risk a dollar.\n\n`trader`\n\nis an agentic loop that:\n\n**Builds a prompt** from your strategy YAML — hard thresholds (stop-loss, position caps, buy filters) and free-text judgment rules.**Hands it to an LLM**(OpenAI, Anthropic, Groq, Ollama, or any compatible endpoint).** The LLM calls Robinhood's MCP tools**to read your portfolio, fetch quotes, and place orders.** Every order is intercepted**by a typed Rust`SafetyValidator`\n\nthat enforces your risk limits — rejecting anything that violates them regardless of what the model decided.**Everything is audited**— system prompt, user message, every tool call and result, intermediate LLM reasoning, and final response — to a JSONL file.\n\nThe agent does not re-implement the Robinhood API. It is an MCP bridge: the LLM drives the tools; we sit in the middle and enforce safety.\n\n```\nscheduler tick\n      │\n      ▼\n  TradingAgent ── build system prompt + user message from strategy YAML\n      │\n      ▼\n  LlmProvider.run_agent_loop()      ← OpenAI / Anthropic / Groq / Ollama\n      │  the LLM calls tools in a loop until it reaches a final answer\n      ▼\n  SafetyValidator  (Rust, hard-enforced)\n      │  ├─ read tools  → forwarded as-is; result observed\n      │  └─ order tools → checked against all risk limits, then forwarded or blocked\n      ▼\n  SimulationExecutor  (paper mode)          or   Robinhood MCP  (live)\n      │  intercepts orders; applies them to                │\n      │  a virtual portfolio on disk                       │\n      ▼                                                    ▼\n  AuditLogger → logs/audit.jsonl  (one JSON line per cycle, full conversation)\n```\n\nThe executor chain is a trait stack (`ToolExecutor`\n\n). Each layer is independent, testable, and composable. Adding a new broker, a new LLM, or a new safety rule does not touch the others.\n\n| Feature | Details |\n|---|---|\nHybrid strategy |\nStructured thresholds enforced by Rust + free-text rules passed to LLM |\nAny LLM |\nOpenAI, Anthropic, Groq, Ollama, Azure, or any OpenAI/Anthropic-compatible endpoint |\nPaper trading |\nSimulation mode uses live Robinhood market data against a virtual portfolio |\nEquity curve |\nASCII chart + CSV export of every simulated cycle's portfolio value |\nResearch tools |\nLLM can call `get_stock_news` (Yahoo Finance RSS) and `web_search` (Brave/DDG) |\nFull audit trail |\nEvery cycle → JSONL: system prompt, user message, all tool calls, full conversation |\nTUI dashboard |\nLive ratatui panels for strategy, portfolio, reasoning, and logs — all scrollable |\nMultiple strategies |\nRun several strategies in parallel, each on its own scheduler interval |\nDocker |\n`docker-compose up` for containerised runs |\n\n- Rust 1.75+\n- A\n[Robinhood Agent Account](https://robinhood.com/us/en/agentic-trading/)and its MCP OAuth token - An LLM:\n[Ollama](https://ollama.com)locally (free), or API keys for OpenAI / Anthropic / Groq\n\n```\ngit clone https://github.com/zhangxd6/Trader.git\ncd Trader\n\ncp .env.example .env\n# Edit .env — add ROBINHOOD_MCP_TOKEN and any LLM API keys\n\ncp config/strategy.example.yaml config/strategy.yaml\n# Edit config/strategy.yaml — choose your LLM and strategy\ncargo build --release\n# Binary is at ./target/release/trader\n./target/release/trader auth    # confirms MCP connection\n./target/release/trader tools   # lists all available Robinhood tools\n# Reset a fresh $10,000 virtual portfolio\n./target/release/trader simulate --reset\n\n# Run one decision cycle and see what the LLM would do\n./target/release/trader simulate --once\n\n# Live TUI dashboard with equity curve\n./target/release/trader simulate --tui\n\n# Check P&L after several cycles\n./target/release/trader simulate --status --chart\n\n# Export equity curve to CSV\n./target/release/trader simulate --csv equity.csv\n# Pretty-print the latest cycle (jq required)\ntail -1 logs/audit.jsonl | jq .\n\n# See every tool call the LLM made\ntail -1 logs/audit.jsonl | jq '.tool_calls[] | {tool, intercepted}'\n\n# Read the full LLM conversation\ntail -1 logs/audit.jsonl | jq '.conversation'\n```\n\nStrategies combine hard limits (Rust-enforced) with free-text rules (LLM-guided):\n\n```\nstrategy:\n  name: \"Mag7 Dip Buyer\"\n  description: >\n    Buy the Magnificent 7 on pullbacks from recent highs. Hold for\n    momentum recovery. Never chase. Preserve 30% cash at all times.\n\n  watchlist: [AAPL, MSFT, NVDA, GOOGL, META, AMZN, TSLA]\n  industries: [Technology, AI, Cloud Computing]\n\n  structured:                          # ← enforced by Rust; LLM cannot override\n    stop_loss_pct:    6.0\n    take_profit_pct: 20.0\n    max_positions:    4\n    min_confidence:   0.75\n    buy_filters:\n      max_price_vs_52w_high_pct: 85.0  # only buy ≥15% off 52w high\n      min_volume_ratio: 0.90\n\n  rules:                               # ← passed verbatim to the LLM prompt\n    - \"Only BUY on a clear pullback — at least 5% below a recent local high\"\n    - \"Do not open a new position if SPY is in a confirmed downtrend\"\n    - \"Prefer NVDA and MSFT for AI exposure; treat TSLA as higher-risk\"\n\n  interval_minutes: 30\n\nrisk:\n  dry_run: true           # set false only when ready for real money\n  max_trade_usd: 1000.0\n  max_position_pct: 0.20\n  max_daily_trades: 4\n  min_cash_reserve_pct: 0.30\n```\n\nSee [ config/strategy.example.yaml](/zhangxd6/Trader/blob/main/config/strategy.example.yaml) for the full reference including multi-strategy and research options.\n\n[ config/small-account.yaml](/zhangxd6/Trader/blob/main/config/small-account.yaml) is a worked example targeting 10% monthly growth from a $300 cash account:\n\n**Concentrated**: max 2 positions, $130 each, $54 cash floor** Disciplined entries**: only buy on ≥5% pullback with volume confirmation** Fast exits**: take-profit at 12%, stop-loss at 5%, no averaging down** LLM-guided**: market context, name selection, and timing rules in plain English\n\n```\n./target/release/trader --config config/small-account.yaml simulate --tui\n```\n\n`provider` value |\nEndpoint | Example models |\n|---|---|---|\n`openai` |\napi.openai.com | `gpt-4o` , `gpt-4o-mini` |\n`anthropic` |\napi.anthropic.com | `claude-opus-4-7` , `claude-sonnet-4-6` |\n`openai-compatible` |\nany (set `base_url` ) |\nGroq `llama-3.3-70b` , Ollama `qwen2.5:7b` , Azure |\n`anthropic-compatible` |\nany (set `base_url` ) |\nClaude proxies / gateways |\n\n**Recommended free options:**\n\n**Ollama locally**:`ollama pull qwen2.5:7b`\n\n— no rate limits, works offline**Groq free tier**:`llama-3.3-70b-versatile`\n\n— fast, generous daily quota\n\nFor reliable tool calling use models ≥7B. Models that don't support the tools API (e.g. some deepseek variants on Ollama) will not work.\n\n```\n┌─ Strategy ▲▼ ────────────────┐┌─ Portfolio ─────────────────────────┐\n│ Nano AI Swing                ││ Cash:      $    170.00               │\n│ Mode: SIMULATE               ││ Equity:    $    130.50               │\n│                              ││ Total:     $    300.50  +0.17%       │\n│ HARD RULES                   ││ ● Running   market: open             │\n│   Stop-loss:      5.0%       │└─────────────────────────────────────┘\n│   Take-profit:   12.0%       │┌─ Positions ──────────────────────────┐\n│   Max positions:  2          ││ Symbol   Qty     Price    P&L%       │\n│   Min confidence: 0.82       ││ ANET     0.55   $236.50   +0.21%    │\n│   Buy filters:               │└─────────────────────────────────────┘\n│     Price < 88% of 52w high  │\n│     Volume > 1.1x avg        │\n└──────────────────────────────┘\n┌─ Latest Reasoning ▲▼ ────────────────────────────┐┌─ Logs ▲▼ ──────────────────────────────┐\n│ Reviewed portfolio: $170 cash, 0.55 ANET @        ││ 14:32:01 CYCLE  starting cycle a1b2…   │\n│ $234.20 avg. ANET is +1.0% from cost — holding.  ││ 14:32:02 MCP    get_portfolio {}        │\n│ MRVL pulled back 6.2% from 3-day high on above-   ││ 14:32:03 MCP    get_equity_quotes …    │\n│ average volume. Confidence 0.85 ≥ 0.82 threshold. ││ 14:32:05 LLM    querying openai/…      │\n│ Placing fractional buy: $125 MRVL.                ││ 14:32:08 ORDER  place_equity_order …   │\n│                                                    ││ 14:32:08 CYCLE  complete — 1 placed    │\n└────────────────────────────────────────────────────┘└────────────────────────────────────────┘\n           [q]quit  [p]pause  [tab]focus  [↑↓/jk]scroll\n```\n\nAll three text panels (Strategy, Reasoning, Logs) are independently scrollable. Tab cycles focus; the active panel gets a cyan border.\n\nTwo independent layers protect every trade:\n\n**Robinhood's structural isolation**— the agent account is separate from your main portfolio and limited to its pre-loaded balance.— on every order the Rust layer checks:`SafetyValidator`\n\n- symbol is on the watchlist (if one is configured)\n- buy/sell direction is permitted\n- per-trade USD cap not exceeded\n- position concentration limit not breached\n- daily trade count not exceeded\n- minimum cash reserve maintained\n`dry_run: true`\n\nblocks all orders entirely\n\nViolations are logged and returned to the LLM as an error; they never reach the broker.\n\nEvery cycle produces one JSON line in `logs/audit.jsonl`\n\n:\n\n```\n{\n  \"cycle_id\": \"a1b2c3...\",\n  \"timestamp\": \"2026-06-01T14:32:01Z\",\n  \"strategy_name\": \"Nano AI Swing\",\n  \"mode\": \"SIMULATE\",\n  \"dry_run\": false,\n  \"system_prompt\": \"You are a disciplined trading agent...\",\n  \"user_message\": \"Current time: 2026-06-01 14:32 UTC. Review my portfolio...\",\n  \"final_response\": \"Placed fractional buy of $125 MRVL at $67.30...\",\n  \"iterations\": 3,\n  \"tool_calls\": [\n    { \"tool\": \"get_portfolio\", \"arguments\": {}, \"result\": {...}, \"intercepted\": false },\n    { \"tool\": \"place_equity_order\", \"arguments\": {...}, \"result\": {...}, \"intercepted\": false }\n  ],\n  \"orders_attempted\": [\n    { \"symbol\": \"MRVL\", \"side\": \"buy\", \"quantity\": 1.858, \"outcome\": \"simulated\" }\n  ],\n  \"conversation\": [...]   // full turn-by-turn thread; disable with audit.full_conversation: false\n}\n# Copy and edit .env, then:\ndocker-compose up\n```\n\nThe compose file mounts `config/`\n\n, `logs/`\n\n, and `simulation/`\n\nas volumes so state persists across restarts.\n\n```\ncargo test      # unit tests\ncargo clippy    # lints\n```\n\nModule layout:\n\n| Path | Responsibility |\n|---|---|\n`src/mcp/` |\nRobinhood MCP client (Streamable HTTP, JSON-RPC + SSE) |\n`src/llm/` |\nProvider-agnostic agent loop; OpenAI & Anthropic implementations |\n`src/safety/` |\nRisk enforcement middleware (`ToolExecutor` trait) |\n`src/research/` |\nNews (Yahoo Finance RSS) and web search (Brave/DDG) tool middleware |\n`src/simulation/` |\nPaper trading with persisted virtual portfolio + equity curve |\n`src/agent/` |\nCycle orchestration, prompt building, TUI event emission |\n`src/scheduler/` |\nInterval loop with market-hours guard |\n`src/tui/` |\nratatui live dashboard |\n`src/audit/` |\nAppend-only JSONL audit trail |\n\n`simulate --once`\n\n— run a single cycle; read`logs/audit.jsonl`\n\nto see what the LLM reasoned.`simulate --tui`\n\n— run continuously; watch the TUI for entries and reasoning.`simulate --status --chart`\n\n— review the equity curve after several sessions.- Tune\n`config/strategy.yaml`\n\nuntil simulated results are convincing. `once --dry-run`\n\n— run against the live account; orders are blocked but you see exactly what would have been placed.- Set\n`dry_run: false`\n\nand start with conservative caps.\n\nTrading involves real financial risk. This software is provided as-is with no warranty. Always start in simulation or dry-run mode. You are solely responsible for any trades placed through your account. Not affiliated with Robinhood Markets, Inc.\n\nApache-2.0 — see [LICENSE](/zhangxd6/Trader/blob/main/LICENSE).", "url": "https://wpnews.pro/news/trader-llm-agent-for-robinhood-with-a-rust-safety-layer-and-paper-trading", "canonical_source": "https://github.com/zhangxd6/Trader/", "published_at": "2026-06-03 13:37:56+00:00", "updated_at": "2026-06-03 13:49:33.682005+00:00", "lang": "en", "topics": ["ai-agents", "large-language-models", "ai-tools", "ai-safety", "ai-products"], "entities": ["Robinhood", "OpenAI", "Anthropic", "Groq", "Ollama", "Rust", "Trader", "SafetyValidator"], "alternates": {"html": "https://wpnews.pro/news/trader-llm-agent-for-robinhood-with-a-rust-safety-layer-and-paper-trading", "markdown": "https://wpnews.pro/news/trader-llm-agent-for-robinhood-with-a-rust-safety-layer-and-paper-trading.md", "text": "https://wpnews.pro/news/trader-llm-agent-for-robinhood-with-a-rust-safety-layer-and-paper-trading.txt", "jsonld": "https://wpnews.pro/news/trader-llm-agent-for-robinhood-with-a-rust-safety-layer-and-paper-trading.jsonld"}}