使用Python的pandas-datareader包下載雅虎財經股價資料

weixin_34007886發表於2017-04-07

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

相關文章