Use Case

How to Build an Earnings Tracker with SEC Data

Track quarterly earnings surprises across your portfolio — beats, misses, and trends — using real data sourced from SEC EDGAR filings.

Why Track Earnings with SEC Data?

Earnings season moves markets. Companies that consistently beat expectations tend to outperform. By tracking earnings surprises with SEC-sourced data, you get:

Official Numbers

Actual EPS from SEC filings, not aggregated third-party data

Historical Patterns

8+ quarters of earnings history to identify consistent beaters

Surprise Detection

Quantify the magnitude of beats and misses for better signals

Step-by-Step: Track Earnings Surprises Over 8 Quarters

Step 1: Install the Python Client

pip install factstream

Step 2: Full Earnings Tracker Code

This script tracks earnings surprises for a list of stocks over the last 8 quarters:

import factstream

client = factstream.Client(api_key="your_api_key")

# Stocks to track
tickers = ["AAPL", "MSFT", "GOOGL", "AMZN", "META"]

print("Earnings Surprise Tracker — Last 8 Quarters")
print("=" * 65)

for ticker in tickers:
    try:
        # Fetch last 8 quarters of earnings data
        earnings = client.earnings.list(
            ticker=ticker,
            limit=8
        )

        if not earnings:
            print(f"\n{ticker}: No earnings data available")
            continue

        beats = 0
        misses = 0
        total_surprise_pct = 0

        print(f"\n{ticker}")
        print(f"{'Quarter':<12} {'Actual':>8} {'Estimate':>10} "
              f"{'Surprise':>10} {'Result':>8}")
        print("-" * 55)

        for q in earnings:
            actual = q.actual_eps
            estimate = q.estimated_eps

            if actual is None or estimate is None:
                continue

            surprise = actual - estimate
            surprise_pct = (surprise / abs(estimate) * 100
                           if estimate != 0 else 0)
            total_surprise_pct += surprise_pct

            if surprise > 0:
                beats += 1
                result = "BEAT"
            elif surprise < 0:
                misses += 1
                result = "MISS"
            else:
                result = "MET"

            print(f"{q.fiscal_quarter:<12} "
                  f"${actual:>7.2f} "
                  f"${estimate:>9.2f} "
                  f"{surprise_pct:>+9.1f}% "
                  f"{result:>8}")

        total_quarters = beats + misses
        if total_quarters > 0:
            beat_rate = beats / (beats + misses) * 100
            avg_surprise = total_surprise_pct / len(earnings)
            print(f"\n  Beat Rate: {beat_rate:.0f}% "
                  f"({beats}/{beats + misses}) | "
                  f"Avg Surprise: {avg_surprise:+.1f}%")

    except Exception as e:
        print(f"\n{ticker}: Error — {e}")

print("\n" + "=" * 65)
print("Data sourced from SEC EDGAR via FactStream API")

Step 3: What to Look For

When analyzing the results, focus on these signals:

  • Consistent beaters (80%+ beat rate) — companies that regularly exceed estimates often have conservative guidance, a positive sign
  • Growing surprise magnitude — if surprises are getting larger each quarter, the company may be accelerating
  • Recent misses after a beat streak — could signal a growth slowdown worth investigating
  • Average surprise percentage — a high average surprise (5%+) suggests systematic analyst underestimation

Extend Your Earnings Tracker

Take your earnings tracker further:

Revenue Surprise Tracking

Track revenue beats alongside EPS — revenue beats are often a stronger signal than EPS beats.

Post-Earnings Price Moves

Combine with price data to analyze how the market reacts to beats vs misses for each stock.

Sector Comparison

Compare beat rates across sectors to identify which industries are outperforming expectations.

Automated Alerts

Run the tracker on a schedule and send notifications when a tracked stock reports earnings.

Start Tracking Earnings Today

Get your API key in 2 minutes. 30-day free trial, no credit card required on Starter.