The Analyst's Path

Adjusted close price

The adjusted close price is a historical closing price restated for splits and dividends, so that returns computed across those events are not distorted. For a long history you compute each event's own factor from the raw prices around it, then multiply the factors together, working backward from the latest date. A wrong order gives a plausible-looking series that is silently off.

5 min readPart of Market & Fundamental Data Pipelines + Vendor LandscapeOpen in course mode

Advertisement

Real securities accumulate many corporate actions over a real history, several splits, dozens of dividends, sometimes both in close succession. The correct general algorithm generalizes Exercise 1 and Exercise 2 into one function, and how it generalizes is worth understanding precisely rather than memorizing, because a subtly wrong composition order is a real, easy-to-make bug.

How does the back-adjustment algorithm work?

The rule: compute each event's own adjustment factor from the RAW (never already-adjusted) prices around it, then apply the cumulative product of every event's factor, working backward from the most recent date. Concretely: walk the series from the last index to the first. Start a running cumulative factor at 1.0. At each date, record the current cumulative factor as that date's adjustment factor, then, if an event's effect begins exactly at this date (this module's consistent convention: closes[event_index] is already on the new basis), multiply the running cumulative factor by that event's own local factor (1/ratio for a split; (prev_close − amount)/prev_close for a dividend, using the raw prev_close) before moving to the next, earlier date. The critical, easy-to-get-wrong detail: a dividend's local factor must always be computed from the raw price at the time it was paid, never from a price some later split has already rescaled, because a dividend is quoted in the actual currency amount paid on the actual share basis in effect at that moment, and rescaling it through the lens of a split that hadn't happened yet would silently distort the ratio. Decoupling "compute each event's factor from raw data" from "accumulate factors across events" is what makes the algorithm correct regardless of how many events you throw at it, and regardless of the order they're supplied in.

Advertisement

Worked example: a split and a dividend in one series

Trace a combined example fully. A fictional NILAM series (₹, illustrative) over eight days carries a ₹15 dividend at index 2 (against a prior close of ₹1,185) and a 2-for-1 split at index 5: raw closes [1180.00, 1200.00, 1185.00, 1190.00, 1205.00, 605.00, 610.00, 615.00]. Working backward: indices 5–7 (on or after the split) get factor 1.0: unchanged. The moment we pass index 5, the running factor picks up the split's local factor 1/2 = 0.5. Indices 3–4 (after the dividend, before the split) get factor 0.5: 1190.00 × 0.5 = 595.00, 1205.00 × 0.5 = 602.50. The moment we pass index 2, the running factor also picks up the dividend's local factor (1185.00 − 15.00)/1185.00 = 0.98734..., compounding with the split's 0.5 already in effect: indices 0–2 get the product of both factors, 0.5 × 0.98734... ≈ 0.49367: 1180.00 → 582.625, 1200.00 → 592.5, 1185.00 → 592.5. The full adjusted series comes out to [582.625, 592.5, 592.5, 595.0, 602.5, 605.0, 610.0, 615.0], verified by running the actual code, not merely asserted (see this module's code pack; every number in this document was produced by running real Python, not hand-arithmetic alone). A US companion on BRPEAK, a 3-for-1 split at index 4 followed by a $1.20 dividend at index 6, composes the same way and is Exercise 3's second hidden test. This composed function (back_adjust(closes, events)) is the one a real pipeline actually ships; Exercise 1 and Exercise 2 exist to make sure you understand its two ingredients before you have to compose them.

{
  "skill": "Drafting a first-pass adjustment function you already understand by hand, then verifying it against your own worked example",
  "use": "After you have hand-traced a small back-adjustment example (like the eight-day NILAM series above) and arrived at the correct numbers yourself, use an AI coding assistant to draft the general `back_adjust(closes, events)` function — then treat the draft exactly as you would a junior colleague's untested first pass.",
  "tools": ["AI coding assistants — Claude, ChatGPT, GitHub Copilot", "This module's code pack's own hidden tests, as the actual judge"],
  "prompt": "I already worked this out by hand: <YOUR HAND-TRACED EXAMPLE, e.g. the 8-day NILAM series above and its final adjusted values>. Write a Python function `back_adjust(closes, events)` that generalizes this to any list of split/dividend events, computing each event's own factor from RAW prices and applying the cumulative product working backward. Do not just match my one example — show me it handles an arbitrary number of events in any order.",
  "verify": "Run the draft on the EXACT example you hand-traced first. If it does not reproduce your own by-hand numbers to the last decimal, the draft is wrong regardless of how clean the code looks — a subtly wrong composition order (e.g. computing a dividend's factor from an already-split-adjusted price instead of the raw one) will still produce a plausible-looking number that is silently off. Then run it against this module's code pack hidden tests before trusting it on real data.",
  "diy": "You must be able to hand-trace a combined split+dividend example yourself, correctly, before asking a tool to generalize it — that is exactly what this section and Worked Examples 1-3 build. An AI cannot verify a composition rule you cannot yourself check.",
  "market": "IN"
}

Advertisement

Part of the course

This page is part of Market & Fundamental Data Pipelines + Vendor Landscape (QD1.01), in Phase 12: Finance Plus, AI and the quant-code track. The module's flashcards and its quiz are in the app.