其實捉歷史股價的工具很多,這篇文章只介紹我正在使用的函式庫
yfinance
如果要捉國外股價,首選是 yfinanace
顧名思義,yfinance 的資料來源是 Yahoo Finance API,以國外股市來說,大概是目前我找的到最完整的資料來源
使用起來也很簡單
安裝
pip install yfinance
舉例要捉 SPY 2021年以後的資料,只需要一行 code 就可以取得資料
import yfinance as yf
# yfinance 取得股價
df = yf.download("spy", "2021-01-01")
df 是 dataframe 格式,可自行再去運用
ffn
ffn 其實用的也是 yfinance 的資料,不過它提供了不少很好用的 function,現在我捉股價幾乎直接都使用 ffn 取代 yfinance (反正是一樣的資料)
安裝
pip install ffn
舉例要捉 SPY 2021年以後的資料,同樣只需要一行 code 就可以取得資料
import ffn
# ffn 取得 股價
prices = ffn.get('spy', start='2021-01-01')
ffn function 介紹
rebase ⇒ 將初始價格改為 100,可以比較兩個以上的股價漲跌變化
prices = ffn.get('spy, tlt', start='2021-01-01')
# rebase 股價繪圖
%matplotlib inline
prices.rebase().plot()
就可以看到在 2021 這兩支 ETF 的走勢變化
to_drawdown_series ⇒ 看最大的虧損
# Max Drawdown 最大虧損
prices.to_drawdown_series().plot()
從這張圖就可以看出今年的 SPY 真的強,一路向上不回頭的
calc_stats ⇒ 統計報表
# 統計報表
stats = prices.calc_stats()
stats.display()
我沒貼全部的資料,統計數據其實蠻完整的,我想看的差不多都有..
display_monthly_returns ⇒ 月報酬
print(stats['spy'].display_monthly_returns())
不僅有年報酬率,連每個月的報酬率都算出來了...
2022-12-27 補充說明
2022-12-26 yahoo 的資料源格式有調整,所以使用 ffn 會有 TypeError: string indices must be integers 的錯誤訊息,解決方法需要在程式中加上
import yfinance
yfinance.pdr_override()
如果發現不需要加上這兩行,有可能是作者也更新調整了
FinMind
yfinance 是有台股資料的,但並不是很齊全,舉例 0050 這檔 ETF 是在 2003 年就成立了,但是 yfinance 從 2008 年才有資料,此外,yfinance 只有上市股票,是沒有上櫃股票價格的,所以要捉台股資料 yfinance 並不是好選擇。原本我的作法是直接去爬證交所的網站,一直到後來發現 FinMind
一樣要先安裝
pip install FinMind
舉例捉 0050 資料,開始時間寫 2000-01-01 (0050 上市時間是 2003-06)
from FinMind.data import DataLoader
stock_no = '0050'
dl = DataLoader()
stock_data = dl.taiwan_stock_daily(stock_id=stock_no, start_date='2000-01-01')
stock_data.head()
很好,第一筆資料是 2003-06-30,看起來資料是完整的
再測試一下捉上櫃股票 6539(台康生技)
from FinMind.data import DataLoader
stock_no = '6539'
dl = DataLoader()
stock_data = dl.taiwan_stock_daily(stock_id=stock_no, start_date='2000-01-01')
stock_data.head()
也成功的捉到資料
FinMind 可以說完美的補足 yfinance 台股資料不足的缺點
FinMind 整合 ffn
既然 ffn 這麼好用,我們可以用 FinMind 取得資料後,然後直接用 ffn 的 function 嗎 ?
答案是可以的,不過資料需要做些處理
ffn 的 index 是日期,但是 FinMind 的 index 是流水號,date 是其中一個欄位而且是 string 格式,所以我們要將 FinMind 的 index 改成日期格式的 date
stock_data.set_index("date" , inplace=True)
stock_data = stock_data.set_index(pd.DatetimeIndex(pd.to_datetime(stock_data.index)))
然後就可以用 ffn 的 function 了
stats = stock_data[["close"]].calc_stats()
stats.display()
成功取得 0050 的統計資料