---
title: "1.4.3 Adjusting prices for splits and dividends"
description: "Backward adjustment factors for a 4-for-1 split and 33 dividends, total return versus price return, false signals and the point-in-time problem."
url: "https://pythonparatrading.com/en/python-trading-course/level-1/adjusting-prices-for-splits-and-dividends/"
lang: "en"
image: "https://pythonparatrading.com/og/en/python-trading-course/level-1/adjusting-prices-for-splits-and-dividends.png"
---

# 1.4.3 · Adjusting for splits and dividends: adjusted and unadjusted prices

> On August 23, 2021 NOVA “fell” 75% and nobody lost any money: it was a 4-for-1 split. This lesson builds by hand the adjustment factors for eight years of corporate actions, checks the method against the example published by a provider and shows when to use each series and what breaks when you use the wrong one.

- Course: [Level 1: Financial data, markets and analysis](https://pythonparatrading.com/en/python-trading-course/level-1/)
- Module: 1.4 · Financial data engineering
- Duration: 55 min
- Prerequisites: [1.2.1 · Stocks: splits, dividends and corporate actions](https://pythonparatrading.com/en/python-trading-course/level-1/stocks-splits-dividends-corporate-actions/), [1.4.2 · Data cleaning: missing values, bad ticks, gaps and time zones](https://pythonparatrading.com/en/python-trading-course/level-1/cleaning-financial-market-data/)

## By the end of this lesson

- Compute the factor of each split and each dividend and the backward cumulative factor, and build the adjusted series with them.
- Check that the adjusted series has no jumps on the ex-dates and that its return is the total return.
- Tell price return and total return apart, and measure how much the dividends contribute.
- Recognize the false signals that unadjusted prices produce in a backtest.
- Explain why an adjusted price changes when a new dividend arrives and how to store the data so that this does not contaminate a backtest.

## A crash that was not one

The NOVA daily series in this lesson has the prices **as they were traded**: unadjusted. Eight years of NYSE sessions,
from 2018 to 2025, with all the corporate actions that lesson 1.2.1 described: one split and 33 dividends, one of them
a special dividend. One week of August 2021 is enough to see it:

```python
import numpy as np
import pandas as pd

bruto = pd.read_csv("nova_diario_sin_ajustar.csv",
                    parse_dates=["fecha"], index_col="fecha")
bruto.loc["2021-08-19":"2021-08-25"]
```
```output
            apertura  maximo  minimo  cierre   volumen
fecha
2021-08-19    239.60  251.84  238.19  241.05   2471611
2021-08-20    238.75  240.55  227.85  240.00   2203366
2021-08-23     60.28   60.41   58.11   59.55  13427377
2021-08-24     59.63   60.11   57.33   59.55  13974110
2021-08-25     59.17   62.40   58.71   60.18   6931159
```

Friday the 20th closes at 240.00 and Monday the 23rd opens at 60.28, with the volume multiplied by six. There was no
panic: from Monday on, each old share is four new ones, and each new one is worth a quarter. Whoever had 100 shares at
240 USD (24,000 USD) has 400 at 60 (24,000 USD). In the raw series, however, it is the biggest drop in its history:

```python
r_bruto = bruto["cierre"].pct_change()
(100 * r_bruto.nsmallest(4)).round(2)
```
```output
fecha
2021-08-23   -75.19
2021-06-02   -12.21
2025-03-26   -12.10
2020-06-23   -12.06
Name: cierre, dtype: float64
```

A −75.19% that cost nobody anything, ahead of three real drops of around 12%. Any calculation on this series
(volatility, drawdown, a signal) is contaminated by it. And there are more jumps, smaller and more frequent: on each
**ex-date** of a dividend, the price opens lower because whoever buys that day no longer collects the dividend. The
adjustment corrects both things.

## The events and their factors

The events table has one row per event: the ex-date, the type, the split ratio or the dividend amount (in the shares
that existed on that date: dividends before the split are per old share) and the payment date.

```python
eventos = pd.read_csv("nova_eventos.csv",
                      parse_dates=["fecha_ex", "fecha_pago"])
print(eventos["tipo"].value_counts().to_dict())
eventos.iloc[13:18]
```
```output
{'dividendo': 32, 'split': 1, 'dividendo_extraordinario': 1}
     fecha_ex       tipo  ratio  importe fecha_pago
13 2021-05-10  dividendo    NaN     0.60 2021-06-01
14 2021-08-10  dividendo    NaN     0.60 2021-08-31
15 2021-08-23      split    4.0      NaN 2021-08-20
16 2021-11-10  dividendo    NaN     0.15 2021-12-01
17 2022-02-10  dividendo    NaN     0.16 2022-03-03
```

The quarterly dividend goes from 0.60 to 0.15 USD with the split: it is the same dividend per company, spread over four
times as many shares. Each event becomes a **factor**, the number by which all prices before its ex-date have to be
multiplied so that the series does not jump:

$$
f_e = \begin{cases} \dfrac{1}{\text{ratio}_e} & \text{split} \\[6pt] 1 - \dfrac{D_e}{C_{e-1}} & \text{dividend}
\end{cases} \qquad\qquad F_t = \prod_{e \,:\, t_e > t} f_e, \qquad\qquad \tilde{P}_t = F_t \cdot P_t
$$

where $D_e$ is the dividend, $C_{e-1}$ the unadjusted close of the session before the ex-date, $F_t$ the cumulative
factor of day $t$ (the product of the factors of all events **after** that day) and $\tilde{P}_t$ the adjusted price.
It is a **backward** adjustment: the last stretch of the series keeps the real prices and the past is rescaled. It is
CRSP's multiplicative method, the one Yahoo describes for its adjusted close.

```mermaid
flowchart LR
  B[Raw prices] --> F[Factor per event]
  E[Events] --> F
  F --> A[Cumulative factor]
  A --> J[Adjusted series]
  B --> J
```

```python
def factores(precios, eventos):
    cierre_ant = precios["cierre"].shift()
    ev = eventos.copy()
    es_split = ev["tipo"] == "split"
    ev["cierre_ant"] = cierre_ant.reindex(ev["fecha_ex"]).to_numpy()
    ev["factor"] = np.where(es_split, 1 / ev["ratio"],
                            1 - ev["importe"] / ev["cierre_ant"])
    return ev

ev = factores(bruto, eventos)
ev.loc[[14, 15, 25, 33],
       ["fecha_ex", "tipo", "importe", "cierre_ant", "factor"]]
```
```output
     fecha_ex                      tipo  importe  cierre_ant    factor
14 2021-08-10                 dividendo     0.60      213.21  0.997186
15 2021-08-23                     split      NaN      240.00  0.250000
25 2023-12-14  dividendo_extraordinario     1.50       42.75  0.964912
33 2025-11-10                 dividendo     0.19       66.13  0.997127
```

The split weighs 0.25; a quarterly dividend, between 0.9956 and 0.9983 depending on that day's price; the special
dividend of 1.50 USD, 0.965. A day's cumulative factor is the product of all those that come after it. It is computed
by walking through the events: each one multiplies by its factor all the days before its ex-date.

```python
def ajustar(precios, ev):
    """F_t: product of the factors of the events after t."""
    F = pd.Series(1.0, index=precios.index)
    for fecha_ex, f in zip(ev["fecha_ex"], ev["factor"]):
        F[F.index < fecha_ex] *= f
    return F

F = ajustar(bruto, ev)
precios = ["apertura", "maximo", "minimo", "cierre"]
ajustado = bruto[precios].mul(F, axis=0)
pd.DataFrame({"bruto": bruto["cierre"], "factor": F,
              "ajustado": ajustado["cierre"]}).loc[
    ["2018-01-02", "2021-08-20", "2021-08-23", "2025-12-31"]]
```
```output
             bruto    factor   ajustado
fecha
2018-01-02  192.00  0.219581  42.159572
2021-08-20  240.00  0.228378  54.810708
2021-08-23   59.55  0.913512  54.399628
2025-12-31   68.19  1.000000  68.190000
```

*Fig. — NOVA cumulative adjustment factor: the product of the factors of all events after each day.* A staircase rising from 0.22 in January 2018 to 1 in November 2025. Each quarterly dividend is a tiny step; the 4-for-1 split of August 2021 (highlighted) multiplies the factor by four, from 0.23 to 0.91; the special dividend of December 2023 is a slightly larger step than the rest.

The cumulative factor is a staircase: it equals 1 in the last stretch (after the last dividend, on November 10, 2025)
and goes down one step at each ex-date, going backward. The big step is the split. On January 2, 2018, the factor is
0.2196: that day's close of 192.00 USD is equivalent to 42.16 USD today, counting the split and the 33 dividends.

## The adjusted series does not jump

The proof that the adjustment is right is that the return of the adjusted series is the one a shareholder got. On the
day of the split, no jump; on an ex-date, the price drop offset by the dividend collected:

```python
r_aj = ajustado["cierre"].pct_change()
print(f"Split, raw:      {r_bruto['2021-08-23']:+.2%}")
print(f"Split, adjusted: {r_aj['2021-08-23']:+.2%}")

dividendo = ev[ev["tipo"] != "split"].set_index("fecha_ex")["importe"]
c, c_ant = bruto["cierre"], bruto["cierre"].shift()
exd = dividendo.index
total = (c[exd] + dividendo) / c_ant[exd] - 1     # price + dividend
print("Largest difference on ex-dates (pp):",
      round(100 * (r_aj[exd] - total).abs().max(), 3))
```
```output
Split, raw:      -75.19%
Split, adjusted: -0.75%
Largest difference on ex-dates (pp): 0.03
```

On the split, the adjusted series moves as much as the market moved that day (−0.75%), not −75%. On the ex-dates,
the adjusted return and the total return computed by hand (price plus dividend, over the previous close) match to
within three thousandths of a point. The remaining difference is one of definition: the multiplicative factor is
equivalent to reinvesting the dividend in the stock itself at the ex-date price, $C_{e-1} - D_e$, while the formula by
hand leaves it in cash that day. Either one is “total return”; what is not acceptable is mixing the two without
knowing it.

The figure at the top compares the two series on a log scale. The raw one has a step in August 2021 and a misleading
slope; the adjusted one is continuous and ends at the same price, because the last stretch is not adjusted.

## Against a provider's example

The method is not an invention of this lesson. Yahoo Finance's help page on its adjusted close publishes an example
with a 2-for-1 split and a dividend of 0.08 USD, and says it follows the CRSP standard. With the same two functions,
the result has to be theirs:

```python
dias = pd.to_datetime(["2001-02-16", "2001-02-17", "2001-02-18",
                       "2001-02-19", "2001-02-20", "2001-02-21",
                       "2001-02-22"])
ej = pd.DataFrame({"cierre": [46.99, 48.30, 24.96, 24.91, 24.95,
                              24.53, 24.54]}, index=dias)
ev_ej = pd.DataFrame({"fecha_ex": pd.to_datetime(["2001-02-18",
                                                  "2001-02-21"]),
                      "tipo": ["split", "dividendo"],
                      "ratio": [2.0, np.nan],
                      "importe": [np.nan, 0.08]})
ev_ej = factores(ej, ev_ej)
print(ev_ej[["tipo", "factor"]].round(4).to_string(index=False))
(ej["cierre"] * ajustar(ej, ev_ej)).round(2).to_list()
```
```output
     tipo  factor
    split  0.5000
dividendo  0.9968
[23.42, 24.07, 24.88, 24.83, 24.87, 24.53, 24.54]
```

The seven adjusted closes are those in Yahoo's table (23.42; 24.07; 24.88; 24.83; 24.87; 24.53; 24.54), with the same
dividend multiplier, 0.9968. The year and the days are filler: Yahoo's example only gives day and month, and for the
calculation it does not matter whether they are real sessions. That the function reproduces a provider's example is a
better proof than any explanation: in a project, this example would go into a test (lesson 0.4.5).

Not every provider adjusts the same way. Some adjust only for splits in the “close” and for splits and dividends in
the “adjusted close”; others adjust the whole OHLC bar; some let you choose. With `yfinance`, for example,
`auto_adjust=True` (the default) returns the four columns already adjusted, and `actions=True` adds the dividends and
splits. The block is not run because it needs a network connection:

```python skip title="yfinance_ajustes.py"
import yfinance as yf

ajustada = yf.download("AAPL", start="2018-01-01", auto_adjust=True)
bruta = yf.download("AAPL", start="2018-01-01", auto_adjust=False,
                    actions=True)   # Dividends and Stock Splits columns
```

Before using a provider's series you need to know which of them it is. The quick way to find out is the one in this
section: look for a known split and see whether the series jumps.

## Price return and total return

There are two useful adjusted series, and they answer different questions. The one adjusted **only for splits** gives
the price return: how much the stock has gone up. The one adjusted for splits and dividends gives the total return:
how much whoever held it and reinvested the dividends has earned. The difference is the dividend yield.

```python
F_split = ajustar(bruto, ev[ev["tipo"] == "split"])
precio = bruto["cierre"] * F_split
anos = (bruto.index[-1] - bruto.index[0]).days / 365.25

def tasa_anual(s):
    return (s.iloc[-1] / s.iloc[0]) ** (1 / anos) - 1

for nombre, s in [("unadjusted", bruto["cierre"]),
                  ("splits only (price)", precio),
                  ("splits and dividends (total)", ajustado["cierre"])]:
    print(f"{nombre:>28}: {tasa_anual(s):+.2%} a year")
```
```output
                  unadjusted: -12.15% a year
         splits only (price): +4.49% a year
splits and dividends (total): +6.20% a year
```

*Fig. — 100 USD in NOVA from January 2018: total return, price return and unadjusted series.* Three lines starting at 100. Total return (highlighted) ends at 161.7, 6.2% a year; price return, adjusted only for the split, at 142.1, 4.5% a year; the unadjusted series drops to a quarter at the split and ends at 35.5, as if 12% a year had been lost.

The unadjusted series says that NOVA loses 12% a year: the split, read as a loss. The price series, that it gains
4.5%; the total one, 6.2%. Dividends contribute 1.7 points a year, more than a quarter of the total return. To compare
a strategy with “buy and hold”, the benchmark is the total return: comparing against the price return hands the
strategy those 1.7 points for free. The same goes for indices: a price index (like the course's FIX) does not include
dividends, and a total return index (like ISX) does (lessons 1.2.2 and 1.2.3).

## False signals in a backtest

With the raw series, any rule that looks at changes or levels stumbles over the events. Two examples:

```python
caida = r_bruto[r_bruto < -0.20]
print("Days with a drop > 20% (raw):", list(caida.index.date))
print("Days with a drop > 20% (adjusted):", (r_aj < -0.20).sum())

despues = slice("2021-08-23", "2022-06-10")
for nombre, s in [("raw", bruto["cierre"]),
                  ("adjusted", ajustado["cierre"])]:
    bajo = (s < s.rolling(200).mean())[despues]
    print(f"Below its 200-session average ({nombre}): "
          f"{bajo.mean():.0%}")
```
```output
Days with a drop > 20% (raw): [datetime.date(2021, 8, 23)]
Days with a drop > 20% (adjusted): 0
Below its 200-session average (raw): 95%
Below its 200-session average (adjusted): 15%
```

With the raw series, a “buy the crash” rule buys on the day of the split; a trend filter (price below its 200-session
average = bear market) declares NOVA bearish in 95% of the sessions of the following ten months, while the average
drags along the pre-split prices. With the adjusted series, the same filter sees a downtrend in only 15%. These are the
most visible false signals; those from the dividends are small and repeated:

```python
diferencia = (r_bruto[exd] - r_aj[exd]) * 100
print(f"Ex-dates: {len(exd)}")
print(f"Average drop the shareholder did not suffer: "
      f"{diferencia.mean():.2f}%")
print(f"Sum over eight years: {diferencia.sum():.1f} points")
```
```output
Ex-dates: 33
Average drop the shareholder did not suffer: -0.39%
Sum over eight years: -12.9 points
```

On each ex-date, the raw series shows a drop of around 0.4% that the shareholder did not suffer, because they collected
the dividend. A strategy that sold short the day before each ex-date would appear to earn that 0.4% regularly in a
backtest on raw data; in reality, whoever is short on the ex-date **pays** the dividend to the lender of the shares and
the edge disappears.

<aside class="callout" data-kind="aviso">

The opposite is also a mistake: using adjusted prices where the real price matters. A limit order, a stop at a price,
the size of a position in shares, a “stocks above 5 USD” filter or a per-share commission are computed with the price
that was in the market that day, that is, unadjusted. Returns, with the adjusted series; levels and orders, with that
day's raw series.

</aside>

Volume is adjusted too, but only for splits and in the opposite direction: before the split there were four times
fewer shares, so the volume in shares is multiplied by the ratio. Dividends do not change the number of shares:

```python
vol_aj = bruto["volumen"] / F_split
antes = slice("2021-07-23", "2021-08-20")
despues = slice("2021-08-23", "2021-09-21")
for nombre, v in [("raw", bruto["volumen"]), ("adjusted", vol_aj)]:
    print(f"{nombre:>8}: median {v[antes].median():>11,.0f} before, "
          f"{v[despues].median():>11,.0f} after")
```
```output
     raw: median   2,578,329 before,   9,953,681 after
adjusted: median  10,313,316 before,   9,953,681 after
```

## The past changes every time a dividend arrives

Backward adjustment has an awkward consequence: the 2018 adjusted series is not the same whether it was downloaded in
October 2025 or in December. The dividend of November 10, 2025 adds one more factor, and that factor multiplies the
entire previous history. You can rebuild what a system would have seen on each date using only the events known at
the time:

```python
def ajustado_a_fecha(precios, ev, fecha):
    conocidos = ev[ev["fecha_ex"] <= fecha]
    hasta = precios.loc[:fecha]
    return hasta["cierre"] * ajustar(hasta, conocidos)

oct25 = ajustado_a_fecha(bruto, ev, "2025-10-31")
dic25 = ajustado_a_fecha(bruto, ev, "2025-12-31")
print("Adjusted close on 2018-01-02:")
print(f"  seen on 2025-10-31: {oct25.iloc[0]:.4f}")
print(f"  seen on 2025-12-31: {dic25.iloc[0]:.4f}")
r_oct = oct25.pct_change().loc[:"2025-10-31"]
r_dic = dic25.pct_change().loc[:"2025-10-31"]
print("Returns through October equal:",
      np.allclose(r_oct, r_dic, equal_nan=True))
```
```output
Adjusted close on 2018-01-02:
  seen on 2025-10-31: 42.2811
  seen on 2025-12-31: 42.1596
Returns through October equal: True
```

The 2018 adjusted prices drop 0.29% from one version to the other; the returns of the days before the event do not
change even in the last decimal. A system that uses only returns or ratios (moving averages on the same series, for
example) does not notice the difference. One that uses absolute levels does: “the 2018 high was 52.10” is a sentence
that expires every quarter. And a database that stores the adjusted series as if it were a fact will, after a few
incremental updates, mix stretches adjusted with different factors.

```mermaid
flowchart LR
  G[Store raw prices] --> T[Adjust at t]
  E[Store events] --> T
  T --> R[Returns]
  G --> O[Orders and levels]
```

The solution is the one in the diagram: store the **unadjusted** prices and the events table, which do not change, and
compute the adjustment when needed, with the events known on the date of interest. It is the **point-in-time** idea
that lesson 1.4.4 applies to stock universes and lesson 1.5.1 to fundamental data: every data point, as it was known at
the time.

## Exercises

1. Adjust the series with the **additive** method: instead of multiplying by a factor, subtract the dividend from all
   prices before each ex-date (and divide by the ratio on the split). Compare the annual total return with that of the
   multiplicative method and look at the lowest adjusted price of each series.

**Solution.**

```python
aditivo = bruto["cierre"] * F_split
for fecha_ex, d in dividendo.items():
    d_hoy = d * F_split[fecha_ex]     # in today's shares
    aditivo[aditivo.index < fecha_ex] -= d_hoy
print(f"Additive:       {tasa_anual(aditivo):+.2%} a year, "
      f"minimum {aditivo.min():.2f}")
print(f"Multiplicative: {tasa_anual(ajustado['cierre']):+.2%} a year, "
      f"minimum {ajustado['cierre'].min():.2f}")
```
```output
Additive:       +6.40% a year, minimum 28.24
Multiplicative: +6.20% a year, minimum 30.12
```

The dividend is first converted to today's shares (those before the split are divided by 4) and then subtracted from
everything before. The additive method preserves price differences in dollars, but not the ratios: by subtracting a
fixed amount, the old prices, proportionally lower, fall more in percentage terms, and the return at the start of the
series comes out inflated. With many dividends and low prices it can leave negative prices in the distant past. That is
why the multiplicative method is the standard for stock series; the additive one only makes sense when what matters are
differences in points, as in some continuous futures series (lesson 1.4.6).

2. Check, with `ajustado_a_fecha`, that the adjusted close of 2018-01-02 changes by exactly the factor of the November
   2025 dividend. Which factor is it?

**Solution.**

```python
f_nov = ev.loc[ev["fecha_ex"] == "2025-11-10", "factor"].item()
print(f"Factor of 2025-11-10: {f_nov:.6f}")
print(f"Ratio dec/oct: {dic25.iloc[0] / oct25.iloc[0]:.6f}")
```
```output
Factor of 2025-11-10: 0.997127
Ratio dec/oct: 0.997127
```

The ratio between the two versions is exactly the factor of the new dividend, 1 − 0.19 / close of November 7. It is
the way to detect, by comparing two downloads from the same provider, that an event has appeared: the whole past moves
in the same proportion.

3. A NOVA backtest uses adjusted prices to decide and places limit orders “at 50 USD” in 2019. What is the problem?
   How would you fix it?

**Solution.**

In 2019 NOVA traded unadjusted at around 200 USD (before the split) and its adjusted price today is around 45. A limit
order at 50 USD computed on the adjusted series would be filled in the backtest at a price that never existed in the
market; placed on the real price, it would never have been filled. The rule can decide with the adjusted series (or
with returns), but the order price must be converted to that day's real price by dividing by the day's cumulative
factor ($P_t = \tilde{P}_t / F_t$), and the size in shares is also computed with the real price.

## Self-assessment

1. The close before the ex-date is 50 USD and the dividend, 0.50 USD. What is the multiplicative factor of that dividend?

   - A. 0.50
   - B. 0.99
   - C. 1.01
   - D. 0.95

   *Answer B: 0.99.* f = 1 − D / C = 1 − 0.50 / 50 = 0.99. All prices before the ex-date are multiplied by 0.99, so that the mechanical price drop on the ex-date disappears from the series.

2. A stock does a 4-for-1 split. What is done with the volume of the earlier sessions in the adjusted series?

   - A. It is divided by 4
   - B. It is left untouched
   - C. It is multiplied by 4
   - D. It is set to zero

   *Answer C: It is multiplied by 4.* After the split there are four times as many shares and each is worth a quarter. For the volume in shares to be comparable, the earlier volume is multiplied by the ratio (just as prices are divided by it). Dollar volume does not change.

3. A backtest on unadjusted prices buys when the price falls more than 20% in a day. What happens with NOVA on August 23, 2021?

   - A. It buys: the raw series falls 75%, although the value of the position did not change
   - B. Nothing: there was no drop that day
   - C. It sells
   - D. It raises an error

   *Answer A: It buys: the raw series falls 75%, although the value of the position did not change.* In the raw series the split shows up as a 75% drop. The rule reads it as a crash and trades. In the adjusted series that day is a normal day.

4. A new dividend arrives in November 2025. What changes in NOVA's adjusted series?

   - A. Only the price on the dividend day
   - B. Nothing
   - C. Every return in the history
   - D. All prices before the ex-date, which are multiplied by the new factor; the earlier returns do not change

   *Answer D: All prices before the ex-date, which are multiplied by the new factor; the earlier returns do not change.* Backward adjustment multiplies the whole past by the new factor. The 2018 price levels change; the ratios between two days before the event do not. That is why a rule that uses absolute levels (a 50 USD price, a limit order) gives different results depending on the day the series was downloaded.

5. What should be stored in a data lake so as not to depend on when the adjustment was computed?

   - A. Only the provider's adjusted series
   - B. Only the returns
   - C. The unadjusted prices and the events table, to compute the adjustment at each date with the events known then
   - D. The two adjusted series, price and total

   *Answer C: The unadjusted prices and the events table, to compute the adjustment at each date with the events known then.* With raw prices and events you can rebuild any version of the adjustment, including the one a system would have seen on a specific date. A stored adjusted series is a snapshot of one day: the next dividend makes it stale.

## Key points

- Traded (unadjusted) prices have jumps that are neither losses nor gains: the split and the price drop on each ex-date.
- Factor of a split: 1 / ratio. Factor of a dividend: 1 − D / C of the close before the ex-date. Each day's factor is the product of those of all later events.
- The adjusted series gives the total return (price plus reinvested dividends); the series adjusted only for splits, the price return. For NOVA, 6.2% versus 4.5% a year.
- A backtest on unadjusted prices sees false crashes (the split) and drops on every ex-date; with prices adjusted for splits but not for dividends, it underestimates the buy-and-hold return.
- Backward adjustment rewrites the past with every new event: store raw prices and events and adjust on the fly. For orders and absolute levels, use the unadjusted price.

## Resources

### Research

- [Zipline, Backtesting in Python 2: My First Data Analysis](https://pythonparatrading.com/en/backtesting-python-zipline-bundle-2/) · Research-0012 · 3 min

### Documentation

- [Yahoo Help: What is the adjusted close? (split and dividend multipliers, CRSP standard)](https://help.yahoo.com/kb/SLN28256.html) · help.yahoo.com
- [Investor.gov (SEC): Ex-Dividend Dates](https://www.investor.gov/introduction-investing/investing-basics/glossary/ex-dividend-dates-when-are-you-entitled-stock-and) · investor.gov
- [Investor.gov (SEC): Stock Split](https://www.investor.gov/introduction-investing/investing-basics/glossary/stock-split) · investor.gov
- [yfinance: download (auto_adjust, actions)](https://ranaroussi.github.io/yfinance/reference/api/yfinance.download.html) · ranaroussi.github.io

### Data

- [Level 1 data: unadjusted NOVA daily bars (CSV)](https://pythonparatrading.com/curso/datos/nivel-1/nova_diario_sin_ajustar.csv) · Download · nova_diario_sin_ajustar.csv
- [Level 1 data: NOVA corporate actions (CSV)](https://pythonparatrading.com/curso/datos/nivel-1/nova_eventos.csv) · Download · nova_eventos.csv

Previous lesson: [1.4.2 · Data cleaning: missing values, bad ticks, gaps and time zones](https://pythonparatrading.com/en/python-trading-course/level-1/cleaning-financial-market-data/)

Next lesson: [1.4.4 · Universes without survivorship bias: delistings, mergers and symbol changes](https://pythonparatrading.com/en/python-trading-course/level-1/survivorship-bias-and-point-in-time-data/)
