download-stock-historical-data-with-python-and-yahoo-finance-api

使用Python及Yahoo Finance API抓取台股歷史資料

目錄

    原始文章

    使用Python及Yahoo Finance API抓取台股歷史資料


    無論是投資或是資料科學專案,經常需要股市資料作分析。證交所在政府資料開放平台中提供了個股日成交資訊,也可以透過API查詢歷史記錄,但很容易因為頻繁抓取資料而被暫時的鎖IP,之後會再寫另外一篇文章說明。

    常見的替代方案是到美國的Yahoo Finance下載,只要搜尋「股票代碼.TW」就可以查詢,如「0050.TW」。網路上有很多文章提到,Yahoo Finance的免費API服務可能會收掉,也確實,我偶爾執行的時候會出現錯誤訊息如下,但通常過個幾分鐘再試就可以正常執行了。如果你每次都是手動執行Python程式的話,我覺得這倒不是太大的問題,但如果你是使用排程自動更新,可能就要先寫個try/except。

    HTTPSConnectionPool(host=’query1.finance.yahoo.com’, port=443): Max retries exceeded with url: /v8/finance/chart/0050.TW?period1=-2208988800&period2=1606746234&interval=1d&includePrePost=False&events=div%2Csplits (Caused by NewConnectionError(‘: Failed to establish a new connection: [Errno 51] Network is unreachable’))

    另外,國外有一些公司也提供類似的API服務,像是IEX CloudAlpha Vantage,但這些資料不一定包含台股的資訊,建議付費前先查詢清楚,使用的關鍵字為Supported Symbols,Symbols指的是股票代號,像是這一篇〈How to Find All Supported Symbols on IEX Cloud〉

    如果你希望獲得歷史資料,並持續累積新資料,最好的方式應該是先用這篇文章的方式抓取所有歷史資料,然後再寫一支程式每日抓取證交所的個股日成交資訊。我在2020年6月25日執行以下程式,並儲存成h5或csv檔,總資料筆數約380萬,檔案大小約300mb,不算太大。

    執行流程與程式碼

    下載台股代碼清單

    import requests
    import numpy as np
    import pandas as pd
    link = 'https://quality.data.gov.tw/dq_download_json.php?nid=11549&md5_url=bb878d47ffbe7b83bfc1b41d0b24946e'
    r = requests.get(link)
    data = pd.DataFrame(r.json())
    data.to_csv(儲存路徑 + '/stock_id.csv', index=False, encoding='utf-8-sig')

    下載Yahoo股市資料

    根據〈Free Stock Data for Python Using Yahoo Finance API〉.)的說法,Yahoo Finance的API的限制為:Using the Public API (without authentication), you are limited to 2,000 requests per hour per IP (or up to a total of 48,000 requests a day)。在我用以下的code抓取1116支股票的歷史記錄後,確實沒有被阻擋的問題。

    首先,我們需要先使用以下的裝令安裝yfinance套件。

    pip install yfinance

    完成安裝後,可以用以下的程式下載歷史資料,並且儲存成csv。

    
    import yfinance as yf
    import pandas as pd
    # 讀取csv檔
    stock_list = pd.read_csv(儲存路徑 + '/stock_id.csv')
    stock_list.columns = ['stock_id', 'name']
    historical_data = pd.DataFrame()
    for i in stock_list.index:    
        # 抓取股票資料
        stock_id = stock_list.loc[i, 'stock_id'] + '.TW'
        data = yf.Ticker(stock_id)
        df = data.history(period="max")
        # 增加股票代號
        df['stock_id'] = stock_list.loc[i, 'stock_id']
        # 合併
        historical_data = pd.concat([historical_data, df])
        time.sleep(0.8)
    historical_data.to_csv(儲存路徑 + '/historical_data.csv', index=False)


    20230116更新

    比起證交所的開放資料或Yahoo Finance API,我發現另外一個更優質的資料來源 ─ 富果Fugle,請參考〈使用Python與富果API下載台股歷史資料〉



    推薦文章

    Aron

    搭載商業思維的資料科學家,工業設計系畢業,曾任職知名品牌行銷企劃。下班後寫機器學習模型,寫網站,也寫文章。興趣是把Side Project當成創業題目來玩,把人生當成遊戲破關。

    facebook telegram

    推薦書單

    研究生完全求生手冊:方法、秘訣、潛規則
    研究生完全求生手冊:方法、秘訣、潛規則 ⭐⭐⭐⭐⭐
    大會計師教你從財報數字看懂產業本質
    大會計師教你從財報數字看懂產業本質 ⭐⭐⭐⭐⭐
    蘭亭序殺局 卷一:玄甲衛
    蘭亭序殺局 卷一:玄甲衛 ⭐⭐⭐⭐⭐
    給兒子的18堂商業思維課
    給兒子的18堂商業思維課 ⭐⭐⭐⭐

    18 則留言

    1. Isaac

      Yfinance 有台指期的代號嗎?

    2. Andy

      目前 API 好像被鎖了?
      我打API都response forbidan,請問有什麼方式繞過去嗎?

    3. Steven

      很棒的分享!我在嘗試用 yfinance 抓 0050 和 0056 的資料時,發現 adj close 是錯誤的,進而注意到大多台灣 ETF 的配息都沒被 yahoo finance 記錄到 (但台灣 yahoo 股市卻有!),在回測時可能要多注意股息對報酬率的影響。

    4. Lucy

      請問照著個程式抓下來的資料沒有日期這個欄位是正常的嗎?
      以下是我抓下來的columns:
      Index([‘Open’, ‘High’, ‘Low’, ‘Close’, ‘Volume’, ‘Dividends’, ‘Stock Splits’,
      ‘STOCK_ID’, ‘NAME’, ‘Adj Close’],
      dtype=’object’)

      謝謝 : )

      1. Aron

        理論上應該有要日期欄位喔,你可以直接到Yahoo Finance看一下原始資料,抓下來的格式應該要是一樣的。
        我猜你的日期可能是在index欄,而且你用reset_index(drop=True),如果是這樣的話,改成reset_index()試試看。

    5. existedeinnettw

      如果要下載daily 的資料可以把第一段的code 改一下
      “`python
      link=’http://www.twse.com.tw/exchangeReport/STOCK_DAY_ALL?response=open_data’
      data = pd.read_csv(link)

      data.to_csv(‘.’ + ‘/stock_id.csv’, index=False, header = True)
      “`

    6. period1的數值

      網址中:period1=-2208988800&period2=1606746234

      很奇怪,period1, 2是什麼數值, 是Ticker嗎?看不出有日期的型式,若要下載 2021-1-1 ~ 2021-1-31間的data,那period1和2,各是多少?

    7. 14711

      ticker 裡面究竟要填什麼才能找到歷史資料呢? 照著原本的程式碼似乎是找不到的 會出現這樣的錯誤
      No data found for this date range, symbol may be delisted

      1. Aron

        如果要抓台股資料的話,要用股票代號加上.TW,如0050要變成「0050.TW」。美股的話就可以直接輸入股票代號,像微軟是MSFT。

    8. Jeff

      請問一下,有沒有什麼辦法可以取得個股過往的K棒開高收低資料嗎?包含 M1, M5,….,D1等等

      1. Aron

        證交所跟Yahoo Finance都只能抓到開盤、收盤、最高、最低、調整後收盤價和交易量。如果你想看到完整的資料,可以試試看富果的API,他們好像可以提供逐筆交易的資料,但這部份我自己也還沒試過。

        〈申請玉山證券富果帳戶及台股API常見問題 – 量化投資第一步〉
        富果API說明文件

    9. Leon

      為何有網站說yahoo finance已不繼續繼了?
      https://rapidapi.com/blog/how-to-use-the-yahoo-finance-api/

      1. Aron

        我也看過滿多類似的文章,但我之前使用上都沒問題,剛才再以0050.TW、0056.TW和MSFT測試,確實前兩次出現錯誤訊息如下,但後來再試又可以了。
        我覺得只要在Python中寫個try except,Yahoo Finance API應該還是可以加減用一下。
        ———-
        HTTPSConnectionPool(host=’query1.finance.yahoo.com’, port=443): Max retries exceeded with url: /v8/finance/chart/0050.TW?period1=-2208988800&period2=1606746234&interval=1d&includePrePost=False&events=div%2Csplits (Caused by NewConnectionError(‘: Failed to establish a new connection: [Errno 51] Network is unreachable’))

    10. Alan

      這個分享真的很棒,但分析上似乎會有suvival bias?過往已經下市的股票資料無法取得。

      1. Aron

        感謝你的提醒,我之前沒注意到yahoo會排除下市的股票,我也同意這可能會在分析上產生偏差,只是目前也不知道該怎麼處理。
        之後如果有新的發展,我會更新在文章中,並用留言回覆給你,這樣你應該就會收到通知的mail了。

    11. s

      請問我照您的code跑出現下面訊息
      ValueError: Length mismatch: Expected axis has 10 elements, new values have 2 elements

      請教是哪邊出問題呢

      1. Dana

        原始數據比較多
        但新的叫用只需要用到兩個元素

      2. kk

        我也有一樣的問題
        請問您解決這個問題了嗎?
        如果有的畫 請問要如何解決?

    發佈留言

    • * 表示必填欄位
    • 您填寫的電子郵件不會被公開
    • 請確認您的電子郵件正確無誤,當您的留言收到新的回覆時,我們會寄送通知信件給您

    發佈留言必須填寫的電子郵件地址不會公開。