agent_panel: persona/synthesizer advisory consensus module

ai-hedge-fund-style panel: 4 DeepSeek personas (macro, technical, risk,
contrarian) review a finished SignalReport concurrently on a
panel-private thread pool, then a synthesizer chair issues
AGREE/NEUTRAL/OPPOSE + confidence + rationale. Advisory/display-only by
construction: consumers attach post-hoc via attach_panel; the fields
live on SignalReport with empty defaults and analyze_from_dataframes
never touches them (backtest parity, locked by test).

Spend control on top of the shared 500/day client cap: max_panels_per_day
UTC budget (default 20), exact per-bar result cache, and a reuse TTL
keyed (symbol, tf, direction) so a persisting signal re-serves its
verdict across bars instead of burning 5 requests per bar. <2 valid
takes skips the synthesizer; any failure degrades to no panel.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SisdfkxnXNL9iZsXxN3T15
This commit is contained in:
Harwinder Sekhon
2026-08-07 22:31:50 -04:00
parent 8d0bc27353
commit 26c8449877
3 changed files with 846 additions and 0 deletions
+9
View File
@@ -88,6 +88,15 @@ class SignalReport:
news_description: str = ""
news_summary: str = "" # LLM market-context blurb (display-only)
# LLM agent-panel consensus (advisory/DISPLAY-ONLY). Populated
# post-hoc by consumers via agent_panel.attach_panel — NEVER inside
# analyze_from_dataframes (backtest parity) and never read by any
# gate or scoring path.
panel_verdict: str = "" # "AGREE" / "NEUTRAL" / "OPPOSE" / ""
panel_confidence: float = 0.0
panel_rationale: str = ""
panel_takes: List[Dict] = field(default_factory=list)
final_signal: SignalStrength = SignalStrength.NEUTRAL
final_score: float = 0.0
final_confidence: float = 0.0