使用Python的yfinance下载股票数据时出现'Adj Close' KeyError
问题
尝试用Python的yfinance库下载SPY、QQQ、GLD、VTI、BND五只标的的5年历史股票数据,提取Adj Close列时触发KeyError错误。
代码
import yfinance as yf import pandas as pd from pandas_datareader import data as pdt import datetime as dt import numpy as np from scipy.optimize import minimize end_date = dt.datetime.now() start_date = end_date - dt.timedelta(days=365*5) tickers = ['SPY', 'QQQ', 'GLD', 'VTI', 'BND'] adj_close_df = pd.DataFrame() for ticker in tickers: data = yf.download(ticker, start = start_date, end = end_date) adj_close_df[ticker] = data['Adj Close'] print(adj_close_df)
报错信息
%runcell -i 0 C:/Users/User/Downloads/untitled0.py [*********************100%***********************] 1 of 1 completed --------------------------------------------------------------------------- KeyError Traceback (most recent call last) File ~\AppData\Local\spyder-6\envs\spyder-runtime\Lib\site-packages\pandas\core\indexes\base.py:3805, in Index.get_loc(self, key) 3804 try: -> 3805 return self._engine.get_loc(casted_key) 3806 except KeyError as err: File index.pyx:167, in pandas._libs.index.IndexEngine.get_loc() File index.pyx:196, in pandas._libs.index.IndexEngine.get_loc() File pandas\_libs\hashtable_class_helper.pxi:7081, in pandas._libs.hashtable.PyObjectHashTable.get_item() File pandas\_libs\hashtable_class_helper.pxi:7089, in pandas._libs.hashtable.PyObjectHashTable.get_item() KeyError: 'Adj Close' The above exception was the direct cause of the following exception: KeyError Traceback (most recent call last) File c:\users\user\downloads\untitled0.py:16 14 for ticker in tickers: 15 data = yf.download(ticker, start = start_date, end = end_date) ---> 16 adj_close_df[ticker] = data['Adj Close'] 18 print(adj_close_df) File ~\AppData\Local\spyder-6\envs\spyder-runtime\Lib\site-packages\pandas\core\frame.py:4101, in DataFrame.__getitem__(self, key) 4099 if is_single_key: 4100 if self.columns.nlevels > 1: -> 4101 return self._getitem_multilevel(key) 4102 indexer = self.columns.get_loc(key) 4103 if is_integer(indexer): File ~\AppData\Local\spyder-6\envs\spyder-runtime\Lib\site-packages\pandas\core\frame.py:4159, in DataFrame._getitem_multilevel(self, key) 4157 def _getitem_multilevel(self, key): 4158 # self.columns is a MultiIndex -> 4159 loc = self.columns.get_loc(key) 4160 if isinstance(loc, (slice, np.ndarray)): 4161 new_columns = self.columns[loc] File ~\AppData\Local\spyder-6\envs\spyder-runtime\Lib\site-packages\pandas\core\indexes\multi.py:3040, in MultiIndex.get_loc(self, key) 3037 return mask 3039 if not isinstance(key, tuple): -> 3040 loc = self._get_level_indexer(key, level=0) 3041 return _maybe_to_slice(loc) 3043 keylen = len(key) File ~\AppData\Local\spyder-6\envs\spyder-runtime\Lib\site-packages\pandas\core\indexes\multi.py:3391, in MultiIndex._get_level_indexer(self, key, level, indexer) 3388 return slice(i, j, step) 3390 else: -> 3391 idx = self._get_loc_single_level_index(level_index, key) 3393 if level > 0 or self._lexsort_depth == 0: 3394 # Desired level is not sorted 3395 if isinstance(idx, slice): 3396 # test_get_loc_partial_timestamp_multiindex File ~\AppData\Local\spyder-6\envs\spyder-runtime\Lib\site-packages\pandas\core\indexes\multi.py:2980, in MultiIndex._get_loc_single_level_index(self, level_index, key) 2978 return -1 2979 else: -> 2980 return level_index.get_loc(key) File ~\AppData\Local\spyder-6\envs\spyder-runtime\Lib\site-packages\pandas\core\indexes\base.py:3812, in Index.get_loc(self, key) 3807 if isinstance(casted_key, slice) or ( 3808 isinstance(casted_key, abc.Iterable) 3809 and any(isinstance(x, slice) for x in casted_key) 3810 ): 3811 raise InvalidIndexError(key) -> 3812 raise KeyError(key) from err 3813 except TypeError: 3814 # If we have a listlike key, _check_indexing_error will raise 3815 # InvalidIndexError. Otherwise we fall through and re-raise 3816 # the TypeError. 3817 self._check_indexing_error(key) KeyError: 'Adj Close'
解决方案
1. 先确认数据的列结构
yfinance部分版本返回的数据可能存在多级列索引,先打印列名确认:
for ticker in tickers: data = yf.download(ticker, start=start_date, end=end_date) print(f"{ticker} 列名:", data.columns)
如果输出是多级索引(比如MultiIndex([('Adj Close',), ...],)),则需要用元组索引:data[('Adj Close',)],或者用data.xs('Adj Close', axis=1, level=0)提取对应列。
2. 直接指定下载目标列
避免列结构异常,下载时直接指定只获取调整后收盘价:
data = yf.download(ticker, start=start_date, end=end_date, progress=False)['Adj Close']
或者改用Ticker对象的history方法,新版yfinance中该方法返回的Close即为调整后收盘价:
data = yf.Ticker(ticker).history(start=start_date, end=end_date)['Close']
3. 批量下载优化代码
没必要循环单下载,直接批量获取所有标的数据,效率更高且避免单标的列结构问题:
adj_close_df = yf.download(tickers, start=start_date, end=end_date)['Adj Close']
如果返回多级列索引,用以下方式提取:
adj_close_df = yf.download(tickers, start=start_date, end=end_date).xs('Adj Close', axis=1)
4. 升级yfinance到最新版本
旧版本yfinance可能存在列名或返回格式bug,执行升级命令修复:
pip install --upgrade yfinance
内容的提问来源于stack exchange,提问作者Kiarash Arian
相关产品推荐
相关产品推荐

