2025年6月21日 星期六

舊版 yfinance 套件無法下載股價資料問題

我這幾天在測試 Plotly 套件, 想要用它來畫 K 線圖, 欲使用 yfinance 取得股價資料時卻發現居然出現錯誤, 我就拿之前 yfinance 筆記中的程式碼來測試, 發現一樣會丟出 JSONDecodeError 錯誤 : 

>>> import yfinance as yf   
import pandas as pd 
import mplfinance as mpf   
df=yf.download('0050.tw', start='2024-07-01', end='2024-08-21')
[*********************100%%**********************]  1 of 1 completed

1 Failed download:
['0050.TW']: JSONDecodeError('Expecting value: line 1 column 1 (char 0)')

我改用美股代號也是一樣 : 

>>> yf.download('AAPL', start='2024-07-01', end='2024-08-21')  
[*********************100%%**********************]  1 of 1 completed

1 Failed download:
['AAPL']: JSONDecodeError('Expecting value: line 1 column 1 (char 0)')
Empty DataFrame
Columns: [Open, High, Low, Close, Adj Close, Volume]
Index: []

搜尋谷歌發現不是只有我遇到, 原來是 yfinance 有改版, 舊的 yfinance (我的是 v0.2.41) 下載資料會出錯, 解決辦法就是升版, 參考 :



1. 更新 yfinance 套件 :  

用 pip install 指令加 -U 參數更新版本 : 

D:\python\test>pip install yfinance -U  
Requirement already satisfied: yfinance in c:\users\tony1\appdata\roaming\python\python310\site-packages (0.2.41)
Collecting yfinance
  Downloading yfinance-0.2.63-py2.py3-none-any.whl.metadata (5.8 kB)
Requirement already satisfied: pandas>=1.3.0 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from yfinance) (2.0.3)
Requirement already satisfied: numpy>=1.16.5 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from yfinance) (1.24.3)
Requirement already satisfied: requests>=2.31 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from yfinance) (2.31.0)
Requirement already satisfied: multitasking>=0.0.7 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from yfinance) (0.0.11)
Requirement already satisfied: platformdirs>=2.0.0 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from yfinance) (3.10.0)
Requirement already satisfied: pytz>=2022.5 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from yfinance) (2023.3)
Requirement already satisfied: frozendict>=2.3.4 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from yfinance) (2.4.4)
Requirement already satisfied: peewee>=3.16.2 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from yfinance) (3.17.6)
Requirement already satisfied: beautifulsoup4>=4.11.1 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from yfinance) (4.12.3)
Collecting curl_cffi>=0.7 (from yfinance)
  Downloading curl_cffi-0.11.4-cp39-abi3-win_amd64.whl.metadata (14 kB)
Requirement already satisfied: protobuf>=3.19.0 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from yfinance) (5.28.1)
Collecting websockets>=13.0 (from yfinance)
  Downloading websockets-15.0.1-cp310-cp310-win_amd64.whl.metadata (7.0 kB)
Requirement already satisfied: soupsieve>1.2 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from beautifulsoup4>=4.11.1->yfinance) (2.4.1)
Requirement already satisfied: cffi>=1.12.0 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from curl_cffi>=0.7->yfinance) (1.15.1)
Collecting certifi>=2024.2.2 (from curl_cffi>=0.7->yfinance)
  Downloading certifi-2025.6.15-py3-none-any.whl.metadata (2.4 kB)
Requirement already satisfied: pycparser in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from cffi>=1.12.0->curl_cffi>=0.7->yfinance) (2.21)
Requirement already satisfied: python-dateutil>=2.8.2 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from pandas>=1.3.0->yfinance) (2.8.2)
Requirement already satisfied: tzdata>=2022.1 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from pandas>=1.3.0->yfinance) (2023.3)
Requirement already satisfied: six>=1.5 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from python-dateutil>=2.8.2->pandas>=1.3.0->yfinance) (1.16.0)
Requirement already satisfied: charset-normalizer<4,>=2 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from requests>=2.31->yfinance) (3.2.0)
Requirement already satisfied: idna<4,>=2.5 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from requests>=2.31->yfinance) (3.4)
Requirement already satisfied: urllib3<3,>=1.21.1 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from requests>=2.31->yfinance) (1.26.19)
Downloading yfinance-0.2.63-py2.py3-none-any.whl (118 kB)
Downloading curl_cffi-0.11.4-cp39-abi3-win_amd64.whl (1.6 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.6/1.6 MB 2.6 MB/s eta 0:00:00
Downloading certifi-2025.6.15-py3-none-any.whl (157 kB)
Downloading websockets-15.0.1-cp310-cp310-win_amd64.whl (176 kB)
Installing collected packages: websockets, certifi, curl_cffi, yfinance
  Attempting uninstall: websockets
    Found existing installation: websockets 10.4
    Uninstalling websockets-10.4:
      Successfully uninstalled websockets-10.4
  Attempting uninstall: certifi
    Found existing installation: certifi 2023.7.22
    Uninstalling certifi-2023.7.22:
      Successfully uninstalled certifi-2023.7.22
  Attempting uninstall: yfinance
    Found existing installation: yfinance 0.2.41
    Uninstalling yfinance-0.2.41:
      Successfully uninstalled yfinance-0.2.41
Successfully installed certifi-2025.6.15 curl_cffi-0.11.4 websockets-11.0.3 yfinance-0.2.63

可見已升到最新的 v.0.2.63, 其實升到 v.2.0.54 以上就不會出錯了.

升版後就能正常下載了 (會出現一個警告, 但不影響資料取得) : 

>>> import yfinance as yf   
import pandas as pd 
import mplfinance as mpf   
df=yf.download('0050.tw', start='2024-07-01', end='2024-08-21')
<stdin>:4: FutureWarning: YF.download() has changed argument auto_adjust default to True
[*********************100%***********************]  1 of 1 completed
>>> df
Price            Close        High         Low        Open    Volume
Ticker         0050.TW     0050.TW     0050.TW     0050.TW   0050.TW
Date                                                                
2024-07-01  183.120392  184.543350  182.776912  183.071321   7319803
2024-07-02  181.893707  183.267595  181.059552  182.482510   5444336
2024-07-03  184.101746  184.101746  182.924111  184.101746   6478757
2024-07-04  188.910370  189.057567  187.045806  187.045806  12644207
2024-07-05  188.223419  189.253842  187.978081  189.008504   9733333
2024-07-08  194.160614  194.798487  188.272499  188.321554  17352467
2024-07-09  193.964325  196.319580  191.805352  193.768057  15488789
2024-07-10  194.651291  194.700347  191.363754  193.277388   7168611
2024-07-11  198.969238  199.018309  196.270519  196.908392   9796730
2024-07-12  192.688583  194.651289  192.345104  194.504077  14158267
2024-07-15  193.032043  194.405946  192.443241  193.964325   9790185
2024-07-16  194.166367  196.287050  193.327949  193.870453  13255538
2024-07-17  191.453857  193.821132  190.960674  193.722490  14489778
2024-07-18  188.001572  188.297470  185.634282  186.028837  17880013
2024-07-19  183.710876  186.423386  183.661555  186.176794  16453910
2024-07-22  178.236526  182.872449  177.595394  182.872449  21211846
2024-07-23  183.760193  183.760193  181.195632  181.195632  12527079
2024-07-26  176.559708  177.003570  174.685616  175.622662  25906618
2024-07-29  178.137909  179.518817  177.496761  179.321546   9946264
2024-07-30  178.137909  178.828363  175.080165  176.806307  13107381
2024-07-31  178.384491  178.680389  176.165165  176.411757   9078554
2024-08-01  181.491547  182.576556  180.209266  182.477914  14061699
2024-08-02  172.318329  176.461068  172.318329  175.721292  29706815
2024-08-05  156.585785  164.378079  156.240550  164.378079  55577204
2024-08-06  165.216492  168.076950  158.607835  165.019221  63140961
2024-08-07  171.775833  172.367659  166.696048  167.534466  31824740
2024-08-08  168.224915  170.049685  166.696043  168.718098  25841105
2024-08-09  173.452667  174.488341  172.121066  172.614249  23353756
2024-08-12  175.622665  177.348808  174.833569  174.833569  17571739
2024-08-13  176.066528  177.052895  175.573345  176.855625  10858460
2024-08-14  178.285858  179.370868  177.496761  177.891317  18714319
2024-08-15  176.904953  178.532453  176.609040  178.137912  11481647
2024-08-16  180.899719  181.146311  179.864046  180.505178  13205915
2024-08-19  181.146317  182.182005  180.653133  180.998367   9280593
2024-08-20  181.244949  182.675179  181.195628  182.083367  10784876

注意, 改版後預設不會顯示 Close Adj 欄位, Close 欄位就是已調整權值後的收盤價 Close Adj. 因為新版的 API 有修改, download() 的 auto_adjust 參數預設值為 True, 亦即 Close 欄位就是 Close Adj, 這就是上面出現的警告 "FutureWarning: YF.download() has changed argument auto_adjust default to True" 所提示的. 只要下載時明確指定 auto_adjust 之值就不會出現警語了, 例如 :

>>> df=yf.download('0050.tw', start='2024-07-01', end='2024-08-21', auto_adjust=True)   
[*********************100%***********************]  1 of 1 completed
>>> df
Price           Close       High        Low       Open     Volume
Ticker        0050.TW    0050.TW    0050.TW    0050.TW    0050.TW
Date                                                             
2024-07-01  45.692062  46.047118  45.606358  45.679818   29279212
2024-07-02  45.385979  45.728790  45.177841  45.532896   21777344
2024-07-03  45.936928  45.936928  45.643085  45.936928   25915028
2024-07-04  47.136772  47.173501  46.671528  46.671528   50576828
2024-07-05  46.965366  47.222477  46.904150  47.161260   38933332
2024-07-08  48.446808  48.605969  46.977610  46.989850   69409868
2024-07-09  48.397835  48.985516  47.859130  48.348862   61955156
2024-07-10  48.569241  48.581481  47.748937  48.226425   28674444
2024-07-11  49.646652  49.658896  48.973270  49.132431   39186920
2024-07-12  48.079510  48.569242  47.993805  48.532510   56633068
2024-07-15  48.165207  48.508022  48.018289  48.397829   39160740
2024-07-16  48.201942  48.728404  47.993805  48.128482   53022152
2024-07-17  47.528557  48.116235  47.406124  48.091746   57959112
2024-07-18  46.671528  46.744985  46.083846  46.181795   71520052
2024-07-19  45.606358  46.279740  45.594114  46.218523   65815640
2024-07-22  44.247345  45.398216  44.088183  45.398216   84847384
2024-07-23  45.618599  45.618599  44.981945  44.981945   50108316
2024-07-26  43.831074  43.941263  43.365829  43.598451  103626472
2024-07-29  44.222866  44.565677  44.063701  44.516705   39785056
2024-07-30  44.222866  44.394272  43.463779  43.892295   52429524
2024-07-31  44.284081  44.357537  43.733131  43.794348   36314216
2024-08-01  45.055408  45.324763  44.737081  45.300275   56246796
2024-08-02  42.778149  43.806587  42.778149  43.622937  118827260
2024-08-05  38.872536  40.806979  38.786831  40.806979  222308816
2024-08-06  41.015114  41.725225  39.374510  40.966141  252563844
2024-08-07  42.643475  42.790396  41.382414  41.590552  127298960
2024-08-08  41.761955  42.214956  41.382412  41.884388  103364420
2024-08-09  43.059750  43.316856  42.729179  42.851612   93415024
2024-08-12  43.598454  44.026970  43.402560  43.402560   70286956
2024-08-13  43.708641  43.953507  43.586208  43.904535   43433840
2024-08-14  44.259594  44.528948  44.063700  44.161649   74857276
2024-08-15  43.916782  44.320810  43.843322  44.222865   45926588
2024-08-16  44.908485  44.969702  44.651379  44.810540   52823660
2024-08-19  44.969704  45.226814  44.847270  44.932975   37122372
2024-08-20  44.994190  45.349246  44.981946  45.202328   43139504

可見警語消失了, 傳回的 DataFrame 除索引外只有五欄資料, Close 欄位是已還原權息之收盤價. 

如果想取得未還原權息之收盤價, 則要傳入 auto_adjust=False, 例如 : 

>>> df=yf.download('0050.tw', start='2024-07-01', end='2024-08-21', auto_adjust=False)
[*********************100%***********************]  1 of 1 completed
>>> df
Price       Adj Close      Close       High        Low       Open     Volume
Ticker        0050.TW    0050.TW    0050.TW    0050.TW    0050.TW    0050.TW
Date                                                                        
2024-07-01  45.692062  46.650002  47.012501  46.562500  46.637501   29279212
2024-07-02  45.385979  46.337502  46.687500  46.125000  46.487499   21777344
2024-07-03  45.936928  46.900002  46.900002  46.599998  46.900002   25915028
2024-07-04  47.136772  48.125000  48.162498  47.650002  47.650002   50576828
2024-07-05  46.965366  47.950001  48.212502  47.887501  48.150002   38933332
2024-07-08  48.446808  49.462502  49.625000  47.962502  47.974998   69409868
2024-07-09  48.397835  49.412498  50.012501  48.862499  49.362499   61955156
2024-07-10  48.569241  49.587502  49.599998  48.750000  49.237499   28674444
2024-07-11  49.646652  50.687500  50.700001  50.000000  50.162498   39186920
2024-07-12  48.079510  49.087502  49.587502  49.000000  49.549999   56633068
2024-07-15  48.165207  49.174999  49.525002  49.025002  49.412498   39160740
2024-07-16  48.201942  49.212502  49.750000  49.000000  49.137501   53022152
2024-07-17  47.528557  48.525002  49.125000  48.400002  49.099998   57959112
2024-07-18  46.671528  47.650002  47.724998  47.049999  47.150002   71520052
2024-07-19  45.606358  46.562500  47.250000  46.549999  47.187500   65815640
2024-07-22  44.247345  45.174999  46.349998  45.012501  46.349998   84847384
2024-07-23  45.618599  46.575001  46.575001  45.924999  45.924999   50108316
2024-07-26  43.831074  44.750000  44.862499  44.275002  44.512501  103626472
2024-07-29  44.222866  45.150002  45.500000  44.987499  45.450001   39785056
2024-07-30  44.222866  45.150002  45.325001  44.375000  44.812500   52429524
2024-07-31  44.284081  45.212502  45.287498  44.650002  44.712502   36314216
2024-08-01  45.055408  46.000000  46.275002  45.674999  46.250000   56246796
2024-08-02  42.778149  43.674999  44.724998  43.674999  44.537498  118827260
2024-08-05  38.872536  39.687500  41.662498  39.599998  41.662498  222308816
2024-08-06  41.015114  41.875000  42.599998  40.200001  41.825001  252563844
2024-08-07  42.643475  43.537498  43.687500  42.250000  42.462502  127298960
2024-08-08  41.761955  42.637501  43.099998  42.250000  42.762501  103364420
2024-08-09  43.059750  43.962502  44.224998  43.625000  43.750000   93415024
2024-08-12  43.598454  44.512501  44.950001  44.312500  44.312500   70286956
2024-08-13  43.708641  44.625000  44.875000  44.500000  44.825001   43433840
2024-08-14  44.259594  45.187500  45.462502  44.987499  45.087502   74857276
2024-08-15  43.916782  44.837502  45.250000  44.762501  45.150002   45926588
2024-08-16  44.908485  45.849998  45.912498  45.587502  45.750000   52823660
2024-08-19  44.969704  45.912498  46.174999  45.787498  45.875000   37122372
2024-08-20  44.994190  45.937500  46.299999  45.924999  46.150002   43139504

可見除索引外有六欄資料, 比傳入 auto_adjust=True 多了一個 Adj Close 欄位 (還原權息之收盤價), 而 Close 欄位則是未還原權息之收盤價.


2. 從多層欄位 DataFrame 取得單層價量資料 :  

觀察上面新版 yfinance API 傳回的 DataFrame 可知與舊版的格式不同 (明顯地多了 Ticker 列), 新版的傳回值改用多層欄位 (MultiIndex), 可表示多種維度的資訊使資料結構更有層次, 這對例如分群統計與交叉分析等應用場景的資料處理非常方便, 對於 yfinance 金融資料而言則是可同時下載多檔股票的價格資料, 此功能若使用舊版的單層欄位來做, 欄位名稱會變得很長, 或需要人工加前綴處理, 

多層欄位 (MultiIndex) 的第一層是價量資料欄位 (例如 Open, Close, High, Low 等), 第二層是股票代號 (例如 0050.TW), 當下載單一股票後, 檢視傳回值的 columns 屬性可知其值為一個 MultiIndex 物件 (一種 Pandas 的 Index 物件) : 

>>> df=yf.download('0050.tw', start='2024-07-01', end='2024-08-21', auto_adjust=False)   
[*********************100%***********************]  1 of 1 completed
>>> df.columns  
MultiIndex([('Adj Close', '0050.TW'),
            (    'Close', '0050.TW'),
            (     'High', '0050.TW'),
            (      'Low', '0050.TW'),
            (     'Open', '0050.TW'),
            (   'Volume', '0050.TW')],
           names=['Price', 'Ticker'])

可見多層欄位相當於是 tuple 的 list, 此處因為是下載單一股票, 所以第二層的股票代號均為 0050.TW. 同時下載多支股票只要將股票代號以 list 傳入 yf.download() 的第一參數即可 :

>>> df=yf.download(['0050.tw', '0056.tw'], start='2024-07-01', end='2024-08-21', auto_adjust=False)  
[*********************100%***********************]  2 of 2 completed
>>> df
Price       Adj Close                 Close  ...       Open     Volume           
Ticker        0050.TW    0056.TW    0050.TW  ...    0056.TW    0050.TW    0056.TW
Date                                         ...                                 
2024-07-01  45.692062  35.880264  46.650002  ...  41.419998   29279212   68378646
2024-07-02  45.385979  35.663326  46.337502  ...  41.290001   21777344   70261055

... (略) ...

可見股價資料會分層排列, 上層是價量資料欄位, 下層是股票代號 (Ticker 名稱), 檢查 df.columns 屬性即知 : 

>>> df.columns  
MultiIndex([('Adj Close', '0050.TW'),
            ('Adj Close', '0056.TW'),
            (    'Close', '0050.TW'),
            (    'Close', '0056.TW'),
            (     'High', '0050.TW'),
            (     'High', '0056.TW'),
            (      'Low', '0050.TW'),
            (      'Low', '0056.TW'),
            (     'Open', '0050.TW'),
            (     'Open', '0056.TW'),
            (   'Volume', '0050.TW'),
            (   'Volume', '0056.TW')],
           names=['Price', 'Ticker'])

新版 yfinance 傳回的多層欄位 df 資料無法直接丟給 mplfinance 套件去繪製 K 線圖, 必須將傳回值改回單層欄位 (只有價量欄位) 才行, 方法是利用 MultiIndex 物件的 map() 方法遍歷它的類串列元素 (都是 tuple), 然後取出以 lambda 函式取出 tuple 中的第一個元素 (即價量欄位名稱) : 

>>> df.columns=df.columns.map(lambda x: x[0])  
>>> df.columns  
Index(['Adj Close', 'Close', 'High', 'Low', 'Open', 'Volume'], dtype='object')

這樣便將多層欄位改成單層的價量欄位了 :

>>> df.head()  
            Adj Close      Close       High        Low       Open    Volume
Date                                                                       
2024-07-01  45.692062  46.650002  47.012501  46.562500  46.637501  29279212
2024-07-02  45.385979  46.337502  46.687500  46.125000  46.487499  21777344
2024-07-03  45.936928  46.900002  46.900002  46.599998  46.900002  25915028
2024-07-04  47.136772  48.125000  48.162498  47.650002  47.650002  50576828
2024-07-05  46.965366  47.950001  48.212502  47.887501  48.150002  38933332

這個調整後的 df 就可以丟給 mplfinance 繪製 K 線圖了 :

>>> import mplfinance as mpf   
>>> color=mpf.make_marketcolors(up='red', down='green', inherit=True)   
>>> font={'font.family': 'Microsoft JhengHei'}   
>>> style=mpf.make_mpf_style(base_mpf_style='default', marketcolors=color, rc=font)    
>>> mpf.plot(df, type='candle', title='台灣五十(0050)', style=style)   




也可以用之前寫的 kbar 模組來簡化程式碼 :

>>> import kbar  
>>> kb=kbar.KBar(df)     
>>> kb.plot()     

結果與上圖是一樣的. 

參考 :


沒有留言 :