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] # three closing prices in orderreturns = [] # the list I am going to fillfor i inrange(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 endprint(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# the one position with no day before itprint(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"] # five weekday labelscloses = [185.40, 187.20, 184.90, 188.10, 190.50] # one close per dayreturns = []for i inrange(1, len(closes)): # 1 to 4, Mon has no day before returns.append((closes[i] - closes[i -1]) / closes[i -1]) # today over yesterdayfor d, r inzip(dates[1:], returns): # dates[1:] drops Monprint(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# the running countfor r in returns:if r >0: up +=1# same as up = up + 1print(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# 1 is neutral for multiplyingfor r in returns: growth = growth * (1+ r) # multiply the growth factors togetherweek = growth -1# take the starting 1 back offprint(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) # the four returns added, not compoundedprint(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?
TipShow answer
closes = [50.0, 55.0, 55.0, 44.0]returns = []for i inrange(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 returnsgrowth =1.0for r in returns: growth = growth * (1+ r)print(f"{growth -1:.4%}") # -> -12.0000%print(f"{closes[-1] / closes[0] -1:.4%}") # -> -12.0000%