Earnings
Analyzer.

A 10-Q is 40 pages long and only a few sentences in it matter. This turns one into a single page, with a sentiment score, a one-line headline and what management actually said, in under 30 seconds.

earnings-analyzer-m7n9.onrender.com/r/a53259ef6c1d
Q3 · July 31, 2026
Apple Inc.
AAPL
+0.78
−1.0 bearish · +1.0 bullish

Apple's 10-Q reads confidently, but market risk exposure is the caveat.

01
The Signal

Sentiment climbed from +0.20 in Feb 2026 to +0.78 today, across 4 filings. Apple reported Q3 2026 net sales of $109.4 billion, up 16% year over year.

RoleProduct, engineering and design
StackPython, Flask, Turso, Groq (gpt-oss-120b), SEC EDGAR
BuiltMar 2025, redesigned Sept 2026
ByKaran Chulliparambil

01 - The problem

40 pages.
Three sentences
that matter.

Retail investors skim the filing, miss the change in tone, or go by the headlines. Analysts pay thousands a month for Bloomberg terminals that pre-digest it for them. I wanted to see how close a weekend project could get.

The question: can a language model pull out what a first-year analyst would, like beats, misses, guidance changes, new risks and shifts in tone, for a fraction of a cent per ticker and fast enough to feel like a search?

<30sfor a fresh analysis
0msto re-run a cached ticker
$0.003per fresh run
4filings per pass

02 - How it works

Ticker in,
brief out.

Everything runs on the server. The page streams progress while the pipeline works, then shows the brief when it's done. Every step is cached, so running the same ticker twice is instant and free.

wants a filing brief on a ticker Cached in Turso? = Core step YES NO SERVE FROM CACHE FETCH SEC EDGAR TRANSCRIPT AVAILABLE? YES ALPHA- VANTAGE NO GROQ LLM ANALYSIS BRIEF

One submission. A cached ticker comes back from Turso in milliseconds. A fresh one goes through SEC EDGAR, an earnings call transcript if there is one, and Groq's gpt-oss-120b, then comes back as a brief.

  1. 01
    Ticker to filingsSEC EDGAR: ticker, company ID, the 4 most recent filings
  2. 02
    Filings to textHTML stripped to raw 10-Q text, cached per filing
  3. 03
    Earnings callAlphaVantage transcript for the latest quarter, if available
  4. 04
    The analysisGroq's gpt-oss-120b reads the filing and transcript
  5. 05
    Historyyfinance scores the 3 older filings by their 30-day price reaction
  6. 06
    Save and shareResult stored in Turso with a permalink
  7. 07
    Market reactionyfinance pulls the price 30 days either side of the filing date

The cache key is (content_hash, prompt_version, model). A second run of the same ticker is instant and uses no AI calls. When I change the prompt, I bump the version and old results expire on their own, with no migration.

03 - The redesign

The first version
was a dashboard.

Version one worked, but it showed its results as a grid of metric cards, gauges and line charts. It looked like every fintech tutorial, and nobody would forward it to a friend.

Version one

A dashboard

Metric cards, gauges and Chart.js line charts. Everything had equal weight, so nothing stood out.

Version two

A one-page Filing Brief

Reads like a Bloomberg opinion column, with the data inside the sentences.

  • 01The signal: a paragraph with a sparkline in the middle of it
  • 02A pull quote from management
  • 03Analyst pushback from the earnings call, side by side
  • 04The market's answer: a thin-line price chart marking the filing date
  • +Themes, risks and trades fold into one "Evidence" section

Type: Manrope for headlines, Cormorant Garamond italic for labels and numbers, Inter for body text. Colors: cobalt on warm cream, based on Bicentra Biotech's brand.

04 - How sentiment is calculated

It's the model's
read, not a
formula.

The score isn't a count of positive and negative words, and it isn't tuned against stock returns. Groq's gpt-oss-120b reads the filing (up to about 18,000 characters) and returns a label and a score in one call, as JSON.

// Sent to gpt-oss-120b for the latest filing You are a financial analyst. Analyze this SEC 10-Q for Apple Inc. (AAPL), filed 2026-07-31. FILING: <18,000 chars of stripped 10-Q text> // Added when a transcript exists EARNINGS CALL TRANSCRIPT (same quarter): <8,000 chars of transcript> Return ONLY a valid JSON object: { "sentiment": "positive" | "neutral" | "negative", "sentiment_score": -1.0 to 1.0, "summary", "key_themes", "management_tone", "key_quotes", "guidance", "risks", "analyst_concerns", "beats_estimates": true | false | null }

Two settings matter. response_format is set to json_object, so the model can't answer in prose. reasoning_effort is set to low, because this is extraction, not a math proof, and longer reasoning would cost more without a better read.

Only the latest filing goes through the model. The three older points on the sparkline come from how the stock moved after each one (section 07). Same −1 to 1 scale, no extra AI calls.

Scores are repeatable. The same filing text always returns the same number until I change the prompt and bump its version, say v3 to v4. Then every ticker gets re-scored.

