All Posts
TutorialStock Split DetectionXBRL DataCorporate Actions API

How to Detect Stock Splits in Historical Data

Detect stock splits in historical data from XBRL ratio tags and share-count cliffs: the corroboration logic behind StockFit's split API.

Published August 20, 202612 min readStockFit Engineering
How to Detect Stock Splits in Historical Data

During StockFit's development we set out to build a historical record of stock splits straight from SEC filings, the same question every split calendar site answers (what split happened, and when), but for the question a backtest actually needs answered: how do you detect a split from the underlying data itself, reliably, for a company that never sends a press release? That is when we ran into the discrepancies. SEC EDGAR tags stock splits in XBRL, but simply reading the required concept turns out not to be enough, for a specific, well-documented reason, and naive detection strategies (watch for a big overnight price jump, trust the ratio tag's sign) both fail on real filings. This is the detection logic behind StockFit's /api/company/stock-splits family, built from roughly 2,500 tagged companies, and the specific ways it had to get corrected before the numbers could be trusted.

Why naive stock split detection fails

The obvious first approach is to watch daily closing prices for a large overnight drop or jump and infer a split from the ratio. It fails for two reasons. First, plenty of overnight price moves that look like a 2-for-1 split are just a bad earnings print or a sector selloff, so a price-only detector needs a second signal to avoid false positives. Second, and more fundamental, a price time series alone cannot tell you which of two exact numbers a split most affects: share count and per-share metrics like EPS. If your data source has already silently split-adjusted historical prices (many do), the split is invisible in price data entirely, but it is still there, unadjusted, in every share count and per-share XBRL fact filed before the event.

The structured evidence lives in the filings themselves, not in price history. That means SEC XBRL, and specifically, the two concepts issuers use to tag a split's conversion ratio.

Where split evidence lives in SEC filings

US GAAP defines us-gaap:StockholdersEquityNoteStockSplitConversionRatio1 (and its pre-2015 predecessor, us-gaap:StockholdersEquityNoteStockSplitConversionRatio) for exactly this: a company that executes a stock split tags the conversion ratio as a footnote fact in its next 10-K or 10-Q. Most filers tag it as a plain, dimensionless value. Some tag it only on the class_of_stock dimension, alongside their per-share-class facts, which means it never reaches a naive fact scan at all, only a dimensional-facts table built specifically to catch it.

json
// A cleanly-tagged forward split (NVIDIA, 10-for-1, June 2024)
{ "concept": "us-gaap:StockholdersEquityNoteStockSplitConversionRatio1", "value": 10, "period_end": "2024-06-30" }

// A split tagged only on the class-of-stock dimension — invisible to a plain facts scan
{ "concept": "us-gaap:StockholdersEquityNoteStockSplitConversionRatio1",
  "axis": "us-gaap:StatementClassOfStockAxis", "member": "hnst:ClassACommonStockMember", "value": 2 }

Reading that tag looks like the whole job. It is not. The tag tells you a split happened and roughly how big it was. It does not reliably tell you which direction.

The XBRL ratio tag direction problem

A forward split and a reverse split can be tagged with the exact same magnitude. A 2-for-1 forward split and a 1-for-2 reverse split are both, in some filer's hands, a value of 2, because the concept's definition does not enforce a sign convention and issuers, their outside counsel, and their XBRL tagging vendors do not all interpret "conversion ratio" the same way. vTv Therapeutics is the clearest case in our data: its own 8-K confirms a single 1-for-40 reverse split approved for both Class A and Class B common stock on the same day in November 2023, yet its FY2023 10-K tags that one event two different ways in the very same filing, 0.025 for Class A (the correct post-split ratio) and 40 (the untouched pre-split magnitude) for Class B, as shown in SEC's own rendered financial report for the filing. The Honest Company tagged its 2021 split both ways across different filings in its filing history. A scan that simply reads whichever tagged context it lands on first ships a wrong-direction split roughly as often as a filer contradicts itself, and a wrong-direction split does not just misdate an event, it inverts every share count and per-share figure computed on either side of it.

