跑通的样子
打印出 (行数, 列数) 且行数明显大于 0;再执行 equities.head(),能看到名称与代码这类元数据列。看到这两样,说明本库已经能正常取数。
FinanceDatabase / First Run
安装完成后,用 Equities().select() 跑通一次查询。它无需自备行情数据源即可返回证券清单,帮你先看清这个库的返回格式与能力边界。
事实核验卡(核验日期 2026-09-29)
以上数字来自本站 2026-09-29 在 Windows + Python 3.11.9 + financedatabase 2.4.0 下的真实运行输出,不是从文章里转抄的;数据文件由上游持续更新,行数会变,以官方 PyPI 与 GitHub Release 为准。采集时 GitHub star 约 9,374(2026-09-29)。
以下为官方 README 快速开始的示意代码(2026-09 核验),可直接复制运行。
import financedatabase as fd # 展示全部股票(返回 pandas DataFrame) equities = fd.Equities().select() print(equities.shape) # 另外六类证券同理 etfs = fd.ETFs().select() funds = fd.Funds().select() indices = fd.Indices().select() currencies = fd.Currencies().select() cryptos = fd.Cryptos().select() moneymarkets = fd.Moneymarkets().select()
(行数, 列数) 的元组——行数取决于上游数据,列数对应元数据字段。只要不抛异常,就说明安装、导入、联网三步都通了。打印出 (行数, 列数) 且行数明显大于 0;再执行 equities.head(),能看到名称与代码这类元数据列。看到这两样,说明本库已经能正常取数。
首次调用要联网读取上游证券清单,等待时间取决于网络与上游响应速度。后续调用通常更快,具体缓存与刷新策略以官方实现为准。
抛 ModuleNotFoundError 多是装到了别的解释器;返回 0 行则多是筛选条件与上游取值不匹配、或上游暂时不可达。两种情况的排查方向完全不同。
把 FinanceDatabase 的首次查询拆成五步,每一步都给出可复制的命令与预期输出,方便判断卡在哪一步。五步的顺序是特意的:先确认环境,再看数据规模,最后才取代码列,出错时能直接定位到某一层。
命令行执行 python -c "import financedatabase as fd; print('ok')"。
预期输出:ok。若报 ModuleNotFoundError,说明当前 python 与你装包时用的不是同一个解释器,先解决环境问题再往下走。
在脚本里执行 fd.Equities().select()、fd.ETFs().select()、fd.Funds().select() 等七类查询。
预期输出:每类各返回一个 pandas DataFrame;某一类为空不代表其它类也空,逐类确认。
执行 print(equities.shape) 与 print(list(equities.columns))。
预期输出:一个形如 (行数, 列数) 的元组,以及元数据列名列表。列名以实际返回为准,这一步决定你后面能筛什么。
执行 print(equities.head())。
预期输出:默认前 5 行,带行索引与各元数据列。注意 head() 只是预览,不等于全部数据。
执行 print(equities["symbol"].head().tolist())。
预期输出:一个证券代码列表。这些代码就是自建流程里交给行情源的输入;本库本身不提供价格。
Equities().select() 返回的 DataFrame 常见字段如下,第三、四列说明它到底能用来做什么(字段以实际返回为准)。
| 字段 | 含义 | 典型用法 | 注意点 |
|---|---|---|---|
name | 证券名称 | 做本地关键词匹配、人工核对 | 不同来源对同一证券的命名写法可能不一致 |
symbol | 证券代码 | 交给行情源或回测框架取数 | 同名代码可能存在于不同市场,需结合国家字段一起看 |
country | 所属国家/市场 | 按市场范围筛选、消歧代码 | 取值口径以数据源为准,混用中英文会得到空结果 |
sector | 所属板块 | 行业轮动、板块内选股 | 板块划分由上游定义,跨源对不上是常见现象 |
industry | 所属行业 | 细分行业筛选 | 比板块更细,取值更容易出现拼写不一致 |
market_cap | 市值规模档位 | 按大/中/小盘初筛 | 档位口径与更新时点依赖上游,不能当实时市值 |
currency | 计价货币 | 跨市场对比前的口径对齐 | 只表示计价币种,不含汇率换算能力 |
跑通无参数 select() 后,用带条件的 select() 按维度缩小范围;按名称找单个标的则用 search()。
# 按维度筛选:美国 + 科技板块 us_tech = fd.Equities().select(country="United States", sector="Technology") print(us_tech[["name", "symbol", "sector"]].head()) # 按名称模糊搜索单个标的 apple = fd.Equities().search(name="Apple")
| 参数 | 取值示例 | 作用 | 什么时候用它 |
|---|---|---|---|
country | "United States" | 按市场/国家收窄范围 | 只想看某一市场的标的时 |
sector | "Technology" | 按板块收窄范围 | 做板块内横向对比时 |
industry | "Software - Infrastructure" | 按细分行业收窄范围 | 板块内还要再细分时 |
market_cap | "Large Cap" | 按市值档位收窄范围 | 先排除小盘、只看大市值时 |
| 多条件组合 | 两个以上参数同时传 | 交集筛选 | 条件越多越可能返回空表,建议逐条加 |
search() | "Apple" | 按名称模糊搜索 | 记得名字但不记得代码时 |
database | "Equities" | 限定搜索的证券类别 | 同名标的跨类别时用来消歧 |
这些坑不会给你任何报错提示,只会让你拿到一个看起来正常、其实用错的结果。下面每一条都给出「怎么自己确认」。
| 你可能以为 | 实际发生 | 怎么自己确认 |
|---|---|---|
| 返回的表里有价格,可以直接看走势 | 只有证券身份与分类字段,没有行情列 | 打印 list(df.columns),确认里面没有开高低收与成交量 |
| 筛选条件写错了会报错提醒我 | 取值不匹配时静默返回空表,不抛异常 | 先打印 df.shape,行数为 0 就要回头核对取值 |
| 一个代码在全世界只有一条记录 | 不同市场可能存在同名代码,返回多行 | 按 symbol 过滤后看命中行数,多行时结合国家字段消歧 |
market_cap 是当前实时市值 | 它是上游给的档位/规模信息,更新时点由上游决定 | 把它当「分类标签」用;需要实时数值就交给行情/财务数据源 |
head() 显示的就是全部数据 | head() 只默认显示前 5 行 | 用 shape 或 len(df) 判断真实行数 |
| 行业名可以写成中文或自己想当然的英文 | 取值必须与上游一致,否则匹配不到 | 对 industry 列取不重复值看取值范围,再复制粘贴使用 |
| DataFrame 的行号就是 0、1、2… | 索引可能沿用了上游的原始索引 | 需要连续序号时显式调用 reset_index(drop=True) |
| 空值会被自动补上或跳过 | 缺失字段会原样保留,不会替你补 | 用「某列缺失比例」先看一眼再决定能不能用 |
首跑最常见的困惑是「结果为空」。空表通常不是安装失败,按下面顺序逐条排除比重新装一遍有效得多。
执行 print(type(result))。
预期输出:<class 'pandas.core.frame.DataFrame'>。是 DataFrame 就说明调用本身没问题,问题在条件或数据。
执行 print(result.shape)。
预期输出:形如 (0, 列数) 说明没有匹配到任何证券;列数正常说明结构完好。
先对其它列取不重复值,例如 print(equities["country"].dropna().unique()[:20])。
预期输出:一批取值样例。把筛选条件改成样例里的写法,大小写与空格都要一致。
先只留 country 跑一次,再叠加 sector。
预期输出:条件越少越可能有结果。哪一步从有结果变成 0 行,问题就出在那个条件上。
换一次宽条件查询,例如直接跑 fd.Equities().select()。
预期输出:宽条件也返回 0 行,通常说明本次没能拿到上游数据,而不是条件写错。
再试 fd.ETFs().select() 之类的另一个类别。
预期输出:只有某一类为空,多半是该类别上游侧的问题;全为空则优先查网络与代理。
| 现象 | 更可能的判断 | 下一步做什么 |
|---|---|---|
抛 ModuleNotFoundError | 环境问题,不是数据问题 | 确认解释器与装包位置一致 |
| 返回 0 行但列名正常 | 条件取值不匹配,或上游本次无数据 | 按上面第 3–5 步二分排查 |
| 某一类全空、其它类正常 | 该类别上游侧问题 | 换个时间段再试,或换类别先继续 |
| 所有类别都为空 | 网络/代理导致取不到上游数据 | 先确认联网与代理设置,再重试 |
| 行数正常但某几列大量空值 | 该字段在上游侧缺失 | 用前先看缺失比例,必要时降级使用 |
| 同一查询两次结果行数不同 | 上游数据在更新 | 把行数波动当正常现象,别写死预期值 |
一次查询跑通只证明「能拿到证券清单」。真正做研究,还要看你缺的是行情、财务指标还是回测框架。
| 你的目标 | 还需要接什么 | 能拿到 | 拿不到 | 适用场景 | 注意点 |
|---|---|---|---|---|---|
| 看某只标的的价格走势 | 第三方行情数据源 | 开高低收、成交量 | 证券身份与分类要先自己对齐 | 技术面研究、画图 | 代码写法与市场前缀各源不同,需逐一验证 |
| 算财务比率与指标 | 财务数据/指标类工具(如同作者的财务工具链) | 比率、报表口径指标 | 不负责证券清单,需与本库配合 | 基本面研究 | 口径与更新时点依赖上游,跨源对比前先对齐 |
| 研究 A 股标的 | A 股方向的接口类库 | 国内市场的标的与数据 | 与本库的市场覆盖不一致,代码不通用 | A 股选股与复盘 | 市场范围与字段口径都不同,不要混用同一套条件 |
| 做策略历史回测 | 回测框架 + 行情数据 | 绩效与风险指标 | 本库只提供清单,不参与撮合与计算 | 策略验证 | 先把清单转成回测框架要求的标的格式 |
| 按规则筛出一批候选标的 | 本库的筛选能力通常就够 | 符合维度条件的清单 | 不含财务与行情条件 | 投研起步阶段的清单收敛 | 条件越多越容易空表,建议逐条加并记录命中数 |
| 不想搭环境,先问清楚研究问题 | 本机已核验的金融数据技能路线 | 对话式得到结构化结果 | 市场覆盖与数据源随技能而异 | 快速验证想法、先看结论 | 结果仅供参考,数据源与前置条件以实际账号为准 |
逐条对照下面七项,全部通过才说明「首次运行真的成功了」,而不只是「没报错」。
| 检查项 | 通过的样子 | 不通过怎么办 |
|---|---|---|
| 解释器与安装位置一致 | pip -V 与 python -V 指向同一套环境 | 用虚拟环境重新安装,避免装到系统 Python |
| 导入无异常 | import financedatabase as fd 无输出无报错 | 确认包名拼写与安装环境 |
| 调用返回 DataFrame | type(result) 是 DataFrame | 检查调用写法是否与官方 README 一致 |
| 行数大于 0 | result.shape 首项不为 0 | 按空表排查顺序二分条件 |
| 列名符合预期 | 能看到名称、代码、国家等元数据列 | 以实际列名为准调整后续代码,别硬编码 |
| 明确行情要另接 | 知道本库不会返回价格 | 按上一节三条路选一个行情/财务/回测来源 |
| 筛选条件可复现 | 同样的条件两次跑出相同量级结果 | 行数小幅波动属正常,别把行数写死进断言 |
把前面五步合成一个文件,之后每次研究都从这个文件改起,比在命令行里逐句试更省事,条件也更容易复现。
import financedatabase as fd
# 第 1 段:先拿到全量清单,确认环境与网络都通
equities = fd.Equities().select()
print("股票清单行数:", len(equities))
# 第 2 段:再按维度收窄到目标范围
us_tech = fd.Equities().select(country="United States", sector="Technology")
print("美国科技板块命中:", len(us_tech))
# 第 3 段:预览并导出代码列,交给后续环节
print(us_tech[["name", "symbol"]].head())
| 脚本片段 | 这一段的作用 | 预期输出 | 想改动时怎么改 | 注意点 |
|---|---|---|---|---|
| 第 1 段:导入与全量取数 | 一次性确认环境、网络、上游三者都通 | 打印出清单的行数 | 换成 ETF、基金、指数等其它类别同样写法 | 行数由上游决定,不要写死在断言里 |
| 第 2 段:按维度收窄 | 把范围缩到你的研究口径 | 打印出命中数量 | 依次叠加国家、板块、行业、市值档位 | 条件越多越可能返回空表,建议逐条加 |
| 第 3 段:预览与取代码列 | 把清单转成后续环节能用的输入 | 打印名称与代码两列 | 改成导出 CSV 留档,方便复查 | 导出的只是清单,不含任何行情数据 |
len() 打印行数 | 判断本次是否真的命中 | 一个整数 | 换成 df.shape 一次看行与列 | 行数会随上游更新而小幅变动 |
head() 预览 | 核对列名与取值写法,避免条件写错 | 默认前 5 行 | 换成 tail() 看结尾几行 | 预览不等于全量,判断数量要用行数 |
| 变量名带条件含义 | 让变量名与筛选条件对应,便于日后复查 | 无输出 | 改成你实际的条件含义 | 变量名与条件脱节时最容易记错口径 |
这四件事在正式运行前想清楚,能省掉后面反复返工的时间;想不清楚也不影响跑通,但会影响你后面接什么工具。
| 先想清楚的问题 | 为什么重要 | 怎么确认 | 常见误判 |
|---|---|---|---|
| 我只要清单,还是要价格 | 决定后面还要接什么工具 | 看返回字段里有没有价格列 | 以为清单自带行情,跑到一半才发现缺价格 |
| 研究范围是单市场还是多市场 | 影响筛选条件写法与代码消歧方式 | 先跑全量,看国家字段都有哪些取值 | 把不同市场的代码混成一套,后续取数对不上 |
| 数据要落盘还是每次现取 | 影响运行耗时与结果可复现性 | 看两次运行的行数是不是同一量级 | 以为行数永远一致,把波动当成漏装数据 |
| 后续接哪个行情或财务来源 | 决定代码格式怎么对接 | 先取一个标的试通整条链路 | 清单能拼上,取数环节才发现代码写法不通用 |
| 要不要固定依赖版本 | 版本升级可能改变调用行为 | 以 PyPI 页面上的版本说明为准 | 以为装最新版一定更好,升级后结果口径变了 |
| 结果要不要让别人复核 | 决定是否把条件与时间一并记录 | 把筛选条件写进脚本注释 | 只记得结论,忘了当时用的条件 |
| 是不是要研究 A 股 | 市场范围不通用,条件与代码都要换 | 先确认本库的市场覆盖范围 | 拿同一套条件直接去查 A 股,得到空表 |
下面是 2026-09-29 在本机 venv(Python 3.11.9 + financedatabase 2.4.0)跑出的真实输出,直接抄这一段就能复现。注意 2.4.0 里没有 show_equities() 这类函数,类要先实例化,再调用实例方法。
import financedatabase as fd equities = fd.Equities() # 这一步会先从 GitHub 取 equities.bz2(实测 13.8 秒) print(type(equities).__name__) # Equities print(equities.data.shape) # (112718, 21) df = equities.select() # 无参数 = 取该类全量,默认排除退市 print(df.shape) # (102314, 21) print(type(df).__name__) # FinanceFrame cn = equities.select(country="China") print(cn.shape) # (6775, 21) print(cn.index[:3].tolist()) # ['000002.SZ', '000004.SZ', '000005.SZ'] print(cn.columns[:6].tolist()) # ['name', 'summary', 'currency', 'sector', 'industry_group', 'industry']
| 你敲的命令 | 实测输出 | 该怎么读 |
|---|---|---|
type(equities).__name__ | Equities | 拿到的是资产类对象,数据挂在 .data 上 |
equities.data.shape | (112718, 21) | 全量含退市在内共 112,718 行、21 列 |
equities.select().shape | (102314, 21) | 默认排除 10,404 行退市标的,这是「已在市」的口径 |
type(df).__name__ | FinanceFrame | 比普通 DataFrame 多一个 to_toolkit() 方法 |
df.head(3) | 普通 DataFrame | 切片会把 FinanceFrame 降级,to_toolkit() 会报 AttributeError |
equities.select(country="China") | (6775, 21) | 中国的 6,775 个在市级标的,代码形如 000002.SZ |
data.shape 打印出 (112718, 21) 这个量级,就说明环境与网络都通了。数字与官方 README 的统计表一致;若明显偏小,先看数据文件是否被中途截断,而不是怀疑筛选条件。这三条在官方 README 的示例里都看不出来,但实际敲一遍就会撞上。
| 你以为 | 实测是什么 | 怎么绕 |
|---|---|---|
有个 fd.show_equities() 直接返回全量 | 2.4.0 里 没有这个函数,dir(fd) 里以 show_ 开头的只有 show_options(顶层函数,用来列取值) | 写 fd.Equities().select() |
| 初始化一次,之后很快 | 每次 fd.Equities() 都会重新下载 14.9 MB 的 .bz2,包内没有任何缓存 | 把对象存进变量复用;或把数据文件放进 site-packages/compression/ |
筛选结果可以直接传给 to_toolkit() | .head() / .iloc[] / 布尔切片返回普通 DataFrame,方法会丢:AttributeError: 'DataFrame' object has no attribute 'to_toolkit' | 先切片确认,再用整段 select() 结果调 to_toolkit();或用 FinanceFrame(...) 重新包装 |
country 是公司所属国家/地区,不是上市地。实测 country="China" 的 6,775 行分布在 34 个交易所(含纳斯达克、纽交所、伦敦、法兰克福),所以「筛一个国家」和「筛一个市场」是两件事。返回股票清单的 pandas DataFrame,含名称、代码、国家、板块、行业、市值档位、计价货币这类元数据列。具体列名与行数以实际返回为准,以官方 README / PyPI 页面为准。
不能。这个库的定位是证券清单与元数据,不提供开高低收与成交量;价格要另接行情数据源,字段口径以各自官方文档为准。
首次调用需要联网读取上游证券清单,耗时取决于网络与上游响应。是否存在本地缓存、缓存多久刷新,以官方实现为准。
通常不是。空表更常见的原因是筛选条件取值与上游不一致,或本次没取到上游数据;可按本页「返回 0 行的排查顺序」逐条排除。以官方说明为准。
本库的数据覆盖以海外上游数据源为主,与 A 股的市场范围不一致,不要直接套用同一套筛选条件。A 股方向可以走本机已核验的 A 股数据技能路线(如 akshare / tushare 方向的接口库),覆盖范围以各自官方说明为准。
想按国家、板块、行业、市值档位这类维度收窄范围用 select();记得名称但不记得代码、想按名称模糊找单个标的用 search()。参数取值与返回字段以官方 README 为准。