yfinance `FundsData` 完全指南:用 Python 抓取 ETF 与共同基金的持仓、费率与资产配置数据
2026/9/22 19:05:28 网站建设 项目流程

yfinanceFundsData完全指南:用 Python 抓取 ETF 与共同基金的持仓、费率与资产配置数据

【免费下载链接】yfinanceDownload market data from Yahoo! Finance's API项目地址: https://gitcode.com/GitHub_Trending/yf/yfinance

本指南围绕 yfinance 官方 API 参考文档 FundsData 类 展开,深入讲解如何通过Ticker.funds_data获取 ETF(交易所交易基金)与共同基金(Mutual Fund)的底层数据,包括基金描述、投资组合概况、运营费率、前十大持仓、债券评级与行业权重等。读完本文,你将掌握FundsData的全部公开属性、底层数据流(quoteSummaryAPI 与_fetch_and_parse解析管线)、返回的数据结构(dict/pd.DataFrame),并能直接参考 示例代码 与 单元测试 快速落地实战。

一、FundsData是什么:为 ETF / 共同基金定制的数据门面

yfinance 的Ticker类主要面向个股,但 ETF 与共同基金除了行情与历史价格外,还有一套特有的"基金数据":持仓明细、资产类别分布、行业权重、债券评级、费率结构等。这些数据在 Yahoo! Finance 上属于quoteSummary接口的不同模块,yfinance 将其封装为一个独立的公开类:

  • 类全名:yfinance.scrapers.funds.FundsData(见 funds.py)
  • 文档注册入口:doc/source/reference/yfinance.funds_data.rst,属于 API Reference 的一部分(reference/index.rst)
  • 公开接入点:Ticker.funds_data属性

从 ticker.py 可以看到,Ticker通过属性转发到基类:

@property def funds_data(self) -> FundsData: return self.get_funds_data()

get_funds_data()在 base.py 中实现了懒加载单例模式:

def get_funds_data(self) -> Optional[FundsData]: if not self._funds_data: self._funds_data = FundsData(self._data, self.ticker) return self._funds_data

即:首次访问时创建FundsData实例,之后复用,避免重复初始化。构造FundsData只需要两个参数(funds.py):

参数类型说明
dataYfData负责发请求的底层数据对象(共享Ticker的会话与缓存)
symbolstr基金代码,如"SPY""VTSAX"

适用范围说明FundsData只对 ETF 与共同基金有效。对普通股票(如 AAPL)调用_fetch_and_parse()会抛出YFDataException——这一点在测试 test_ticker.py 中有明确验证:ticker.funds_data._fetch_and_parse()对 AAPL 会assertRaises(YFDataException)

二、底层数据流:一次请求,四个quoteSummary模块

FundsData的源码注释明确列出了它查询的模块(funds.py):

Queried Modules:quoteType,summaryProfile,fundProfile,topHoldings

2.1 请求构造

_fetch()方法(funds.py)负责组装 HTTP 请求:

def _fetch(self): modules = ','.join(["quoteType", "summaryProfile", "topHoldings", "fundProfile"]) params_dict = {"modules": modules, "corsDomain": "finance.yahoo.com", "symbol": self._symbol, "formatted": "false"} result = self._data.get_raw_json(_QUOTE_SUMMARY_URL_ + self._symbol, params=params_dict) return result

关键细节:

  • 请求端点:_QUOTE_SUMMARY_URL_ = f"{_BASE_URL_}/v10/finance/quoteSummary/",其中_BASE_URL_在 const.py 中定义为https://query2.finance.yahoo.com
  • 四个模块一次性拼入modules参数,一次 HTTP 往返拿到全部基金数据;
  • "formatted": "false"要求返回未格式化的原始数值(raw 值),方便后续解析与计算,这与后面_parse_raw_values的设计是配套的;
  • 请求通过YfData.get_raw_json发出,从而复用了 yfinance 的会话管理、限流与缓存机制。

2.2 解析管线

_fetch_and_parse()(funds.py)是核心解析入口:

