AI 原生量化投研平台AI-native quantitative research platform
正在加载…Loading…
页面仍在加载,可以继续等待,或重新加载。The page is still loading. You can keep waiting or reload.
部分页面资源未能加载,请重新加载。Some page resources could not load. Please reload.
设备当前处于离线状态,恢复连接后可以继续等待或重新加载。Your device is offline. Once connected, you can keep waiting or reload.
沪深北A股日频公司资料:三套行业分类归属、所属申万一级行业指数行情、可转债发行标记。
30 个字段 · 主键 date + instrument
沪深北A股日频公司资料:三套行业分类归属、所属申万一级行业指数行情、可转债发行标记。
公司资料表 cn_stock_factors_company_profile 以「交易日期 + 证券代码」为主键,把一只股票在某个交易日的行业归属和公司层面属性汇总到一行,共 30 个字段。
这张表回答的是「这只股票当天属于哪个行业、行业当天表现如何」这类问题:
行业字段是状态量,主要用于行业中性化、分组统计和行业轮动;行业指数行情是价格量,可直接用于计算行业动量、个股相对行业的超额收益;可转债标记是 0/1 事件量。
| 项目 | 说明 |
|---|---|
| 数据表名称 | cn_stock_factors_company_profile |
| 数据粒度 | 日频,股票维度 |
| 主键字段 | date、instrument |
| 标的范围 | 沪深北全部 A 股,与 cn_stock_instruments 严格对齐(包含北交所) |
| 数据开始日期 | 2010-01-01(部分字段的有效起点更晚,见「数据开始日期」一节) |
| 数据结束日期 | 最新交易日,每日增量更新 |
| 字段数量 | 30 个(2 个主键 + 18 个行业成分 + 9 个行业指数 + 1 个可转债标记) |
本表历史数据从 2010-01-01 开始,之前的日期查不到任何数据。
这个起点由上游决定:cn_stock_instruments 和 cn_stock_industry_component 的最早可用年份都是 2010 年,本表以前者为骨架逐日 LEFT JOIN 加工,因此起点与之保持一致。
需要注意的是,表内有数据不等于每个字段都有意义。下面这几组字段的有效起点晚于 2010-01-01:
| 字段 | 有效起点 | 说明 |
|---|---|---|
sw2021_level1 等申万(2021)字段 | 2010-01(全历史回溯) | 申万 2021 版分类对历史区间做了回溯划分,覆盖度较高 |
sw_level1_open 等行业指数字段 | 约 2014 年 | 2014 年之前存在旧版申万代码无法映射到现行行业指数的情况,覆盖度门槛因此放宽到 90% |
cbond_issue_factor | 可转债市场活跃之后 | 早期存续可转债极少,该字段大面积为 0,不代表数据缺失 |
因此取数时的一般建议是:整体区间不早于 2010-01-01;若用到行业指数行情,起点放到 2014 年之后更稳妥;若研究可转债相关逻辑,起点放到 2017 年之后。
| 字段名 | 类型 | 含义 | 取值说明 |
|---|---|---|---|
date | TIMESTAMP_NS | 日期 | 主键 |
instrument | VARCHAR | 证券代码 | 主键,形如 000001.SZ |
| 字段名 | 类型 | 含义 | 取值说明 |
|---|---|---|---|
sw2021_level1 | VARCHAR | 申万一级行业代码(2021) | 共 31 个,形如 801010 |
sw2021_level2 | VARCHAR | 申万二级行业代码(2021) | — |
sw2021_level3 | VARCHAR | 申万三级行业代码(2021) | — |
sw2014_level1 | VARCHAR | 申万一级行业代码(2014) | 2023 年起不再为新上市股票分配 |
sw2014_level2 | VARCHAR | 申万二级行业代码(2014) | 同上 |
sw2014_level3 | VARCHAR | 申万三级行业代码(2014) | 同上 |
cs_level1 | VARCHAR | 中信一级行业代码 | 不覆盖全部 A 股 |
cs_level2 | VARCHAR | 中信二级行业代码 | 同上 |
cs_level3 | VARCHAR | 中信三级行业代码 | 同上 |
| 字段名 | 类型 | 含义 | 取值说明 |
|---|---|---|---|
sw2021_level1_name | VARCHAR | 申万一级行业名称(2021) | 形如 农林牧渔 |
sw2021_level2_name | VARCHAR | 申万二级行业名称(2021) | — |
sw2021_level3_name | VARCHAR | 申万三级行业名称(2021) | — |
sw2014_level1_name | VARCHAR | 申万一级行业名称(2014) | — |
sw2014_level2_name | VARCHAR | 申万二级行业名称(2014) | — |
sw2014_level3_name | VARCHAR | 申万三级行业名称(2014) | — |
cs_level1_name | VARCHAR | 中信一级行业名称 | — |
cs_level2_name | VARCHAR | 中信二级行业名称 | — |
cs_level3_name | VARCHAR | 中信三级行业名称 | — |
| 字段名 | 类型 | 含义 | 取值说明 |
|---|---|---|---|
sw_level1_name | VARCHAR | 申万一级行业指数名称 | 由 sw2021_level1 映射得到 |
sw_level_index_code | VARCHAR | 申万一级行业指数代码 | 与 sw2021_level1 一一映射,形如 801010.SWI |
sw_level1_open | DOUBLE | 行业指数开盘价 | — |
sw_level1_high | DOUBLE | 行业指数最高价 | — |
sw_level1_low | DOUBLE | 行业指数最低价 | — |
sw_level1_close | DOUBLE | 行业指数收盘价 | — |
sw_level1_volume | BIGINT | 行业指数成交量 | — |
sw_level1_amount | DOUBLE | 行业指数成交额 | — |
sw_level1_turn | DOUBLE | 行业指数换手率 | — |
同一天同一行业的所有成分股,这 9 个字段的取值完全相同,它们描述的是行业而不是个股。
| 字段名 | 类型 | 含义 | 取值说明 |
|---|---|---|---|
cbond_issue_factor | INTEGER | 可转债发行标记 | 0-当日无成交的存续可转债;1-当日存在成交量大于 0 的存续可转债 |
该字段无缺失值,未命中一律补 0。
本表不含任何自有原始数据,30 个字段全部由下面 6 张上游表加工而来。任一张表停更或回补,本表对应字段都会跟着变化。
| 原始数据表 | 读取的源字段 | 产出的本表字段 | 角色 |
|---|---|---|---|
cn_stock_instruments | date、instrument | date、instrument | 基准表,决定输出的股票池与行数 |
cn_stock_industry_component | date、instrument、industry、industry_level1/2/3_code、industry_level1/2/3_name | 18 个行业成分字段 | 行业成分明细,同一股票在三套体系下各占一行 |
cn_stock_industry_index_mapper | kind、industry_level1_code、industry_level1_name、index_level1_code | sw_level1_name、sw_level_index_code | 行业代码到行业指数的静态映射,无 date 字段,当前 31 行 |
cn_stock_industry_sw_bar1d | date、instrument、open、high、low、close、volume、amount、turn | 7 个行业指数行情字段 | 申万行业指数日线行情 |
cn_cbond_bar1d | date、instrument、volume | cbond_issue_factor | 可转债日线行情,用 volume > 0 判断当日是否活跃 |
cn_cbond_basic_info | instrument、stock_code | cbond_issue_factor | 可转债到正股的对应关系 |
cn_stock_instruments ──────────────── 基准骨架 (date, instrument) │ ├── cn_stock_industry_component ──── 18 个行业成分字段 │ │ │ └── (全历史聚合) ─────── 行业名称字典, 补齐「有代码无名称」 │ ├── cn_stock_industry_index_mapper ── sw2021_level1 → 指数代码/名称 │ │ │ └── cn_stock_industry_sw_bar1d ── 7 个行业指数行情字段 │ └── cn_cbond_bar1d + cn_cbond_basic_info ───── cbond_issue_factor几点补充说明:
cn_stock_industry_component 被读取两次:一次按当前取数窗口取行业成分明细,一次按全历史聚合出「体系 + 层级 + 代码 → 名称」字典用于补名。后者结果只有一千行左右,成本可以忽略。cn_stock_industry_sw_bar1d 的关联路径是间接的:先由 cn_stock_industry_index_mapper 把 sw2021_level1 换算成指数代码,再用「日期 + 指数代码」关联行情,所以行业指数字段的可用性同时受这两张表制约。cn_cbond_basic_info 提供 stock_code,比 cn_cbond_bar1d 自带的正股字段更完整(后者近年有少量缺失),因此正股代码一律取自前者。cn_stock_instruments(行数与主键一致性)和 cn_stock_industry_index_mapper(行业代码基数上限),不产出字段。以 cn_stock_instruments 作为基准股票池,确定输出的 (date, instrument) 粒度,其余数据表一律 LEFT JOIN,因此本表的行数与 cn_stock_instruments 严格一致,不会多出已退市标的。
三个子表都不能用 PRUNE JOIN:它带分区裁剪优化,语义上接近 INNER JOIN,右表未匹配的行会被直接过滤掉,变成行缺失而不是字段补 NULL。
| 字段 | 来源表 | 加工方式 |
|---|---|---|
| 18 个行业成分字段 | cn_stock_industry_component | 按 date, instrument 分组,max(if(industry = '体系', 字段, null)) 把三套体系打平成一行 |
sw_level1_name、sw_level_index_code | cn_stock_industry_index_mapper | 按 sw2021_level1 关联,kind = 'sw',1:1 映射不会膨胀 |
| 7 个行业指数行情字段 | cn_stock_industry_sw_bar1d | 按 date, sw_level_index_code 关联 |
cbond_issue_factor | cn_cbond_bar1d、cn_cbond_basic_info | 可转债行情按 stock_code 映射到正股,要求 volume > 0,同一天多只转债聚合去重,未命中 coalesce 补 0 |
行业分类是状态量,上游 cn_stock_industry_component 并非每个交易日都有记录,直接用会出现大量假缺失。加工时做两层填充:
ffill 不做 bfill,保证不引入未来信息。(交易日 × 指数) 网格后按列填充,再还原成长表。按指数自身而不是按股票填充,避免个别指数某日缺行情时,该行业全部成分股的行业指数字段一起变成缺失值。为了让区间头部也能填充到位,加工时统一往前多取 lookback_days = 400 个自然日的数据,填充完成后再裁剪回目标区间。400 天足以覆盖一年以上的行业分类空档。
前值填充放在 pandas 侧而不是 SQL 的窗口函数里:DAI 的 date 过滤会下推到分区裁剪,与窗口函数叠加时窗口范围会被静默改写,结果不可控。
上游存在少量「有代码、无名称」的记录(申万 2014 体系约 1%)。行业名称是行业代码的静态属性,加工时用全历史聚合出的「体系 + 层级 + 代码 → 名称」字典补齐,不涉及未来信息。字典按全历史聚合而不是只看当前取数窗口,保证窗口再短也能补全。
即便做了前值填充和字典补名,本表仍有一部分字段无法做到 100% 覆盖,原因都在上游,不是加工遗漏。数据检查脚本 tester.py 因此对不同字段设置了不同的覆盖度门槛:
| 字段组 | 覆盖度门槛 | 缺失原因 |
|---|---|---|
| 申万(2021) 各级代码与名称 | 95% | 新上市股票在首次分类披露前无归属 |
| 申万(2014) 各级代码与名称 | 70% | 该体系 2023 年起不再为新上市股票分配代码,越往后缺失越多 |
| 中信各级代码与名称 | 80% | 中信体系本身不覆盖全部 A 股 |
| 9 个行业指数字段 | 90% | 2014 年之前存在旧版申万代码无法映射到现行行业指数 |
cbond_issue_factor | 100% | 该字段不允许缺失,未命中补 0 |
低于门槛会触发关键测试失败,增量任务会直接报错而不是把脏数据写进表里。
申万(2021) 覆盖度最高且仍在维护,做行业中性化时建议默认用 sw2021_level1。申万(2014) 只在需要与旧研究口径对齐时使用,注意它 2023 年之后对新股缺失严重。中信体系覆盖面窄,适合做交叉验证而不是主口径。
行业字段经过按证券的前值填充,某一天的取值可能来自更早的一次分类披露,而不是当天上游真的有记录。这对回测是安全的(只用了过去信息),但如果你要统计「行业分类调整发生在哪一天」,本表看到的调整日期会晚于实际生效日,应回原始表 cn_stock_industry_component 确认。
sw_level1_open 等 9 个字段描述的是行业指数而不是个股,同一天同一行业的成分股取值完全相同。做截面回归时直接把它们当个股因子会引入强共线性,通常的用法是先算行业收益,再取个股相对行业的超额。
行业指数行情也经过按指数序列的前值填充,指数停更日会沿用上一交易日的价格,此时 sw_level1_volume 同样是沿用值而不是 0。
cbond_issue_factor = 1 表示「当日有成交量大于 0 的存续可转债」,不是「当日发行可转债」。它反映的是转债处于活跃交易状态,成交量为 0 的停牌类快照被剔除。若要研究发行事件本身,应回 cn_cbond_basic_info 取发行日。
历史数据按 2 年一批(builder 的 history_step = 2)从 2010 年逐批加工写入,批次之间按右开区间切分,不会在边界日重复。每批约 260 万行,步长调大会显著吃内存,因为前值填充在 pandas 侧完成。
import dai
df = dai.query( "SELECT * FROM cn_stock_factors_company_profile", filters={"date": ["2025-01-01", "2025-06-30"]},).df()import dai
sql = """SELECT date, instrument, sw2021_level1, sw2021_level1_nameFROM cn_stock_factors_company_profileWHERE sw2021_level1 IS NOT NULLORDER BY date, instrument"""df = dai.query(sql, filters={"date": ["2025-01-01", "2025-06-30"]}).df()SELECT p.date, p.instrument, p.sw2021_level1_name, b.close / lag(b.close) OVER (PARTITION BY p.instrument ORDER BY p.date) - 1 AS stock_ret, p.sw_level1_close / lag(p.sw_level1_close) OVER (PARTITION BY p.sw_level_index_code ORDER BY p.date) - 1 AS industry_retFROM cn_stock_factors_company_profile AS pLEFT JOIN cn_stock_bar1d AS b ON p.date = b.date AND p.instrument = b.instrumentWHERE p.sw_level_index_code IS NOT NULLSELECT date, sw2021_level1_name, count(DISTINCT instrument) AS stock_numFROM cn_stock_factors_company_profileWHERE sw2021_level1_name IS NOT NULLGROUP BY date, sw2021_level1_nameORDER BY date, stock_num DESCSELECT date, instrument, sw2021_level1_nameFROM cn_stock_factors_company_profileWHERE cbond_issue_factor = 1ORDER BY date, instrument展示最新一日数据的前 5 行和后 5 行
{{sample_data}}
SELECT date, instrument, sw2021_level1, sw2021_level2, sw2021_level3, sw2014_level1, sw2014_level2 FROM cn_stock_factors_company_profile WHERE date >= '2026-10-06' ORDER BY date LIMIT 100
SELECT date, instrument, sw2021_level1, sw2021_level2, sw2021_level3, sw2014_level1, sw2014_level2 FROM cn_stock_factors_company_profile WHERE date >= '2026-10-06' ORDER BY date LIMIT 100