这篇是 Datafeed 模块的实战手册,讲解交易日生成、可交易池过滤、行情/因子查询的常用 API 与语义边界。学完这篇,你能在任何需要自定义数据查询的场景里快速写出正确的代码。
导言
Datafeed 是 Betalens 通往 PostgreSQL 的唯一大门。所有数据——无论是股价、股息率、换手率、行业分类——都要通过 Datafeed 的 API 查询。理解这些 API,能让你在框架提供的高层函数(pre_query_characteristic_data、single_characteristic)之外,也能在需要时直接写自定义查询。
配置与连接
Datafeed 的数据库连接遵循以下优先级(高 → 低):
- 运行时传入的
db_config BETALENS_DB_*环境变量BETALENS_CONFIG指定的配置文件~/.config/betalens/config.jsonbetalens/datafeed/config.local.json
通常只需要配置 config.local.json(见 03 篇),不需要改其他地方:
1 | from betalens.datafeed.config import get_config |
交易日生成:get_absolute_trade_days
这是使用频率最高的函数之一,用于生成调仓日序列。
1 | from betalens.datafeed import get_absolute_trade_days, trade_days_offset |
period 支持的取值:
| 值 | 含义 | 典型用法 |
|---|---|---|
D |
每日交易日 | 日频策略 |
W |
每周(最后交易日) | 周频调仓 |
M |
每月(最后交易日) | 月频调仓 |
Q |
每季度末 | 季频因子(如财务数据) |
S |
每半年末 | 半年调仓 |
Y |
每年(4月30日或最近交易日) | 对齐年报披露 |
注意:
get_absolute_trade_days只从本地的trade_calendar_day表读取,不访问任何在线服务。第一次使用前需要通过betalens_db_manager导入交易日历。
可交易池:get_tradable_pool
这个函数基于 trade_status(交易状态)过滤,返回哪些股票在哪些日期是”可以正常买卖的”。
1 | from betalens.factor.factor import get_tradable_pool |
get_tradable_pool 返回两个对象:
date_ranges:日期 × 股票代码矩阵,标记每天哪些股票可交易。code_ranges:哪些股票在整个回测区间内有任何可交易日。
这两个对象会传给 pre_query_characteristic_data 的 date_ranges 和 code_ranges 参数,确保查询时只取可交易证券的数据。
默认行为(include_abnormal=False):只保留”正常交易”的证券,即 trade_status = 1 的证券。停牌(0)和未上市(-1)的证券被排除。
include_abnormal=True:包含退市/停牌证券,主要用于事后分析或特殊场景(如想看停牌期间的因子值变化)。日常因子回测不要开这个选项。
1 | # 用于事后分析场景(看停牌证券的历史因子值) |
Datafeed 查询:行情
1 | from betalens.datafeed import Datafeed |
常用表名映射:
| 表名 | 内容 | 常见 metric |
|---|---|---|
daily_market |
A股/港股日行情 | 收盘价(元)、成交量(股)、成交额(元) |
daily_index |
指数日行情 | 收盘价(元)(用于 benchmark) |
daily_fund |
基金日行情 | 收盘价(元)、净值(元) |
daily_bond |
债券日行情 | 收盘价(元) |
fundamentals |
财务因子 | 股息率(报告期)、ROE(报告期)、市净率 |
industry |
行业分类 | 行业代码、行业名称 |
PIT 查询:query_nearest_before / query_nearest_after
这是做因子研究时最重要的查询方式——在某观测时点,找到最近一个可用的数据点。
1 | data = Datafeed("fundamentals") |
返回结果大概是:
| code | query_date | trade_date | value |
|---|---|---|---|
| 000001.SZ | 2024-04-30 | 2024-04-29 | 3.24 |
| 000001.SZ | 2024-08-31 | 2024-04-29 | 3.24 |
| 000002.SZ | 2024-04-30 | 2024-04-29 | 2.81 |
| 000002.SZ | 2024-08-31 | 2024-08-30 | 2.95 |
query_date是你做决策的日期。trade_date是实际找到的数据的披露日(满足trade_date <= query_date且value_end_date <= query_date)。time_tolerance如果设小了(比如24*30),超过 30 天没找到数据就返回空。
query_nearest_after:找某日期之后最近的数据,常用于分红送转等”未来已知”事件的处理(不常用,了解即可)。
行业查询
1 | from betalens.datafeed import query_industry, get_industry_members |
开发者侧:为什么要用 Datafeed 而不直接写 SQL
有几个实际原因:
- 统一连接管理:不需要每次查询都写连接池初始化代码。
- PIT 语义封装:不用自己写
value_end_date比较逻辑。 - metric 映射:用中文 metric 名(如
"收盘价(元)")查询,Datafeed 内部自动做metric_alias映射。 - 懒加载/批量优化:内部有批量查询优化,减少数据库往返次数。
如果你确实需要直接写 SQL,Datafeed 对象有一个 .conn 属性可以访问原始连接,但不推荐在研究脚本里直接写 SQL——除非你在开发 Datafeed 本身的功能。
常见错误
1. 交易日历为空
1 | days = get_absolute_trade_days("2020-01-01", "2024-12-31", "Y") |
原因:本地 trade_calendar_day 表没有数据。用 betalens_db_manager 导入日历数据:
1 | python -m betalens_db_manager import-calendar |
2. metric 名写错
1 | # 报错:metric not found |
可以用 Datafeed 的 get_metric_names() 列出所有可用 metric。
3. 忘记 data.close()
Datafeed 使用连接池,查询完记得关闭,避免连接泄漏:
1 | data = Datafeed("daily_market") |
延伸阅读
- Betalens 新手系列 · 05:数据库架构全图——fact/dim 架构与 PIT 原理。
- Betalens 新手系列 · 07:数据治理工具 betalens_db_manager——数据导入详解。
docs/guide/datafeed.rst——官方 Datafeed 文档。