def _fetch_and_parse(self) -> None: result = self._fetch() try: data = result["quoteSummary"]["result"][0] # check quote type self._quote_type = data["quoteType"]["quoteType"] self._parse_description(data["summaryProfile"]) self._parse_top_holdings(data["topHoldings"]) self._parse_fund_profile(data["fundProfile"]) except KeyError: if not YfConfig.debug.hide_exceptions: raise raise YFDataException(f"{self._symbol}: No Fund data found.") except Exception as e: if not YfConfig.debug.hide_exceptions: raise logger = utils.get_yf_logger() logger.error(f"Failed to get fund data for '{self._symbol}' reason: {e}") ...

要点解读:

  1. 先取 quoteType 做类型校验——确保目标确实是基金类标的;
  2. 三个解析器分工明确_parse_description(简介)、_parse_top_holdings(持仓族数据)、_parse_fund_profile(基金画像);
  3. 异常处理双通道KeyError表示响应中没有基金数据(典型的非基金标的场景),统一转为YFDataException;其他异常则记录日志。两条路径都受全局配置YfConfig.debug.hide_exceptions控制,关闭该开关(默认关闭hide_exceptions即为False?)时会直接向上抛出原始异常,方便调试(详见 config.py)。

懒加载机制:所有公开属性(如descriptiontop_holdings)都遵循同一模式——缓存字段为None时触发一次_fetch_and_parse(),之后直接返回缓存结果。因此多次访问同一属性不会重复发请求,这也是测试里连续调用多个属性而只发生少量请求的原因。

三、公开属性全览:从简介到持仓的一站式接口

FundsData共暴露 10 个公开属性/方法,以下按主题分组,均可在 funds.py 中找到实现。

3.1 基金画像(fundProfile / summaryProfile)

quote_type()(funds.py) 返回字符串类型的基金类别,例如"ETF""MUTUALFUND"。注意它是一个方法而非属性,调用需写data.quote_type()

description(funds.py) 返回基金的longBusinessSummary(长文业务简介),类型为str。底层取自summaryProfile模块。

fund_overview(funds.py) 返回Dict[str, Optional[str]],包含三个键(见_parse_fund_profile,funds.py):

含义
categoryName基金所属类别名称(如 Large Growth、High Yield Bond)
family基金家族 / 发行公司(如 Vanguard、SPDR)
legalType法律结构类型(如 Open Ended Investment Company)

fund_operations(funds.py) 返回pd.DataFrame,对比基金自身与"同类平均(Category Average)"的运营指标(funds.py):

指标(index: Attributes)字段
Annual Report Expense RatiofeesExpensesInvestment.annualReportExpenseRatio
Annual Holdings TurnoverfeesExpensesInvestment.annualHoldingsTurnover
Total Net AssetsfeesExpensesInvestment.totalNetAssets

DataFrame 的列为[Attributes, <symbol>, Category Average],行索引为指标名。其中基金侧数值取自feesExpensesInvestment,同类平均取自feesExpensesInvestmentCat

3.2 持仓族数据(topHoldings)

asset_classes(funds.py) 返回Dict[str, float],表示基金资产的类别分布百分比(funds.py),键包括:

  • cashPosition(现金)
  • stockPosition(股票)
  • bondPosition(债券)
  • preferredPosition(优先股)
  • convertiblePosition(可转债)
  • otherPosition(其他)

top_holdings(funds.py) 返回pd.DataFrame,行索引为Symbol,列含Name(持仓名称)与Holding Percent(持仓占比)。解析逻辑见 funds.py:

_holdings = data.get("holdings", []) for item in _holdings: _symbol.append(item["symbol"]) _name.append(item["holdingName"]) _holding_percent.append(item["holdingPercent"]) self._top_holdings = pd.DataFrame({ "Symbol": _symbol, "Name": _name, "Holding Percent": _holding_percent }).set_index("Symbol")

equity_holdings(funds.py) 返回pd.DataFrame,行索引为Average,列为[Average, <symbol>, Category Average],六行估值指标(funds.py):

  • Price/Earnings(市盈率)
  • Price/Book(市净率)
  • Price/Sales(市销率)
  • Price/Cashflow(市现率)
  • Median Market Cap(市值中位数)
  • 3 Year Earnings Growth(三年盈利增长)

bond_holdings(funds.py) 返回pd.DataFrame,同样带同类平均对比,三行指标(funds.py):

  • Duration(久期)
  • Maturity(到期期限)
  • Credit Quality(信用质量)

bond_ratings(funds.py) 返回Dict[str, float],债券评级分布。解析采用字典推导(funds.py):

