Scooooooootttt/Equitylens
EquityLens
Agentic financial analysis pipeline for European public companies. Ingests SEC 20-F filings, IFRS-tagged XBRL financials, and ECB/Eurostat macro data; orchestrates specialist agents via a Supervisor pattern; outputs a structured research memo with sentence-level citation traceability.
Architecture
Streamlit UI (HuggingFace Spaces)
Sidebar: controls + agent trace + quality report
Centre: four-section memo (clickable sentences)
Right: citation detail panel
│
▼
LangGraph 4-node graph
┌─────────────────────────────────────────────────┐
│ Supervisor (ReAct loop, max 8 tool calls) │
│ Dynamically routes specialist agents based on │
│ intermediate findings. Different sectors and │
│ anomaly patterns produce different call paths. │
└──────┬──────────────┬──────────────┬────────────┘
│ │ │
Financial Document Macro
Agent (ReAct) Agent (ReAct) Agent (ReAct)
XBRL metrics LanceDB RAG ECB / Eurostat
ratio analysis hybrid search rate + GDP data
│ │ │
└──────────────┴──────────────┘
│
AnalysisState
│
┌─────────▼──────────┐
│ Synthesis Agent │
│ XBRL vs narrative │
│ cross-validation │
│ confidence scoring│
└─────────┬──────────┘
│
┌─────────▼──────────┐
│ Writer Agent │
│ 4-section memo │
│ citation_ids per │
│ sentence │
└─────────┬──────────┘
│
┌─────────▼──────────┐
│ QA Agent │◄──── retry (max 2)
│ citation grounding│
│ numeric tracing │
└────────────────────┘Graph topology: supervisor → synthesis → writer → qa, with a conditional edge qa → writer on failure (max 2 iterations). Supervisor routing complexity lives inside the ReAct loop, not in graph edges — this is the core architectural claim.
Tech Stack
Coverage Universe
Five European companies cross-listed on US exchanges. The app also supports any 20-F filer via dynamic SEC EDGAR CIK lookup — first-run analysis fetches and indexes the filing automatically.
Sector diversity is intentional: it produces observable differences in Supervisor call sequences (e.g. Enterprise Software skips macro_agent; Energy always calls it).
Quickstart
Prerequisites: Python 3.11
git clone <repo-url>
cd equitylens
pip install -r requirements.txt
cp .env.example .env # fill in required values (see below)
streamlit run app/app.pyPre-built assets (XBRL metrics, macro data, LanceDB index for all 5 companies FY2022–2023) are committed to the repository. The UI loads instantly for the pre-indexed companies. For any other company/year, the preflight step auto-fetches and indexes on first request.
Environment Variables
Copy .env.example to .env and set:
HuggingFace Spaces: set EDGAR_USER_AGENT and DEEPSEEK_API_KEY as Secrets in the Space settings. LangSmith credentials are optional but recommended for trace inspection.
Data Ingestion (manual)
Pre-indexed data covers all 5 companies for FY2023. To add a company or year:
# XBRL metrics + 20-F download + macro data
python data/ingest.py --company ASML --year 2022
# Build LanceDB index from downloaded filing
python rag/indexer.py --company ASML --year 2022
# Or let the UI handle it automatically on first runEvaluation
Two evaluation scripts use DeepSeek as the judge LLM. No ground-truth QA pairs required.
LLM-as-Judge — evaluates the generated memo on 5 dimensions (1–5 scale, target ≥ 4):
python evaluation/llm_judge_eval.py --company ASML --year 2023
python evaluation/llm_judge_eval.py --all --year 2023
python evaluation/llm_judge_eval.py --all --year 2023 --runs 2 # average over 2 judge runsSector Routing Verification — validates that the Supervisor's agent call sequence matches sector rules:
python evaluation/routing_eval.py --company SHEL --year 2023
python evaluation/routing_eval.py --all --year 2023The --all run also checks the diversity claim: ≥ 3 unique call sequences across 5 companies, demonstrating that sector-aware routing is real, not uniform.
Results are saved to evaluation/results/.
Repository Structure
equitylens/
├── config.py # all env vars in one place (imported by all modules)
│
├── data/
│ ├── coverage_universe.py # hardcoded registry + dynamic SEC EDGAR CIK lookup
│ ├── edgar.py # 20-F HTM download from SEC EDGAR
│ ├── xbrl.py # IFRS metrics from SEC XBRL companyfacts API
│ ├── macro.py # ECB SDW + Eurostat fetch + ECB publication index
│ ├── storage.py # local / Cloudflare R2 dual-mode read/write
│ ├── ingest.py # CLI orchestrator
│ ├── preflight.py # auto-ingestion on first UI request
│ └── local/ # pre-fetched data committed to repo
│ ├── metrics/ # XBRL JSONs (5 companies × FY2022–2023)
│ └── macro/ # ECB + Eurostat cache (2022, 2023)
│
├── rag/
│ ├── parser.py # unstructured.io wrapper
│ ├── chunker.py # three-path chunking (narrative / table / footnote)
│ ├── indexer.py # LanceDB table management + FTS index build
│ ├── embed.py # BGE embedding wrapper
│ └── tools.py # search_narrative, extract_table, fetch_section (RRF)
│
├── tools/
│ ├── financial_tools.py # get_xbrl_metrics, compute_derived_ratios, compare_yoy, detect_anomalies
│ └── macro_tools.py # get_ecb_rates, get_eurostat_indicator, search_ecb_publications
│
├── agents/
│ ├── state.py # AnalysisState TypedDict + all sub-TypedDicts
│ ├── supervisor.py # Supervisor ReAct agent + sector-keyed macro routing rules
│ ├── financial_agent.py # Financial ReAct subgraph
│ ├── document_agent.py # Document ReAct subgraph
│ ├── macro_agent.py # Macro ReAct subgraph
│ ├── synthesis_agent.py # Synthesis node (cross-validation, confidence scoring)
│ ├── writer_agent.py # Writer node + WriterLLMClient abstraction
│ ├── qa_agent.py # QA node + route_after_qa conditional
│ └── graph.py # LangGraph graph assembly + compile()
│
├── evaluation/
│ ├── llm_judge_eval.py # LLM-as-Judge: 5-dimension memo scoring (CLI)
│ ├── routing_eval.py # Sector routing verification (CLI)
│ ├── results/ # JSON outputs per company/year
│ └── test_dataset/ # 12 QA pairs × 5 companies (reference only)
│
├── app/
│ └── app.py # Streamlit UI
│
├── notebooks/
│ └── agent_traces.ipynb # LangSmith trace comparison across sectors
│
├── data/lancedb_index/ # pre-built LanceDB index committed to repo
└── requirements.txtCost
DeepSeek-V3: ~$0.03 per analysis run (65k input + 15k output tokens across all agents).
