TradingAgents/docs/agent/decisions/014-finviz-smart-money-scan...

79 lines
5.4 KiB
Markdown

# ADR 014: Finviz Smart Money Scanner — Phase 1b Bottom-Up Signal Layer
## Status
Accepted
## Context
The macro scanner pipeline produced top-down qualitative analysis (geopolitical events, market movers, sector rotation) but selected stocks entirely from macro reasoning. There was no bottom-up quantitative signal layer to cross-validate candidates. Adding institutional footprint detection (insider buying, unusual volume, breakout accumulation) via `finvizfinance` creates a "Golden Overlap" — stocks confirmed by both top-down macro themes and bottom-up institutional signals carry higher conviction.
Key constraints considered during design:
1. `run_tool_loop()` has `MAX_TOOL_ROUNDS=5`. The market_movers_scanner already uses ~4 rounds. Adding Finviz tools to it would silently truncate at round 5.
2. `finvizfinance` is a web scraper, not an official API — it can be blocked or rate-limited at any time.
3. LLMs can hallucinate string parameter values when calling parameterized tools.
4. Sector rotation context is available from sector_scanner output and should inform smart money interpretation.
## Decisions
### 1. Separate Phase 1b Node (not bolted onto market_movers_scanner)
A dedicated `smart_money_scanner` node avoids the `MAX_TOOL_ROUNDS=5` truncation risk entirely. It runs sequentially after `sector_scanner` (not in the Phase 1a parallel fan-out), giving it access to `sector_performance_report` in state. This context lets the LLM cross-reference institutional footprints against leading/lagging sectors.
Final topology:
```
Phase 1a (parallel): START → geopolitical_scanner
START → market_movers_scanner
START → sector_scanner
Phase 1b (sequential): sector_scanner → smart_money_scanner
Phase 2: geopolitical_scanner, market_movers_scanner, smart_money_scanner → industry_deep_dive
Phase 3: industry_deep_dive → macro_synthesis → END
```
### 2. Three Zero-Parameter Tools (not one parameterized tool)
Original proposal: `get_smart_money_anomalies(scan_type: str)` with values like `"insider_buying"`.
Problem: LLMs hallucinate string parameter values. The LLM might call `get_smart_money_anomalies("insider_buys")` or `get_smart_money_anomalies("volume_spike")` — strings that have no corresponding filter set.
Solution: Three separate zero-parameter tools:
- `get_insider_buying_stocks()` — hardcoded insider purchase filters
- `get_unusual_volume_stocks()` — hardcoded volume anomaly filters
- `get_breakout_accumulation_stocks()` — hardcoded 52-week high + volume filters
With zero parameters, there is nothing to hallucinate. The LLM selects tools by name from its schema — unambiguous. All three share a `_run_finviz_screen(filters_dict, label)` private helper to keep the implementation DRY.
### 3. Graceful Degradation (never raise)
`finvizfinance` wraps a web scraper that can fail at any time (rate limiting, Finviz HTML changes, network errors). `_run_finviz_screen()` catches all exceptions and returns a string starting with `"Smart money scan unavailable (Finviz error): <message>"`. The pipeline never hard-fails due to Finviz unavailability. `macro_synthesis` is instructed to note the absence and proceed on remaining reports.
### 4. `breakout_accumulation` over `oversold_bounces`
Original proposal included an `oversold_bounces` scan (RSI < 30). This was rejected: RSI < 30 bounces are retail contrarian signals, not smart money signals. Institutions don't systematically buy at RSI < 30. Replaced with `breakout_accumulation` (52-week highs on 2x+ volume) the O'Neil CAN SLIM institutional accumulation pattern, where institutional buying drives price to new highs on above-average volume.
### 5. Golden Overlap in macro_synthesis
`macro_synthesis` now receives `smart_money_report` alongside the 4 existing reports. The system prompt includes explicit Golden Overlap instructions: if a smart money ticker fits the top-down macro narrative (e.g., an energy stock with heavy insider buying during a supply shock), assign it `"high"` conviction. If no smart money tickers align, proceed on remaining reports. The JSON output schema is unchanged.
## Consequences
- **Pro**: Dual evidence layer top-down macro + bottom-up institutional signals improve conviction quality
- **Pro**: Zero hallucination risk no string parameters in any Finviz tool
- **Pro**: Pipeline never fails due to Finviz graceful degradation preserves all other outputs
- **Pro**: Sector context injection smart money interpretation is informed by rotation context from sector_scanner
- **Con**: `finvizfinance` is a web scraper brittle to Finviz HTML changes; requires periodic maintenance
- **Con**: Finviz screener results lag real-time institutional data (data is end-of-day); not suitable for intraday signals
- **Con**: Adds ~620 tokens to scanner pipeline token budget (quick_llm tier, acceptable)
## Source Files
- `tradingagents/agents/scanners/smart_money_scanner.py` (new)
- `tradingagents/agents/utils/scanner_tools.py` (3 new tools + `_run_finviz_screen` helper)
- `tradingagents/agents/utils/scanner_states.py` (`smart_money_report` field)
- `tradingagents/graph/scanner_setup.py` (Phase 1b topology)
- `tradingagents/graph/scanner_graph.py` (agent instantiation)
- `tradingagents/agents/scanners/macro_synthesis.py` (Golden Overlap prompt)
- `pyproject.toml` (`finvizfinance>=0.14.0`)
- `tests/unit/test_scanner_mocked.py` (6 new tests for Finviz tools)