title: Corporate actions and price adjustment description: Raw is sacred. Adjustment is derived at read time, versioned, and always explained by an action you can query.
Splits, dividends and spin-offs make a raw price series discontinuous. A 10-for-1 split turns a 1000 close into a 100 open overnight with no economic change. Any analysis over that boundary needs adjusted prices, and every adjusted price needs an action that explains it.
Raw is sacred
Ingested prices are never rewritten. Adjustment is computed at read time from the corporate action set, which has two consequences worth relying on:
- The raw series always remains available and always matches what the exchange
printed. Ask for
adjusted=falseand you get exactly that. - A later correction to an action changes the adjusted answer without corrupting the underlying record, so a mistake is recoverable rather than baked in.
curl -H "Authorization: Bearer $PULSE_SANDBOX_KEY" \
".../v1/instruments/{id}/prices?from=2020-08-24&to=2020-09-04&adjusted=false"
curl -H "Authorization: Bearer $PULSE_SANDBOX_KEY" \
".../v1/instruments/{id}/prices?from=2020-08-24&to=2020-09-04&adjusted=true"
Both responses state which you got. meta.adjusted is a boolean on every price
response, so no consumer ever has to infer it from the numbers.
The action that explains the jump
Actions are queryable on the same instrument id, in the same call shape. There is no second product to buy and no join for you to write.
curl -H "Authorization: Bearer $PULSE_SANDBOX_KEY" \
".../v1/instruments/{id}/corporate-actions?from=2020-01-01&to=2020-12-31"
Each action carries kind, effectiveDate, createdAt, a params object whose
shape depends on the kind, and source.
Which kinds adjust prices
| Kind | Effect on prices | Key params |
|---|---|---|
| split, reverse_split | Price and volume rescaled by the ratio | ratio, e.g. "10:1" |
| cash_dividend, special_dividend | Prices before the ex-date scaled down by the distribution | cash_amount |
| spin_off | Prices before the effective date rescaled | ratio parameters |
Every other kind - merger, acquisition, ticker_change, delisting,
halt, rights_issue, bonus_issue, redenomination - is returned to you but
applies no price adjustment.
That is deliberate. An action we cannot adjust for correctly must not silently
apply a wrong number. The same rule applies within an adjustable kind: if a
split row arrives with a malformed or missing ratio, it adjusts nothing rather
than guessing. You still see the action in the corporate-actions response, so
you can handle it yourself and you are never unaware that something happened.
actionSetVersion, and why adjustment changes under you
Adjusted prices are a function of the action set. When the action set changes, adjusted prices change - correctly, but retroactively. That is the thing most APIs let happen silently.
Every price response carries meta.actionSetVersion. Record it with your
results. It gives you three things:
- Reproducibility. The same instrument, window and version returns the same numbers, permanently.
- A change signal. A version that moved between two runs tells you the adjustment basis changed, so a diff in your output is explained rather than mysterious.
- An audit trail. A published backtest can name the exact basis it used.
Ticker changes and reused tickers
Instrument identity is an id, not a ticker. instrument_symbols is
effective-dated, so a ticker that changed hands resolves to the right instrument
as of a date rather than to whichever company holds it today.
Delisted instruments are retained and remain queryable. Dropping them is what creates survivorship bias, and a universe that quietly excludes everything that failed will make almost any strategy look good.
Combine this with asOf when reconstructing a historical
universe: you want the instruments that existed then, under the tickers they
carried then.