Spaces:
Sleeping
Sleeping
Commit ·
bfab9f9
1
Parent(s): b329f6a
docs: update README for Sprint 9 — debate, Alpaca, catalyst, evaluators
Browse files- Add multi-agent debate architecture section
- Add Alpaca paper trading module docs
- Add catalyst polling daemon docs
- Add grading engine / evaluators docs
- Update project structure tree with all new files
- Update configuration section with new env vars
- Update LangGraph features table with subgraph
Made-with: Cursor
README.md
CHANGED
|
@@ -10,13 +10,13 @@ app_port: 7860
|
|
| 10 |
|
| 11 |
# PrimoGreedy Agent
|
| 12 |
|
| 13 |
-
**PrimoGreedy** is an automated, AI-driven financial analysis agent designed to hunt, filter, and evaluate Micro-Cap and Small-Cap stocks. It acts as a ruthless "Logic Firewall," aggressively rejecting high-debt, cash-burning, and overvalued companies before deploying a
|
| 14 |
|
| 15 |
---
|
| 16 |
|
| 17 |
## Core Architecture (The LangGraph Engine)
|
| 18 |
|
| 19 |
-
The system is built on **LangGraph** following modern best practices (partial state updates, `Command` routing, `Send` parallel fan-out, checkpointing,
|
| 20 |
|
| 21 |
### Hunter Pipeline (`src/agent.py` / `src/whale_hunter.py`)
|
| 22 |
|
|
@@ -32,7 +32,11 @@ START --> initial_routing --> [chat] --> END
|
|
| 32 |
- Share Price: under $30.00
|
| 33 |
- Zombie Filter: rejects unprofitable companies with < 6 months cash runway
|
| 34 |
- Routes directly to `analyst` (PASS / retries exhausted) or back to `scout` (FAIL) via `Command`.
|
| 35 |
-
3. **Analyst Node** —
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
|
| 37 |
### Workflow Pipeline (`src/workflows/workflow.py`)
|
| 38 |
|
|
@@ -42,6 +46,20 @@ START --> [data_collection] --> [technical_analysis] --> [news_intelligence] -->
|
|
| 42 |
|
| 43 |
A linear 4-node pipeline for deep single-ticker analysis (used by `main.py` CLI).
|
| 44 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
### Parallel Region Orchestrator (`src/whale_hunter.py`)
|
| 46 |
|
| 47 |
The daily cron dispatches all 4 markets (USA, UK, Canada, Australia) **in parallel** via the LangGraph `Send` API:
|
|
@@ -55,6 +73,8 @@ START --> dispatch_regions --> [hunt_region: USA] \
|
|
| 55 |
|
| 56 |
Each `hunt_region` invokes the full per-region subgraph (scout -> gatekeeper -> analyst -> email).
|
| 57 |
|
|
|
|
|
|
|
| 58 |
---
|
| 59 |
|
| 60 |
## LangGraph Features Used
|
|
@@ -69,6 +89,7 @@ Each `hunt_region` invokes the full per-region subgraph (scout -> gatekeeper ->
|
|
| 69 |
| `RetryPolicy` | All nodes | `max_attempts=3, initial_interval=2.0` for transient errors |
|
| 70 |
| `recursion_limit` | All `invoke()` calls | Set to 30 to prevent infinite loops |
|
| 71 |
| Structured output | Analyst nodes | `with_structured_output(InvestmentVerdict)` for validated verdicts |
|
|
|
|
| 72 |
| `@tool` decorator | `sec_edgar.py`, `finance_tools.py` | LangChain tool pattern for API integrations |
|
| 73 |
| `START` / `END` | All graphs | Modern entry-point API (no deprecated `set_entry_point`) |
|
| 74 |
|
|
@@ -87,14 +108,41 @@ A Chainlit-powered chat interface.
|
|
| 87 |
### The Morning Cron (`src/whale_hunter.py`)
|
| 88 |
Headless agent running as a **GitHub Action** daily cron. Hunts all 4 regions in parallel, evaluates candidates through the full pipeline, and emails HTML reports via Resend.
|
| 89 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 90 |
### VPS Data Layer (`vps/`)
|
| 91 |
Optional **FastAPI + DuckDB** backend deployed on a VPS (behind Tailscale) that replaces local JSON files for persistence:
|
| 92 |
- `seen_tickers` — Prevents re-analysing the same ticker within 30 days
|
| 93 |
-
- `paper_portfolio` — Records all
|
| 94 |
- `agent_runs` — Operational metrics for LangSmith correlation
|
| 95 |
|
| 96 |
The agent (`src/core/memory.py`, `src/portfolio_tracker.py`) auto-detects the VPS via `VPS_API_URL` env var and falls back to local JSON files when unavailable.
|
| 97 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 98 |
### SEC EDGAR Ground Truth (`src/sec_edgar.py`)
|
| 99 |
Fetches the most recent 10-K or 10-Q filing from SEC EDGAR for US equities and extracts two investment-critical sections:
|
| 100 |
- **Item 7: Management's Discussion & Analysis (MD&A)** — Management's own view of operations
|
|
@@ -135,7 +183,7 @@ pip install -r requirements.txt
|
|
| 135 |
|
| 136 |
### 2. Configuration (`.env`)
|
| 137 |
```env
|
| 138 |
-
OPENROUTER_API_KEY=your_key # LLM Inference (
|
| 139 |
FINNHUB_API_KEY=your_key # Deep Fundamentals & Insider Data
|
| 140 |
BRAVE_API_KEY=your_key # Web Search
|
| 141 |
RESEND_API_KEY_CISCO=your_key # Email Reporting (Cron only)
|
|
@@ -143,6 +191,19 @@ RESEND_API_KEY_CISCO=your_key # Email Reporting (Cron only)
|
|
| 143 |
# Optional: VPS Data API
|
| 144 |
VPS_API_URL=http://your-vps:8080
|
| 145 |
VPS_API_KEY=your_vps_key
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 146 |
```
|
| 147 |
|
| 148 |
### 3. Launching the UI
|
|
@@ -160,6 +221,12 @@ python3 main.py
|
|
| 160 |
bash vps/deploy.sh
|
| 161 |
```
|
| 162 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 163 |
---
|
| 164 |
|
| 165 |
## Project Structure
|
|
@@ -172,25 +239,28 @@ primogreedy/
|
|
| 172 |
├── src/
|
| 173 |
│ ├── agent.py # Interactive Chainlit pipeline (scout/gatekeeper/analyst)
|
| 174 |
│ ├── whale_hunter.py # Daily cron pipeline + parallel Send orchestrator
|
| 175 |
-
│ ├── llm.py # OpenRouter LLM with
|
| 176 |
│ ├── sec_edgar.py # SEC EDGAR 10-K/10-Q filing fetcher + parser (@tool)
|
| 177 |
│ ├── finance_tools.py # Finnhub tools (@tool decorated)
|
| 178 |
-
│ ├── portfolio_tracker.py # Paper trade recording +
|
| 179 |
│ ├── email_utils.py # Resend email dispatch
|
| 180 |
│ ├── core/
|
| 181 |
-
│ │ ├── state.py # AgentState (TypedDict with Annotated reducers)
|
| 182 |
│ │ ├── memory.py # Seen-tickers ledger (VPS or local JSON)
|
| 183 |
-
│ │ ├── search.py # Brave Search wrapper
|
| 184 |
-
│ │ ├── ticker_utils.py # Ticker extraction, suffix resolution
|
| 185 |
│ │ └── logger.py # Logging config
|
| 186 |
│ ├── models/
|
| 187 |
-
│ │ ├── verdict.py # InvestmentVerdict Pydantic model (with
|
| 188 |
-
│ │ └── kelly.py # Kelly Criterion position sizing
|
| 189 |
-
│ ├── agents/
|
|
|
|
| 190 |
│ │ ├── data_collection_agent.py
|
| 191 |
│ │ ├── technical_analysis_agent.py
|
| 192 |
│ │ ├── news_intelligence_agent.py
|
| 193 |
│ │ └── portfolio_manager_agent.py
|
|
|
|
|
|
|
| 194 |
│ ├── workflows/
|
| 195 |
│ │ ├── workflow.py # 4-node linear workflow graph
|
| 196 |
│ │ └── state.py # Workflow-specific AgentState
|
|
@@ -200,13 +270,18 @@ primogreedy/
|
|
| 200 |
│ │ └── insider_feed.py # SEC EDGAR / Finnhub insider data
|
| 201 |
│ └── prompts/
|
| 202 |
│ └── senior_broker.py # LangSmith Hub prompt template
|
|
|
|
|
|
|
|
|
|
|
|
|
| 203 |
├── vps/
|
| 204 |
-
│ ├── api.py # FastAPI + DuckDB data API
|
|
|
|
| 205 |
│ ├── schema.sql # DuckDB table definitions
|
| 206 |
│ ├── deploy.sh # VPS deployment script
|
| 207 |
│ └── requirements.txt # VPS-specific dependencies
|
| 208 |
└── .github/workflows/
|
| 209 |
-
└── hunter.yml # Daily cron GitHub Action
|
| 210 |
```
|
| 211 |
|
| 212 |
---
|
|
|
|
| 10 |
|
| 11 |
# PrimoGreedy Agent
|
| 12 |
|
| 13 |
+
**PrimoGreedy** is an automated, AI-driven financial analysis agent designed to hunt, filter, and evaluate Micro-Cap and Small-Cap stocks. It acts as a ruthless "Logic Firewall," aggressively rejecting high-debt, cash-burning, and overvalued companies before deploying a multi-agent LLM pipeline to write highly structured fundamental investment memos — and optionally execute paper trades via Alpaca.
|
| 14 |
|
| 15 |
---
|
| 16 |
|
| 17 |
## Core Architecture (The LangGraph Engine)
|
| 18 |
|
| 19 |
+
The system is built on **LangGraph** following modern best practices (partial state updates, `Command` routing, `Send` parallel fan-out, checkpointing, `RetryPolicy`, and multi-agent subgraphs).
|
| 20 |
|
| 21 |
### Hunter Pipeline (`src/agent.py` / `src/whale_hunter.py`)
|
| 22 |
|
|
|
|
| 32 |
- Share Price: under $30.00
|
| 33 |
- Zombie Filter: rejects unprofitable companies with < 6 months cash runway
|
| 34 |
- Routes directly to `analyst` (PASS / retries exhausted) or back to `scout` (FAIL) via `Command`.
|
| 35 |
+
3. **Analyst Node** — Two modes controlled by `USE_DEBATE` env var:
|
| 36 |
+
- **Single-LLM** (default): Senior Broker analysis via OpenRouter (6-model fallback chain) with structured `InvestmentVerdict` output.
|
| 37 |
+
- **Multi-Agent Debate** (`USE_DEBATE=true`): Three-agent Investment Committee subgraph (Pitcher → Skeptic → Judge) that produces a hallucination-resistant verdict.
|
| 38 |
+
|
| 39 |
+
Both modes fetch **SEC EDGAR** 10-K/10-Q filings (US equities), call Finnhub tools for deep fundamentals, and compute **Kelly Criterion position sizing**.
|
| 40 |
|
| 41 |
### Workflow Pipeline (`src/workflows/workflow.py`)
|
| 42 |
|
|
|
|
| 46 |
|
| 47 |
A linear 4-node pipeline for deep single-ticker analysis (used by `main.py` CLI).
|
| 48 |
|
| 49 |
+
### Multi-Agent Debate (`src/agents/debate.py`)
|
| 50 |
+
|
| 51 |
+
When `USE_DEBATE=true`, the analyst node runs a 3-agent LangGraph subgraph:
|
| 52 |
+
|
| 53 |
+
```
|
| 54 |
+
START --> [pitcher (Gemma)] --> [skeptic (Mistral)] --> [judge (Nemotron)] --> END
|
| 55 |
+
```
|
| 56 |
+
|
| 57 |
+
1. **The Pitcher** — Writes the strongest bullish thesis using only provided data.
|
| 58 |
+
2. **The Skeptic** — Challenges the bull case, flagging any fabricated claims.
|
| 59 |
+
3. **The Judge** — Synthesises the debate into a structured `InvestmentVerdict`, downgrading if fabrications were found.
|
| 60 |
+
|
| 61 |
+
Models are configurable via `DEBATE_PITCHER_MODEL`, `DEBATE_SKEPTIC_MODEL`, `DEBATE_JUDGE_MODEL` env vars.
|
| 62 |
+
|
| 63 |
### Parallel Region Orchestrator (`src/whale_hunter.py`)
|
| 64 |
|
| 65 |
The daily cron dispatches all 4 markets (USA, UK, Canada, Australia) **in parallel** via the LangGraph `Send` API:
|
|
|
|
| 73 |
|
| 74 |
Each `hunt_region` invokes the full per-region subgraph (scout -> gatekeeper -> analyst -> email).
|
| 75 |
|
| 76 |
+
Supports **catalyst-triggered single-ticker mode** via `CATALYST_TICKER` env var (used by `repository_dispatch` from the VPS polling daemon).
|
| 77 |
+
|
| 78 |
---
|
| 79 |
|
| 80 |
## LangGraph Features Used
|
|
|
|
| 89 |
| `RetryPolicy` | All nodes | `max_attempts=3, initial_interval=2.0` for transient errors |
|
| 90 |
| `recursion_limit` | All `invoke()` calls | Set to 30 to prevent infinite loops |
|
| 91 |
| Structured output | Analyst nodes | `with_structured_output(InvestmentVerdict)` for validated verdicts |
|
| 92 |
+
| Subgraph | `src/agents/debate.py` | Pitcher/Skeptic/Judge multi-agent debate as nested graph |
|
| 93 |
| `@tool` decorator | `sec_edgar.py`, `finance_tools.py` | LangChain tool pattern for API integrations |
|
| 94 |
| `START` / `END` | All graphs | Modern entry-point API (no deprecated `set_entry_point`) |
|
| 95 |
|
|
|
|
| 108 |
### The Morning Cron (`src/whale_hunter.py`)
|
| 109 |
Headless agent running as a **GitHub Action** daily cron. Hunts all 4 regions in parallel, evaluates candidates through the full pipeline, and emails HTML reports via Resend.
|
| 110 |
|
| 111 |
+
### Alpaca Paper Trading (`src/broker/alpaca.py`)
|
| 112 |
+
Optional **Alpaca Markets** integration for live paper trading of US equities:
|
| 113 |
+
- Automatically submits market orders for **BUY / STRONG BUY** verdicts on US tickers
|
| 114 |
+
- Calculates share quantity from Kelly position sizing and account equity
|
| 115 |
+
- Safety limits: minimum $1 order, maximum 25% of equity per position
|
| 116 |
+
- Records `order_id`, `fill_price`, and `broker_status` to VPS
|
| 117 |
+
- Dry-run mode when `ALPACA_ENABLED` is not set (logs but doesn't submit)
|
| 118 |
+
|
| 119 |
### VPS Data Layer (`vps/`)
|
| 120 |
Optional **FastAPI + DuckDB** backend deployed on a VPS (behind Tailscale) that replaces local JSON files for persistence:
|
| 121 |
- `seen_tickers` — Prevents re-analysing the same ticker within 30 days
|
| 122 |
+
- `paper_portfolio` — Records all paper trades with Kelly sizing, Alpaca order IDs, and fill prices
|
| 123 |
- `agent_runs` — Operational metrics for LangSmith correlation
|
| 124 |
|
| 125 |
The agent (`src/core/memory.py`, `src/portfolio_tracker.py`) auto-detects the VPS via `VPS_API_URL` env var and falls back to local JSON files when unavailable.
|
| 126 |
|
| 127 |
+
### Catalyst Polling Daemon (`vps/catalyst_poll.py`)
|
| 128 |
+
VPS-based systemd timer that polls every 15 minutes during US market hours for intraday triggers:
|
| 129 |
+
- **Volume spike** — Current volume > 3x average daily volume
|
| 130 |
+
- **Price move** — Intraday move > 10%
|
| 131 |
+
- **Insider filing** — New SEC Form 4 purchase for a tracked ticker
|
| 132 |
+
|
| 133 |
+
When triggered, fires a GitHub Actions `repository_dispatch` event to run the pipeline for that specific ticker.
|
| 134 |
+
|
| 135 |
+
### Grading Engine (`scripts/`)
|
| 136 |
+
Automated quality assurance via LangSmith Evaluators:
|
| 137 |
+
- `scripts/build_golden_dataset.py` — Curates 50 representative traces into a LangSmith Dataset
|
| 138 |
+
- `scripts/evaluators.py` — 5 custom evaluators:
|
| 139 |
+
- **Catalyst Grounding** (LLM-as-a-Judge) — Scores whether claims are backed by data
|
| 140 |
+
- **Company Identity** (LLM-as-a-Judge) — Catches "name-trap" hallucinations
|
| 141 |
+
- **Format** — Validates headers, no duplicates, Kelly present for BUY
|
| 142 |
+
- **Verdict Validity** — Ensures verdict is one of the 4 valid values
|
| 143 |
+
- **Kelly Math** — Checks allocation is within [1%, 25%] bounds
|
| 144 |
+
- `scripts/run_evals.py` — Runs all evaluators against the golden dataset
|
| 145 |
+
|
| 146 |
### SEC EDGAR Ground Truth (`src/sec_edgar.py`)
|
| 147 |
Fetches the most recent 10-K or 10-Q filing from SEC EDGAR for US equities and extracts two investment-critical sections:
|
| 148 |
- **Item 7: Management's Discussion & Analysis (MD&A)** — Management's own view of operations
|
|
|
|
| 183 |
|
| 184 |
### 2. Configuration (`.env`)
|
| 185 |
```env
|
| 186 |
+
OPENROUTER_API_KEY=your_key # LLM Inference (6-model fallback chain)
|
| 187 |
FINNHUB_API_KEY=your_key # Deep Fundamentals & Insider Data
|
| 188 |
BRAVE_API_KEY=your_key # Web Search
|
| 189 |
RESEND_API_KEY_CISCO=your_key # Email Reporting (Cron only)
|
|
|
|
| 191 |
# Optional: VPS Data API
|
| 192 |
VPS_API_URL=http://your-vps:8080
|
| 193 |
VPS_API_KEY=your_vps_key
|
| 194 |
+
|
| 195 |
+
# Optional: Alpaca Paper Trading (US equities only)
|
| 196 |
+
ALPACA_API_KEY=your_key
|
| 197 |
+
ALPACA_SECRET_KEY=your_secret
|
| 198 |
+
ALPACA_ENABLED=true
|
| 199 |
+
|
| 200 |
+
# Optional: Multi-Agent Debate
|
| 201 |
+
USE_DEBATE=true # Enable pitcher/skeptic/judge pipeline
|
| 202 |
+
|
| 203 |
+
# Optional: LangSmith Observability
|
| 204 |
+
LANGCHAIN_TRACING_V2=true
|
| 205 |
+
LANGCHAIN_API_KEY=your_key
|
| 206 |
+
LANGCHAIN_PROJECT=primogreedy
|
| 207 |
```
|
| 208 |
|
| 209 |
### 3. Launching the UI
|
|
|
|
| 221 |
bash vps/deploy.sh
|
| 222 |
```
|
| 223 |
|
| 224 |
+
### 6. Running Evaluations (optional)
|
| 225 |
+
```bash
|
| 226 |
+
python scripts/build_golden_dataset.py # Build the golden dataset from LangSmith
|
| 227 |
+
python scripts/run_evals.py # Run all evaluators
|
| 228 |
+
```
|
| 229 |
+
|
| 230 |
---
|
| 231 |
|
| 232 |
## Project Structure
|
|
|
|
| 239 |
├── src/
|
| 240 |
│ ├── agent.py # Interactive Chainlit pipeline (scout/gatekeeper/analyst)
|
| 241 |
│ ├── whale_hunter.py # Daily cron pipeline + parallel Send orchestrator
|
| 242 |
+
│ ├── llm.py # OpenRouter LLM with 6-model fallback + structured output
|
| 243 |
│ ├── sec_edgar.py # SEC EDGAR 10-K/10-Q filing fetcher + parser (@tool)
|
| 244 |
│ ├── finance_tools.py # Finnhub tools (@tool decorated)
|
| 245 |
+
│ ├── portfolio_tracker.py # Paper trade recording + Alpaca execution
|
| 246 |
│ ├── email_utils.py # Resend email dispatch
|
| 247 |
│ ├── core/
|
| 248 |
+
│ │ ├── state.py # AgentState (TypedDict with Annotated reducers + debate fields)
|
| 249 |
│ │ ├── memory.py # Seen-tickers ledger (VPS or local JSON)
|
| 250 |
+
│ │ ├── search.py # Brave Search wrapper (with retry/backoff)
|
| 251 |
+
│ │ ├── ticker_utils.py # Ticker extraction, suffix resolution, noise filtering
|
| 252 |
│ │ └── logger.py # Logging config
|
| 253 |
│ ├── models/
|
| 254 |
+
│ │ ├── verdict.py # InvestmentVerdict Pydantic model (with header-stripping)
|
| 255 |
+
│ │ └── kelly.py # Kelly Criterion position sizing (with 10-min cache)
|
| 256 |
+
│ ├── agents/
|
| 257 |
+
│ │ ├── debate.py # Multi-agent pitcher/skeptic/judge subgraph
|
| 258 |
│ │ ├── data_collection_agent.py
|
| 259 |
│ │ ├── technical_analysis_agent.py
|
| 260 |
│ │ ├── news_intelligence_agent.py
|
| 261 |
│ │ └── portfolio_manager_agent.py
|
| 262 |
+
│ ├── broker/
|
| 263 |
+
│ │ └── alpaca.py # Alpaca Paper Trading order router + execution
|
| 264 |
│ ├── workflows/
|
| 265 |
│ │ ├── workflow.py # 4-node linear workflow graph
|
| 266 |
│ │ └── state.py # Workflow-specific AgentState
|
|
|
|
| 270 |
│ │ └── insider_feed.py # SEC EDGAR / Finnhub insider data
|
| 271 |
│ └── prompts/
|
| 272 |
│ └── senior_broker.py # LangSmith Hub prompt template
|
| 273 |
+
├── scripts/
|
| 274 |
+
│ ├── build_golden_dataset.py # LangSmith golden dataset builder
|
| 275 |
+
│ ├── evaluators.py # Custom LangSmith evaluators (5 scorers)
|
| 276 |
+
│ └── run_evals.py # Evaluation runner
|
| 277 |
├── vps/
|
| 278 |
+
│ ├── api.py # FastAPI + DuckDB data API (with broker fields)
|
| 279 |
+
│ ├── catalyst_poll.py # Intraday catalyst polling daemon
|
| 280 |
│ ├── schema.sql # DuckDB table definitions
|
| 281 |
│ ├── deploy.sh # VPS deployment script
|
| 282 |
│ └── requirements.txt # VPS-specific dependencies
|
| 283 |
└── .github/workflows/
|
| 284 |
+
└── hunter.yml # Daily cron + catalyst dispatch GitHub Action
|
| 285 |
```
|
| 286 |
|
| 287 |
---
|