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