EP09 advanced

Building a Multi-Agent Investment Research System

4 parallel subagents pulling financial data, analyst ratings, peer comparisons, and fund flows — then colliding their findings into a structured research memo.

A single agent researching a stock does what most people do: reads a few articles, picks a direction, and builds a case for it. Confirmation bias baked in. Four agents researching the same stock will disagree with each other. That disagreement is the entire point.

I built a system where four specialized subagents run in parallel, each pulling different data, each forming independent conclusions. The output isn’t consensus. It’s structured conflict — a research memo that shows you exactly where the bull case and bear case collide.

The Architecture

┌─────────────────────────────────────────┐
│             Master Agent                │
│  (dispatches tasks, merges results)     │
└──────┬──────┬──────┬──────┬─────────────┘
       │      │      │      │
       ▼      ▼      ▼      ▼
   ┌──────┐┌──────┐┌──────┐┌──────┐
   │Research││Finance││Industry││Fund Flow│
   │Agent  ││Agent  ││Agent   ││Agent   │
   └──────┘└──────┘└──────┘└──────┘
       │      │      │      │
       ▼      ▼      ▼      ▼
   Analyst  Balance  Peer    Capital
   ratings  sheets   comps   movement

Each agent gets a focused brief and runs independently. No communication between agents during execution. The Master collects all four reports and synthesizes them.

Research Agent — Scans analyst ratings, price targets, institutional research notes, and recent coverage changes. Its job is answering: what do the professionals think, and are they changing their minds?

Financial Agent — Pulls balance sheets, income statements, cash flow statements, and key ratios (P/E, EV/EBITDA, debt-to-equity, free cash flow yield). Pure numbers. No narrative.

Industry Agent — Compares the target company against 3-5 peers. Market share, revenue growth rates, margin profiles, competitive positioning. Context that financial statements alone can’t provide.

Fund Flow Agent — Tracks institutional buying and selling. Who increased their position last quarter? Who dumped shares? Are ETF inflows supporting the stock or is passive money exiting?

Why 4 Agents, Not 1

A single agent with all four tasks would do them sequentially — 60 seconds total. It would also cross-contaminate its own analysis. After reading bullish analyst reports, it unconsciously cherry-picks financial metrics that support the bullish view. That’s not a Claude problem. It’s a language model problem. Context influences output.

Four independent agents can’t see each other’s work. The Financial Agent doesn’t know that analysts are bullish. It just reports the numbers. If the numbers tell a bearish story while analysts are bullish, that tension shows up in the final report as a contradiction. Contradictions are where the alpha lives.

Performance is the other reason. Four agents in parallel finish in about 10 seconds. One agent doing everything sequentially takes a minute. The speedup isn’t theoretical — I’ve timed it repeatedly.

The Data Layer: AkShare

AkShare is an open-source Python library with 500+ financial data APIs. Free. No API key needed for most endpoints. It focuses on Chinese markets (A-shares, Hong Kong), but the architecture I’m showing you works identically with yfinance, Alpha Vantage, or any data source. Swap the data calls and the rest stays the same.

import akshare as ak

# Analyst ratings and price targets
ratings = ak.stock_analyst_rank_em(symbol="000001")

# Full financial statements
balance_sheet = ak.stock_balance_sheet_by_report_em(symbol="000001")
income_stmt = ak.stock_profit_sheet_by_report_em(symbol="000001")
cash_flow = ak.stock_cash_flow_sheet_by_report_em(symbol="000001")

# Industry peer comparison
peers = ak.stock_board_industry_cons_em(symbol="BK0475")

# Institutional fund flows
fund_flows = ak.stock_individual_fund_flow(stock="000001")

For US markets, the equivalent calls use yfinance:

import yfinance as yf

ticker = yf.Ticker("AAPL")
balance_sheet = ticker.balance_sheet
income_stmt = ticker.income_stmt
cash_flow = ticker.cashflow
recommendations = ticker.recommendations
institutional_holders = ticker.institutional_holders

The Subagent Dispatch Pattern

Here’s the implementation. The Master Agent dispatches four subagents using Claude Code’s Task tool, collects results, and writes the final memo.

# research_system.py — Master Agent dispatch logic
# This runs as a Claude Code prompt with Task-based subagents

MASTER_PROMPT = """
You are a research coordinator. For the given stock ticker,
dispatch 4 parallel subagents, then synthesize their findings.

## Subagent Briefs

### Agent 1: Research
Pull analyst ratings, consensus price targets, recent upgrades/downgrades.
Report format: bullet points with source attribution.

### Agent 2: Financial
Pull latest balance sheet, income statement, cash flow.
Calculate: P/E, EV/EBITDA, debt-to-equity, FCF yield, revenue CAGR (3yr).
Report format: table of metrics with YoY comparison.

### Agent 3: Industry
Identify 3-5 direct competitors. Compare revenue, margins, growth rate.
Report format: comparison table with the target company highlighted.

### Agent 4: Fund Flow
Pull institutional holder changes (last 2 quarters).
Report format: net buyers vs sellers, largest position changes.

## Synthesis Rules
- Present each agent's findings in its own section
- Add a CONFLICTS section listing contradictions between agents
- End with bull case (3 bullets), bear case (3 bullets), confidence level
- Cite specific data points, not vague summaries
"""

