Insights
SEC Filing-Intensity API for Event Detection
Alphanume Team · August 3, 2026
Use the Filing Intensity API to find issuer-days with unusually high filing counts, then inspect the underlying filings before assigning materiality, direction, or a trade.
Alphanume's SEC Filing Intensity dataset provides one daily row per equity with ticker, name, date, and filing_count. It is a wide event-detection layer: cheap to screen across issuers, simple to normalize, and deliberately agnostic about what the filings said.
A burst measures activity. Several routine ownership forms can produce a large count, while one 8-K can carry a material event. The count alone has no bullish or bearish direction, so the research job is to surface unusual issuer-days and route them into filing-level review.
Know what one row means
Field | Meaning | Research constraint |
|---|---|---|
ticker | Case-normalized equity symbol | Ticker identity can change through time |
name | Company name associated with the ticker | Reference label, not an event classification |
date | Observation date | Use as the count date, then inspect filing timestamps separately |
filing_count | Number of SEC filings for the entity that day | Activity only, with no form or content fields |
The endpoint can isolate high-count days with filing_count_gte or quiet baselines with filing_count_eq=0. Equality cannot be combined with count-range parameters. Exact date also cannot be combined with date-range parameters, which keeps the query contract unambiguous.
Retrieve the full candidate window
The endpoint is GET /v1/filing-intensity. For a cross-sectional screen, request a fixed date range and paginate using both cursor fields returned by the server. Results are ordered by date descending and ticker ascending.
import os
import requests
url = "https://api.alphanume.com/v1/filing-intensity"
headers = {"X-API-Key": os.environ["ALPHANUME_API_KEY"]}
params = {"date_gte": "2026-04-01", "date_lte": "2026-06-30"}
rows = []
while True:
response = requests.get(url, headers=headers, params=params, timeout=30)
response.raise_for_status()
payload = response.json()
rows.extend(payload["data"])
if not payload["has_more"]:
break
params.update(
cursor_date=payload["next_cursor"]["date"],
cursor_ticker=payload["next_cursor"]["ticker"],
)Supplying only one cursor field returns a 400 error. Save each raw page and its request parameters so a missing page cannot silently change the cross-section. Free access provides a trailing 20-trading-session window ending one session behind the latest observation.
Normalize each issuer against itself
A fixed threshold such as five filings is easy to explain, but it treats a normally busy issuer and a normally quiet issuer the same. A trailing z-score compares today's count with that ticker's own earlier distribution. Shift the rolling statistics by one day so today's count does not help define its own baseline.
import pandas as pd
frame = pd.DataFrame(rows).sort_values(["ticker", "date"])
grouped = frame.groupby("ticker")["filing_count"]
frame["baseline_mean"] = grouped.transform(
lambda s: s.shift(1).rolling(60, min_periods=30).mean()
)
frame["baseline_std"] = grouped.transform(
lambda s: s.shift(1).rolling(60, min_periods=30).std(ddof=0)
)
frame["filing_z"] = (
frame["filing_count"] - frame["baseline_mean"]
) / frame["baseline_std"].replace(0, pd.NA)
candidates = frame.loc[frame["filing_z"] >= 3].copy()Choose the 60-session lookback, 30-observation minimum, and z-score threshold before examining returns. Issuers with zero baseline variance should remain null or receive a separately defined rule. Converting the zero denominator into a huge score manufactures an event where the statistic is undefined.
Route counts into labeled evidence
The four-field response cannot identify a capital raise, insider transaction, cyber disclosure, or routine ownership update. For each candidate, collect the underlying EDGAR filings and group them by form and timestamp. Alphanume's labeled datasets can provide a second pass for supported event classes such as S-1 dilution, shelf registrations, and cyber incidents.
That second pass should preserve the original denominator. Report how many high-intensity issuer-days mapped to a labeled event, how many contained unsupported filing types, and how many could not be resolved. The absence of a match in one labeled dataset does not turn the candidate into a false positive.
Respect timing and coverage
- Nightly refresh. The dataset refreshes at 11:30 PM EST, and filings after the cutoff appear in the following night's update.
- Daily aggregation. A date-level count does not reveal whether a filing arrived before, during, or after market hours.
- Ticker history. Corporate actions and symbol changes can break naive joins to later price data.
- Threshold mining. Trying many lookbacks and cutoffs on the same outcomes inflates apparent performance.
- Direction. Filing activity alone does not establish positive or negative price pressure.
Define the first tradable outcome session from the underlying filing timestamps, not from the daily count alone. Then maintain a complete exclusions table for missing prices, ticker changes, and unresolved filing content. The Filing Intensity API reference documents filters, pagination, and update timing.
Run one reproducible event screen
Pull a fixed period, calculate one preregistered threshold, and export the full issuer-day denominator plus candidates. Inspect every candidate's EDGAR forms, label the reason for the burst, and calculate returns only after the timing rule is frozen. Save raw pages, code, baseline parameters, and exclusion reasons beside the output.
For deeper context on why the raw SEC stream rewards careful timestamp and document handling, read A Cracked Quant's Guide to Beating the SEC's Feed. Use that context to improve the review layer, while keeping the API count and the filing content as separate evidence.