Why Multi-Agent?

Single-model approaches to stock analysis suffer from a fundamental problem: they try to compress too many distinct reasoning tasks into one function. A single LLM call that must simultaneously analyze market data, assess risk, verify news, and write a report inevitably produces shallow, hallucinated outputs.

The solution is multi-agent decomposition — split the task into specialized sub-tasks, each handled by an agent with a focused context. StockAudit AI implements this with three CrewAI agents, an XGBoost risk model, and a TF-IDF RAG pipeline.


System Architecture

Ticker Input
     |
     v
+------------------+    +--------------------+
|   Market Data    |--->| Feature Engineering |
|   (yfinance)     |    | 30+ indicators     |
+------------------+    +--------------------+
                                |
                 +--------------+--------------+
                 |              |              |
                 v              v              v
         +-----------+   +----------+   +-----------+
         | Risk      |   | Alpha    |   | RAG       |
         | XGBoost   |   | Signals  |   | TF-IDF    |
         | + SHAP    |   | Whale    |   | News      |
         +-----------+   | Momentum |   +-----------+
                         | Retail   |
                         +----------+
                 |              |              |
                 v              v              v
         +-----------------------------------------+
         |          CrewAI Agents                  |
         |  Market Analyst -> Risk & Compliance    |
         |   -> Report Summary                     |
         +-----------------------------------------+
                 |
                 v
         SSE Stream -> Frontend

Layer 1: Market Data + Feature Engineering

The market_data.py module fetches from yfinance:

  • Info: price, market cap, sector, P/E, beta
  • History: 6 months of OHLCV at daily resolution
  • Financials: balance sheet, cash flow, income statement

From these, 30+ technical features are computed:

Category Features
Momentum RSI, MACD, MACD signal, MACD histogram
Trend SMA 20/50, EMA 12/26, price vs MA ratios
Volatility ATR, Bollinger Band width, rolling std dev
Volume Volume ratio (current vs avg), volume trend
Macro SPY return, sector ETF return, VIX, Treasury yield

Layer 2: XGBoost Risk Model

The risk model is an XGBoost Regressor trained on synthetic data engineered to reflect realistic financial risk patterns.

Why XGBoost?

  • Handles non-linear feature interactions naturally (e.g., high RSI + low volume has different risk implications than high RSI + high volume)
  • Built-in regularization prevents overfitting on noisy financial data
  • Native feature importance and SHAP compatibility for interpretability

The model outputs two scores:

  • Risk Score (0–100) — higher = riskier. Driven by volatility, momentum divergence, and volume anomalies.
  • Confidence Score (0–100) — how certain the model is in its risk assessment. Lower when features fall outside training distribution.

SHAP Explainability

Every prediction is accompanied by a SHAP waterfall showing which features contributed most to the risk score:

import shap

def explain(features: np.ndarray) -> list[dict]:
    explainer = shap.TreeExplainer(model)
    shap_values = explainer.shap_values(features)
    return [
        {'feature': name, 'contribution': float(val)}
        for name, val in zip(FEATURE_NAMES, shap_values[0])
    ]

This gives users actionable insight: not just "risk score is 72" but "risk score is 72, driven primarily by elevated RSI (+14), volume ratio anomaly (+9), and momentum divergence (+6)."


Layer 3: Alpha Signals

Three domain-specific anomaly detectors run in parallel:

Whale Detection

Looks for block trades exceeding 2 standard deviations from the 20-day rolling mean trade size. Filters for institutional-scale activity.

def detect_whale(trades: pd.Series) -> WhaleSignal:
    rolling_mean = trades.rolling(20).mean()
    rolling_std  = trades.rolling(20).std()
    z_scores = (trades - rolling_mean) / (rolling_std + 1e-8)
    anomalies = trades[z_scores > 2.0]
    return WhaleSignal(
        detected=len(anomalies) > 0,
        magnitude=anomalies.max() / rolling_mean.iloc[-1] if len(anomalies) > 0 else 0
    )

Momentum Exhaustion

Detects divergence between price trend and momentum (MACD histogram rate-of-change). Price may still be rising, but if momentum is decelerating, a reversal becomes statistically more likely.

Retail Concentration

Measures the fraction of odd-lot and small-order volume relative to total volume. When retail participation exceeds the 90th percentile of the trailing 60-day distribution, short-term noise is elevated.


Layer 4: RAG Over News

A TF-IDF vectorizer indexes recent financial news articles for the target ticker. At report time, the top-3 most relevant articles are retrieved via cosine similarity and injected into the report generation prompt.

Why TF-IDF instead of embeddings?

  • Lower latency (no GPU required for encoding)
  • Deterministic and reproducible
  • Sufficient for short financial news snippets
  • Zero operational cost
vectorizer = TfidfVectorizer(max_features=5000, stop_words='english')
tfidf_matrix = vectorizer.fit_transform(all_articles)

def retrieve(query: str, k: int = 3) -> list[Article]:
    query_vec = vectorizer.transform([query])
    scores = cosine_similarity(query_vec, tfidf_matrix).flatten()
    top_indices = scores.argsort()[-k:][::-1]
    return [articles[i] for i in top_indices]

Layer 5: CrewAI Agent Orchestration

Three agents collaborate in a sequential workflow:

1. Market Analyst

Role: Interpret market data, technical indicators, and alpha signals. Input: All raw data + computed features + signal detections. Output: Structured analysis noting key patterns and anomalies.

2. Risk & Compliance

Role: Assess risk posture using the XGBoost model output and SHAP explanations. Input: Market analyst's output + risk score + confidence score + SHAP contributions. Output: Risk assessment narrative, flagging specific concerns.

3. Report Summary

Role: Compile the final audit report, including RAG-retrieved news context. Input: Risk assessment + retrieved articles. Output: Comprehensive markdown report streamed via SSE.


Progressive Streaming

The frontend consumes analysis results via Server-Sent Events (SSE) — each phase emits events as they complete:

event: market_data
event: alpha_signals
event: risk_analysis
event: agent_progress
event: report_chunk
event: analysis_complete

This gives the user a live, progressive experience rather than a static loading spinner.


Performance

Phase Average Latency
Data fetch + features 1.8s
Alpha signals 0.4s
Risk model + SHAP 0.7s
Agent pipeline (3 agents) 3.2s
RAG retrieval 0.3s
Total ~6.4s

The system is designed for interactive exploration — a full audit in under 10 seconds.


What's Next

  1. Live market data via WebSocket feeds instead of yfinance polling
  2. Fine-tuned LLM agents specialized for financial analysis (BloombergGPT-style)
  3. Portfolio-level analysis — running the pipeline across all holdings simultaneously

The full source is on GitHub with a live interactive demo at live_stock.