The dispatch happens through Claude Code’s subagent pattern. Each subagent gets its own context window:

## Prompt to Claude Code (paste this directly)

Research [TICKER] using 4 parallel subagents.

Launch these as parallel Task calls:

Task 1 - Research Agent:
"Pull analyst ratings and price targets for [TICKER].
Use available financial APIs or web search.
Return: consensus rating, average price target, recent changes."

Task 2 - Financial Agent:
"Pull financial statements for [TICKER].
Calculate key ratios: P/E, EV/EBITDA, debt/equity, FCF yield.
Return: metrics table with trailing 4 quarters."

Task 3 - Industry Agent:
"Identify top 3-5 competitors of [TICKER].
Compare: revenue, operating margin, revenue growth.
Return: comparison table."

Task 4 - Fund Flow Agent:
"Check institutional ownership changes for [TICKER].
Return: top 5 buyers, top 5 sellers, net flow direction."

After all 4 complete, write a research memo with:
1. Each agent's findings (separate sections)
2. Contradictions between agents
3. Bull case (3 points) / Bear case (3 points)
4. Overall confidence: HIGH / MEDIUM / LOW with reasoning

What the Output Looks Like

Here’s a condensed version of an actual run on a Chinese bank stock:

# Research Memo: Ping An Bank (000001.SZ)

## Research Agent Findings
- Consensus: 8 Buy, 4 Hold, 0 Sell
- Average price target: 14.20 (current: 11.85, +19.8% upside)
- Recent: 2 upgrades in past 30 days, 0 downgrades

## Financial Agent Findings
| Metric | Current | YoY Change |
|--------|---------|------------|
| P/E | 5.2x | -0.8x |
| P/B | 0.52x | -0.06x |
| ROE | 10.1% | -1.2pp |
| NPL Ratio | 1.06% | +0.03pp |
| Provision Coverage | 262% | -15pp |

## Industry Agent Findings
| Bank | P/E | P/B | ROE | NPL |
|------|-----|-----|-----|-----|
| **Ping An** | **5.2x** | **0.52x** | **10.1%** | **1.06%** |
| China Merchants | 6.1x | 0.78x | 14.3% | 0.95% |
| Industrial Bank | 4.8x | 0.48x | 9.8% | 1.12% |

## Fund Flow Agent Findings
- Net institutional buying: 2.1B (last quarter)
- Largest buyer: National Social Security Fund (+180M shares)
- Largest seller: Morgan Stanley (-45M shares)

## CONFLICTS
1. Analysts say BUY (+19.8% upside) but ROE is declining
   and provision coverage is dropping
2. Institutions are net buying, but foreign money (MS) is exiting
3. Cheapest on P/E vs peers, but also lowest ROE

## Bull Case
- Trading at 0.52x book value, historically bottoms at 0.45x
- Social Security Fund buying signals policy support
- Analyst consensus unanimously positive with 20% upside

## Bear Case
- ROE compression suggests earnings quality deteriorating
- Foreign institutional exit often leads domestic by 1-2 quarters
- Rising NPL ratio in a slowing property market

## Confidence: MEDIUM
Strong valuation support conflicts with deteriorating fundamentals.
The institutional flow split (domestic buying, foreign selling)
is an unresolved signal.

The CONFLICTS section is what you can’t get from a single-agent run. One agent sees the buy ratings. Another sees the declining ROE. Neither is wrong. The tension between them is the actual insight.

Performance Numbers

Metric4 Parallel Agents1 Sequential Agent
Wall-clock time~10 seconds~60 seconds
Total tokens15K-25K20K-30K
Data coverage4 independent perspectives1 blended perspective
Contradictions found2-4 per run0 (self-consistent by construction)

The parallel run uses slightly fewer tokens because each agent has a smaller, focused context. The sequential agent accumulates context as it works through each section, inflating later calls.

Extending the System

The four-agent structure isn’t sacred. I’ve experimented with variants:

  • Add a Macro Agent that pulls GDP data, interest rate expectations, and sector rotation signals. Useful for cyclical stocks.
  • Add a Sentiment Agent that scans social media and retail investor forums. Useful for meme stocks and momentum plays.
  • Replace Fund Flow with an Options Agent for US stocks — open interest, put/call ratios, unusual activity.

The hard rule: keep the team under 6 agents. Beyond that, the Master Agent struggles to synthesize conflicting signals coherently. Five is my practical ceiling.

The other rule: never let agents communicate during execution. The moment one agent can read another’s work, you lose the independence that makes contradictions meaningful. Sequential contamination is exactly what this architecture is designed to prevent.

Build the four-agent version first. Run it on 10 stocks you know well. Compare its output to your own analysis. Where it surprises you — where two agents genuinely disagree about the same company — that’s where the system earns its keep.