使用Python的pandas-datareader包下载雅虎财经股价数据

0.378字数 1719阅读 28436

0 准备工作

首先,使用pip方法安装pandas和pandas-datareader两个功能包. 安装的方法十分简单,以管理员身份运行cmd. 输入以下命令。

$ pip install pandas
$ pip install pandas-datareader

需要注意的是,安装pandas时将自动安装numpy等功能包,因此可以使用pandas即代表安装了numpy功能包。今后,在安装所有Python所需功能包时,皆可使用以上方法。

在Yahoo Finance对API进行升级后,你可能需要安装最新开发版本(latest development version)的pandas-datareader(目前是0.5.0版本),才能对雅虎财经的部分数据进行访问,安装方法可以参考原git

pandas-datareader包中的pandas_datareader.data.DataReader函数可以根据输入的证券Ticker,起始日期和终止日期来返回包含所有历史日价格的数据,其数据类型是DataFrame,这是pandas包引入的一个数据类型。在这里假设需要苹果公司(Ticker: AAPL)从2016年初到今天(2017年4月6日)的历史日价格。

到这里,打开你的Python代码编辑器,你便完成了所有的准备工作。

1 获取股价数据

此处需使用的包是datetime,pandas,和pandas-datareader. 导入datetime的原因是,我们要使用datetime包中的datetime.datetime.today()函数来调用今天的日期。

import datetime
import pandas as pd
import pandas_datareader.data as web
## !!! here it is 'pandas_datareader' rather than 'pandas-datareader'

在以上代码中,import A as B 的作用是导入A,并给A起一个别名叫做B. 此例中,pandas_datareader.data这个名称显然过长,因此给它起一个别名叫做web,这样在后文中使用pandas_datareader.data.DataReader函数时,直接使用web.DataReader即可。一定要注意的是,这里的pandas_datareader中使用的是下划线'_',而非在pip安装时使用的连接符‘-’.

接下来,设置起始日期和终止日期。使用datetime.datetime函数指向给定日期,使用datetime.date.today函数指向今天的日期。运行DataReader函数并将其保存到一个名为prices的变量中。

start = datetime.datetime(2016, 1, 1) # or start = '1/1/2016'
end = datetime.date.today()
prices = web.DataReader('AAPL', 'yahoo', start, end)
print prices.head()  # print first rows of the prices data

注意DataReader函数中第二个参数代表数据来源,DataReader支持包括雅虎、谷歌在内的十数种数据来源,本篇笔记只关注来源为雅虎财经的数据。

观察一下获得的prices数据的前六行(含列名),

                  Open        High         Low       Close    Volume  \
Date                                                                   
2016-01-04  102.610001  105.370003  102.000000  105.349998  67649400   
2016-01-05  105.750000  105.849998  102.410004  102.709999  55791000   
2016-01-06  100.559998  102.370003   99.870003  100.699997  68457400   
2016-01-07   98.680000  100.129997   96.430000   96.449997  81094400   
2016-01-08   98.550003   99.110001   96.760002   96.959999  70798000   

             Adj Close  
Date                    
2016-01-04  102.612183  
2016-01-05  100.040792  
2016-01-06   98.083025  
2016-01-07   93.943473  
2016-01-08   94.440222  

这个DataFrame的index是日期,总共有六列数据,通常情况下我们只关注最后一列Adjusted Closing Price 并使用它计算收益率。Adj Close的好处是已将所有的权重、分割和股利分发等因素考虑在了价格中进行调整。

2 获取股利数据

pandas-datareader包也可以用来获取股利或股票分割等数据,只要将DataReader函数中的数据源参数修改为'yahoo-actions'即可。

actions = web.DataReader('AAPL', 'yahoo-actions', start, end)
print actions.head()

这样返回的actions仍是一个DataFrame类型的变量,其index为日期。观察前六行的数据。

              action  value
2017-02-09  DIVIDEND   0.57
2016-11-03  DIVIDEND   0.57
2016-08-04  DIVIDEND   0.57
2016-05-05  DIVIDEND   0.57
2016-02-04  DIVIDEND   0.52

此处的action表示证券所进行的操作,如派发股利,或股票分割等等,而value则表示操作值。我们可以看到,苹果公司最近一笔股利发放是在2017年2月9日,每股发放了0.57美元的股利。

值得一提的是,如果在给定日期内,该证券并没有操作活动,DataReader函数将返回一个空的DataFrame,既没有index,也没有列名。

print web.DataReader('AAPL', 'yahoo-actions', datetime.datetime(2017, 4, 1), datetime.date.today())

