Blogs

Log Returns vs. Percentage Returns

Consider below prices as a stock's daily closing prices.

prices = [100, 150, 50, 100, 150]
stock = pd.DataFrame(prices, columns=['price'])
Day  Price
1    100
2    150
3     50
4    100
5    150
stock['log_return'] = np.log(stock.price / stock.price.shift(1))
stock['pct_return'] = stock.price.pct_change()

This stock's daily log returns and percentage returns would be:

Day  price  log_return  pct_return
0    100         NaN         NaN
1    150    0.405465    0.500000
2     50   -1.098612   -0.666667
3    100    0.693147    1.000000
4    150    0.405465    0.500000

It's always possible to convert log return to cumilative ruturn:

np.e ** stock.log_return[1]

In this case, it gives 1.5 as a result which is 150 divided by 100 (first day's return).

Compare daily cumilative returns. 

stock['log_cumilative'] = round(stock.log_return.cumsum(),6)
stock['pct_cumilative'] = round((stock.pct_return+1).cumprod() - 1, 6)
day  price  log_return  pct_return  log_cumilative  pct_cumilative
0    100         NaN         NaN             NaN             NaN
1    150    0.405465    0.500000        0.405465             0.5
2     50   -1.098612   -0.666667       -0.693147            -0.5
3    100    0.693147    1.000000       -0.000000            -0.0
4    150    0.405465    0.500000        0.405465             0.5
cumilative_logreturn = stock.log_return.sum()
pct_converted_from_log = np.e ** cumilative_logreturn - 1

As a result of transformation above we get 0.5 return from logreturns.

 

Average log returns gives the compounded growth rate. First calculate cgr without log returns:

ending_value = stock.iloc[-1,0]
beginning_value = stock.iloc[0,0]
total_period = len(stock) - 1 # Looking at number of changes

compounded_growth_rate = (ending_value / beginning_value) ** (1/total_period)

The same result (1.10668) can be gathered from log returns:

avg_log_return = stock.log_return.mean()
cagr = np.e ** avg_log_return