Skip to content

kamend/tickerlens

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TickerLens

Three perspectives on any ticker.

TickerLens is a calm, editorially-designed financial research tool. Enter a stock ticker and you get back three reasoned perspectives — the case for buying, holding, and selling — each grounded in real fundamentals, current news, and the kind of implicit connections most tools miss.

Not a trading terminal. Not a single buy/sell signal. An analyst note that argues with itself, so you can make your own call.


What it does

  • Header — company name, price, market cap, trailing P/E, 52-week range, dividend yield. Enough to orient, not enough to overwhelm.
  • Three perspective cards — Buy, Hold, Sell. Each a 2-3 sentence summary with a confidence tag (strong / moderate / thin), expandable into full reasoning and linked sources.
  • Implicit connections — not "Apple reported earnings," but "new EU digital-payments regulation threatens Services margin just as hardware cost pressure is rising."

How it works

A small multi-agent system orchestrated with LangGraph:

START → validate → ┬─ fundamentals (Sonnet 4.6) ─┐
                   └─ news (Sonnet 4.6 + web_search) ─┼→ synthesis (Opus 4.7) → END
  • Validate — confirms the ticker exists via yfinance before any LLM spend.
  • Fundamentals agent — pulls yfinance data, builds header metrics, writes an editorial posture summary with Claude Sonnet 4.6. The header is emitted mid-stream via LangGraph's custom stream channel so the UI fills in while news is still working.
  • News agent — yfinance headlines + Anthropic's web_search tool (Sonnet 4.6) for macro context and implicit connections. Falls back to yfinance-only if search fails.
  • Synthesis agent — Claude Opus 4.7 reads both dossiers and produces all three arguments in a single call, using a forced emit_briefing tool for structured output. One call so the cases can coherently disagree.
  • Streaming — Server-Sent Events over FastAPI with a pacing wrapper (≥1.2s between progress messages) so the UI feels considered, not machine-gun.

Tech stack

Backend: Python 3.11+, FastAPI, LangGraph, Anthropic SDK (Claude Opus 4.7 + Sonnet 4.6), yfinance, Pydantic, sse-starlette, uv.

Frontend: Next.js (App Router), TypeScript, Tailwind CSS, @microsoft/fetch-event-source, Source Serif 4 + Inter via next/font.


Install & run

Prerequisites

  • Python 3.11–3.13
  • uv (Python package manager)
  • Node.js 20+
  • pnpm
  • An Anthropic API key

1. Clone

git clone https://github.com/kamend/tickerlens.git
cd tickerlens

2. Backend

cd backend
cp .env.example .env
# edit .env and set ANTHROPIC_API_KEY=sk-ant-...
# optionally set CORS_ORIGINS to a comma-separated list of allowed frontend URLs
# (defaults to http://localhost:3000)

uv sync
uv run uvicorn main:app --reload --port 8000

Backend runs on http://localhost:8000. Sanity check:

curl http://localhost:8000/health
# {"ok":true}

3. Frontend

In a second terminal:

cd frontend
cp .env.local.example .env.local
# set NEXT_PUBLIC_API_URL to your backend URL (defaults to http://localhost:8000)
# for production, point it at your deployed backend (e.g. https://api.yourapp.com)

pnpm install
pnpm dev

Open http://localhost:3000 and enter a ticker.

Run with Docker

A single-image setup that bundles both backend and frontend is provided. The frontend calls the backend over loopback inside the container, so only port 3000 needs to be exposed.

Prerequisites: Docker 20.10+ and an Anthropic API key.

# Build the image (from the repo root)
docker build -t tickerlens .

# Run it
docker run --rm -p 3000:3000 \
  -e ANTHROPIC_API_KEY=sk-ant-... \
  tickerlens

Open http://localhost:3000.

Alternatively, keep your key in a file and pass it via --env-file:

# backend/.env already has ANTHROPIC_API_KEY=sk-ant-...
docker run --rm -p 3000:3000 --env-file backend/.env tickerlens

Configurable env vars:

Variable Default Purpose
ANTHROPIC_API_KEY — (required) Claude API key
CORS_ORIGINS http://localhost:3000 Comma-separated allowed frontend origins
FRONTEND_PORT 3000 Port the Next.js server listens on inside the container
BACKEND_PORT 8000 Port uvicorn listens on inside the container (loopback only)

To expose on a different host port, remap with -p, e.g. -p 8080:3000.


Usage

  • Type any valid stock ticker (e.g. AAPL, FIG, TSLA, GOOG). Press Enter.
  • Watch the progress messages cross-fade as the agents work.
  • The company header arrives mid-stream; the three perspective cards appear when synthesis completes (typically 60-90s on a cold run — web_search is the slow part).
  • Click any card to expand reasoning and view sources.

Project structure

backend/
  main.py                    # FastAPI app + /health, /validate, /research
  sse.py                     # SSE pacing wrapper + event formatters
  graph/
    state.py                 # ResearchState TypedDict
    graph.py                 # LangGraph wiring
    nodes/                   # validate, fundamentals, news, synthesis
  clients/                   # yfinance + anthropic shared clients
  prompts/                   # fundamentals_summary / news_analyst / synthesis prompts
  schemas/briefing.py        # Pydantic: Citation, Argument, Briefing
  tests/                     # pytest suite
frontend/
  app/
    page.tsx                 # landing
    results/[ticker]/page.tsx
    layout.tsx globals.css
  components/                # TickerInput, CompanyHeader, ProgressDisplay,
                             # PerspectiveCard(s), ErrorState, ResultsView
  lib/                       # api.ts, sse.ts, types.ts
docs/                        # scope, PRD, spec, checklist, learner profile

API surface

Method Path Purpose
GET /health Liveness — returns {ok: true}
POST /validate Sync — confirms a ticker exists, returns name
POST /research SSE — streams progress / header / result / error events

Tests

cd backend
uv run pytest -v

Notes & known quirks

  • Cold runs take time. web_search + Sonnet reasoning on a rich ticker can run 60-90s. This is intentional — the pacing wrapper and mid-stream header emit keep the UI alive during the wait.
  • yfinance flakiness. Occasional empty info responses; the validate node + news fallback handle this gracefully.
  • Not financial advice. TickerLens is a research tool for informed self-directed investors. Read the three cases, weigh the evidence, make your own call.

License

MIT

About

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors