Skip to main content
EARNINGS AUTOMATION · PART 2 OF 5

Consensus Estimates & Analyst Revisions

The stock doesn't move on what actually happened — it moves on whether it beat expectations. OpenClaw pulls live Wall Street consensus estimates and tracks when analysts quietly revise them up or down.

EPS Estimates Revenue Consensus Analyst Revisions Free via yfinance
Earnings Automation Series

What Are Consensus Estimates?

Before a company reports, dozens of Wall Street analysts publish their own predictions for revenue and earnings per share (EPS). The "consensus" is the average of all those predictions. This is the number the market is priced around. A company can grow revenue 20% and the stock still drops — if analysts expected 25% growth. It's all relative to expectations.

Three Types of Estimates

Here's how the market reacts:

Analysts → Consensus → Market prices around it → Company reports Beat? +10% Miss? -15% In-line? ±2%

The consensus estimate is the baseline. Everything is measured relative to it. Miss by a penny, and you can see a 5% sell-off. Beat by a penny, and a 5% rally. The actual growth rate matters far less than whether you met expectations.

Why Analyst Revisions Matter (The Real Signal)

This is the advanced insight — learn it well. When analysts revise their estimates up before a report, it often means they have informal intelligence that things are going well. When they revise down, the opposite. Tracking revision direction in the 30 days before a report is a well-known signal among professional traders.

Example: If Apple had 15 analysts covering it, and 12 of them raised their EPS estimate in the last 30 days, that's bullish momentum going into the report. The direction and concentration of revisions often predicts the stock's reaction more accurately than the earnings surprise itself.

Pro Tip: Revisions made in the 2 weeks before earnings are especially valuable. Near-term revisions suggest the analyst has seen something material. A late upward revision from 3+ analysts is a strong bullish signal.

Why? Because analysts don't revise lightly. Each revision represents a call to their trading desk, their fund clients, their reputation. If multiple analysts are revising up together, it's not random noise — it's a coordinated signal that fundamentals are improving.

What OpenClaw Tracks: Before & After

Without OpenClaw With OpenClaw
Manually check analyst pages for each stock Script pulls estimates for your full watchlist automatically
No revision history. Can't see what changed. Compares current vs 30-days-ago estimates. Tracks every change.
No automated alerts. You miss signals. Flags significant revisions. Flags when +5% consensus change detected.
Data trapped in browser tabs Logs all estimates to CSV. Build strategies on top of historical data.
No dashboard. Can't see trends across 30+ stocks. Central log. Compare revision patterns across your entire watchlist.

OpenClaw does the heavy lifting. You get data. You make decisions.

YAML Configuration

Here's the config file that tells OpenClaw what to track and how to alert you:

watchlist:
  tickers: [AAPL, MSFT, NVDA, AMZN, GOOGL]

estimates:
  track_revisions: true
  revision_window_days: 30
  flag_revision_pct: 5.0    # flag if estimate moved ±5% or more
  sources: ["yfinance"]

alerts:
  email: "you@example.com"
  daily_digest: true

Field Explanations

The Python Script: earnings_estimates.py

Here's the complete, heavily commented script that pulls estimates and tracks revisions:

"""
earnings_estimates.py — OpenClaw Earnings Estimates Tracker
Pulls EPS and revenue consensus estimates for your watchlist.
Flags significant analyst revisions in the configured window.
"""

import yaml
import yfinance as yf
import pandas as pd
from datetime import datetime

# ── Load config ────────────────────────────────────────────────────────────
with open("earnings-config.yaml") as f:
    cfg = yaml.safe_load(f)

tickers       = cfg["watchlist"]["tickers"]
flag_pct      = cfg["estimates"].get("flag_revision_pct", 5.0)

# ── Fetch estimates for each ticker ───────────────────────────────────────
print("📊 EARNINGS ESTIMATES — YOUR WATCHLIST")
print("=" * 60)

results = []

for ticker in tickers:
    stock = yf.Ticker(ticker)

    try:
        # Get analyst earnings estimates (quarterly)
        estimates = stock.earnings_estimate
        revenue   = stock.revenue_estimate

        if estimates is None:
            print(f"  {ticker}: No estimate data available")
            continue

        # Current quarter estimates
        current_q = estimates.iloc[0] if not estimates.empty else None

        if current_q is not None:
            eps_est     = current_q.get("avg", "N/A")
            eps_low     = current_q.get("low", "N/A")
            eps_high    = current_q.get("high", "N/A")
            num_analysts = current_q.get("numberOfAnalysts", "N/A")

            # Revenue estimate (if available)
            rev_est = "N/A"
            if revenue is not None and not revenue.empty:
                rev_row = revenue.iloc[0]
                rev_est = rev_row.get("avg", "N/A")

            print(f"\n  {ticker}")
            print(f"    EPS Estimate:     ${eps_est}")
            print(f"    Range:            ${eps_low} – ${eps_high}")
            print(f"    Revenue Estimate: {rev_est}")
            print(f"    # Analysts:       {num_analysts}")

            results.append({
                "Ticker":       ticker,
                "EPS Estimate": eps_est,
                "EPS Low":      eps_low,
                "EPS High":     eps_high,
                "Revenue Est":  rev_est,
                "Analysts":     num_analysts,
                "Fetched":      datetime.today().strftime("%Y-%m-%d"),
            })

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

