JerBouma / 数据质量

FinanceDatabase 数据质量审计:八个边界与实测证据

它不是一个选股器,而是一张标的黄页。这页把「用之前必须先知道」的八个边界逐条配上 2026-09-29 的实测证据:哪些列大量为空、同一家公司为什么会重复出现、symbol 为什么用 df["symbol"] 取不到、哪些写法不报错却会给出全表。看完再决定这份清单能不能进你的研究流程。

Equities 112,718 行 × 21 列同名记录 65,317 行ISIN 不同取值仅 9,406 个
重复上市同名 65,317 行
字段稀疏isin 缺失 73%
索引陷阱symbol 不在列里
静默失败错写法返回全表
数据质量审计的四个关注点:重复上市、字段稀疏、索引陷阱与静默失败(基于 2026-09-29 实测,非官方架构图)。

事实核验卡(核验日期 2026-09-29)

FinanceDatabase 版本
2.4.0(PyPI 与 GitHub Release,2026-06-02 发布)
Python 版本
3.11.9(本站实测);包要求 ≥3.10, <3.16
数据库快照
GitHub main 分支 compression/*.bz2(main 最后提交 2026-09-27)
核验日期
2026-09-29
Equities 行数
112,718 行 × 21 列
ETF 行数
36,481 行 × 9 列
数据来源
raw.githubusercontent.com/JerBouma/FinanceDatabase/main/compression/
最后验证时间
2026-09-29(本机 venv 实跑,输出已归档)

以上数字来自本站 2026-09-29 在 Windows + Python 3.11.9 + financedatabase 2.4.0 下的真实运行输出,不是从文章里转抄的;数据文件由上游持续更新,行数会变,以官方 PyPI 与 GitHub Release 为准。采集时 GitHub star 约 9,374(2026-09-29)。

FinanceDatabase · Eight boundaries

八个数据边界:先把这份清单读完再动手

每条都对应一个实测数字。这些不是「注意事项」,而是会直接改变你结论的东西。

#边界实测证据(2026-09-29)你该怎么做
1同一家公司会在多个交易所重复出现全库 65,317 行与其它行同名,涉及 19,633 个名字先按 micro/exchange 锁市场,再按业务规则去重
2symbol 是索引,不是列写 df["symbol"] 或 search(symbol=...) 都不会得到你要的结果用 df.index;搜索用 search(index=...)
3market_cap 是档位标签,不是市值数字取值只有 Nano/Small/Micro/Mid/Large/Mega + Cap 六种需要数值市值就另接数据源,别在这一列上排序
4标识符大量为空isin 缺失 73.00%、cusip 缺失 75.79%、figi 缺失 48.05%ISIN 只能作为辅助键,空值不会被匹配上
5分类字段缺失严重industry 缺失 35.54%、market_cap 缺失 32.26%用它们筛选前先跑一次 isna().mean()
6退市只用一个布尔值表示delisted 全库 10,404 行为 True;默认查询已排除它们分不清「退市」与「长期停牌」,需结合行情侧判断
7没有行情、财报与实时数据定位为证券清单与元数据;官方明说不提供最新基本面与股价下游接 yfinance、AKShare 或 FinanceToolkit 等
8筛选结果不等于投资结论按行业筛出的是「属于该行业分类的标的」,不含估值、盈利质量、流动性把筛选看作建池的起点,而不是结论
记住一句话:这份数据能回答「有哪些标的、属于什么分类、在哪个交易所」,不能回答「值不值得买」。把两件事混在一起,是使用这类数据库时最常见的错误。
FinanceDatabase · Duplicates

重复上市实测:同名记录到底有多少?

「去重」这件事在这里不是可选项。下面是从 Equities 全表统计出来的实测结果。

指标实测值说明
Equities 总行数112,718含退市,索引可取(代码本身不重复)
存在同名记录的行数65,317占全表的 57.9%
涉及的名称个数19,633这些名字都出现了不只一次
同名次数最多的名字ISHARES(257 行)注意:这 257 行的国家字段全都写着 Brazil
索引为空的行1 行数量极小,但取索引时要防 NaN 导致类型错误
有 ISIN 的行30,429 行其余 82,289 行(73.00%)该列为空
一个实测例子:把 name 等于 ISHARES 的 257 行全部取出来看,会发现它们的 market_cap 全都写着 Mid Cap、country 全都写着 Brazil——而代码却分布在伦敦、香港、法兰克福、圣地亚哥等地。这类字段组合说明名称列不是可靠的去重键,也说明个别记录的元数据本身就有问题。要判断是不是「真重复」,至少要看代码、交易所与 ISIN 的组合;本页第五步的可复现脚本里就有对应的检查片段,直接用 FinanceDatabase 的结果做分组即可跑出来。
FinanceDatabase · Identifiers

标识符稀疏度:ISIN 只有 9,406 个不同取值,能当锚点吗?

很多人想用 ISIN 做跨市场匹配。实测下来,这个思路在本库上会漏掉大部分标的。

标识符有值的行缺失率不同取值个数跨市场匹配可用性
isin30,42973.00%9,406偏弱:空值不参与匹配,且同一 ISIN 会对应多条记录
cusip27,28675.79%12,946弱:以北美为主,非美市场基本为空
figi58,55648.05%58,232尚可,但覆盖率仍不到一半
composite_figi60,89245.98%41,131可用于分组,注意不同取值个数少于有值行数
shareclass_figi63,99043.23%29,164与上面的 figi 配合使用
直接后果:同一家公司多地上市时,如果只有部分记录填了 ISIN,那么「按 ISIN 去重」会静默保留那些没填 ISIN 的重复记录。实测 isin 有值的只有 9,406 个不同值,却覆盖 30,429 行——也就是说有 5,181 个 ISIN 对应多条记录。更稳的键是「代码 + 交易所」,ISIN 只用来做交叉验证。
FinanceDatabase · Delisted

delisted 字段怎么用:默认查询已经帮你过滤了

这个字段看起来简单,但和「能不能取到行情」是两件事。

项实测值说明
delisted=True 的行10,404占 Equities 的 9.2%
delisted=False 的行102,314select() 的默认口径
字段取值种类只有 True / False没有「停牌」「暂停上市」等中间状态
重置方法select(exclude_delisted=False)需要看历史全量时显式关闭过滤
search() 里的对应参数exclude_delisted与 select() 用法一致
与本库清单的关系清单里有 ≠ 行情可取实测清单第 2、3 行的代码在 yfinance 上取不到数据
实测的坑:把 delisted 过滤掉之后,清单里仍可能出现取不到行情的代码(退市边缘、长期停牌或上游未更新)。反过来,某些标的状态字段没标退市,但行情侧早就没有成交。判断「可交易性」要靠行情侧,不能只看这个布尔列。
FinanceDatabase · Audit recipe

五步审计脚本:拿到表先跑这五段

本站 2026-09-29 的审计就是按这五步做的,可直接复制。每步都给出预期输出,便于你判断是否跑对。

import financedatabase as fd

equities = fd.Equities()
df = equities.select()                      # 默认排除退市,实测 (102314, 21)

# 第 1 步:规模与结构
print(df.shape, type(df).__name__)          # 预期:(102314, 21) FinanceFrame

# 第 2 步:字段缺失率(决定哪些列能当筛选条件)
missing = df.isna().mean().sort_values(ascending=False)
print(missing.head(8))                      # 预期:industry / market_cap 等排在前列

# 第 3 步:字段取值数量(确认筛选参数合法值)
print(df["market_cap"].value_counts(dropna=False))
print(equities.show_options(selection="market_cap"))   # 预期:6 个档位

# 第 4 步:重复标的检查
base = df.index.to_series().astype(str).str.split(".", n=1).str[0]
dup = base.duplicated(keep=False)
print(dup.sum(), "行与其它行共享基础代码")   # 预期:数量可观,需按业务口径再去重

# 第 5 步:标识符稀疏度(判断能否当匹配键)
for col in ["isin", "cusip", "figi"]:
    print(col, round(df[col].isna().mean() * 100, 2))
步骤目的预期输出判读标准
1 规模与结构确认装对版本、数据量级正常(102314, 21) FinanceFrame行数明显偏小 → 数据文件可能被截断
2 字段缺失率决定哪些列能做筛选条件缺失率从高到低的列列表缺失率超过 30% 的列不建议当条件
3 取值与选项拿到合法参数值六档 market_cap 等直接拿它当 select() 的参数白名单
4 重复检查识别同一公司的多条记录共享基础代码的行数结合交易所字段判断,不要只看名称
5 标识符稀疏度判断能否用 ISIN 做键各标识符的缺失率缺失率高时改用「代码 + 交易所」
为什么要在建池之前做:这五步一共几十行代码,但它决定了后面所有结论的可信度。跳过它直接筛选,你就会在不知道 industry 缺了三分之一的情况下,把「行业分布统计」当成事实来用。把五步跑完再动手,是本站使用 FinanceDatabase 的固定顺序。
Universe building

筛选器不是选股器:从清单到可回测标的池的八步

本库只覆盖这条链路的前几步,后面每一步都要换工具,而换工具时代码口径会变。

步骤谁来做本库能覆盖吗这一步的典型失败点
1 分类筛选(国家/行业/市值档)本库可以取值写错会静默返回空表
2 去重(跨市场重复标的)本库 + 自己的规则部分覆盖only_primary_listing 在中国标的上会反向筛选
3 过滤退市本库可以布尔字段分不清退市与长期停牌
4 核对证券代码本库 + 行情源部分覆盖清单里有、行情侧取不到(实测已复现)
5 接入行情数据yfinance / AKShare / OpenBB 等不覆盖各源后缀与复权口径不同
6 补充基本面数据FinanceToolkit 等不覆盖to_toolkit() 免 key 只有 5 年基本面数据
7 加入流动性与估值条件自建规则不覆盖流动性指标要用行情侧数据算
8 形成可回测标的池并留档自建流程不覆盖没有版本的池子无法复现,结论不可追溯
最后一条建议:把每一步的中间结果落盘,并在文件名里带上采集日期与本库版本(例如 universe_20260929_fd240.csv)。这样当上游数据更新之后,你还能说清当初的结论是在哪一份快照上得出的——这正是这套数据最需要补上的那部分工程习惯。
FAQ

数据质量常见问题

为什么筛选结果里会有重复的股票?

因为同一家公司可能在多个交易所挂牌,本库会为每个挂牌分别建一条记录。实测全库有 65,317 行与其它行同名,涉及 19,633 个名字。要收敛,先按 exchange/mic 锁定你要的市场,再按业务规则去重;单靠名称或 only_primary_listing 都会误伤。数据以官方仓库当前版本为准。

symbol 为什么不是普通列?

它是 DataFrame 的索引,索引名就叫 symbol。所以 df["symbol"] 会报 KeyError,而 search(symbol="TSLA") 更隐蔽——它只打印一句 symbol is not a valid column.,然后返回全部 112,718 行。正确写法是 df.index 或 search(index="TSLA")。

ISIN 缺失这么严重,还能做跨市场匹配吗?

可以做辅助校验,不建议做可取匹配键。实测 isin 缺失 73.00%,仅有 9,406 个不同取值却覆盖 30,429 行;空值不参与匹配,会静默漏掉大量记录。更稳的键是「代码 + 交易所」,另外注意中国标的的 ISIN 缺失率更高(77.58%)。

market_cap 为什么不能用来算分位数?

因为它不是数字,而是 Nano/Small/Micro/Mid/Large/Mega 六档文字标签(各档后面跟一个空格与 Cap)。实测行数最多的是 Nano Cap(22,793 行),最少的是 Mega Cap(641 行),另有 32.26% 的列为空。需要真实市值数字必须另接数据源。

这份数据能替代财报或行情吗?

不能。官方在 README 里明确写出,它的目的不是提供最新的基本面或股价数据。它解决「有哪些标的」,行情与财报要交给 yfinance、AKShare、OpenBB 或 FinanceToolkit 一类工具。本站的边界页记录了 to_toolkit() 的实际调用情况。

数据多久更新一次,会不会突然变化?

数据由社区与维护者持续更新,行数会随版本变化:本站实测 Equities 112,718 行与官方 README 的统计表一致(2026-09-29 核验),但这不代表下个月还是同一个数字。写结论时请带上核验日期;以官方 PyPI 与 GitHub Release 为准。

下一步怎么走?

审计做完之后,通常有两个方向:如果是中国市场研究,先看 A 股与港股的字段口径与代码映射;如果是通用流程,先看七类数据的规模与字段覆盖,再决定接哪一个行情源。