AI For Trading: Quiz: Rate of Returns Over Multiple Periods (36)
Rate of Returns Over Multiple Periods
Numpy.cumsum and Numpy.cumprod
You've just leared about active returns and passive returns. Another important concept related to returns is "Cumulative returns" which is defined as the returns over a time period. You can read more about rate of returns here!
There are two ways to calcualte cumulative returns, depends on how the returns are calculated. Let's take a look at an example.
import numpy as np
import pandas as pd
from datetime import datetime
dates = pd.date_range(datetime.strptime('1/1/2016', '%m/%d/%Y'), periods=12, freq='M')
start_price, stop_price = 0.24, 0.3
abc_close_prices = np.arange(start_price, stop_price, (stop_price - start_price)/len(dates))
abc_close = pd.Series(abc_close_prices, dates)
abc_close
2016-01-31 0.240
2016-02-29 0.245
2016-03-31 0.250
2016-04-30 0.255
2016-05-31 0.260
2016-06-30 0.265
2016-07-31 0.270
2016-08-31 0.275
2016-09-30 0.280
2016-10-31 0.285
2016-11-30 0.290
2016-12-31 0.295
Freq: M, dtype: float64
Here, we have the historical prices for stock ABC for 2016. We would like to know the yearly cumulative returns for stock ABC in 2016 using time-weighted method, assuming returns are reinvested. How do we do it? Here is the formula:
Assume the returns over n successive periods are:
$$ r_1, r_2, r_3, r_4, r_5, ..., r_n $$
The cumulative return of stock ABC over period n is the compounded return over period n:
\( (1 + r_1)(1 + r_2)(1 + r_3)(1 + r_4)(1 + r_5)...(1 + r_n) - 1\)
First, let's calculate the returns of stock ABC.
print("abc_close:")
print(abc_close)
print("abc_close shift:")
print(abc_close.shift(1))
returns = abc_close / abc_close.shift(1) - 1
returns
abc_close:
2016-01-31 0.240
2016-02-29 0.245
2016-03-31 0.250
2016-04-30 0.255
2016-05-31 0.260
2016-06-30 0.265
2016-07-31 0.270
2016-08-31 0.275
2016-09-30 0.280
2016-10-31 0.285
2016-11-30 0.290
2016-12-31 0.295
Freq: M, dtype: float64
abc_close shift:
2016-01-31 NaN
2016-02-29 0.240
2016-03-31 0.245
2016-04-30 0.250
2016-05-31 0.255
2016-06-30 0.260
2016-07-31 0.265
2016-08-31 0.270
2016-09-30 0.275
2016-10-31 0.280
2016-11-30 0.285
2016-12-31 0.290
Freq: M, dtype: float64
2016-01-31 NaN
2016-02-29 0.020833
2016-03-31 0.020408
2016-04-30 0.020000
2016-05-31 0.019608
2016-06-30 0.019231
2016-07-31 0.018868
2016-08-31 0.018519
2016-09-30 0.018182
2016-10-31 0.017857
2016-11-30 0.017544
2016-12-31 0.017241
Freq: M, dtype: float64
The cumulative return equals to the product of the daily returns for the n periods.
That's a very long formula. Is there a better way to calculate this.
The answer is yes, we can use numpy.cumprod().
For example, if we have the following time series: 1, 5, 7, 10 and we want the product of the four numbers. How do we do it? Let's take a look!
lst = [1,5,7,10]
np.cumprod(lst)
array([ 1, 5, 35, 350])
The last element in the list is 350, which is the product of 1, 5, 7, and 10.
OK, let's use numpy.cumprod() to get the cumulative returns for stock ABC
(returns + 1).cumprod()[len(returns)-1] - 1
0.22916666666666652
The cumulative return for stock ABC in 2016 is 22.91%.
The other way to calculate returns is to use log returns.
The formula of log return is the following:
$$ LogReturn = ln(\frac{P_t}{P_t - 1}) $$
The cumulative return of stock ABC over period n is the compounded return over period n:
$$ \sum_{i=1}^{n} r_i = r_1 + r_2 + r_3 + r_4 + ... + r_n $$
Let's see how we can calculate the cumulative return of stock ABC using log returns.
First, let's calculate log returns.
log_returns = (np.log(abc_close).shift(-1) - np.log(abc_close)).dropna()
log_returns.head()
2016-01-31 0.020619
2016-02-29 0.020203
2016-03-31 0.019803
2016-04-30 0.019418
2016-05-31 0.019048
Freq: M, dtype: float64
The cumulative sum equals to the sum of the daily returns for the n periods which is a very long formula.
To calculate cumulative sum, we can simply use numpy.cumsum().
Let's take a look at our simple example of time series 1, 5, 7, 10.
lst = [1,5,7,10]
np.cumsum(lst)
array([ 1, 6, 13, 23])
The last element is 23 which equals to the sum of 1, 5, 7, 10
OK, let's use numpy.cumsum() to get the cumulative returns for stock ABC
cum_log_return = log_returns.cumsum()[len(log_returns)-1]
np.exp(cum_log_return) - 1
0.22916666666666696
The cumulative return for stock ABC in 2016 is 22.91% using log returns.
Quiz: Arithmetic Rate of Return
Now, let's use cumprod() and cumsum() to calculate average rate of return.
For consistency, let's assume the rate of return is calculated as \( \frac{P_t}{P_t - 1} - 1 \)
Arithmetic Rate of Return:
$$ \frac{1}{n} \sum_{i=1}^{n} r_i = \frac{1}{n}(r_1 + r_2 + r_3 + r_4 + ... + r_n) $$
import quiz_tests
def calculate_arithmetic_rate_of_return(close):
"""
Compute returns for each ticker and date in close.
Parameters
----------
close : DataFrame
Close prices for each ticker and date
Returns
-------
arithmnetic_returns : Series
arithmnetic_returns at the end of the period for each ticker
"""
# TODO: Implement Function
print(close)
print(close.shift(1))
returns = close / close.shift(1) - 1
print(returns)
arithmetic_returns = returns.cumsum(axis=0).iloc[returns.shape[0]-1]/returns.shape[0]
print(arithmetic_returns)
return arithmetic_returns
quiz_tests.test_calculate_arithmetic_rate_of_return(calculate_arithmetic_rate_of_return)
ZUM NTNW LKD VFR WOH
2001-07-13 21.05081048 17.01384381 10.98450376 11.24809343 12.96171273
2001-07-14 15.63570259 14.69054309 11.35302769 475.74195118 11.95964043
2001-07-15 482.34539247 35.20258059 3516.54167823 66.40531433 13.50396048
2001-07-16 10.91893302 17.90864387 24.80126542 12.48895419 10.52435923
2001-07-17 10.67597197 12.74940144 11.80525758 21.53903949 19.99766037
2001-07-18 11.54549538 23.98146843 24.97476306 36.03196210 14.30433232
ZUM NTNW LKD VFR WOH
2001-07-13 nan nan nan nan nan
2001-07-14 21.05081048 17.01384381 10.98450376 11.24809343 12.96171273
2001-07-15 15.63570259 14.69054309 11.35302769 475.74195118 11.95964043
2001-07-16 482.34539247 35.20258059 3516.54167823 66.40531433 13.50396048
2001-07-17 10.91893302 17.90864387 24.80126542 12.48895419 10.52435923
2001-07-18 10.67597197 12.74940144 11.80525758 21.53903949 19.99766037
ZUM NTNW LKD VFR WOH
2001-07-13 nan nan nan nan nan
2001-07-14 -0.25723988 -0.13655355 0.03354944 41.29534136 -0.07731018
2001-07-15 29.84897463 1.39627496 308.74483411 -0.86041737 0.12912763
2001-07-16 -0.97736283 -0.49126900 -0.99294726 -0.81192839 -0.22064647
2001-07-17 -0.02225135 -0.28808672 -0.52400584 0.72464717 0.90013092
2001-07-18 0.08144677 0.88098779 1.11556274 0.67286764 -0.28469971
ZUM 4.77892789
NTNW 0.22689225
LKD 51.39616553
VFR 6.83675173
WOH 0.07443370
Name: 2001-07-18, dtype: float64
Tests Passed
为者常成,行者常至
自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)