How do I turn prices into returns?

Build a list of returns in a loop, then compound them into the return for the whole stretch.

A return is the change from yesterday’s price to today’s price, divided by yesterday’s price. A list of prices becomes a list of returns one day at a time.

In this lesson I build that list with a loop, run it on a week of closing prices, and compound the daily returns into the return for the whole week.

Step 1. Three prices, two returns

Start with an empty list. Each pass through the loop computes one return and appends it to the end.

The loop starts at position 1, not 0, because position 0 has no day before it.

closes  = [100.0, 110.0, 99.0]
returns = []                                        # the list I am going to fill

for i in range(1, len(closes)):                     # i = 1, 2
    r = (closes[i] - closes[i - 1]) / closes[i - 1] # today minus yesterday, over yesterday
    returns.append(r)                               # put it on the end

print(returns)                                      # -> [0.1, -0.1]
print(len(closes), "prices ->", len(returns), "returns")
# -> 3 prices -> 2 returns
[0.1, -0.1]
3 prices -> 2 returns

The price went from 100 to 110, a gain of 10%, then from 110 to 99, a fall of 10%. Three prices give two returns.

Here is what position 0 would reach for:

i = 0
print(closes[i - 1])    # -> 99.0    <- closes[-1] is the last price in the list
99.0

closes[-1] counts from the end of the list.

Step 2. A week of closes

Now the same loop on five closes with the dates they belong to. Each return sits on the later of the two days it was computed from, so dates[1:] drops Monday.

dates  = ["Mon", "Tue", "Wed", "Thu", "Fri"]
closes = [185.40, 187.20, 184.90, 188.10, 190.50]

returns = []
for i in range(1, len(closes)):
    returns.append((closes[i] - closes[i - 1]) / closes[i - 1])

for d, r in zip(dates[1:], returns):
    print(f"{d}  {r:.2%}")
# -> Tue  0.97%
# -> Wed  -1.23%
# -> Thu  1.73%
# -> Fri  1.28%
Tue  0.97%
Wed  -1.23%
Thu  1.73%
Fri  1.28%

Five closes, four returns, and four days with a return attached.

Counting the up days is a loop over the list I just built.

up = 0
for r in returns:
    if r > 0:
        up += 1

print(up, "up days out of", len(returns))   # -> 3 up days out of 4
3 up days out of 4

Step 3. Compound the week into one number

To get the return for the whole week, multiply the growth factors 1 + r together and subtract 1 at the end.

growth = 1.0
for r in returns:
    growth = growth * (1 + r)     # multiply the growth factors together

week = growth - 1

print(f"compounded:  {week:.4%}")                          # -> compounded:  2.7508%
print(f"from prices: {closes[-1] / closes[0] - 1:.4%}")    # -> from prices: 2.7508%
compounded:  2.7508%
from prices: 2.7508%

The compounded figure equals the last close over the first close, minus 1.

Now the same four returns added instead of multiplied.

added = sum(returns)

print(f"added:      {added:.4%}")   # -> added:      2.7488%
print(f"compounded: {week:.4%}")    # -> compounded: 2.7508%
added:      2.7488%
compounded: 2.7508%

The prices moved 2.7508%. Adding gives 2.7488%.

Your turn

Take closes = [50.0, 55.0, 55.0, 44.0]. Build the list of returns, then compound them into a total. How many returns do four prices give?

closes  = [50.0, 55.0, 55.0, 44.0]
returns = []

for i in range(1, len(closes)):
    returns.append((closes[i] - closes[i - 1]) / closes[i - 1])

print([round(r, 4) for r in returns])   # -> [0.1, 0.0, -0.2]
print(len(returns), "returns")          # -> 3 returns

growth = 1.0
for r in returns:
    growth = growth * (1 + r)

print(f"{growth - 1:.4%}")                   # -> -12.0000%
print(f"{closes[-1] / closes[0] - 1:.4%}")   # -> -12.0000%