The fix is not a better parser. It is a second, independent signal that can confirm or override the tag: what actually happened to the company's reported share count around that date.

Corroborating a split with the share-count cliff

Every company also tags its outstanding share count, in us-gaap:CommonStockSharesOutstanding and dei:EntityCommonStockSharesOutstanding facts, filed quarterly regardless of whether a split happened. Bracket a candidate split date with the nearest share-count observation before and after it, and a real split shows up as a clean, discrete jump, the share-count cliff, close in magnitude to the tagged ratio. A wrongly-tagged direction shows up as a mismatch: the tag says 40 but the actual share count fell by roughly 40x, not rose.

The cliff is not treated symmetrically, because the two directions carry different amounts of ambiguity:

  • Shares fell by roughly the tagged magnitude. This is unambiguous. A share count cannot collapse tenfold except through a reverse split, so a corroborated drop overrides the tag's stated direction and stores the reverse ratio. This is exactly what resolves vTv's contradictory Class B tag of 40 to 0.025, the value its Class A tag already had.
  • Shares rose by roughly the tagged magnitude. This is never forced to a forward split. A rising share count can be a real forward split, but it can just as easily be an IPO primary offering or heavy equity issuance, both of which move share count by a large factor with no split involved. A rise only confirms a split when the filer's own tag already said forward; it never invents one.
  • No real cliff, or a cliff that matches neither the ratio nor its reciprocal. Trust the filer's tag as filed (or, for a filer that tagged the same event both ways in different filings, take the earliest-disclosed direction) rather than dropping a real event over a noisy or absent share-count observation.

One more guardrail matters before any of this runs: magnitude. Pre-IPO recapitalizations can tag conversion ratios in the millions (Elanco Animal Health tagged a founder-share conversion ratio of 2,932,900 ahead of its 2018 IPO), which is a legitimate XBRL fact but not a market split with public per-share history on both sides, so anything above roughly 1,000x is excluded outright. No real market split comes close; Chipotle's 50-for-1 in 2024 is the largest in our dataset.

Worked examples: what the detector flags, and what it deliberately doesn't

Pulled directly from /api/company/stock-splits for each ticker:

json
// Forward splits: tag and cliff agree, direction is not in question
GET /api/company/stock-splits?symbol=NVDA
[
  { "date": "2024-06-30", "ratio": 10, "type": "forward", "accession": "0001045810-24-000264", "firstDisclosedAt": "2024-08-28" },
  { "date": "2021-07-19", "ratio": 4,  "type": "forward", "accession": "0001045810-21-000131", "firstDisclosedAt": "2021-08-20" }
]

// Reverse split, correctly resolved even though vTv's own 10-K tags the same event two ways
// in one filing — "0.025" for Class A, "40" (the untouched pre-split magnitude) for Class B —
// the share-count cliff resolves it independent of which tag a naive scan lands on
GET /api/company/stock-splits?symbol=VTVT
[
  { "date": "2023-11-20", "ratio": 0.025, "type": "reverse", "accession": "0001641489-24-000012", "firstDisclosedAt": "2024-03-13" }
]

Ashford Hospitality Trust (AHT) is the clearest illustration of why reverse-split detection matters beyond just getting one date right. The hotel REIT executed three separate 1-for-10 reverse splits, in 2020, 2021, and 2024, each one to regain the NYSE's $1.00 minimum-price listing requirement. Looked at individually, each is a routine corporate action. Stacked, one AHT share today represents 1,000 pre-2020 shares, and a series of reverse splits at shrinking intervals is itself a signal worth surfacing to anyone screening for listing-compliance distress, not just a number to silently adjust away.

Ashford Hospitality Trust: three 1-for-10 reverse splits in four years
Each split individually looks routine. Stacked, one AHT share today represents 1,000 pre-2020 shares, a compliance-driven pattern worth flagging, not just adjusting for.

Equally important is what a correct detector refuses to flag. A rising share count from an IPO primary offering or a heavy secondary raise is never forced into a forward split, even when the magnitude happens to land near a round number, because trusting a rise without a filer's own tag would misclassify ordinary equity issuance as a corporate action that never happened.

Disclosure lag and date semantics: what firstDisclosedAt actually means

Two fields on every split record answer two different questions, and conflating them is a common bug. date is the split date as tagged in the XBRL footnote itself, typically the ex-date, record date, or payable date depending on the filer. firstDisclosedAt is the SEC acceptance date of the filing where that fact first became machine-readable, which can lag the actual event by weeks or, in one real case in our data, over a year and a half.

XBRL disclosure lag: split date vs. first machine-readable disclosure
14 real split events. Lag ranges from -89 days (Alphabet disclosed its ratio before the split executed) to 559 days (Honest Company).

A few of these are worth reading closely. Amazon's tagged date of May 27, 2022 is its shareholder record date for the 20-for-1 split, not the June 6 trading-adjusted date. Alphabet's tagged date of July 15, 2022 is its distribution date; and because Alphabet disclosed the ratio in a subsequent-events footnote of its Q1 2022 10-Q, filed April 27, before the split even executed, its lag is negative, disclosed 89 days ahead of the event it describes. Different filers, different reference points, same concept, exactly the "date semantics vary by filer" caveat documented on the endpoint itself.

NVIDIA is the one worth being honest about rather than smoothing over: its tagged date for the 2024 split is 2024-06-30, which matches none of the split's three public dates, not the May 22 announcement, the June 6 record date, or the June 10 split-adjusted trading date. It lands on an ordinary calendar-quarter boundary, most likely a duration context the filer's tagging software defaulted to rather than a corporate-action date. It is a real caveat, not a bug we can parse around: for time-sensitive work, treat date as the tag's reported context, cross-check it against a primary source when the exact day matters, and never assume it equals a record, distribution, or trading date without checking which one a given filer used.

The Honest Company is the disclosure-lag outlier: its 2-for-1 split executed April 30, 2021, ahead of its May IPO, but the XBRL fact did not surface until a 10-Q filed November 10, 2022, 559 days later. A detector that only looks back 90 or even 180 days for a company's most recent split would have missed it entirely for a year and a half.

Detecting stock splits programmatically via the StockFit API

All of the above, XBRL fact extraction across two concepts and both plain and dimensional tagging, magnitude-based event clustering, share-count cliff corroboration, and the asymmetric drop-vs-rise logic, runs once per lake update and is served as a plain lookup, not recomputed per request. Three endpoints cover the three shapes of the problem:

  • /api/company/stock-splits — full split history for one company, ordered newest first.
  • /api/company/recent-stock-splits — market-wide feed of splits within a configurable lookback window (up to 365 days), useful for screening reverse-split candidates as a listing-compliance signal.
  • /api/company/upcoming-stock-splits — declared splits not yet executed, sourced from a separate corporate-actions calendar rather than XBRL, since a split that has not happened yet cannot be in a filing.
bash
curl "https://api.stockfit.io/v1/api/company/stock-splits?symbol=CMG" \
  -H "Authorization: Bearer $STOCKFIT_TOKEN"

Getting the split record right is not the end goal, it is the input to every other endpoint that has to stay consistent across a split boundary. /api/financials/income-statement and the other statement endpoints default to splitAdjust=true, applying the same corrected ratios so a five-year EPS or share-count series reads on one consistent basis instead of jumping 10x at a split date. Get the direction wrong once in the detector, and every downstream per-share figure before that date is wrong by the same factor, silently, which is exactly the class of error point-in-time backtesting work cannot tolerate.

The same multi-class dimensional tagging that hides a split ratio on the class_of_stock axis also hides EPS and share count for issuers like Visa; see extracting EPS and share count with Arelle for the as-converted reconstruction that problem needs. For the broader case of why any of this matters to a systematic strategy, see building a backtest on the StockFit API.

The underlying facts come from SEC EDGAR full-text search, and every split event StockFit resolves is parsed from the filing's own XBRL via Arelle, the open-source XBRL processor, rather than scraped from a calendar or press-release feed.

