An autonomous equity trading agent built with Claude AI and the Robinhood MCP server. Runs daily on Vercel, rebalances a real portfolio, and emails a summary report — no human required.
Updated every trading day. No login required — it's the real account (number redacted).
⚠️ Disclaimer — not financial advice. This is a personal, experimental engineering project built for educational and portfolio purposes only. It is not financial, investment, or trading advice, and nothing here is a recommendation to buy or sell any security. The author is not a licensed financial advisor. Autonomous trading carries real risk: this software trades a real brokerage account and can and does lose money; past performance does not indicate future results. The software is provided "as is," without warranty of any kind, and the author accepts no liability for any loss or damage arising from its use. It is not affiliated with, endorsed by, or sponsored by Robinhood, Anthropic, or any other company named here. Use at your own risk.
Every weekday at 7:30am PT, a Vercel cron fires /api/trade:
Session 1 — Sonnet analysis (no MCP) Fetches market data (price momentum, insider buys, analyst ratings, earnings calendar), then calls Claude Sonnet to reason about the portfolio and output a structured trade decision:
TRADE_DECISION:{"thesis":"...","sells":[...],"buys":[...]}
Session 2 — Haiku sell execution (MCP) Claude Haiku places all sell orders via the Robinhood MCP tool, sequentially.
Session 3 — Haiku buy execution (MCP) Claude Haiku places all buy orders, one at a time, using only settled cash (T+1 compliance).
Session 4 — Haiku verification (MCP)
Calls get_equity_orders to confirm every order actually exists in Robinhood. Replaces unconfirmed placeholders with real fill prices. Sends an alert if any order is missing.
The run is saved to Upstash Redis and surfaced on a live dashboard.
All crons are scheduled via Vercel (vercel.json), which sends Authorization: Bearer $CRON_SECRET automatically. Requires Vercel Pro (the Hobby plan silently caps at 2 active cron jobs).
| Time (PT) | Endpoint | Purpose |
|---|---|---|
| 6:30am | /api/insider |
Refresh EDGAR insider buy cache |
| 7:30am | /api/trade |
Daily rebalance |
| 8:00am | /api/autopilot |
Monitoring email + self-heal |
| 10:00am | /api/drop-check |
Stop-loss: exit any position down ≥5% intraday |
.github/workflows/cron.yml is kept as a manual fallback (workflow_dispatch) for triggering individual endpoints on demand.
/api/earnings-exit is not on the schedule — it's a manual/latent fallback (a blunt force-sell of any holding within ~3 days of earnings). Earnings are instead handled as a per-position judgment in the daily /api/trade run (hold serial beaters through the print, trim/exit weak-thesis names), so the mechanical pre-earnings exit is deliberately kept off the cron.
The agent builds a deterministic shortlist ("the rails") that the LLM may pick from, then reasons within it. Two signals do the work — one gates, one ranks:
- Quality — the GATE. A name must clear an SEC-derived quality percentile (0–1) to be a candidate at all.
- 12-1 momentum — the RANK. Among quality-eligible names with positive 12-1 momentum (12-month return excluding the most recent month — the classic momentum factor; skipping the last month avoids short-term reversal noise), the shortlist is ranked by that momentum, subject to the per-sector cap.
The following are context signals shown alongside each candidate — they inform the LLM's choice within the rails but do not change eligibility or the ranking:
- α (alpha) — return vs SPY over the same window
- Insider buys — recent EDGAR Form 4 filings by officers/directors
- Analyst upgrades / raised price targets — recent rating changes
- Material news (⚡NEWS) — a distilled corporate event (M&A, guidance, litigation, product) with direction
- Earnings-beat record — last-8-quarter surprise history for held names near earnings
Note: short-horizon risk-adjusted momentum (
mom5/mom14, "sharpe5d/14d") was the primary ranking signal in an earlier version (V0). It is not used in the live strategy — short-window returns mean-revert, so 12-1 momentum replaced it.
- T+1 settlement: buys only use settled cash, never same-day sell proceeds
- Position cap: no single position exceeds ~20% of book value (max of $400 or 20%); a soft ~40% cap per sector
- Earnings blackout: exits all positions before imminent earnings (≤2 days)
- Stop-loss: intraday drop ≥5% triggers an immediate sell
- Minimum buy: $50 floor — no fractional deploys
- Universe: S&P 500 stocks only
Alongside the momentum book, ~25% of the portfolio is a separate, deliberately high-risk / high-reward sleeve that trades on what finance YouTubers are actually saying — an independent, momentum-oriented crowd signal that occasionally surfaces names the quality-momentum screen would never buy.
Signal pipeline (refreshed every weekday at 6am PT via /api/influencer-cache):
- Pull recent videos from a fixed set of 10 finance channels (Meet Kevin, Tom Nash, Ticker Symbol YOU, Joseph Carlson, InvestAnswers, …).
- Fetch each video's transcript (Supadata; falls back to title + description) — the real thesis lives in what they say, not the clickbait title.
- Claude Haiku extracts a structured buy / avoid / insight per video. Transcript text is delimited + spotlighted so it can't inject instructions into the extractor.
- Aggregate into a net conviction score per ticker = confidence-weighted buys (high = 3, medium = 2, low = 0) − avoid mentions, then validate every ticker for real tradeable liquidity.
Entry rules (enforced in code, not just the prompt):
- Hard floor — buy a pick only if its net score ≥ 3. No catalyst/rumor exception; if nothing clears the bar, buying nothing is the correct outcome.
- Falling-knife screen — reject any pick down >8% over 5 days or >15% below its 10-day high (popularity ≠ price trend — a crashing stock is often the most-talked-about one), unless it has reclaimed its 5-day average.
- Per-position cap applied in code regardless of the influencer tag; at most ~2 sleeve slots at a time.
Exit rules (/api/drop-check?scope=influencer, checked several times a day — far more often than the main book's once-daily stop, because these names are volatile):
- −5% stop-loss from the buy price (tighter, and measured from cost rather than the main book's intraday-from-prev-close).
- +40% take-profit, always sold in code — a winner locking its gain is never held on sympathy.
Attribution ledger — every qualifying pick is logged with its entry price, and /api/influencer-ledger tracks each channel's forward returns and alpha vs SPY (which YouTubers' picks actually work, stripped of the market's move). Small, correlated samples: a ranking hint, not a verdict.
This sleeve is really an experiment in turning a noisy, unstructured, adversarial signal (video transcripts) into a disciplined, guardrailed strategy. It has no proven edge — it's sized small precisely so it can take these higher-variance bets without threatening the book.
This agent trades real money, so security is a hard constraint, not an afterthought. The repo enforces a set of Security Invariants (documented in CLAUDE.md):
- a reasoning LLM never holds the trade token — it emits a decision, code applies the guardrails, and a constrained executor places only pre-computed orders;
- every buy is capped in code, regardless of strategy;
- auth fails closed on a missing secret (no
SECRET ?? ""fallback), and no secret ever lives in a URL or a tracked file — a committed scanner (bun run check:secrets) gates every push and prod deploy.
Much of this hardening was set off by a responsible disclosure from @hirad121, who spotted a fail-open authentication gap — which then prompted a full whole-repo security audit and a wave of fixes, several contributed by Hirad himself. See SECURITY.md to report a vulnerability.
| Layer | Tech |
|---|---|
| Runtime | Next.js 15 (App Router), TypeScript |
| Deploy | Vercel (crons, serverless functions) |
| AI | Claude Sonnet 4 (analysis), Claude Haiku 4 (execution) |
| Brokerage | Robinhood MCP server |
| Storage | Upstash Redis |
| Alerts | Resend |
| Market data | Financial Modeling Prep API |
| Insider data | SEC EDGAR |
12 scenarios, 25+ structural checks covering the full decision space. Run with:
bun --env-file=.env.local test evals/eval.test.ts| Scenario | What it tests |
|---|---|
empty-portfolio |
Builds a new portfolio from cash |
rebalance-losers |
Rotates out laggards, keeps winners |
no-buying-power |
Holds or sells to rebalance, no overspend |
overweight-single-position |
Respects 40% position cap |
bear-market |
Conservative / cash-preservation behavior |
imminent-earnings |
Does not buy into earnings |
t1-settlement |
Buys only within settled cash |
min-position-size |
No buys when cash < $50 |
analyst-upgrade |
Acknowledges and weights upgrade signal |
earnings-exit |
Exits held positions before earnings |
drop-check |
Sells positions down ≥5% intraday |
insider-signal |
Acknowledges and weights insider buy signal |
Each scenario runs 10 structural checks (sell-before-buy ordering, position caps, T+1 compliance, earnings avoidance, etc.) plus an LLM-graded reasoning quality check.
git clone https://github.com/alidaftar1/robinhood-agent
cd robinhood-agent
bun installCreate .env.local:
ANTHROPIC_API_KEY= # Claude API key
UPSTASH_REDIS_REST_URL= # Upstash Redis URL
UPSTASH_REDIS_REST_TOKEN= # Upstash Redis token
CRON_SECRET= # Secret for protecting cron/trade endpoints — generate separately from DASHBOARD_SECRET
DASHBOARD_SECRET= # Separate secret for the dashboard login (manual entry only — never emailed, must differ from CRON_SECRET)
RESEND_API_KEY= # Resend API key for email reports
FMP_API_KEY= # Financial Modeling Prep (market data + insider)
APP_URL= # Your deployed Vercel URL (e.g. https://your-app.vercel.app)
ALERT_EMAIL= # Email address for daily reports and alerts
AGENTIC_ACCOUNT_ID= # Robinhood account ID the agent trades
PERSONAL_ACCOUNT_ID= # Robinhood account ID for read-only comparison (optional)The agent uses the Robinhood MCP server for order execution. Configure it in your Claude Code MCP settings and authenticate before the first run.
vercel --prodSet all environment variables in the Vercel dashboard (or vercel env add).
Fill in your account IDs, email, and budget cap in CLAUDE.md — this file drives the local autopilot agent.
To run the daily monitoring check locally via macOS launchd:
# Make the script executable
chmod +x scripts/autopilot.sh
# Create a LaunchAgent plist that runs it at 8am weekdays
# Edit the plist to point to your project path, then:
launchctl load ~/Library/LaunchAgents/com.yourname.robinhood-autopilot.plistThe script sources .env.local and calls claude --print with the autopilot instructions from CLAUDE.md.
app/api/trade/route.ts — Four-session daily rebalance cron
app/api/autopilot/route.ts — Monitoring cron + self-heal
app/api/drop-check/route.ts — Intraday stop-loss
app/api/earnings-exit/route.ts — Pre-earnings exit
app/api/runs/route.ts — Dashboard data API
app/page.tsx — Run history dashboard
lib/strategy.ts — System prompt + analysis prompt
lib/market-data.ts — Price data, momentum signals, formatting
lib/run-store.ts — Redis read/write helpers
lib/insider.ts — EDGAR insider buy fetching
lib/analyst.ts — Analyst rating fetching
evals/eval.test.ts — Full eval suite (12 scenarios, 25+ checks)
evals/fixtures.ts — Market data fixtures + scenario definitions
evals/checks.ts — Structural assertion library
scripts/autopilot.sh — Local autopilot shell script
CLAUDE.md — Autopilot guardrails for Claude Code
Why three AI sessions instead of one? A single long-running Claude + MCP session hit Vercel's function timeout. Splitting into analysis (Sonnet, no tools) → sell execution (Haiku + MCP) → buy execution (Haiku + MCP) keeps each session well under the limit and lets us use the right model for each task.
Why Haiku for execution?
Execution sessions are tool-calling loops with no complex reasoning. Haiku is faster and cheaper while being equally reliable for sequential place_equity_order calls.
Why sequential buy orders? Placing all buys simultaneously caused the session to hit token limits mid-execution. Sequential ordering is slower but reliable.
T+1 settlement Robinhood cash accounts (non-margin) require sell proceeds to settle before they can fund new buys. The agent tracks settled buying power separately and never uses same-day sell proceeds for buys.
0 comments
log in to comment.