What the score is not

  1. 1

    A word count

    No positive words minus negative words. VADER and FinBERT do that. This doesn't.

  2. 2

    A price prediction

    +0.78 doesn't mean the stock goes up 78%. It means the model read the writing as confidently positive.

  3. 3

    Adjusted for each company

    A company that always sounds cautious might score −0.2 in a good quarter. The change over time matters more than the number.

  4. 4

    A replacement for reading the filing

    If real money is on the line, read the 10-Q. The brief tells you which filings are worth reading. That's why the Signal section leads with the trend, not the score alone.

05 - Diff mode

What changed
since last time.

A filing only means something next to the last one. Diff mode compares any two runs and shows what moved.

01

Sentiment shift

The change in score between two runs, and whether the label flipped.

02

Themes added and dropped

A new theme like "AI acceleration" showing up three quarters in a row is a real signal.

03

Beat or miss flip

When a company goes from missing estimates to beating them, the diff says so directly.

04

New analyst concerns

Questions analysts asked on this call that they didn't ask last quarter. Needs a transcript.

06 - Earnings call context

The 10-Q has the
numbers. The call
has the confidence.

When AlphaVantage has the transcript, part of it goes into the prompt with the filing. The model can compare the polished filing with how executives actually talked, and with what analysts pushed back on.

That adds a management tone field, quotes with speaker names, and an analyst pushback section. With no transcript, that section just doesn't show up. No error, the brief runs on the filing alone.

07 - The three-minute timeout

Stop asking AI
what the price
already says.

The demo started dying at exactly three minutes, the app's own time limit. It was making four Groq calls in a row, one full analysis and three quick scores for the history chart, and on a slow day for Groq that took longer than three minutes.

The logs were silent while it happened, because Gunicorn holds Python's output until later. One setting, PYTHONUNBUFFERED=1, fixed that.

Let the market score the past

The history chart answers one question: how did each past filing land? The stock price already answers that. So the three older filings are scored by how the stock moved in the 30 trading days after each one.

The newest point stays the model's read, since a filing that just came out doesn't have 30 days of price history yet.

// Score for each older filing move = price 30 trading days later ÷ price on filing day − 1 score = move ÷ 10%, capped at [−1, 1] // +10% = +1.0 label = positive above +0.2, negative below −0.2 // Before → after, per run Groq calls 4 → 1 time limit 180s → 300s

Keeping it awake for $0

Render's free tier puts the app to sleep after 15 minutes with no traffic, and it takes about a minute to wake up. That's a bad first impression if a recruiter is the one clicking.

  1. 1

    Fly.io

    About $3 to $4 a month for one always-on machine, but there's no spending cap, so you have to watch the bill.

  2. 2

    Hugging Face Spaces

    Plenty of hardware, but Docker apps now need a paid plan.

  3. 3

    Render Starter

    $7 a month, fixed, no cold starts. The right move once this is a real product.

  4. 4

    What shipped: a free ping

    cron-job.org hits the health check every 10 minutes, so the app never sleeps. Render's 750 free hours a month cover one app running nonstop, since even a 31-day month is 744 hours.

08 - The information gap

The filing is the
story. Trades are
what people did.

Insider trades come from SEC Form 4. When a CEO, CFO or 10% owner buys or sells their own stock, they have two business days to report it. Congressional trades come from the House Clerk. Under the 2012 STOCK Act, representatives have 45 days.

Both are delayed and self-reported. What's interesting isn't whether either group traded. It's whether they agree.

Corporate insidersvsU.S. Congress
Executives buyingForm 4 purchases climbing
In agreement
Congress buyingPurchases on the same ticker
Executives sellingInsiders exiting positions
Disagreement, worth a look
Congress buyingHouse members going long
Executives buyingInsiders adding on weakness
Disagreement, worth a look
Congress sellingHouse members trimming
Executives sellingInsider distributions
In agreement
Congress sellingBoth sides selling

Four possible states. Agreement backs up the filing. Disagreement, especially executives selling while Congress buys, is worth reading closely. The two are never merged into one score, since that would be false precision. They sit side by side in the Evidence section, sorted by date, so you can see whose money moved first.

09 - Decisions

Six choices,
and why.

01

Turso over Postgres

The app is small and mostly reads. Turso keeps the main copy in the cloud with a local copy on the server, so reads are fast and writes sync in the background. Postgres would have been heavier for no benefit.

02

Prompt versions instead of expiry times

Cached results are keyed by (content_hash, prompt_version, model). Change the version and old results stop matching, so new runs re-analyze automatically.

03

Streaming progress instead of polling

A run takes 8 to 25 seconds, long enough to need a progress bar. Server-Sent Events send one stream of updates and work with plain Gunicorn. WebSockets would have been overkill.

04

API keys stay on the server

The Groq and AlphaVantage keys live in Render's settings and never reach the browser. The demo only allows five tickers, and anything else gets a polite error.

05

An editorial page, not a dashboard

Most finance tools default to a grid of cards. This one is a single page you read. The signal isn't a card that says "Sentiment: +0.78." It's a sentence with the trend inside it.

06

$0 a month at 20 users

Render's free tier plus Turso's free storage. A free ping every 10 minutes keeps the app awake, so the first click doesn't wait a minute.

Try it

See it in action.

The live demo runs on AAPL, NVDA, TSLA, MSFT and JPM. Clone the repo for anything else.