Validate adjusted stock prices against corporate actions
Validate adjusted stock data by connecting raw observations, a declared adjustment convention and independently obtained corporate-action records. Recalculate expected factors, compare the supplier’s values field by field and isolate discrepancies before a downstream calculation consumes the sequence. A smooth chart is not enough: an incorrect factor can remove a visible jump while leaving price or volume on the wrong basis.
This guide actually builds a four-date synthetic adjusted-close and volume series, validates one supplier fixture and identifies two injected mismatches. It does not maintain an investor’s share quantities or cost basis. CoTrading’s corresponding data-validation workflow remains planned or unverified, and the calculation does not establish a complete corporate-action service for any market.
Specify exactly what adjusted means
Our declared policy anchors the latest date, 22 October 2026, at its raw value. Earlier closes are scaled backward for a two-for-one split and a later cash dividend using a proportional dividend multiplier. Earlier volume is adjusted for the split only. The output is an analytical adjusted-close and split-adjusted-volume table, not actual historical execution prices or complete OHLC bars.
MathWorks documents a split and cash-dividend adjustment method that divides prior prices by the split ratio and scales earlier closes using the dividend relative to the preceding raw close. We use that explicit convention in our own synthetic calculation; we do not run MATLAB or claim that every supplier implements identical rules.
JPX’s J-Quants calculation reference illustrates cumulative price factors and separate volume treatment, while explicitly defining the corporate actions covered by that API. Its documented scope is not the same as our dividend-inclusive fixture. The important implementation lesson is to retain event types and separate factor chains, rather than applying every price factor to volume.
Obtain three aligned input tables
Keep raw daily observations, supplier-adjusted observations and event records separately. Each needs a confirmed security identifier, date convention, currency, unit and source revision. Corporate-action records should state the effective or ex-date, split direction and cash amount per applicable share. Do not infer the event solely from the price jump you are trying to validate.
The raw fixture has closes 100, 50, 49 and 50 on 19–22 October, with volumes 100, 200, 220 and 240. A two-for-one split becomes effective on the 20th. A cash dividend of 1 per post-split share goes ex on the 21st. These events occur on separate dates, avoiding an unresolved simultaneous-event unit convention.
The expected supplier fixture will match the declared policy. A separate bad fixture changes the 19th’s adjusted close to 50 and the 20th’s adjusted volume to 204. Keeping good and bad suppliers separate allows the assertions to demonstrate both normal acceptance and anomaly detection.
Build independent price and volume factors
For an observation before the split, multiply the price factor by one half and the volume factor by two. On or after the split date, that event is already reflected in raw units and should not be applied again. The event’s effective boundary therefore matters as much as the ratio direction.
For the cash dividend, the preceding raw close is 50. The declared proportional multiplier is (50 − 1) / 50 = 0.98. Apply it to prices strictly before the ex-date. Do not change volume for the cash dividend because it does not change the unit of an existing share under this fixture’s policy.
if day < event["date"]:
price_factor /= event["split"]
volume_factor *= event["split"]
if event["dividend"]:
multiplier = (previous_close-event["dividend"]) / previous_close
price_factor *= multiplier
The full example checks that split ratios are positive and dividend multipliers are in a valid positive range. It accumulates all later applicable events for each observation. Same-day combined actions, rights issues, spin-offs, missing event histories and foreign-currency distributions require additional explicit policies; this short function does not silently generalize to them.
Compare the generated series with the supplier
| Date | Raw close | Raw volume | Price factor | Volume factor | Expected adjusted close / volume |
|---|---|---|---|---|---|
| 19 October | 100 | 100 | 0.49 | 2 | 49 / 200 |
| 20 October | 50 | 200 | 0.98 | 1 | 49 / 200 |
| 21 October | 49 | 220 | 1 | 1 | 49 / 220 |
| 22 October | 50 | 240 | 1 | 1 | 50 / 240 |
Download the complete example. Use Python 3.12+, the standard library and synthetic records; run python R531.py. The authoring file is docs/growth/research/round-5/examples/R531.py.
Actual execution reconstructs all four expected rows and asserts equality with the good supplier fixture. It verifies the 19th’s factors 0.49 and 2 and the 20th’s factors 0.98 and 1. Against the bad fixture, the anomaly map identifies close on the 19th and volume on the 20th. Both dates are quarantined; the unchanged 21st and 22nd remain usable under the declared contract.
The example uses a numerical tolerance of 0.0001 for the injected comparison. A real tolerance should reflect documented output precision for each field. Do not round cumulative factors after every event merely to make the final series match a displayed chart. Retain intermediate precision and compare at the agreed publication precision.
Diagnose a missing dividend factor and a wrong volume factor
The bad 19 October close of 50 reflects the split adjustment but omits the dividend multiplier. It is not necessarily an arithmetic typo: it could be a valid split-only series mislabeled as matching our dividend-inclusive contract. Reclassify the basis or obtain the correct series; do not average 49 and 50 into a new unsupported price.
The bad 20 October volume of 204 is a different mechanism. That date is already post-split, and a cash dividend should not rescale volume in this policy. A common coding mistake reuses the entire price factor for volume, producing an economically wrong unit transformation. Separate price and volume chains expose it directly.
The generated expected table can support a proposed repaired sequence after the raw inputs, event packet and convention are approved. Preserve the supplier’s original values and the repair delta. Until that approval, a quarantined supplier interval is incomplete; do not call the remaining two dates a fully validated four-date dataset.
Prevent dividend double counting downstream
From the 20th to the 21st, adjusted close remains 49, so the declared adjusted-price return is zero. The fixture then intentionally adds the cash dividend again and computes (49 + 1) / 49 − 1, approximately 2.04%. That positive number is a double-counting error under the chosen adjustment convention, not a new investment gain.
Choose a consistent downstream method: use the declared adjusted-price convention for its intended analytical return, or use raw observations with an explicit distribution and share-unit accounting method. Do not treat these methods as interchangeable without checking their precise reinvestment and event assumptions. An adjusted close on the 19th is also not evidence that a trader could have executed at 49 when the raw observation was 100.
Deliver an event-linked validation package
Retain raw and supplier tables, event sources, anchor date, factor chains, expected values, tolerance, anomalies and the approved single-basis output. A reviewer should be able to rebuild the 19th’s 0.49 factor from the split and dividend separately, then see why the volume factor remains two rather than following the dividend adjustment.
Recalculate affected history after a verified event correction, anchor change or supplier-methodology change. A changing adjusted series is not automatically a corrupted raw series, but it requires a new declared version. This workflow validates a concrete analytical dataset and its failure branches; it does not certify all corporate actions, replace execution-price records or reproduce an account’s holdings ledger.
Review the proposed repair as a separate artifact
Create a repair table with date, field, original supplier value, expected value, event references and approval state. The expected sequence is a reproducible calculation under a chosen policy; it should not silently overwrite the supplier’s original series. A reviewer can accept the new analytical source or decide that the supplier’s different basis should simply be relabeled.
Check the anchor row and each event boundary as well as an older cumulative row. The anchor tests that no later event was applied unnecessarily; the event date tests strict before-date application; the older row tests factor accumulation. A series can pass one of these positions while failing another through an off-by-one event boundary.
For downstream use, attach the adjustment definition directly to the selected fields. A generic adjusted flag is insufficient when price includes cash dividends but volume follows only share-unit changes. Keeping those distinctions in the handoff prevents a correct local validation from becoming a later accounting mismatch after another tool interprets the columns under different defaults.
FAQ
Can the same cumulative factor adjust both price and volume?
Only where the declared event treatment supports it. Cash-dividend price factors must not automatically change volume in this fixture.
Can adjusted prices be used as historical fills?
Not without reconciling their units and purpose. Preserve raw execution observations separately.