# ── Check for revision signals (compare to prior log if it exists) ─────────
print("\n\n🔍 REVISION CHECK")
print("=" * 60)

try:
    prior = pd.read_csv("data/estimates_log.csv")
    prior_latest = prior.groupby("Ticker").last().reset_index()

    for r in results:
        prior_row = prior_latest[prior_latest["Ticker"] == r["Ticker"]]
        if prior_row.empty:
            print(f"  {r['Ticker']}: No prior data for comparison (first run)")
            continue

        prior_eps = prior_row["EPS Estimate"].values[0]
        curr_eps  = r["EPS Estimate"]

        try:
            change_pct = ((float(curr_eps) - float(prior_eps)) / abs(float(prior_eps))) * 100
            direction  = "⬆️ UP" if change_pct > 0 else "⬇️ DOWN"
            flag       = " ⚠️ SIGNIFICANT" if abs(change_pct) >= flag_pct else ""
            print(f"  {r['Ticker']}: {direction} {abs(change_pct):.1f}%{flag}")
        except:
            print(f"  {r['Ticker']}: Could not compute revision")

except FileNotFoundError:
    print("  No prior log found — this is your first run. Baseline saved.")

# ── Save to CSV ────────────────────────────────────────────────────────────
if results:
    df = pd.DataFrame(results)
    df.to_csv("data/estimates_log.csv", mode="a", header=not pd.io.common.file_exists("data/estimates_log.csv"), index=False)
    print("\n💾 Saved to data/estimates_log.csv")

How This Script Works

  1. Load config — Reads your YAML file to get tickers and settings.
  2. Loop through tickers — For each stock in your watchlist, fetch data from yfinance.
  3. Extract estimates — Pulls current-quarter EPS and revenue estimates, plus analyst count.
  4. Print raw data — Displays current estimates in a readable format.
  5. Compare to prior run — Looks at your historical CSV log to detect revisions.
  6. Calculate change % — Shows whether estimates moved up or down, and by how much.
  7. Flag significant changes — If a revision exceeds your threshold (e.g., ±5%), mark it with ⚠️.
  8. Save to CSV — Appends the new data to your historical log for next week's comparison.

Run this weekly (before earnings week) to track revision momentum. The longer your CSV log, the more patterns you'll spot.

Sample Output

Here's what you see when you run the script:

📊 EARNINGS ESTIMATES — YOUR WATCHLIST ============================================================ AAPL EPS Estimate: $1.61 Range: $1.49 – $1.72 Revenue Estimate: $94.2B # Analysts: 32 MSFT EPS Estimate: $3.22 Range: $3.10 – $3.38 Revenue Estimate: $68.4B # Analysts: 38 NVDA EPS Estimate: $0.89 Range: $0.82 – $0.95 Revenue Estimate: $43.1B # Analysts: 44 🔍 REVISION CHECK ============================================================ AAPL: ⬆️ UP 2.5% MSFT: ⬆️ UP 8.1% ⚠️ SIGNIFICANT NVDA: ⬇️ DOWN 1.2%

In this example:

Check your email inbox for the daily digest. You're ready to trade on this intelligence.

What To Watch For

Use these signals to interpret estimate data and spot trading opportunities:

Wide EPS Range (Low vs High Spread)

If analysts predict EPS between $1.20 and $2.00 for the same quarter, there's massive disagreement. This high uncertainty usually means the stock will move more on the actual report. Set alerts for wide ranges.

Large Upward Revisions

When you see +5%, +8%, +10% revisions, insiders may be leaking guidance to favored analysts. This is illegal but happens. The point: upward revisions are often early signals of outperformance.

Revisions in the Final 2 Weeks

Revisions made 30 days before earnings are old news. Revisions made 7–14 days before are hot. The closer to the report date, the more material the revision. A 3+ analyst upward revision 10 days before earnings is a strong buy signal.

Downward Revisions (The Warning Sign)

Downward revisions are less common and more serious. When they happen, the consensus is shrinking. This precedes missed earnings and stock drops. Watch for a pattern of multiple downward revisions — that's your exit signal.

Many Analysts = More Reliable Consensus

A stock covered by 50+ analysts has a tighter consensus. One analyst's revision doesn't move the needle. A stock covered by 5 analysts can swing wildly on a single revision. Pay attention to analyst count.

Automated Scheduling with Cron

You don't want to run this manually every week. Set it on a schedule. Here's the cron command to run the script every Monday at 7 AM (before market open, so you see revisions before the week's earnings):

# Run weekly on Monday mornings to track revision trends
0 7 * * 1 cd /path/to/openclaw && python earnings_estimates.py

Breaking Down the Cron Syntax

Replace /path/to/openclaw with your actual directory path. You can also add > /tmp/earnings.log 2>&1 at the end to capture output for debugging.

Alternative: Daily Digest

If you prefer a daily check (more responsive to last-minute revisions), change the cron to:

0 7 * * * cd /path/to/openclaw && python earnings_estimates.py

The last * instead of 1 means "every day" instead of "Monday only". You'll get daily alerts, which is more sensitive but also more noise.

Disclaimer: Consensus estimates are sourced from analyst forecasts and subject to revision. This content is for educational purposes only and is not financial advice. Past performance does not guarantee future results. Always conduct your own research and consult a financial advisor before making investment decisions.