股本因子 (cn_stock_factors_shares)

数据描述: 沪深北 A 股日频股本与市值因子:总股本、流通股、自由流通股及对应市值。

文档
数据简介

## 数据描述 沪深北 A 股日频股本与市值因子:总股本、流通股、自由流通股及对应市值。 ## 数据简介 股本因子表 `cn_stock_factors_shares` 以「交易日期 + 证券代码」为主键,把一只股票在某个交易日的**股本结构**和**市值规模**汇总到一行,共 9 个字段。 这张表回答的是「这只股票当天有多大」这类问题: - **有多少股**:总股本、流通 A 股、自由流通股、流通股合计; - **值多少钱**:真实价格(不复权),以及由四个股本口径分别乘以真实价格得到的四个市值字段。 市值是 A 股最基础也最有效的风格因子之一(规模效应),本表的 `total_shares_mv`、`a_float_shares_mv`、`free_float_shares_mv` 可直接作为市值因子使用,或作为其他因子的中性化基准、流动性加权依据。自由流通市值 `free_float_shares_mv` 剔除了限售股和大股东长期持股,更接近真实可交易的规模,通常比总市值更贴近实际的规模暴露。 ## 数据表基本信息 | 项目 | 说明 | |---|---| | 数据表名称 | `cn_stock_factors_shares` | | 数据粒度 | 日频,股票维度 | | 主键字段 | `date`、`instrument` | | 标的范围 | 沪深北全部 A 股,与 `cn_stock_instruments` 严格对齐(**包含北交所**) | | 数据开始日期 | **2010-01-01** | | 数据结束日期 | 最新交易日,每日增量更新 | | 字段数量 | 9 个 | | 单日行数 | 与 `cn_stock_instruments` 一致,2010 年约 1700 行,2026 年约 5500 行 | ## 数据开始日期 本表历史数据从 **2010-01-01** 开始,之前的日期查不到任何数据。对应到代码里就是 builder 的 `history_start_date = "2010-01-01"`。 表内数据的覆盖度很高:实测 2010-01-01 至今,全部 9 个字段的**单日最低覆盖度为 99.12%**,绝大多数交易日为 100%。唯一存在少量缺失的是 `free_float_shares` 及其派生的 `free_float_shares_mv`,集中在 2010—2013 年(上游 `cn_stock_shares` 早期未提供部分标的的自由流通股),2014 年以后基本为 100%。 ## 字段说明 ### 股本数量 | 字段名 | 类型 | 含义 | 取值说明 | |---|---|---|---| | `date` | TIMESTAMP_NS | 日期 | 主键 | | `instrument` | VARCHAR | 证券代码 | 主键,形如 `000001.SZ` | | `total_shares` | DOUBLE | 总股本 | 单位:股。取自 `cn_stock_shares` | | `a_float_shares` | DOUBLE | 流通 A 股 | 单位:股。取自 `cn_stock_shares` | | `free_float_shares` | DOUBLE | 自由流通股 | 单位:股。剔除限售股与大股东长期持股,取自 `cn_stock_shares` | | `total_float_shares` | DOUBLE | 流通股合计 | 单位:股。取自 `cn_stock_shares` | ### 价格 | 字段名 | 类型 | 含义 | 取值说明 | |---|---|---|---| | `real_price` | DOUBLE | 真实价格(不复权) | 单位:元。当日未复权收盘价;停牌日向前填充最近一个有成交的交易日收盘价 | ### 股本市值 | 字段名 | 类型 | 含义 | 取值说明 | |---|---|---|---| | `total_shares_mv` | DOUBLE | 总市值 | 单位:元。= `total_shares` × `real_price` | | `a_float_shares_mv` | DOUBLE | 流通 A 股市值 | 单位:元。= `a_float_shares` × `real_price` | | `free_float_shares_mv` | DOUBLE | 自由流通市值 | 单位:元。= `free_float_shares` × `real_price` | | `total_float_shares_mv` | DOUBLE | 流通市值合计 | 单位:元。= `total_float_shares` × `real_price` | ## 依赖的原始数据表 本表不含任何自有原始数据,9 个字段全部由下面 3 张上游表加工而来。任一张表停更或回补,本表对应字段都会跟着变化。 | 原始数据表 | 使用的字段 | 角色 | |---|---|---| | `cn_stock_instruments` | `date`、`instrument` | **基准表**,决定输出的股票池与行数 | | `cn_stock_shares` | `total_shares`、`a_float_shares`、`free_float_shares`、`total_float_shares` | 股本原始数据 | | `cn_stock_real_bar1d` | `close`、`pre_close` | 未复权日行情,用于计算 `real_price` | 另有一张表仅用于数据质量校验,不参与加工: | 数据表 | 用途 | |---|---| | `cn_stock_valuation` | 校验基准,比对 `total_market_cap` / `float_market_cap` | ## 加工逻辑说明 以 `cn_stock_instruments` 作为基准股票池,确定输出的 `(date, instrument)` 粒度,其余数据表一律 `LEFT JOIN`,因此本表的行数与 `cn_stock_instruments` 严格一致,**每个交易日都是全市场标的的因子数据**,不会多出已退市标的,也不会因停牌而丢行。 | 字段 | 来源表 | 加工方式 | |---|---|---| | 4 个股本数量字段 | `cn_stock_shares` | 直接取自源表,缺失时向前填充最近一次有效值 | | `real_price` | `cn_stock_real_bar1d` | 当日未复权 `close`;为空时向前填充最近一个有收盘价的交易日;再为空则回退到最近一次 `pre_close` | | 4 个市值字段 | — | 对应股本数量 × `real_price` | ### 为什么价格用 `cn_stock_real_bar1d` 而不是后复权表 一个直觉的做法是用后复权表算真实价格:`cn_stock_bar1d.close / adjust_factor`。在**正常交易日**这与 `cn_stock_real_bar1d.close` 逐行相等(实测 2010/2015/2020/2026 四个年度,最大相对误差 2.2e-16,即浮点精度极限)。 但**停牌日**后复权表的 `close` 为空,若用同表的 `pre_close` 兜底就会出错:`pre_close` 是按**上一交易日**的复权因子归一的,除以**当日**的复权因子,在除权除息日会得到错误的价格。实测 2015 年 5—6 月约 **2% 的记录**因此偏离估值表,最大相对误差达 **67%**。 因此本表统一使用未复权表 `cn_stock_real_bar1d` 的 `close`,停牌日则向前填充最近一个有成交日的真实收盘价——这也正是估值表的口径。 ### 缺失值处理:向前填充 + 冗余回溯 停牌、上游入库延迟都会造成当日取不到值。本表用窗口函数向前填充最近一次有效值: ```sql last_value(x IGNORE NULLS) OVER ( PARTITION BY instrument ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) ``` 窗口只看得到**当前行及之前**的数据,因此不存在前视偏差。 为了让填充能取到查询窗口之外的历史值,加工时会**向前多读取 730 个自然日**的冗余数据(builder 的 `lookback_days`),算完再把结果裁剪回目标区间。多读一段时间不影响结果,只是多一点查询开销,但能显著降低缺失:以停牌最密集的 2015 年为例, | 冗余回溯天数 | 取不到真实收盘价的记录占比 | |---|---| | 0 天 | 7.54% | | 90 天 | 1.57% | | 180 天 | 0.32% | | 365 天 | 0.10% | | **730 天(当前配置)** | **0.00%** | ### 与估值表的口径校验 加工结果与宽邦估值表 `cn_stock_valuation` 逐行比对:`total_shares_mv` 对其 `total_market_cap`、`a_float_shares_mv` 对其 `float_market_cap`,在 2015 / 2020 / 2026 三个抽样区间上**最大相对误差为 2.1e-16**(浮点精度极限),即完全一致,验证了加工口径的正确性。该校验已固化为 `tester.py` 中的 `test_market_cap_consistency`。 ## 使用注意事项 ### 停牌日的价格是上一个交易日的收盘价 停牌期间没有成交,`real_price` 会保持停牌前最后一个交易日的收盘价不变,对应的市值也随之保持不变。这与估值表口径一致,但意味着长期停牌标的的市值是「陈旧」的。若策略对此敏感,建议联用 `cn_stock_factors_security_profile.suspended` 过滤停牌标的。 ### 单位是股和元,量级很大 股本字段单位为**股**,市值字段单位为**元**。大盘股的总市值可达 1e12 量级。实际用作因子时通常取对数(`log(total_shares_mv)`)以压缩量纲、改善分布,这也是市值因子的常规处理方式。 ### 上游存在极少量股本大小关系异常 正常情况下应满足 `free_float_shares <= a_float_shares <= total_float_shares <= total_shares`。上游 `cn_stock_shares` 本身存在极少量违反该关系的记录(实测 2015 年 6—9 月有 19 只标的共 53 条记录的 `free_float_shares` 略大于 `a_float_shares`,占比约 0.02%),本表原样透传不做修正。`tester.py` 中的 `test_shares_relationship` 以 0.1% 的占比阈值监控该情况,只在大面积违例时才报警。 ### 自由流通市值的早期缺失 `free_float_shares` 及 `free_float_shares_mv` 在 2010—2013 年存在少量缺失(单日最低覆盖度 99.12%)。若回测区间覆盖这一时期且强依赖自由流通口径,建议做缺失值处理,或改用 `a_float_shares_mv`。 ## 数据访问示例 ### Python:取某段区间的全部字段 ```python import dai df = dai.query( "SELECT * FROM cn_stock_factors_shares", filters={"date": ["2025-01-01", "2025-06-30"]}, ).df() ``` ### Python:构造对数市值因子 ```python import dai sql = """ SELECT date, instrument, log(total_shares_mv) AS log_total_mv, -- 对数总市值 log(free_float_shares_mv) AS log_free_mv, -- 对数自由流通市值 free_float_shares / total_shares AS free_float_ratio -- 自由流通占比 FROM cn_stock_factors_shares WHERE total_shares_mv > 0 ORDER BY date, instrument """ df = dai.query(sql, filters={"date": ["2025-01-01", "2025-06-30"]}).df() ``` ### SQL:查询单只股票的历史股本变化 ```sql SELECT date, instrument, total_shares, a_float_shares, free_float_shares, real_price, total_shares_mv FROM cn_stock_factors_shares WHERE instrument = '000001.SZ' ORDER BY date ``` ### SQL:每日按自由流通市值筛选小市值股票池 ```sql SELECT date, instrument, free_float_shares_mv FROM cn_stock_factors_shares QUALIFY row_number() OVER (PARTITION BY date ORDER BY free_float_shares_mv ASC) <= 100 ORDER BY date, free_float_shares_mv ``` ### SQL:与证券资料表联用,剔除不可交易标的后取市值 ```sql SELECT s.date, s.instrument, s.total_shares_mv, s.free_float_shares_mv FROM cn_stock_factors_shares AS s LEFT JOIN cn_stock_factors_security_profile AS p ON s.date = p.date AND s.instrument = p.instrument WHERE p.suspended = 0 AND p.st_status = 0 AND p.list_days > 365 ``` ### SQL:统计全市场每日总市值 ```sql SELECT date, count(*) AS 标的数, sum(total_shares_mv) / 1e12 AS 总市值万亿元, sum(free_float_shares_mv) / 1e12 AS 自由流通市值万亿元 FROM cn_stock_factors_shares GROUP BY date ORDER BY date ``` ## 示例数据 展示最新一日数据的前 5 行和后 5 行 {{sample_data}}

用例
表结构
字段 字段类型 字段描述
free_float_shares_mv double 自由流通市值 = 自由流通股 x 真实价格
total_float_shares_mv double 流通市值合计 = 流通股合计 x 真实价格
date timestamp[ns] 日期
__PARTITION__ int64 -
a_float_shares double 流通 A 股. 取自 cn_stock_shares
real_price double 真实价格(不复权). 取自 cn_stock_real_bar1d 的收盘价, 停牌日向前填充最近一个交易日的收盘价
total_shares double 总股本. 取自 cn_stock_shares
instrument string 证券代码
total_shares_mv double 总市值 = 总股本 x 真实价格
a_float_shares_mv double 流通 A 股市值 = 流通 A 股 x 真实价格
free_float_shares double 自由流通股. 取自 cn_stock_shares
total_float_shares double 流通股合计. 取自 cn_stock_shares

表名:cn_stock_factors_shares

起始时间:

最近更新时间: