Split-Adjusted Prices: The Crashes in Your Data That Never Happened

Published on: August 12, 2026 | By: Rizky Setya Maulana

Open a raw price file for almost any large-cap stock and you will find single days where the price fell by half, or by three quarters. No crisis, no earnings miss, no halt. Just a number that dropped and never came back. Those days are not market events, and a model that learns from them is learning from something that never happened.

Market data workstation showing historical price series and order book depth

A price series looks like a continuous record of what a market did. It is not. It is a record of what was quoted, and quotes are periodically reset by events that have nothing to do with supply and demand. Three of them do nearly all of the damage: stock splits, cash dividends, and the expiry and roll of futures contracts.

Each one leaves a discontinuity. Each discontinuity is indistinguishable from a return to any code that compares today's close with yesterday's. And unlike a parsing error or a missing file, none of them produces an exception — the pipeline runs cleanly and hands you a number that is wrong in a specific, repeatable direction.

The split: a 75% loss that cost nobody anything

A four-for-one stock split replaces each share with four shares worth a quarter as much. A 500 close becomes a 125 open. Arithmetically the holder is exactly where they were the previous evening.

In the raw file it reads as a 75% single-day loss. Feed that into a volatility estimate and the estimate is contaminated for the entire length of the lookback window, not just on the split date. Feed it into a model and the model has one enormous, entirely fictional observation to explain. Feed it into a risk system and the system will size positions against a tail event that never occurred.

The repair is arithmetic: divide every price before the split by four and multiply every volume before it by four. Do the second half and the volume profile stays comparable across the event; skip it and average daily volume appears to quadruple overnight.

The dividend: a small error that compounds

On the ex-dividend date, the price of a share drops by roughly the cash being paid out. The shareholder is not poorer — the value simply moved from the share price into their account.

Each individual drop is small, which is exactly why this one is dangerous. A split is visible from across the room; a 0.6% dividend adjustment is invisible in any single observation and yet it recurs four times a year, every year. Measure a decade of returns on unadjusted prices and the whole series is biased downward by roughly the cumulative dividend yield. For an index-tracking study, that is the difference between a strategy that clears its benchmark and one that quietly does not.

The correct treatment produces what is usually called a total-return series: multiply every price before the ex-date by one minus the dividend divided by the previous close. The reference price matters, and it is the close immediately before the ex-date — not the open on it, and not an average.

The roll: the error that repeats forever

Futures contracts expire. Any history longer than a few months is therefore not one instrument but a chain of them, stitched together at each roll.

At every stitch the price steps by the spread between the expiring contract and the next one. This is the worst of the three, for two reasons. It recurs on a schedule, so the error accumulates rather than appearing once. And its direction is not random: in a market in contango the next contract trades above the expiring one, so a naively stitched series contains a systematic negative step every quarter. A strategy tested on it will show a return that comes entirely from the stitching, in whichever direction the term structure happens to point.

This is the same category of problem we described in trading sessions and time zones: an error that does not break the pipeline, produces a plausible number, and therefore survives review.

Two conventions, and why the choice is not cosmetic

Back-adjustment leaves the most recent segment at the prices that actually printed and restates everything before each event so the joins are seamless. There are two ways to restate, and they answer different questions.

Ratio adjustment multiplies earlier prices by a factor. Percentage returns are preserved exactly and every price stays positive. This is the right default for equities, where research is almost always expressed in returns.

Difference adjustment adds a constant offset instead. Price differences are preserved exactly, which is what matters when the quantity of interest is a spread rather than a return. It is the conventional choice for futures. Its known cost is that a long back-adjusted history can approach zero or cross into negative prices — an accepted artefact of the convention, not a defect, but one you should know about before it appears in a chart.

This choice is also the main reason two vendors hand you two different "adjusted" series for the same instrument. Add the question of whether dividends were included at all, and which roll dates were used, and the differences look like data errors when they are simply undocumented conventions. When you compare series, compare conventions first.

What this does to research, concretely

The common thread across all three events is that the error flatters or distorts rather than crashing. Volatility is overstated on split dates and understated across dividend-heavy periods. Long-horizon equity returns are biased downward. Futures strategies inherit a drift manufactured by the stitching. Maximum drawdown statistics pick up fictional single-day collapses. Any feature built on rolling windows carries the contamination for the length of the window, not just for one row.

For machine-learning work the consequence is sharper still. A model trained on unadjusted data spends capacity learning to predict events that are, by construction, unpredictable and meaningless. We have written before about how easily a model can be taught the wrong lesson in the overfitting trap; corporate actions are the version of that problem that arrives before the model is even specified. The upstream discipline is the same one described in the hidden cost of dirty market data.

Doing it correctly

The rules are short. Adjust before aggregation, so bars are built from restated prices rather than restated after the fact. Apply adjustment strictly to data before each event, so the ex-date's own prints are untouched. Scale volume for splits and only for splits. Take the dividend reference from the last close before the ex-date. Record which convention was used, because a series without that note is not reproducible. And keep the raw prices — adjustment factors change when a new action occurs, so an adjusted series is a derived artefact, not a source of truth.

In our open-source tooling that looks like this:

from decimal import Decimal
from mdnorm import Pipeline, split, dividend, roll, iso_to_ns

actions = [
    split(iso_to_ns("2026-06-06T00:00:00Z"), Decimal("4")),
    dividend(iso_to_ns("2026-05-09T00:00:00Z"), Decimal("0.25")),
]

bars = (
    Pipeline()
    .adjust(actions)             # splits, dividends, rolls
    .time_bars(86_400_000_000_000)
    .run(events)
)

Or, with the actions in a CSV file and no Python at all:

$ pip install market-data-normalizer
$ mdnorm bars trades.csv --interval 1d \
      --actions actions.csv -o adjusted.csv

Futures rolls use the same mechanism with --adjust difference, and adjustment_at reports the exact factors in force at any timestamp, which is what you want when reconciling against a vendor series. The wider normalization pipeline this fits into — canonical schemas, deduplication, quality checks and bar sampling — is described in our market data normalization guide.

An arithmetic detail worth stating

Adjustment factors compose. A stock that splits twice carries the product of both factors on every price before the earlier of them, and that product has to be exact.

Our first implementation held those factors as decimals. A one-for-two followed by a one-for-three restated a price of 600 as 99.99999999999999999999999996, because one sixth has no finite decimal representation and the residue survived the multiplication. The test that caught it asserted exact equality. The two available responses were to loosen the assertion or to fix the arithmetic; we hold the factors as exact rationals now and divide once, at the point of application, and the test stayed strict. It is a small thing that is easy to round away and hard to find afterwards, and a library whose purpose is data correctness does not get to be approximately correct.

The implementation is public and free to inspect on GitHub and installable from PyPI. For the infrastructure layer beneath all of this, see what HFT infrastructure looks like and the true cost of latency; for the delivery side, our API documentation. If you are building research on these foundations and want to talk, our partnership page is the place to start.

Frequently asked questions

What are split-adjusted prices?

Split-adjusted prices are historical prices restated so that a stock split does not appear as a price change. When a company performs a four-for-one split, the quoted price divides by four overnight while the value of a holding stays the same. Adjustment divides every price before the split by the same factor and multiplies the volumes by it, so the return measured across the split date is zero rather than minus 75 percent.

Why does an unadjusted stock split look like a crash?

Because a return is normally computed by comparing today's price with yesterday's, and the split changes the price without changing anything about the investment. A 500 close followed by a 125 open after a four-for-one split reads as a 75 percent single-day loss to any code that does not know a split occurred. Nothing was lost: the shareholder now holds four times as many shares.

What is the difference between ratio and difference back-adjustment?

Ratio adjustment multiplies earlier prices by a factor, which preserves percentage returns exactly and keeps every price positive. Difference adjustment adds a constant offset instead, which preserves price differences exactly. Ratio is the right default for equities because most research works in returns. Difference is conventional for futures, where spreads matter, but a long back-adjusted history can approach zero or turn negative.

How are dividends handled in adjusted price data?

On the ex-dividend date the price drops by approximately the cash paid, which is not a loss to the shareholder. A total-return series multiplies every price before the ex-date by one minus the dividend divided by the previous close. Skipping this biases every long-horizon return downward by roughly the dividend yield, which is large enough to change whether a strategy beats its benchmark.

What is a back-adjusted continuous futures contract?

Futures contracts expire, so a long history has to be stitched from successive contracts. At each roll the price steps by the spread between the expiring contract and the next one. A back-adjusted continuous contract removes those steps by restating the earlier segments, leaving the most recent contract at the prices that actually traded. Without it, a market in contango produces a systematic negative drift that comes entirely from the stitching.

Do I need to adjust volume as well as price?

For splits, yes. A four-for-one split multiplies the share count by four, so pre-split volumes must be multiplied by four to be comparable with post-split volumes. Cash dividends and futures rolls do not change the quantity traded, so volume is left alone in those cases.

Why do adjusted price series from different vendors disagree?

Mostly because of three choices that are rarely documented: whether dividends are included at all, whether adjustment is applied by ratio or by difference, and which reference price and roll date were used. None of the choices is wrong, but comparing two series built on different conventions produces differences that look like data errors and are not.

Is there an open-source tool for adjusting market data for corporate actions?

Yes. HarvestGroup360 maintains market-data-normalizer, an MIT-licensed Python library that back-adjusts price series for stock splits, cash dividends and futures contract rolls, using either the ratio or the difference convention. It also normalises heterogeneous feeds into one schema, aggregates OHLCV and event-driven bars and filters by trading session. Install it with pip install market-data-normalizer (the import name is mdnorm); it has no runtime dependencies and the source is public at github.com/Harvestgroup360/market-data-normalizer.

Empowering quantitative research with high-frequency market data and analytics.