使用Pandas DataFrame计算每日收益

29

这是我的Pandas数据框架:

prices = pandas.DataFrame([1035.23, 1032.47, 1011.78, 1010.59, 1016.03, 1007.95, 
              1022.75, 1021.52, 1026.11, 1027.04, 1030.58, 1030.42,
              1036.24, 1015.00, 1015.20])

这是我的daily_return函数:

def daily_return(prices):
    return prices[:-1] / prices[1:] - 1

这是来自该函数的输出:

0    NaN
1      0
2      0
3      0
4      0
5      0
6      0
7      0
8      0
9      0
10     0
11     0
12     0
13     0
14   NaN

为什么我会得到这个输出?

4个回答

86

为什么不默认使用由pandas提供的非常方便的pct_change方法:

import pandas as pd

prices = pandas.DataFrame([1035.23, 1032.47, 1011.78, 1010.59, 1016.03, 1007.95, 
          1022.75, 1021.52, 1026.11, 1027.04, 1030.58, 1030.42,
          1036.24, 1015.00, 1015.20])

daily_return = prices.pct_change(1) # 1 for ONE DAY lookback
monthly_return = prices.pct_change(21) # 21 for ONE MONTH lookback
annual_return = prices.pct_change(252) # 252 for ONE YEAR lookback

原始价格

print(prices)
          0                                                                    
0   1035.23                                                                    
1   1032.47                                                                    
2   1011.78                                                                    
3   1010.59                                                                    
4   1016.03                                                                    
5   1007.95                                                                    
6   1022.75                                                                    
7   1021.52                                                                    
8   1026.11                                                                    
9   1027.04                                                                    
10  1030.58                                                                    
11  1030.42                                                                    
12  1036.24                                                                    
13  1015.00                                                                    
14  1015.20                                                                    

每日回报率prices.pct_change(1):

print(prices.pct_change(1))
           0                                                                   
0        NaN                                                                   
1  -0.002666                                                                   
2  -0.020039                                                                   
3  -0.001176                                                                   
4   0.005383                                                                   
5  -0.007953                                                                   
6   0.014683                                                                   
7  -0.001203                                                                   
8   0.004493                                                                   
9   0.000906                                                                   
10  0.003447                                                                   
11 -0.000155                                                                   
12  0.005648                                                                   
13 -0.020497                                                                   
14  0.000197 

6
当数据按升序排列时(如2016-01-03、2016-01-02等),请使用以下代码: df['Adj Close'].pct_change(-1) - Melroy van den Berg
1
有没有想过为什么pct_change的答案与直接计算newValue - oldValue / newValue的结果略有不同?例如,(1032.47 - 1035.23) / 1032.47得到的是-0.0026732,而pct_change给出的答案是-0.002666。 - Simon Nicholls
2
你必须除以起始值,而不是结束值... 正确答案是:(1032.47 - 1035.23) / 1035.23 = -0.002666。 - ylnor
我知道这是一个旧答案,但文档中没有提到您在pct_change中使用的值,1表示每日,21表示每月,252表示每年。您能解释一下这是如何工作的,还是这些值是特定于此问题的周期? - Ishan Sharma
3
关键在于“背景”。当我们谈论股票市场时,1、21、252是正确的时间段,因为股票市场并非每天交易。 - YaOzI

31

因为操作会对索引进行对齐,所以你可以将其中一个DataFrame转换为数组:

prices[:-1].values / prices[1:] - 1
或者
prices[:-1] / prices[1:].values - 1

取决于您想要的结果的索引。

或使用shift()方法:

prices.shift(1) / prices - 1

和:

prices / prices.shift(1) - 1

2
“shift”比下降到“values”要好得多。 - DSM
注意:根据你的价格数据按日期排序的方式(升序、降序),移位示例可能是错误的。prices / prices.shift(1) - 1 是针对升序排列的情况。(日期,SPY,XOM 2012年7月2日,136.51,84.79 2012年7月3日,137.41,85.72)等等 - mimoralea
所以,对于降序排列,它是这样的:df['Adj Close'] / df['Adj Close'].shift(-1) - 1,对吧?!? - Melroy van den Berg
为什么我们只需要将一个参数转换为数组?如果两个参数都转换为数组值并执行除法,我觉得更直观。 - crjacinro

4

我喜欢上述所有方法。然而,我们也可以这样做:

daily_returns = (prices/prices.shift(1)) -1
daily_returns.iloc[0,:] = 0

*prices是一个pandas数据框架,而daily_returns将是一个系列对象。

4

对@YaOzl的回答进行补充,以防有人阅读此文。如果您的返回数据是一个包含多个股票的面板电子表格:

>>> prices = pandas.DataFrame(
{"StkCode":["StockA","StockA","StockA","StockA","StockA","StockB","StockB","StockB","StockB","StockB","StockC","StockC","StockC","StockC","StockC",], 
"Price":[1035.23, 1032.47, 1011.78, 1010.59, 1016.03, 1007.95, 1022.75, 1021.52, 1026.11, 1027.04, 1030.58, 1030.42, 1036.24, 1015.00, 1015.20]}
)

这给您带来了:

      Price StkCode
0   1035.23  StockA
1   1032.47  StockA
2   1011.78  StockA
3   1010.59  StockA
4   1016.03  StockA
5   1007.95  StockB
6   1022.75  StockB
7   1021.52  StockB
8   1026.11  StockB
9   1027.04  StockB
10  1030.58  StockC
11  1030.42  StockC
12  1036.24  StockC
13  1015.00  StockC
14  1015.20  StockC

那么您可以简单地使用.pct_change(k).groupby(StkCode)进行联合使用。它比使用迭代器快上千倍...(我在我的数据集上尝试过,成功将处理时间从10小时缩短到20秒!)

>>> prices["Return"] = prices.groupby("StkCode")["Price"].pct_change(1)

为您提供:

      Price StkCode    Return
0   1035.23  StockA       NaN
1   1032.47  StockA -0.002666
2   1011.78  StockA -0.020039
3   1010.59  StockA -0.001176
4   1016.03  StockA  0.005383
5   1007.95  StockB       NaN
6   1022.75  StockB  0.014683
7   1021.52  StockB -0.001203
8   1026.11  StockB  0.004493
9   1027.04  StockB  0.000906
10  1030.58  StockC       NaN
11  1030.42  StockC -0.000155
12  1036.24  StockC  0.005648
13  1015.00  StockC -0.020497
14  1015.20  StockC  0.000197

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接