Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

quant-analyst-agent

Give it a ticker. It reads the company's SEC filings, checks the tape and the headlines, and writes an investment memo where every claim carries a citation you can click.

analyst demo          # see the output shape — no API key, no network
# Acme Robotics Inc. (ACME)

**Stance:** Cautious  |  **Confidence:** 55%  |  **Generated:** 2026-03-01 09:30 UTC

## Thesis

Acme has compounded revenue at 18% but the growth is renting three customers'
capex budgets, and the January guidance withdrawal suggests management does not
currently know what 2026 looks like.

## Findings

**1. Revenue is concentrated in three customers, and getting more so.**

Top three customers were 61% of FY2025 revenue, up from 54% in FY2024. Contracts
are cancellable on 90 days notice.

> Source: [FY2025 10-K, Item 1 & 1A](https://example.invalid/acme/10-K-2025.htm)

...

Why this exists

Most "AI research assistant" demos summarise a press release. The hard part of equity research isn't summarising — it's sourcing. An analyst who says "margins compressed" and can't tell you which line of which filing says so is not doing research, and neither is a model that does the same thing more fluently.

So the design constraint here was: the agent must not be able to make a claim it cannot cite. Everything below follows from that.

How it works

ticker
  │
  ├─ resolve ──────────────► SEC company index → CIK
  │
  ├─ PHASE 1: research loop (agentic, tools, unconstrained)
  │     model chooses what to read ──► list_filings
  │                                    read_filing     ──► EDGAR
  │                                    recent_news     ──► Google News RSS
  │                                    price_history   ──► Stooq
  │     every tool result is appended to a dossier
  │
  └─ PHASE 2: synthesis (single call, JSON-schema constrained)
        dossier ──► Memo{stance, thesis, findings[], risks[], confidence}
                     └─ each finding: claim + evidence + citation

The two-phase split is the design

Phase 1 needs freedom — the model should decide whether the 8-K matters more than the 10-Q. Phase 2 needs a guaranteed shape — a deliverable that sometimes comes back as prose is not a deliverable.

Doing both in one call means either constraining the exploration or trusting the final turn to hold its format after a dozen tool results. Splitting them also means phase 2 starts from a clean context containing only what was actually read, so a citation can be checked against the dossier rather than taken on faith. If a source isn't in the dossier, the model has nowhere to have got it from.

Guarantees, and their limits

Mechanism What it actually buys you
JSON schema on the synthesis call Shape. Every memo has findings, each with a citation field.
Pydantic validation on the way in Range. The schema can't express 0 ≤ confidence ≤ 1; a model returning 1.4 fails here rather than rendering a memo claiming 140% confidence.
Read-only tool surface Blast radius. There is nothing the agent can call that mutates state or reaches a host we didn't choose, so a prompt injection buried in a filing has nothing to reach for.
Dossier-only context in phase 2 Auditability. Citations are checkable against the run, not just plausible-looking.

What it does not buy you: truth. A correctly-cited finding can still misread the filing. This is a research aid, not an analyst.

Install

git clone https://github.com/K611-dot/quant-analyst-agent
cd quant-analyst-agent
python -m venv .venv && .venv/bin/activate     # Windows: .venv\Scripts\activate
pip install -e ".[dev]"

Run

See the output shape with no credentials at all. demo renders a stored example memo — it is an artefact, not a run, and says so on stderr:

analyst demo

A real run:

export ANTHROPIC_API_KEY=sk-ant-...
export ANALYST_SEC_USER_AGENT="your-project you@example.com"   # SEC requires this
analyst memo AAPL --out memos/aapl.md --json memos/aapl.json

A real run against fixed inputs--offline swaps the data providers for bundled fixtures, so the pipeline is deterministic and touches no network. The model is still called, so this needs an API key:

analyst memo ACME --offline
Flag Effect
--offline Fixture data instead of network sources. Still calls the model.
--out PATH Write Markdown to a file instead of stdout.
--json PATH Also emit the structured memo for downstream tooling.
--no-cache Bypass the disk cache (default TTL 12h).
-q Suppress the token/tool run summary.

Exit codes are distinct per failure class (2 config, 3 data source, 4 model refusal, 5 agent) so this composes in a pipeline.

Data sources

Deliberately keyless, so anyone can clone this and get a working run without a signup step:

Source Used for Notes
SEC EDGAR Filings, company identity Requires a descriptive User-Agent; rate-limited, so responses are cached.
Stooq Daily closes and volume Answers unknown symbols with a 200 and a junk body — handled.
Google News RSS Headlines Treated as leads to verify, never as evidence.

Everything sits behind a ResearchProvider protocol, which is what makes the offline fixture a drop-in and keeps the test suite hermetic.

Development

pytest                 # no network, no API calls
ruff check . && ruff format --check .
mypy

The test suite scripts exact model turn sequences through a fake transport, so loop behaviour is asserted rather than observed — parallel tool results going back in a single message, pause_turn being resumed rather than mistaken for completion, an empty dossier refusing to produce a memo, tool errors being handed to the model instead of aborting the run.

Disclaimer

Output is generated from public filings by an automated system. It is not investment advice, carries no price target, and has not been reviewed by a licensed analyst. Verify every citation before relying on anything it says.

Licence

MIT

About

Autonomous equity-research agent: a ticker in, a sourced investment memo out. Claude tool-use loop over SEC EDGAR + market data, schema-constrained synthesis, every claim cited.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages