You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

yfinance脚本yf.download列应用故障修复及期权链历史数据咨询

问题背景

我基于yfinance库编写了脚本,流程为:下载SPY股票行情数据,获取季度期权链,计算并添加上下行权价、上下期权合约代码列。但执行倒数第二行Stocks['Call_lower_price'] = Stocks['Call_lower_ticker'].apply(yf.download(['Call_lower_ticker'], start=Stocks.index)['Close'].iloc[0])时出现错误,报错信息如下:

[*********************100%%**********************]  1 of 1 completed
[*********************100%%**********************]  1 of 1 completed

**1 Failed download:
['CALL_LOWER_TICKER']: ValueError('The truth value of a DatetimeIndex is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().')
---------------------------------------------------------------------------**
IndexError                                Traceback (most recent call last)
File <timed exec>:19

File C:\ProgramData\anaconda3\Lib\site-packages\pandas\core\indexing.py:1191, in _LocationIndexer.__getitem__(self, key)
   1189 maybe_callable = com.apply_if_callable(key, self.obj)
   1190 maybe_callable = self._check_deprecated_callable_usage(key, maybe_callable)
-> 1191 return self._getitem_axis(maybe_callable, axis=axis)

File C:\ProgramData\anaconda3\Lib\site-packages\pandas\core\indexing.py:1752, in _iLocIndexer._getitem_axis(self, key, axis)
   1749     raise TypeError("Cannot index by location index with a non-integer key")
   1751 # validate the location
-> 1752 self._validate_integer(key, axis)
   1754 return self.obj._ixs(key, axis=axis)

File C:\ProgramData\anaconda3\Lib\site-packages\pandas\core\indexing.py:1685, in _iLocIndexer._validate_integer(self, key, axis)
   1683 len_axis = len(self.obj._get_axis(axis))
   1684 if key >= len_axis or key < -len_axis:
-> 1685     raise IndexError("single positional indexer is out-of-bounds")

IndexError: single positional indexer is out-of-bounds

技术问题

  1. 如何修改代码使该行yf.download函数正常工作?
  2. 是否可以下载yf.option.chain的历史数据?

完整代码

%%time
import yfinance as yf
import pandas as pd
import warnings
import datetime 
warnings.filterwarnings("ignore", message="The 'unit' keyword in TimedeltaIndex construction is deprecated and will be removed in a future version. Use pd.to_timedelta instead.", category=FutureWarning, module="yfinance.utils")

Stocks=yf.download('SPY', period="1y", interval="1d", group_by='ticker')

stock = yf.Ticker('SPY')
Expirations = stock.options
options_chain = stock.option_chain('2024-09-20')
Calls_desk=options_chain.calls

Stocks['110_for_Call'] = Stocks['Close']*1.1
Stocks['Call_lower_strike']  = Stocks['110_for_Call'].apply(lambda x: Calls_desk.iloc[Calls_desk[Calls_desk['strike'] < x]['strike'].idxmax()]['strike'])
Stocks['Call_upper_strike']  = Stocks['110_for_Call'].apply(lambda x: Calls_desk.iloc[Calls_desk[Calls_desk['strike'] > x]['strike'].idxmin()]['strike'])
Stocks['Call_lower_ticker']  = Stocks['110_for_Call'].apply(lambda x: Calls_desk.iloc[Calls_desk[Calls_desk['strike'] < x]['strike'].idxmax()]['contractSymbol'])
Stocks['Call_upper_ticker']  = Stocks['110_for_Call'].apply(lambda x: Calls_desk.iloc[Calls_desk[Calls_desk['strike'] > x]['strike'].idxmin()]['contractSymbol'])
Stocks['Call_lower_price']   = Stocks['Call_lower_ticker'].apply(yf.download(['Call_lower_ticker'], start=Stocks.index)['Close'].iloc[0])
Stocks

解答

问题1:修复yf.download调用错误

原代码错误有两个核心原因:

  • apply未用lambda接收每行的合约代码,导致传入固定字符串'Call_lower_ticker'而非实际合约代码
  • start=Stocks.index传入整个DataFrame索引,引发DatetimeIndex歧义错误

方案1:逐行处理(简单直接)

用lambda接收每行的合约代码和对应日期,同时处理下载失败的情况:

def get_option_price(contract_ticker, row_date):
    try:
        data = yf.download(contract_ticker, start=row_date, period="1d")
        return data['Close'].iloc[0] if not data.empty else None
    except Exception as e:
        print(f"下载{contract_ticker}失败: {e}")
        return None

Stocks['Call_lower_price'] = Stocks.apply(
    lambda row: get_option_price(row['Call_lower_ticker'], row.name),
    axis=1
)

方案2:批量下载(效率更高)

先收集所有唯一合约代码批量下载,再映射回DataFrame,避免重复请求:

# 收集唯一合约代码
unique_tickers = Stocks['Call_lower_ticker'].unique()
# 批量下载所有合约的历史数据
all_option_data = yf.download(unique_tickers, start=Stocks.index.min(), end=Stocks.index.max())['Close']

# 映射每行对应的期权价格
Stocks['Call_lower_price'] = Stocks.apply(
    lambda row: all_option_data.loc[row.name, row['Call_lower_ticker']] 
    if row['Call_lower_ticker'] in all_option_data.columns 
    else None,
    axis=1
)

问题2:yfinance是否支持下载历史期权链数据

yfinance不支持直接获取历史期权链数据,它只能获取当前有效的未到期合约期权链。如果需要历史期权链数据,有两种替代方案:

  • 使用专业金融数据API(如Interactive Brokers、Polygon.io等),这类服务商提供历史期权数据接口
  • 自行定期抓取并存储当前期权链数据,构建私人历史数据库(适合长期需求场景)

内容的提问来源于stack exchange,提问作者Vasiliy Deryuga

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 07:23:16