输出结果为,

Empty DataFrame
Columns: []
Index: []

3 合并股利和股价数据

因为actions的index是prices的index的一个子集,所以我们可以直接将actions的各列添加到prices后面。下面介绍两种合并股利和股价的方法。

第一种方法思路比较简单,直接将actions的每一列提取出来,添加到prices后面。

一个DataFrame变量的某一列单独提取出来,是一个Series变量,这也是pandas包中独有的一个数据类型。通常,在列名不含空格和连接符的情况下,可以直接将列名作为DataFrame变量的Attribute进行调用。如actions.action即为actions中action这一列,它的类型是Series. 而在prices变量中,‘Adj Close’列,因为列名中含有空格,只能使用prices['Adj Close']来调用。

Attribute可以理解为一个对象(如prices,actions,甚至start,end等等)所包含的一系列属性、方法、函数等等,如在之前使用的prices.head()即是在调用prices的head这一Attribute.

将actions的列调用出来后,即可对prices的新列进行赋值。

prices['action'], prices['value'] = actions.action, actions.value
print prices

观察合并后的数据中间的某几行。

                  Open        High         Low       Close     Volume  \
Date          
...
2016-02-01   96.470001   96.709999   95.400002   96.430000   40943500   
2016-02-02   95.419998   96.040001   94.279999   94.480003   37357200   
2016-02-03   95.000000   96.839996   94.080002   96.349998   45964300   
2016-02-04   95.860001   97.330002   95.190002   96.599998   46471700   
2016-02-05   96.519997   96.919998   93.690002   94.019997   46418100   
2016-02-08   93.129997   95.699997   93.040001   95.010002   54021400   
...

             Adj Close    action  value  
Date               
...
2016-02-01   93.923996       NaN    NaN  
2016-02-02   92.024676       NaN    NaN  
2016-02-03   93.846074       NaN    NaN  
2016-02-04   94.600127  DIVIDEND   0.52  
2016-02-05   92.073538       NaN    NaN  
2016-02-08   93.043048       NaN    NaN  
...

可以发现,所有没有action和value的日期,该处数值将为NaN(Not a Number),而有效的股利数据被加入了相应行中。

第二种方法是使用pandas包中的merge函数,它可以根据一定规则将两个DataFrame变量合并。

prices = pd.merge(prices, actions, how='outer', left_index=True, right_index=True)
print prices

以上代码,可以得到与第一种方法同样的结果。其中how='outer'是说最后合并结果的长度将是prices和actions中较长的长度,因此才会有NaN的出现。left_index和right_index都设为True,即当左右DataFrame的index相符时才合并。

4 输出为CSV文件

DataFrame类型有一个Attribute可以直接将数据导出为CSV文件。如将合并好的股价和股利数据保存到根目录out文件夹中,并起名为AAPL.csv.

prices.to_csv('.\\out\\AAPL.csv)

其中.to_csv()方法需要一个字符型参数,即所需保存路径。在该字符串中,'.'表示working directory,使用PyCharm等编译器的话,一般都是代码文件所在的目录。而两个反斜杠表示文件夹的层级关系,之所以用两个,是因为''在字符串中有转义作用。

需要注意的一点是,此例中,'.\out'文件夹应事先建好。直观的方法是直接新建文件夹,并命名为'out'. 使用Python的os包也可以实现。

import os
os.mkdir('.\\out')

将prices导出为CSV文件后,可以打开查看。也可以使用EXCEL进行操作。

Date,Open,High,Low,Close,Volume,Adj Close,action,value
...
2016-02-01,96.470001,96.709999,95.400002,96.43,40943500,93.923996,,
2016-02-02,95.419998,96.040001,94.279999,94.480003,37357200,92.024676,,
2016-02-03,95.0,96.839996,94.080002,96.349998,45964300,93.846074,,
2016-02-04,95.860001,97.330002,95.190002,96.599998,46471700,94.600127,DIVIDEND,0.52
2016-02-05,96.519997,96.919998,93.690002,94.019997,46418100,92.073538,,
2016-02-08,93.129997,95.699997,93.040001,95.010002,54021400,93.043048,,
...

Python可以很方便地对金融数据进行相关操作,我将在未来的笔记中讨论具体的做法。如果您发现任何问题或有任何疑问,欢迎指正或讨论。

by JohnnyMOON, COB @UIUC
这只是做Finance作业的学习笔记
EM: gengyug2@illinois.edu

推荐阅读更多精彩内容