self._bond_ratings = dict((key, d[key]) for d in data.get("bondRatings", []) for key in d)

sector_weightings(funds.py) 返回Dict[str, float],行业权重分布(如 Technology、Health Care 等),解析方式与bond_ratings相同(funds.py)。

数值清洗的通用工具_parse_raw_values(data, default=None)(funds.py)专门处理 Yahoo 的{"raw": ..., "fmt": "..."}双字段结构——只取raw原始数值,若传入的不是 dict 则原样返回,缺字段时返回default(多数场景为pd.NA)。这正是"formatted": "false"请求模式下安全解析的关键。

3.3 各属性的返回类型速查表

属性返回类型数据来源模块
quote_type()strquoteType
descriptionstrsummaryProfile
fund_overviewDict[str, Optional[str]]fundProfile
fund_operationspd.DataFramefundProfile
asset_classesDict[str, float]topHoldings
top_holdingspd.DataFrametopHoldings
equity_holdingspd.DataFrametopHoldings
bond_holdingspd.DataFrametopHoldings
bond_ratingsDict[str, float]topHoldings
sector_weightingsDict[str, float]topHoldings

四、实战:五分钟拉取 SPY 的完整基金画像

官方在 examples/funds_data.py 中给出了最简示例,文档 index.rst 的"Funds"一节也展示了同样的用法:

import yfinance as yf # 1. 拿到 FundsData 对象 spy = yf.Ticker('SPY') data = spy.funds_data # 2. 基金简介 data.description # 3. 运营信息 data.fund_overview # 类别 / 家族 / 法律类型 data.fund_operations # 费率、换手率、净资产(含同类平均) # 4. 持仓族信息 data.asset_classes # 资产类别分布 data.top_holdings # 前十大持仓 data.equity_holdings # 股票估值指标(含同类平均) data.bond_holdings # 债券特征(含同类平均) data.bond_ratings # 债券评级分布 data.sector_weightings # 行业权重

几个实战要点:

  1. 兼容性判断:先用data.quote_type()判断标的类型,避免对非基金标的误用(普通股票会触发YFDataException,见 tests/test_ticker.py 的TestTickerFundsData用例);
  2. 测试覆盖的标的类型:仓库测试用 SPY(股票 ETF)、JNK(债券 ETF)、VTSAX(共同基金)三类标的验证了全部属性(test_ticker.py),说明FundsData对权益 ETF、债券 ETF 与共同基金均有良好支持;
  3. 无重复请求:得益于懒加载缓存,同一FundsData实例上多次访问任一属性不会产生额外网络请求,可放心在循环/批量脚本中使用;
  4. 同类平均对比fund_operationsequity_holdingsbond_holdings均同时返回基金自身值与 Category Average,可直接用于横向对比基金相对同类的性价比与估值水平。

五、注意事项与限制

  • 不适用于普通股票FundsData面向 ETF 与共同基金;对个股调用会因响应缺少基金模块而抛出YFDataException
  • fundPerformance模块未实现:源码注释明确说明"fundPerformance module is not implemented as better data is queryable using history"(funds.py)——历史业绩表现应改用Ticker.history()等历史数据接口获取,不要期待FundsData提供业绩曲线;
  • 依赖网络可用性:所有数据来自 Yahoo! Finance 的quoteSummary接口,字段可能随上游 API 变化而增减;解析逻辑对缺失字段做了兜底(default/pd.NA),但字段结构变化仍可能影响结果完整性;
  • 异常开关YfConfig.debug.hide_exceptions(见 config.py)决定解析异常是被隐藏并以YFDataException兜底,还是直接抛出,排查问题时可以临时调整该配置查看完整错误栈与响应日志。

六、延伸阅读

  • 类实现源码:yfinance/scrapers/funds.py
  • API 参考文档:doc/source/reference/yfinance.funds_data.rst
  • 入门示例:doc/source/reference/examples/funds_data.py 与 doc/source/index.rst 的 Funds 小节
  • 完整测试用例:tests/test_ticker.py 中的TestTickerFundsData
  • 接入方式与懒加载实现:yfinance/base.py、yfinance/ticker.py
  • 底层请求地址常量:yfinance/const.py

【免费下载链接】yfinanceDownload market data from Yahoo! Finance's API项目地址: https://gitcode.com/GitHub_Trending/yf/yfinance

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询