Earnings miss predictor (track record, sector, analysts, price, guidance)

Predicts the probability that a US company will miss the consensus EPS estimate at its next quarterly earnings announcement, about 90 days ahead, from:

  • its own recent earnings surprises (5 numbers),
  • its GICS sector (10 sectors; Real Estate not supported),
  • analyst actions in the 90 days before: rating changes and price targets raised or cut (4 numbers),
  • the stock's run-up vs the S&P 500 (SPY) over 1 and 3 months, and its volatility (3 numbers), and
  • what its latest earnings press release says about guidance: raised, cut, maintained, narrowed, introduced or withdrawn, and how hedged the outlook is (10 numbers from regex rules).

It is a logistic regression (32 features β†’ 1 logit) wrapped as a PyTorch module. It was built as a learning project; the GitHub repo has the full pipeline and the docs, including every idea that did not work.

What the evaluation says: most of the skill comes from the track record and the sector. On companies the model never saw, analyst, price and guidance features add +0.020 AUC over those two [+0.010, +0.030]. Forward in time the gain is +0.010 [-0.006, +0.027]: it helped in 2023 and 2024 but not in 2025–26 (table below).

Usage

# pip install torch huggingface_hub numpy pandas yfinance
# download miss_model.py, guidance_rules.py and market_features.py from this repo
from miss_model import HubMissModel

model = HubMissModel.from_pretrained("Guruprasath12/lie-detect")
p_miss = model.predict(
    past_surprises=[4.2, -1.5, 2.8, 6.0],   # EPS surprise % of earlier announcements, oldest β†’ newest
    sector="Industrials",                     # one of model.sectors
    release_text=open("press_release.txt").read(),   # latest earnings press release (8-K Exhibit 99.1)
    ticker="CAT",                             # analyst actions and prices are fetched from Yahoo Finance
    announcement_date="2026-11-04",           # the announcement being predicted (YYYY-MM-DD)
)

Pass market_inputs=(analyst_actions, prices, spy_prices) instead of ticker to use your own data (format: market_features.market_vector). model.predict_proba(X) takes a raw feature matrix in model.features order; the model standardises inputs with training-set statistics stored as buffers.

History features (computed from announcements before the one predicted):

Feature Definition
prev_miss 1 if the company missed the EPS estimate at its previous announcement, else 0
prev_surprise previous announcement's EPS surprise in %, clipped to [-100, 100]
miss_rate_4q share of misses over the last 4 announcements
mean_surprise_4q mean EPS surprise % over the last 4 announcements
std_surprise_4q std of EPS surprise % over the last 4 announcements (0 if < 2)

Sector: one-hot over model.sectors (Communication Services, Consumer Discretionary, Consumer Staples, Energy, Financials, Health Care, Industrials, Information Technology, Materials, Utilities).

Analyst and price features: market_features.market_vector. Windows end 2 days before the announcement date, so the release and the reactions to it never leak in. Analyst actions (last 90 days): log count, upgrades βˆ’ downgrades, share of price targets raised βˆ’ lowered, mean % target change. Price: 1- and 3-month return minus SPY's, 3-month volatility.

Guidance features: guidance_rules.guidance_vector(text) finds sentences mentioning guidance / outlook / forecast (minus boilerplate) and takes the direction verb closest to that noun. About 85% precise on spot checks. Use the text of the press release, without tables.

Training data

  • 6,916 (press release, next announcement) pairs from 188 S&P 500 companies, 2017–2026; 16.8% misses. The release is filed on announcement day; it is paired with the next announcement (83–98 days later), never its own.
  • Text: 8-K Item 2.02 Exhibit 99.1 from SEC EDGAR. Labels, analyst actions and prices: Yahoo Finance. The data itself is not included here.
  • Logistic regression with balanced class weights; C = 10.0 chosen on validation 2024 (train < 2024). The released weights are refit on all years with that C.

Evaluation

Rolling-origin test: each year predicted by a model trained only on earlier years (2,816 announcements, 469 misses):

Model Pooled AUC Ξ”AUC vs history [95%] Precision in top 10%
history only 0.655 β€” 34%
history + sector 0.670 +0.015 [-0.002, +0.033] 36%
this model 0.680 +0.025 [+0.004, +0.047] 36%

By test year:

Test year Announcements / misses history + sector this model Ξ”
2023 726 / 138 0.670 0.704 +0.034
2024 727 / 135 0.658 0.679 +0.021
2025-26 1,363 / 196 0.673 0.671 -0.002

Base rate 16.7%. On companies held out of training (5-fold by company): AUC 0.688, +0.020 [+0.010, +0.030] over history + sector. The analyst + price part of that gain (+0.019) is unchanged when each test row's own year is left out of training, so it is not a same-quarter market shock.

Limitations

  • Modest skill. AUC β‰ˆ 0.68 ranks misses better than chance, not reliably. Flagging the riskiest 10% finds misses at 2.2Γ— the base rate.
  • The most recent test period (2025–26) shows no gain over history + sector. With three test years we can't tell a change in markets from noise.
  • Depends on Yahoo Finance at prediction time. Yahoo's analyst-action history is used as if it were complete and unrevised; that isn't guaranteed.
  • The text adds little on its own; an LLM reading the same guidance passages did no better.
  • Survivorship: companies are today's S&P 500 members (plus 49 large caps); REITs are excluded because their EPS labels mix FFO and GAAP bases.
  • Probabilities come from class-weighted training, so they are not calibrated (they overstate the miss rate). Use them for ranking.
  • Not investment advice. Educational project only.
Downloads last month
42
Safetensors
Model size
97 params
Tensor type
F32
Β·
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support