FAQ

Q.How do I detect stock splits in historical financial data?
Read the XBRL conversion-ratio tags (us-gaap:StockholdersEquityNoteStockSplitConversionRatio1 and its predecessor) from each 10-K and 10-Q, including the copies tagged only on the class-of-stock dimension, then corroborate each candidate event against the company's own reported share-count history around that date. The tag alone tells you a split happened and roughly how large; the share-count cliff is what confirms the direction. StockFit runs this pipeline once per update and serves the result via /api/company/stock-splits.
Q.Why can't I just look for a big overnight price jump to detect a split?
Because a price jump alone cannot distinguish a split from an earnings gap, a sector selloff, or any other large one-day move, and because many price data sources already silently split-adjust their historical series, which erases the very signal you would be looking for. The split is still present, unadjusted, in every share count and per-share XBRL fact filed before the event, which is why the filings, not the price series, are the reliable source.
Q.Why does the XBRL stock-split ratio tag sometimes report the wrong direction?
Because the underlying concept has no enforced sign convention, and different filers, tagging vendors, and outside counsel interpret "conversion ratio" differently. In real filings, vTv Therapeutics tagged one 1-for-40 reverse split two ways in the same 10-K, 0.025 for Class A and 40 for Class B, and The Honest Company tagged its 2021 split both ways across different filings. Trusting the raw sign of whichever tag a scan lands on first ships a wrong-direction event roughly as often as a filer contradicts itself.
Q.What is a share-count cliff, and how does it confirm a stock split?
It is the discrete jump in a company's reported outstanding share count straddling a candidate split date, measured from the nearest share-count XBRL facts before and after. When the cliff's magnitude matches the tagged ratio (or its reciprocal), the split is corroborated. A cliff that shows shares falling by roughly the tagged magnitude is treated as unambiguous, since a share count cannot collapse tenfold except via a reverse split, and overrides a forward-tagged ratio to the correct reverse value.
Q.Why do some companies take over a year to disclose a stock split in structured XBRL data?
Because the XBRL tag only becomes machine-readable when the company files its next 10-K or 10-Q, and reporting cadence varies. The Honest Company's April 2021 split was not tagged in XBRL until a 10-Q filed November 2022, 559 days later. A detector with only a 90 or 180-day lookback window would have missed it for a year and a half; StockFit's full per-company history endpoint has no such window.
Q.Can a rising share count ever be mistaken for a stock split?
Yes, which is exactly why a rise is never forced into a forward split on cliff evidence alone. An IPO primary offering or a large secondary equity raise can move share count by a large factor with no split involved. A rising cliff only confirms an event as a forward split when the filer's own XBRL tag already said forward; a rise is never invented from price or share-count movement by itself.
Q.What is the difference between a forward and a reverse stock split?
A forward split increases share count and proportionally lowers the price per share (a 10-for-1 split turns one $1,000 share into ten $100 shares). A reverse split decreases share count and raises the price per share (a 1-for-10 reverse split turns ten $0.50 shares into one $5 share), most commonly executed to regain a minimum listing price, as Ashford Hospitality Trust did three times between 2020 and 2024. Both ride the same XBRL concept: ratios greater than 1 are forward, fractional ratios are reverse.
Q.Are ETF and mutual fund share splits covered by the same stock-split endpoints?
No. /api/company/stock-splits, /api/company/recent-stock-splits, and /api/company/upcoming-stock-splits are scoped to common stocks; passing a fund or ETF symbol returns an error. Fund share splits are a distinct, less common corporate action disclosed through different filings.
Q.Which StockFit plan includes the stock split endpoints?
All three stock-split endpoints require the Stock plan ($39/mo) or the Professional plan ($69/mo). There is no free-tier access to split history specifically, though downstream endpoints like /api/financials/income-statement apply the resulting split adjustment automatically via splitAdjust=true regardless of tier.

Ready to build?

Free API key, no credit card. Every endpoint mentioned in this post is available on the free tier.