金融爬蟲(一):大盤報酬指數 [附程式碼]

前兩篇快速地介紹了資料庫的存取,是為了接下來的「金融爬蟲」教學做準備。

不熟資料庫的讀者,請參考:
Python資料庫(上)
Python資料庫(下)

做量化交易,必須先取得歷史資料,這時候就需要網路爬蟲上場了。

哇!還要學網路爬蟲喔!會不會很難啊?

「別怕!!」

首先恭喜你,在爬蟲領域,Python也是首選的程式語言!

而且,用Python做爬蟲,很簡單喔!

跟著量化操盤手,手把手的教學,新手也能實作出網路爬蟲。

「金融爬蟲」第一篇,先來小試身手,教大家怎麼抓證交所的大盤報酬指數。

之前量化操盤手文章中的範例,大盤指數都是直接採用加權指數,因為大多數網站都只有提供加權指數,為方便教學,使用像是ffn等套件時,只能將就使用了。

但是,若要回測大盤策略,其實應該要用「報酬指數」或是「期貨數據」,會比較準確。

這是因為加權指數會受到除息影響,而產生點數蒸發現象,由於沒有計入現金股利,通常會造成多頭策略的報酬率被低估。

(關於除息點數影響,可參考這篇)

報酬指數就是為了解決這個問題而誕生的,它將現金股利計入報酬率,使得報酬指數更加貼近持有股票的真實報酬率。

趕快來看看怎麼把報酬指數爬下來:
# 載入需要用到的函式庫
import time # 時間函式庫
import sqlalchemy # SQL資料庫ORM函式庫
import pandas as pd # 數據分析函式庫
from io import StringIO # 記憶體文字檔案函式
from requests import get # HTTP請求函式
from datetime import datetime # 日期函式
from dateutil.relativedelta import relativedelta # 日期增減函式

# 資料區間
start = datetime(2019, 1, 1) # 起始月份
end = datetime(2019, 10, 1) # 結束月份

# 爬資料
df_total = pd.DataFrame() # 用來放報酬指數
date = start # 從起始月份開始
while date <= end: # 跑迴圈
    str_date = date.strftime('%Y%m%d') # 日期轉字串
    url = "https://www.twse.com.tw/indicesReport/MFI94U?response=csv&date="+str_date # 資料網址
    df = pd.read_csv(StringIO(get(url).text), header=1, usecols=[0, 1], dtype={0:str, 1:float}, thousands=',') # 依格式讀取資料
    df.insert(0, 'datetime', pd.to_datetime(str(date.year)+'/'+df['日 期'].str[-5:])) # 處理日期格式
    df.set_index('datetime', inplace=True) # 將日期當成索引
    df.drop(columns='日 期', inplace=True) # 去掉用不到的資料
    df_total = df_total.append(df) # 合併各月份報酬指數
    print(date.strftime('%Y-%m')) # 顯示下載進度
    date = date + relativedelta(months=1) # 跳到下一個月份
    time.sleep(3) # 拉長下載間距

# 連結SQLite資料庫
engine = sqlalchemy.create_engine('sqlite:///data.db') # 生成或連結到現有的資料庫檔案
df_total.to_sql('total_return_index', engine, if_exists='replace', index_label='table_index') # 將報酬指數存入資料庫(建立Table: total_return_index)

往後需要讀取資料時,只要運用以下簡短的程式碼:
import sqlalchemy
import pandas as pd

# 連結SQLite資料庫
engine = sqlalchemy.create_engine('sqlite:///data.db')

# 讀取報酬指數資料
df_total = pd.read_sql('total_return_index', engine, index_col='table_index', parse_dates=['table_index'])