Skip to main content
Glama
README.md
# equity-desk

![CI](https://github.com/maxrotemberg04-spec/equity-desk/actions/workflows/ci.yml/badge.svg)
![Python](https://img.shields.io/badge/python-3.12+-2563eb)
![License](https://img.shields.io/badge/license-MIT-059669)

**A grounded AI equity-research analyst** — give it a ticker; it pulls the real SEC filings and market prices, computes the fundamentals itself, and writes a cited buy/hold/sell memo in which **every number is enforced to trace to a source. The LLM is never allowed to invent a figure.**

![equity-desk dashboard](docs/dashboard.png)

## Why grounded?

Most "AI stock analyst" projects hand a ticker to an LLM and hope. An AI that invents numbers in a financial report isn't a demo problem — it's the reason enterprises don't ship LLM features. equity-desk inverts the trust:

1. **Hand-rolled Python computes every number** — ratios, peer ranks, a DCF fair value — from SEC EDGAR filings and market prices.
2. **The LLM receives a fact sheet** of pre-computed, source-tagged figures. Its only job is prose.
3. **A citation guard scans the finished memo** and rejects it if any number matches no fact. Fail loud, not quiet.

**Headline metric: 100% of numbers in every memo trace to source — enforced by a test, not a promise.**

```mermaid
flowchart LR
    T[ticker] --> D[data layer\nEDGAR + yfinance\nlive, cached fallback]
    D --> A[analysis engine\nratios · peers · DCF\nhand-rolled]
    A --> F[fact sheet\nevery number + its source]
    F --> W[LLM writer\nqwen local / claude opt-in\nprose only]
    W --> G{citation guard}
    G -->|every number traces| M[cited memo ✓]
    G -->|invented number| X[memo rejected ✗]
```

## What the analysis engine computes (all hand-rolled)

| Axis | Metrics |
|---|---|
| **Valuation** | P/E, P/S, EV/EBITDA, market cap |
| **Profitability** | gross→net margins, return on equity |
| **Growth** | revenue YoY, EPS |
| **Leverage** | debt/equity, net debt |
| **Peers** | the same ratios computed from each peer's own filings; median comparison |
| **Intrinsic value** | 5-year DCF over EDGAR free cash flow → fair value vs price, assumptions stated |
| **Verdict** | a stated rule over DCF gap + peer valuation — decided by code, never by the LLM |

The interesting parts are deliberately framework-free (~600 lines of plain Python): XBRL tag extraction from EDGAR company-facts, the ratio math, the DCF, and the guard's number-matching are all in `equitydesk/`, readable and defensible line by line.

## Run it (no API key, no network needed)

```bash
pip install -r requirements.txt

python -m equitydesk AAPL --offline          # bundled SEC snapshots, deterministic writer
python -m equitydesk AAPL                    # live EDGAR + yfinance
python -m equitydesk AAPL --provider ollama  # a local LLM writes the prose
python -m equitydesk AAPL --provider claude  # opt-in; only the fact sheet is sent, never the vault of filings
python -m equitydesk AAPL --json             # just the grounded fact sheet

python -m equitydesk.web                     # the dashboard → http://127.0.0.1:8000
```

Sample output: [memos/AAPL-sample.md](memos/AAPL-sample.md)

When the guard catches an invented number, the memo is rejected with the receipt:

```
CITATION GUARD FAILED — memo rejected:
  ✗ 31.2 does not trace to any fact in the AAPL fact sheet
```

## The recommendation is a rule, not a vibe

> **buy**: DCF upside > +15% AND not richer than peer median P/E
> **sell**: DCF downside < −15% AND not cheaper than peer median P/E
> **hold**: everything else

The LLM explains the verdict; it cannot change it. The DCF's assumptions (FCF growth clamped to 2–15%, WACC 9%, terminal 2.5%, 5 years) are printed in every memo — conservative by design, and honestly stated rather than hidden.

## MCP server

The desk doubles as an [MCP](https://modelcontextprotocol.io) server, so AI agents on your machine can use grounded equity research as a tool:

```bash
python mcp_server.py
```

```json
{"mcpServers": {"equity-desk": {"command": "python", "args": ["/path/to/equity-desk/mcp_server.py"]}}}
```

Tools: `analyze_ticker(ticker, provider)` → citation-guarded memo · `fact_sheet(ticker)` → grounded numbers as JSON.

## Measured, not vibed

- **Citation-integrity test** — generates a memo from real (frozen) AAPL data and asserts the guard finds **0 un-sourced numbers**. This is the repo's headline claim, running in CI on every push.
- **Hand-worked math tests** — every ratio and the DCF are asserted against fixtures computed by hand first.
- **Golden-ticker CI** — a committed EDGAR/yfinance snapshot makes the whole pipeline run offline and identically every time.

```bash
pip install -r requirements-dev.txt && python -m pytest   # 28 tests
```

## Honest limitations

- Supported universe is the 8 tickers in `data/peers.json` (v1) — add a ticker by adding its CIK and peers.
- FCF growth is proxied by revenue growth (clamped 2–15%); WACC is a fixed 9%. A conservative DCF will call every richly-valued growth stock overvalued — the point is that the assumptions are *stated*, not that they're clairvoyant.
- EDGAR tag mapping trusts `fp=FY` labelling; odd fiscal calendars may misparse.
- The guard checks numeric provenance, not narrative truth — it stops invented figures, not bad arguments.

## Phase 2 (documented, not built)

10-K risk-factor mining · multi-ticker comparison memos · PDF export · broader universe

---

**Not investment advice.** Data: SEC EDGAR company facts + Yahoo Finance. MIT.