119 KiB
A 股多数据源融合层设计
日期:2026-07-21 创建 | 基于 brainstorming + 4 源全能力调查(akshare / baostock / miniQMT / csindex) 状态:活文档(唯一数据设计文档) —— 2026-09-02 起用户钦定:本文件是数据架构唯一权威设计, 每次数据架构变更必须同批更新到最新状态;演进采用「日期节追加,新节覆盖旧节相关决策」模式。 最后更新:2026-09-02(A 档截面数据域全量上生产,§15;使用层 provider 接口,§16;首夜巡查修正,§17)
1. 背景与痛点
多数据源(akshare / baostock / xtdata / miniQMT)各不全,整合时格式有偏差:
- symbol 格式:
600519vssh.600000vs600519.SH - exchange 命名:
SSEvsSH - 复权口径:raw vs qfq
- volume 单位:xtdata÷100 vs 原值
- 价格源间漂移:同股同日不同源 close 微差
用户约束(明确)
- ❌ 不要查询时网络源切换(源变化/限流不可控)
- ✅ VPS 本地一份稳定数据,日常只读本地
- ✅ 网络源只用于「采集时拼凑完整本地」
- ✅ 使用层无感(本地缺才网络兜底,罕见)
- ✅ 优先 miniQMT + baostock
2. 设计原则(三层)
| 层 | 职责 | 原则 |
|---|---|---|
| 采集层 | 多网络源 → 拼凑完整本地 | 各源 adapter + 定时 schtask;源不可控隔离在采集(失败重试,不影响使用层) |
| 数据层 | 整理(重叠定权威,特定保留) | 不强合物理表(vnpy 回归风险);每类定权威源(优先 baostock+miniqmt) |
| 使用层 | LocalUnifiedProvider 逻辑融合 |
读权威表 + 归一化 + 本地缺网络兜底;策略无感 |
核心:网络源不稳的风险只影响采集层(定时跑、可重试),使用层永远读本地 —— 风险隔离。
3. 数据源全能力盘点(综合调查)
3.1 已下(稳定源)
| 表/源 | 内容 | 范围 | 增量 |
|---|---|---|---|
dbbardata |
日线+5m/15m(xtdata/akshare/baostock) | 日线2010+/分钟2020+ | ✅ 16:30 |
daily_baostock_full |
日线 18 字段(pe/pb/turn/pctChg) | 1990–2026 | 待 #7 |
bs_index_constituent |
成份股 300/500/50(含退市) | 2006+ | 待增量 |
bs_adjust_factor |
复权因子 | 全史 | 待增量 |
| akshare 静态表 | 三表/估值/北向/龙虎榜/融资融券/股本/解禁/业绩预告 | - | 部分增量 |
| miniQMT xtdata | 日线+5m/15m 全周期(实时 T+0,零漂移) | 16年 | 按需 |
| miniQMT PershareIndex | ROE/毛利率/EPS | 季频 | 按需 |
| parquet | data/raw、daily_baostock、minute_5/15、static/index_const、qfq+raw ETF(5只) | - | 部分 |
3.2 重叠(5 处)
- 日线 OHLCV:dbbardata ∩ daily_baostock_full ∩ parquet raw(三处)
- 估值 PE/PB:akshare valuation ∩ daily_baostock_full(peTTM/pbMRQ)
- 15min:dbbardata ∩ parquet minute_15
- 基本面:akshare 三表 ∩ miniQMT PershareIndex ∩ baostock 季频
- 成份股:bs_index_constituent ∩ parquet index_const
3.3 新发现缺口(本次调查)
- ETF 全市场日线(现仅 5 只,策略资产类别缺口)
- 深证/中证历史成份股(治幸存者偏差,当前仅最新快照 = latent bug)
- 退市股 K 线(baostock 有,从未提取;反幸存者偏差核心)
- 申万行业 SW1/2/3 + 历史变动
- 龙虎榜 / 合约信息(涨跌停/ST)/ 可转债 / 研报一致预期 / 股东户数 / 除权明细
4. 权威源地图(数据层整理)
| 数据类 | 权威源 | 物理存储 | 重叠处理 / 备注 |
|---|---|---|---|
| 日线 OHLCV(个股,历史) | baostock | daily_baostock_full |
dbbardata 日线保留(vnpy 回测硬依赖);parquet raw 冗余 |
| 日线(盘中实时) | miniQMT xtdata | xtdata API | 独有(T+0 实时) |
| 日线 ETF(全市场) | miniQMT xtdata | parquet/dbbardata | universe 加 沪深ETF∪沪深基金,dividend_type='front' 自动复权 |
| 估值 PE/PB/turn | baostock | daily_baostock_full |
akshare valuation 兜底/校验 |
| 基本面指标 ROE/毛利率 | miniQMT PershareIndex | miniQMT API | akshare 三表补原始报表 |
| 基本面三表(原始) | akshare | akshare 表 | miniQMT Balance/Income/CashFlow + baostock 季频交叉 |
| 15min | baostock | dbbardata |
parquet minute_15 冗余可清 |
| 成份股 300/500/50(含退市) | baostock | bs_index_constituent |
query_*_stocks(date) 任意时点 |
| 成份股 深证/国证(399xxx) | akshare(国证源) | parquet | index_detail_hist_cni + index_detail_hist_adjust_cni |
| 成份股 中证1000/2000(000852/932000) | 新浪 | parquet | vII_HistoryComponent(gb2312,含退市) |
| 退市股 K 线 | baostock | daily_baostock_full |
query_all_stock status=0 + query_stock_basic 退市日期 + 逐只 K |
| 复权因子 | baostock | bs_adjust_factor |
独有 |
| 申万行业 SW1/2/3 | miniQMT xtdata | parquet | get_sector_list + get_stock_list_in_sector;akshare 补历史变动 |
| 龙虎榜 | miniQMT xtdata | parquet | get_longhubang;akshare 兜底 |
| 合约信息(涨跌停/ST/上市日) | miniQMT xtdata | parquet | get_instrument_detail 全 A 一入库 |
| 可转债 | akshare | parquet | bond_zh_hs_cov_min + bond_cb_adj_logs_jsl(转股价) |
| 研报/一致预期 EPS | akshare | parquet | stock_research_info_em |
| 股东户数 | miniQMT/akshare | parquet | Holdernum 表 / stock_zh_a_gdhs_detail |
| 除权明细 | miniQMT xtdata | parquet | get_divid_factors |
| 龙虎榜/北向/融资融券/解禁 | akshare | akshare 表 | 独有(保留) |
5. 归一化规则
| 维度 | 统一标准 | 源映射 |
|---|---|---|
| symbol | 600519.SH(数字+交易所后缀) |
baostock sh.600000→600000.SH;dbbardata 纯数字+exchange 字段 |
| exchange | SH/SZ |
dbbardata SSE/SZSE → SH/SZ |
| 日期 | ISO 2026-07-21 |
各源统一 |
| 复权 | raw 存储 + factor 字段(QLib:factor=adj/raw) |
查询时按需 qfq($close/$factor);治 raw/qfq 冲突 |
| volume | 原值(股) | xtdata ÷100 还原 |
| 停牌 | OHLCV 全 NaN | QLib 约定 |
| 溯源 | source 字段 |
每行标来源 + 主源/补丁标记 |
6. 使用层:LocalUnifiedProvider(逻辑融合)
接口:
get_daily(symbol, start, end, adjust='raw') # 个股日线
get_etf_daily(symbol, ...) # ETF 日线
get_fundamentals(symbol, fields, date) # 财务指标/三表
get_constituent(index, date) # 成份股(含历史,治幸存者偏差)
get_industry(symbol, date) # 申万行业(含历史变动)
get_longhubang(symbol, start, end) # 龙虎榜
get_instrument_detail(symbol) # 涨跌停/ST
get_delisted_kline(...) # 退市股 K 线
职责:
- 按数据类路由到权威表(§4 地图)
- 归一化(§5 规则):源格式 → 统一 vt_symbol/exchange/复权/单位
- 本地缺 →
network_fetcher透明兜底(罕见,如新股未及采集)→ 写本地 → 返回 source字段溯源;可选多源交叉校验- 使用层 API 不变,不知数据来自哪个源
实现:扩展现有 sanguo_portfolio/providers/ 的 DataProvider 接口(BaostockProvider/LocalParquetProvider 已有)。
7. 增量 schtask 清单
| schtask | 数据 | 源 | 时间 |
|---|---|---|---|
sanguo-daily-update(已有) |
日线+分钟→dbbardata | xtdata | 16:30 |
sanguo-bs-daily-increment(#7 待建) |
日线→daily_baostock_full | baostock | 17:00 |
sanguo-etf-daily-increment(新) |
ETF 全市场日线 | xtdata(universe 沪深ETF) | 17:30 |
sanguo-akshare-static-increment(新) |
估值/龙虎榜/三表/北向 | akshare | 18:00 |
sanguo-index-hist(新,半年度) |
历史成份股调样 | akshare 国证 + 新浪 | 调样后(6/12 月) |
sanguo-delisted(新,月度) |
退市股列表+K 线 | baostock | 月初 |
query 预算守 48000/天/IP(baostock 硬限):各 baostock schtask 错开 + 日计数器。
8. 分阶段实现
P0 — 治幸存者偏差 + 策略核心缺口
- 历史成份股:深证/国证(
index_detail_hist_cni)+ 中证1000/2000(新浪vII_HistoryComponent)+ 300/500/50(baostock 已有) - ETF 全市场日线:xtdata universe 改
沪深A股∪沪深ETF∪沪深基金+dividend_type='front'(改build_daily_from_xtdata.py:40+daily_update_xtdata.py:114) - 退市股 K 线:baostock
query_all_stock筛 status=0 +query_stock_basic退市日期 + 逐只 K →daily_baostock_full
P1 — 策略增强
- 申万行业 SW1/2/3(xtdata
get_sector_list)+ 历史变动 - 龙虎榜(xtdata
get_longhubang) - 合约信息涨跌停/ST(xtdata
get_instrument_detail)全 A 入库 - 可转债(akshare
bond_zh_hs_cov_min+ 转股价调整) - 研报/一致预期 EPS(akshare
stock_research_info_em)
P2 — 按需
- 股东户数 / 除权明细 / 业绩快报 / 大宗交易 / 宏观 / 期货
融合层(贯穿)
- 归一化库(vt_symbol/exchange/factor/volume 映射)
LocalUnifiedProvider(读权威表 + 归一化 + 网络兜底)- 完整度监控报表(每类覆盖率/缺口,源退化早发现)
9. 陷阱清单(实证)
ak.index_stock_hist已下线(akshare 1.10.37,2024 初)—— 别抄 2022-23 旧博客ak.index_stock_cons的"纳入日期"字段有迷惑性 —— 只是当前 300 只各自最初纳入日,不含被剔除,治不了幸存者偏差- csindex.com.cn 是 Vue SPA ——
requests.get拿空壳,官网只当前 Excel 无历史 - 新浪
fund_etf_hist_sina不复权 —— 不适合回测;ETF 复权走 xtdatadividend_type='front' - 东财
fund_etf_hist_em封 IP —— 单线程限速或避用 - baostock
query_all_stock不列退市日期 —— 配合query_stock_basic - 申万历史板块有变更 —— 回测用当时分类
ak.index_detail_cni(非 hist 版)2025-11-25 起只近期 —— 必须用 hist 版
10. YAGNI(不做)
- ❌ 不强合物理表(冲突解决/历史一致性/vnpy 回归风险,代价大)
- ❌ 不引 QLib/OpenBB 框架(几百 MB,只摘模式:factor/source/归一)
- ❌ CS 截面归一(中期按需,先解决不全+格式)
- ❌ 实时 tick/盘口(非日终策略才需)
11. 风险与对策
| 风险 | 对策 |
|---|---|
| vnpy 回测硬读 dbbardata | 不动 dbbardata,provider 层 SSE↔SH 映射 |
| baostock query 预算 48000/天 | 增量 schtask 错开 + 日计数器(#7+day2b 同天 44296<48000) |
| 东财封 IP | 避用东财,优先 baostock/xtdata/新浪/国证 |
| 接口下线(如 index_stock_hist) | 调查实证,不抄旧文 |
| 数据源漂移/幽灵尖峰 | source 溯源 + 涨跌停/量异常校验 |
| 历史成份股缺口致回测幸存者偏差 | P0 优先补(深证+中证1000/2000+退市) |
12. 实现路径(writing-plans 拆)
- Phase 1(P0 数据补全):历史成份股 + ETF 全市场 + 退市 K 线(3 个采集脚本 + 灌库)
- Phase 2(融合层):归一化库 +
LocalUnifiedProvider(读现有+新表) - Phase 3(P1 增强):板块/龙虎榜/合约/可转债/研报
- Phase 4(运维):增量 schtask 全套 + 完整度监控
13. 开放问题与默认决策(自行决策,你可推翻)
| # | 问题 | 默认(我定) | 备选 | 理由 |
|---|---|---|---|---|
| 1 | exchange 统一格式 | SH/SZ(provider 映射 dbbardata SSE→SH) | 保留 SSE/SZSE | baostock/xtdata 都用 SH/SZ,主流;vnpy SSE 在 provider 层映射 |
| 2 | P0 三项优先级 | 全做(历史成份股 + ETF + 退市 K 线) | 先 ETF(策略即用) | 三项都治幸存者偏差/核心缺口,并行不冲突 |
| 3 | ETF 复权方式 | xtdata dividend_type='front'(前复权) |
raw + factor(精确还原) | 前复权够策略用;raw+factor 中期按需 |
| 4 | 退市股 K 线范围 | 近 5 年退市(守 baostock 48000/天预算) | 全退市(几千只,慢) | 近 5 年覆盖绝大多数回测;全量可后补 |
| 5 | LocalUnifiedProvider 接口 |
§6 签名(get_daily/get_etf/get_fundamentals/get_constituent/get_industry/...) | 精简 | 覆盖全天候 + CTA 需求 |
| 6 | 增量 schtask 时间 | 17:00(baostock 日线)/ 17:30(ETF)/ 18:00(akshare 静态) | 调整 | 错开 sanguo-daily-update 16:30 + day2b 02:00 |
| 7 | 物理表 | 不新建统一表,provider 读现有(dbbardata/daily_baostock_full/各 parquet) | 建 daily_unified | 避免 vnpy 回归 + 数据迁移(§10 YAGNI) |
默认推进路径:按以上默认 → spec 定稿 → 转 writing-plans(P0 拆 3 个采集脚本实现计划)。你审 spec 时可推翻任一项,我改。
14. 方案 A 定稿(2026-07-22 讨论收敛 — 本节为最新,覆盖前文相关决策)
14.1 背景
P0 补全 + schtask 部署完成后,审计(audit_data_layout.py + dbbardata_probe.py 实证)发现「同类多源、多份落地、DB 多表」混乱。讨论收敛为方案 A:每类数据唯一权威源(允许互补 fallback,禁止并行)、DB 表唯一、估值/三表/事件不进 DB、DB 只放高频随机读取的 K 线+成份股+复权。
14.2 权威源最终分工
| 数据类 | 权威源 | 备注 |
|---|---|---|
| 个股日线 OHLCV(含退市) | baostock | raw 真实价 → dbbardata('d') |
| ETF/基金日线 | xtata | baostock 盲区(只取 type=1) |
| 个股当天实时(盘后 baostock 未更窗口/盘中) | xtata | 拼 baostock 历史,同为 raw |
| 15min | baostock | 历史+增量同源 |
| 5min/1min | baostock(暂停) | 战略占位,size 扩容续 |
| 估值 pe/pb/ps/pcf/turn/pctChg/isST | baostock | 日线18字段拆出 |
| 基本面三表 | akshare | |
| 成份股 300/500/50 | baostock(历史) | |
| 成份股 深证 399xxx | akshare cni(历史 union) | |
| 成份股 中证1000/2000 | akshare csindex(当前快照) | 历史不可补=永久 gap |
| 复权因子 | baostock | 全链路复权基准 |
| 事件类(龙虎榜/大宗/北向/两融/解禁/预告) | akshare |
三大源:xtata(ETF+实时) / baostock(个股日线+估值+15min+复权+300.500.50) / akshare(三表+事件+深证中证成份股)。同类不并行,按标的/字段互补。
14.3 DB 边界(只放)
dbbardata:日线('d')+15min('15m')+5min('5m'占位)— 唯一行情表constituent_unified:成份股合并唯一表(date,index_code,code,code_name,source)bs_adjust_factor:复权backtest_stats:回测(已有)- 不进 DB:基本面三表、估值 pe/pb、事件类、回测明细(独立 db)
- 废弃
daily_baostock_full(OHLCV→dbbardata,pe/pb→parquet)、bs_index_constituent(合入 constituent_unified)
14.4 pe/pb 落地:parquet 按年宽表
data/valuation_baostock/<year>.parquet,列 date,symbol,pe_ttm,pb_mrq,ps_ttm,pcf_ncf_ttm,turn,pct_chg,is_st。选股排序(全市场某日)列存宽表秒级。baostock 日线增量同源拆出。
14.5 增量 schtask(4 个)
| schtask | 时间 | 源 | 内容 | 落点 | 预算 |
|---|---|---|---|---|---|
| sanguo-bs-eod | 18:05 | baostock | 个股日线+15min 增量+拆 pe/pb | dbbardata('d'/'15m')+valuation_baostock/ | ~11000/48000 |
| sanguo-xt-eod | 18:40 | xtata | ETF/基金日线+个股当天实时补 | dbbardata('d') | 无限流 |
| sanguo-bs-akshare | 19:00 | akshare | 三表+事件类 | parquet | 限频单线程 |
| sanguo-index | 月度 19:50 | baostock+akshare | 成份股合并 | constituent_unified | 小 |
baostock 单进程单登录,DAILY_LIMIT=48000,sleep 限速,login 探针 graceful skip,直连不走代理。5min/1min 不设 schtask。
14.6 dbbardata 补退市(本次审计发现,顺带治回测幸存者偏差)
实证(dbbardata_probe):退市股(000005/000023/600811)在 dbbardata 只有 15m,无日线 → 回测读 dbbardata 日线天然幸存者偏差。迁移:daily_baostock_full OHLCV 全量(含退市)→ dbbardata('d') INSERT OR REPLACE(本地 DB 迁移,无网络)。ETF 已在 dbbardata(不碰)。
14.7 复权统一
全链路 raw 真实价存储(dbbardata 存 raw),前复权由消费端按 bs_adjust_factor(baostock)统一算。xtata 当天实时同为 raw,可拼接。禁止混 xtata dividend_type=front。
14.8 数据迁移(5 单元,风险升序,备份+staging+可回滚+审计日志)
- 存量垃圾清理(
_staging_xtdata14万文件 /_xtdata.tar1.4G / 归拢 cta_* dbg_* → backtest_files/) - config 统一 VPS 路径(NAS 仅备份)
- 成份股合并(bs_index_constituent + index_const_hist union → constituent_unified,按指数代码去重,新浪300/50丢弃)
- daily_baostock_full 拆分(OHLCV→dbbardata('d') 含退市;pe/pb→valuation_baostock/.parquet;旧表 rename _old)
- dbbardata 个股日线切 baostock 源(单元4已覆盖:daily_baostock_full 含全量,在市股 REPLACE 覆盖 xtata,数值一致)
每单元:全库 sqlite3 .backup + rsync NAS → 脚本写 staging(新表/新目录)→ 验证探针(行数/distinct symbol/抽样价格/成功率)→ 用户确认合并 → 旧数据 rename _old 保留 7 天。全程 nohup + 审计日志 data/migration_logs/。
14.9 config 清理
VPS config 的 daily_dir/raw_dir/qfq_dir/minute_15_dir 改 C:\sanguo_vnpy_v2\data\...(当前 yaml 指 NAS /volume1,容器版遗留)。NAS config 保留作备份。read_parquet_daily 的 daily_dir 统一指向 qfq(消除 daily/ vs qfq/ 分叉)。
15. 增补 2026-09-02:A 档截面数据域全量上生产(本节为最新,覆盖前文相关决策)
本节数据的使用层读取接口见 §16(get_event_panel / get_limit_pool,同日落地)。
背景:调研 daily_stock_analysis(Gitea 镜像
sanguo/daily_stock_analysis) 的数据采集面,双机实验(Mac + VPS 生产 IP 49.232.102.198)后落地。四 commit db789d6→020d7cd→00cfd45→46a0569,CI#303 NAS 验证绿 + vps-deploy#304 绿,tag=46a0569。
15.1 架构红线:单脚本注册表,零新采集脚本(用户钦定)
脚本按**数据源(栈)*分类恒定:akshare 栈唯一采集入口=scripts/data_platform/akshare_static_download.py,
baostock 栈=bs_ 系列,xtdata 栈=daily_update_xtdata,新浪指数=sina_index_eod。新数据类型=注册表添行
+一个 fetcher 函数+wrapper 加名字,禁止每类型开新脚本。akshare 本身是聚合库(东财/新浪/同花顺都在内),
新浪/同花顺数据进 akshare 脚本=按栈分类,不算混源。
15.2 新数据域清单(全部落 data/static//,parquet+marker)
| 数据域 | 类型 | 源/端点(集群) | 调度 | 行数 | 回补能力 |
|---|---|---|---|---|---|
| zt_pool 涨停池 | per-date | 东财 stock_zt_pool_em(push2ex) | ak-events 19:30 | ~83/日 | 30 交易日内可回补 |
| zt_pool_zbgc 炸板池 | per-date | 东财 zbgc_em(push2ex) | 同上 | ~6/日 | 同上 |
| zt_pool_dtgc 跌停池 | per-date | 东财 dtgc_em(push2ex) | 同上 | 0-2/日(空=当日真无跌停,写空+done) | 同上 |
| fund_flow_industry 行业资金流 | per-date 快照 | 新浪 stock_fund_flow_industry('即时') | 同上 | 90/日(净额/流入/流出/领涨股) | ❌无历史回补,洞即永久 |
| fund_flow_concept 概念资金流 | per-date 快照 | 新浪 fund_flow_concept | 同上 | ~387/日 | ❌ |
| ths_industry 行业榜 | per-date 快照 | 同花顺 board_industry_summary_ths | 同上 | 90×12列/日 | ❌ |
| ths_concept 概念名单 | per-date 快照 | 同花顺 board_concept_name_ths | 同上 | ~375/日 | ❌ |
| xueqiu_hot 雪球热度 | per-date 快照 | 雪球 stock_hot_follow_xq('最热门') | 同上 | ~5634/日 | ❌ |
| sina_sector 新浪行业 | per-date 快照 | 新浪 stock_sector_spot | 同上 | 49/日(ths_industry 对账源) | ❌ |
| hot_rank 东财人气榜 | per-date 快照 | 东财 stock_hot_rank_em(emappdata) | fetcher 就位未挂载,待墙测量拍板 | ~100/日 | ❌ |
| gdhs 股东户数 | per-period | 东财 stock_zh_a_gdhs(datacenter) | ak-weekly 周六 | ~5342/期 | marker 去重,无新期零网络 |
- ak-events 事件窗现状 13 类 = 上表前 9 + 原有 dragon_tiger/block_trade/margin_sse/restricted
- gdhs 形状特殊:
build_gdhs_units只枚举距今>90 天的季度末(披露守卫)——防未披露期拉空走「真空+done」 被 marker 锁死永不重拉;cyq 筹码判死后的筹码结构免费替代(策略侧共识) - 快照族节假日拉到上一交易日态(端点无 date 参数无自日期列),接受重复,消费方按交易日历过滤
15.3 东财墙模型(实测,勿再踩)
- 每 IP 每窗口(~30-60min)放 1 发:push2 clist(行业/概念榜/资金流榜)、push2his(kline/cyq/个股资金流)、 emappdata(人气榜)三集群同款;第二发必死、镜像(1./17./79.push2)共享、请求形状无关 (dsa 的 efinance 四差异 http+IE11UA+无ut+fid=f12 全复刻也死)、失败重试不重置窗口
- datacenter 集群(三报表/gdhs/top_holders)独立健康,不受 push2 惩罚波及;push2ex(涨停池)独立稳定连打全绿
- cyq 筹码全市场=数学死(5552×40min≈154 天);dsa 的答案是 tushare cyq_chips token 且免费档 15 次/天
- 行业/概念榜+资金流的免费答案=换域:同花顺(行业+概念榜)+新浪(资金流+行业)实测秒级零限流
15.4 语义与防线(全族统一)
- 失败→返 None 不写不标保旧数据(次日重试);真空 df→写空+done;列名零清洗 akshare 原样落盘
- 缺日防线(static_vintage_check.py 09:00):panel_gap_check 每工作日应有 1 个 parquet(节假日空文件也算有); 可回补族(zt_pool×3)洞≤42 日历日→告警+回补指引;快照族洞即永久→近窗洞告警查日志、旧洞只入 json 不刷告警
- vintage_status.json 的 panel 块=策略守卫层消费契约:
panel.<type>={n_files,first_date,holes_backfillable,holes_permanent}
15.5 消费契约(与策略 session 09-02 对齐)
- 炸板率 = 炸板池行数/(涨停池+炸板池行数):涨停池=收盘仍封(「炸板次数」>0 行=炸过又回封),炸板池=触板未封, 并集≈当日触板全集,分母无遗漏
- 涨停池 16 列:封板资金/首次封板时间/最后封板时间/炸板次数/涨停统计/连板数/所属行业( =免费当日热点行业分布信号,涨停行业集中度原料)/换手率/市值等
- 温度计三支柱=涨跌停(hot_rank 待批)+雪球;情绪周期/打板/行业轮动因子原料自 2026-08 起逐日积累
16. 增补 2026-09-02:使用层 provider 接口(A 档数据的读取出口)
§15 采集落盘的数据在本节获得 provider 出口。设计经业界对照定稿(2026-09-02 用户拍板): dsa
get_limit_up_pool/ tusharelimit_list_d(U/D/Z 参数化)/ 聚宽 per-domain 方法 / OpenBB TET ——共识三条:接口轴=数据域、列名在数据层边界标准化(无一家透传原始中文列)、 泛型传输+语义入口分层(tushare 底层也是pro.query(api_name, params)泛型通道)。 miniQMT/QMT/PTrade 均无涨停池/龙虎榜类接口(业界惯例=外部源补),实盘 provider 同样读本地文件。
16.1 两层出口(「泛型底座 + 域语义门面」)
| 接口 | 定位 | 返回列 |
|---|---|---|
get_event_panel(event_type, date / start+end, trading_days_only=True) |
保真底座:白名单 14 类统一通道(§15.2 全部+gdhs),研究/因子探索用 | akshare 原样中文列 + trade_date(YYYY-MM-DD,文件名合成);别把底座列名当生产契约 |
get_limit_pool(kind="zt"|"zbgc"|"dtgc", date / start+end, ...) |
涨停池门面:kind 三合一(← tushare limit_list_d),唯一有消费契约的域先建(温度计/炸板率/行业集中度) | 英文标准列:code/consecutive_boards/seal_amount/break_count/first_seal_time/industry/limit_stat…(键名对齐 dsa) |
- 实现=TET Fetcher(
fetchers/event_panel.py,FETCHERS 注册表新增event_panel/limit_pool), LocalUnifiedProvider(回测)与 SanguoMiniQmtProvider(实盘,委托self._unified)双侧同款 ——方法面钉死测试(issue #35)强制无缺口;双侧同 schema 支持副本对照验证 - 列名漂移吸收:akshare 改中文列名时,门面映射表(
_LIMIT_POOL_COLUMNS,基于 VPS 真实 parquet 实测 2026-09-02,dtgc 实测含 动态市盈率/封单资金/板上成交额/连续跌停/开板次数)吸收, 下游英文键不炸;有行但缺源列→DataSchemaError fail-fast - trading_days_only=True(默认):用
get_trade_days滤非交易日——治快照族「周中法定假日文件 =上一交易日态复制品」的区间双计数;=False按周一~五枚举(=采集侧口径) - 缺文件(洞/未来日/从未采集)=合法缺失→空 DataFrame;真空日(dtgc 0 跌停)→门面仍返标准列空表
- hot_rank 未挂载不在白名单(拍板后与采集注册表、PANEL_TYPES 三处同步加)
- 新数据类型接入=底座白名单加一行(零新方法);某域有消费契约后再升格门面(YAGNI,不加投机门面)
16.2 MCP 出口预留
FETCHERS 注册表新增两键即自动可被未来 provider MCP server 暴露
(Fetcher.fetch(ctx=provider, **kwargs) 直接调用,fetchers 包设计初衷)。
17. 增补 2026-09-02 深夜:首夜巡查修正(覆盖 §15 相关决策)
- 首夜实绩(09-02 19:30,13 类): 12/13 绿——快照族 6/6 行数与双机实验一致 (资金流 90/387、同花顺 90/375、雪球 5634、新浪行业 49);唯一红=margin_sse(下条)。
- margin_sse 结构性缺陷根治(用户批准): SSE 融资融券 T+1 供应(当晚拉当天→空响应
→akshare Length mismatch 崩),自 07-22 起慢性失血 43 天全空(旧码 empty+done 锁死,
缺日检查未覆盖老四类故无人发现)。修=①
--force回补 07220901(30/30 ok 59865 行, VPS+NAS 双端);②wrapper 拆 margin_sse 单独 **T-1T 两天窗**(564160d):每晚稳定写昨日, 当天失败不写不标、次晚同窗自愈。 - NAS 同步链扩容(
ab8f4e3):sync_parquet_daily.shTYPES 原写死老 4 类——扩到 13 类; gdhs=per-period 季度日期永不落 7 天滚动窗,单独全量拉(≤10 文件幂等)。⚠️NAS 坑:03:00 链 以 root 跑留 root 属主文件,admin scp 覆盖之=Permission denied,先 rm 再拉。 - 回灌纪律(zt_pool 0902 事故): 回灌窗口绝不含当日——盘前拉当日=拿到上一交易日态 复制品(0902 文件≡0901 逐值同)+marker 占位致当晚 19:30 跳过;已删+盘后重拉 52/15/8 真数据。
- VPS 部署终态: 使用层 3 commit(4966d30/7f01c5f/564160d)推 VPS(run#1043,tag=564160d, gap=0),VPS 端 8/8 功能验证过(双层接口/区间滤日/回补数据可读/白名单拒绝/实盘方法面)。
18. 增补 2026-09-06:基本面语料库(新闻+公告)采集设计——NAS 域(本节为最新,覆盖前文相关决策)
用户拍板(2026-09-06,经 factor session 转达):范围=六项全做(新闻标题+摘要级增量/新闻全文级/ 新闻历史回补/公告元数据全量回补 2000 起/公告每日增量/定期+业绩类 PDF),唯一不做=公告 PDF 全量 (520GB/年)。前置调研=
docs/fundamental_corpus_probes_20260906.md(三摸底实测)。 本节为 spec,验收通过后才实施;spec 阶段零建表零采集。
18.1 硬约束(用户原话级)
- 存储全部落 NAS、一律不上 VPS——「vps承载有压力,之前基本面都放在了nas上,没有放vps,本次
也一样」。VPS 零参与:零 schtask、零存储、零采集进程;repo 里进脚本随 nas-deploy 到
/volume1/homes/admin/.sanguo_projects/sanguo_vnpy_v2/(= 采集容器的-v只读挂载/app, 与 5m 同款分发通道),VPS 侧永远不会被调度。**(09-17 修订,§20.11)**采集仍 100% NAS、VPS 零 schtask/零采集进程不变;唯一放宽=「零存储」→ VPS 持每日 只读镜像副本(corpus 四子域+dmsk,382M 级日更),推送任务在 NAS 侧调度。 - 采集进程=一次性容器,与 sanguo-5m 统一(用户终拍板 2026-09-06「统一到5min吧」)。方案
演进:初版按用户「不要和docker绑定,避免docker重启就失败」设计为宿主机 venv 零 docker;
验收中用户权衡「不想搞出多种下载方法」,比较两方向后拍板 corpus 向 5m 的
docker run --rm模式统一(反向统一有硬阻塞:5m 写入的 data_backup 库为 03:00 链 root 属主产物,admin venv 写不进;且需重验 baostock@py3.8、动在跑系统)。被治的痛点不变——主容器重启不再杀任务 (08-22 5m 被 CI 杀三案后的同款根治);保留的弱依赖=docker daemon 在跑+镜像 tag 不改名 (与 5m 同款,已跑一个月实证;daemon 停一天,数据次日自愈)。两项 corpus 专属改进:①DSM 任务以 admin 跑(09-06 实测 admin 可执行 docker 命令);②容器加--user <admin-uid>→ 输出文件 admin 属主(root 文件坑不复发),杀进程=docker stop sanguo-corpus(admin 一条 命令)。镜像环境完整+版本自动跟随 CI 部署,零 venv 自举/锁版本/漂移问题。家宽出口 IP ≠ VPS 公网 IP(49.232.102.198),与 VPS 侧 ak-daily/ak-events 的东财限流零冲突。09-06 实测 佐证:np-listapi/巨潮/东财文章页 ~35 发连续探测自家宽 IP 全成功、零限流。统一后全图 (机器内一种,物理下限):VPS=Windows schtask 家族(数值类)|NAS=DSM→bash wrapper→docker run --rm(5m+corpus 同款,对外爬取)+sync 链(内部搬运)。 - 时间带:全部采集限于 00:30–17:30,避开 18:05–23:45 傍晚带(VPS 夜任务密集+家宽使用)。 唯一日窗=每日 06:00 起(见 18.3)。
- 慢爬纪律:单进程单线程、per-domain 限速+抖动、直连不走代理(Session.trust_env=False,防 Mac 系统代理同款坑)。新浪线已判不可依赖(09-06 实测空返),本设计不使用。
18.2 数据模型(NAS 落位:/volume1/stock/corpus/,与 A股数据/ 平级)
/volume1/stock/corpus/
news_meta/dt=YYYY-MM-DD/part-0.parquet # 东财个股新闻·标题+摘要级(仅新条目,append-only)
news_fulltext/dt=YYYY-MM-DD/part-0.parquet# 东财新闻正文(按 art_code 全局去重,4.1KB/条)
ann_meta/dt=YYYY-MM-DD/part-0.parquet # 巨潮公告元数据(仅新条目;回补的也落发现日分区)
ann_pdf/YYYY/<announcementId>.pdf # 定期+业绩类 PDF(文件名=唯一id,天然幂等)
state/ # 断点水位+unit marker(JSON/parquet)
logs/corpus_YYYYMMDD_HHMMSS.log
Schema(列名冻结,消费方=factor session 因子加工层,后续 provider fetcher 可包):
- news_meta:
art_code(pk),stock_code(6位),show_time,title,summary(可 null: np-listapi 回补段无摘要——search-api 只有最近100条,历史摘要物理不存在),media_name(同上可 null),url,first_seen_date。 - news_fulltext:
art_code(pk,跨股票全局一条——同一篇稿提及多股只在 meta 层多行),url,show_time,content_text(去标签正文),fetch_date。 - ann_meta:
announcement_id(pk),sec_code,sec_name,org_id,title,short_title,content(摘要原文),ann_time(epoch ms→ts),ann_type,ann_type_name,column_id,important,adjunct_url,adjunct_size,batch_num,first_seen_date。 - ann_pdf 索引(state/ann_pdf_index.parquet):
announcement_id,sec_code,ann_type_name,report_year(从报告类别+公告年推),local_path,bytes,fetch_date。
设计要点:id 键控、无「$today 文件名」语义——条目自带时间戳(show_time/ann_time),分区键是 发现日而非业务日,盘前跑/隔夜跑都无 0902/0904 式错标风险(与 A 档快照族的root差异);append-only 不重写(仅新条目入区,短窗 id 去重=读近 N 日分区),无 merge 改写类事故面。
18.3 采集设计:1 个脚本 + 1 个调度入口(脚本整合原则,用户追加指令②)
- 脚本:
scripts/data_platform/corpus_download.py(repo 内唯一新文件;单脚本红线同款—— corpus 栈一个入口,类型靠内部注册表,禁再开新脚本)。参数--lane daily|backfill、--until HH:MM(墙钟自停)、--limit N(手动冒烟)。 - 调度: DSM 任务计划 sanguo-corpus-daily,每日 06:00 一条,以 admin 身份跑,机制=与
sanguo-5m 完全同款的「bash wrapper → 一次性容器」(wrapper=
/volume1/stock/corpus/ run_corpus.sh,宿主文件 CI 不覆盖,改后手动同步——同 5m 的 run_5m.sh 部署纪律)。 为何 admin 而非统一 root(用户问):①03:00 链 root 属主文件坑已在案——admin scp 覆盖 root 文件 Permission denied 只能先 rm 再拉;语料库生命周期内 admin 侧操作密集(venv 装包/ 回补盯跑/删错分区/debug),admin 属主=全程零摩擦 ②最小权限:出网慢爬+写文件的进程没必要 root,出错爆炸半径小一截 ③成本为零:DSM 建任务本就选用户,不比 root 贵——统一到 root 统一 的是坏模式。存量脚本一个都不迁移(用户问「有必要全改admin吗」:没有——03:00 链等既有 root 任务照旧跑,没坏不动;admin 仅是新建 corpus 任务从第一天的选型;两套并行零冲突:目录 隔离/时间窗错开/部署管道不同,互不碰对方文件)。admin 权限逐项实测(2026-09-06): /volume1/stock 建目录/写/删全通(rwxrwxrwx+ACL,admin 属主);admin 可执行 docker 命令 (docker ps 实测通过)→ wrapper/容器/docker stop全程 admin 可运维;读 admin 家 CI 部署 路径无障碍(初版 venv 方案及其 /tmp 坑实测,已随「统一到 5m」拍板作废,记录在 git 历史)。 设计内无任何一步需要 root;万一未来例外,人工 sudo/改任务属主是逃生门非设计依赖。 root vs admin 终局论证(用户问「root 数据不可修改的设计更好吗」):root 属主的「写保护」 是半吊子幻觉——admin 不能覆写 root 文件但能删(删看目录权限,/volume1/stock rwxrwxrwx, 03:00 链「先 rm 再拉」workaround 实证),防住原地改防不住删了重建;而 root 跑采集的代价是 全天候的——root 进程 admin 杀不动(Synology sudo 要交互密码,自动化做不了;本设计验收 含 kill -9 续跑项,root 方案连测试都无法执行)+venv 装包/盯跑全要 root 陪跑+外网爬虫拿最大 权限。不可改性交给正确工具:append-only 协议(dt=分区只追加/tmp+rename/id 键控)+ 可再生性(公告新闻都在源站,断点机制可重拉,语料=全体系唯一可完全再生的数据类);如仍需 防篡改层,验收后加 DSM 快照/每周 tar+校验和归档——对任何属主都生效,属主只是假不可变。 「root=和之前数据一致」前提实测不成立(用户追问后核查):/volume1/stock 现状=三种属主 混合——cfdaily(A股数据/minute_kline/knowledge_base 等,用户记忆中的「之前基本面数据」 恰是 cfdaily 属主而非 root)/root(03:00 链产物+sanguo_5m)/admin(_dbuild/gitea/frp 等); 且文件全 rwxrwxrwx+ACL,无任何消费方依赖属主。真正的一致在方法论层(schtask 语义/marker/ 慢爬/单脚本红线),root 与 admin 两案完全同款;唯一实质差异=运维通道(admin ssh 可杀进程/ 装 vps 包,root 全要 DSM 一次性任务或交互 sudo,自动化不可达)。终判 admin,若用户仍拍 root 亦可行,代价=venv 引导与 kill 全走 DSM 一次性 root 任务/人工 sudo。 为何独立任务而非并进 03:00 链(用户问):①失败不连坐——03:00 链=从 VPS 拉 行情的对内同步,corpus=对外 HTTP 慢爬+数小时回补马拉松,合成一条则 corpus 卡死会拖死每日 行情同步(断路器饿死同款教训,绝不复刻)②属主/部署管道不同——sync 脚本在 /volume1/stock root 地盘 CI 不覆盖须手动 scp,corpus 脚本走 CI deploy 的 repo 路径,搅进一条任务两头别扭 ③06:00 起跑避开 03:00 链跑道(26G 库同步 IO+家宽带宽),且 00 时档公告(54%)凌晨已入库, 06:00 全吃到;DSM 加一条任务代价≈零,改 root 生产链脚本才是真风险: wrapper 内部(同 5m 结构+corpus 两改进):/var/packages/Docker/target/usr/bin/docker run --rm --name sanguo-corpus --user <admin-uid> --entrypoint python -v /volume1/stock:/volume1/stock -v /volume1/homes/admin/.sanguo_projects/sanguo_vnpy_v2:/app:ro sanguo_vnpy_v2:lock-aligned /app/scripts/data_platform/corpus_download.py --lane daily成功后同款第二发--lane backfill --until 17:30(两 lane 串行=天然互斥;rc 聚合,任一 lane 失败 log 留痕)。--name sanguo-corpus=运维锚点:杀进程=docker stop sanguo-corpus(admin 一条命令);--user <admin-uid>=输出文件 admin 属主。镜像 tag 与主容器同源,CI 部署自动 跟随;tag 若将来基建重建改名,wrapper 跟着改(与 5m 同款注意事项)。
断点续传(用户钦点加固,所有 lane 的第一设计原则):
- 粒度=unit(公告=(stock,year)/新闻=(stock,page)/全文/PDF=单 id),每 unit 一枚 marker(state/ 下原子写 tmp+rename);进程被杀/断电/重启后,重启即从「未标 done 的最老 unit」续跑,无任何 全局重启语义;17:30 墙钟=完成当前 unit 即 checkpoint 退出,次日 06:00 自动接续。
- daily lane 幂等可重跑(短窗 id 去重,重复执行零副作用);漏日自愈=公告 T-1~T 两天窗,新闻 recent-100 页面天然覆盖数日缺口(冷门股 100 条跨数月)——某天整个任务没跑,次日一次执行即可 补齐,不依赖专门回补。
- 从 sanguo-5m 借鉴三件(用户问「断点续传是否一样/可否互借」后盘点 bs_5m_eod.py):① 单实例锁(bs_5m.lock pid 活性检测同款——防 DSM 定时与手动补跑撞车双进程竞写 state, corpus 原设计缺口,采纳为 state/corpus.lock)②退出码细分(对齐 5m 语义并适配: 0=完成,1=致命,2=限流让路,3=墙钟自停让路——rc 即运维信号)③state 损坏降级路径 (5m「state 坏→幂等重头无伤」思想;corpus=marker 坏→该 unit 重拉,append-only+id 去重 保证幂等无伤)。5m 反向无需借鉴改造:其整片推进粒度粗(半年片 3-4h,中断=整片重拉), 但回灌已完结、OR REPLACE 幂等无害、每日增量 LOOKBACK=7 独立自愈,改造无未来收益—— 5m 不做结构性改造,仅两个顺手项下次动 run_5m.sh 时一并(docker run 加 --name 便于 定向 stop;头注释 DSM 时点 19:05→00:05 过时修正),不专门跑。
股票池口径(用户 09-06 拍板「都按你说的来」):全 A 含退市(~5547 只),清单源=NAS 副本库 data_backup/quant_trading.db 的 distinct symbol(本地零网络、天然含退市,同 dbbardata 治幸存者 偏差原则);退市股新闻层自然为空不浪费,公告层=事件因子回测原料。PDF 类别=六类(同日拍板): 年报/半年报/一季报/三季报/业绩预告/业绩快报(≈45GB/年;权益分派/增发等不进,元数据层仍全量有)。
daily lane(每日,总 ~4.5h,06:00–10:30 前后)(06:00 晨窗依据 09-06 实测:深市 600 条公告 发布时刻分布=盘中(09-15时)0%(3条)、盘后 15-20 时 46%、00 时档 54%(巨潮深夜批处理 披露)——公告主体在盘后+零点档,06:00 拉取 T+1 晨=前日公告 100% 入账,优于任何傍晚方案 (17:30 前收工的方案会漏 19-20 时 18%+00 时 54%);新闻当日条目盘中占 27%、盘后晚间 73%, 日频消费 T+1 晨拉零损失):
- 公告增量(巨潮,
5400 req @1/s≈1.5h):每股 seDate=T-1T 两天窗+announcement_id短窗去重 (同 margin_sse 两天窗自愈模式,漏一天次日自动补上); - 新闻增量(东财 search-api=akshare stock_news_em 同款端点,~5400 req @1/s≈1.5h):带摘要, 每股最近100条,新 art_code 入 news_meta;
- 新闻全文(东财文章页,@2/s,~1万 req≈1.5h):仅下载昨日新发现的 art_code 正文;
- 当日 PDF(定期+业绩类 category 过滤,数量级 ~100-400 份/日,峰值在 4 月年报季)。
backfill lane(每日 10:30–17:30 剩余时间,断点续跑,顺序=因子价值优先):
① ann_meta 全量回补(2000→今,unit=(stock,year),~19 万 req,预计 3–6 天跑完);
② news_meta 回补(np-listapi 标题级,unit=(stock,page),翻到空页或 page≥200 止,~11 万 req,
2–4 天)——历史段 summary=null 是物理上限(search-api 只有最近100条),spec 如实约定;
③ news_fulltext 回补(①②清单里的 url,@2/s,~1000万 req≈1–2 个月慢车道);
④ 定期+业绩类 PDF 回补(年份新→旧,2026→2000,~34 万份/~300GB,慢车道数周–数月)。
容量闸门: /volume1 实测空闲 645G(2026-09-06);PDF 回补每落 50GB 自查 df,空闲<200G 即
暂停 PDF 段并 log 告警升级用户重拍(其余段不受影响——非 PDF 段总盘子 <60G)。
失败语义(吸收 09-01/09-05 教训): fetch 失败→unit 不标 done 不写半截(parquet tmp+rename); 真空(该股该年 0 公告)→标 done 合法;确定性解析错→记日志跳过该 unit 绝不烧重试、绝不连坐后续 unit(northbound 断路器饿死教训);域名级连续传输错(403/429/超时×10)→该域本日冷却、它域继续、 rc=1 留痕,次日自然重试。
探测优先(用户追加指令①): 深度不预设上限——巨潮按年翻到空、东财按页翻到空/PAGE 硬顶为止, PDF 按可得性实下(404 标 missing 不重试);每源每股记录 first_date 入 state/depth_summary.json, 实施期边探边记,实际深度以落盘数据为准(三摸底测得:巨潮≈2000 起渐密/1993 有零星,东财≈最热股 3 年)。
18.4 预算汇总(实测口径)
| 层 | 增量/年 | 回补累计 | 请求量级 |
|---|---|---|---|
| news_meta(标题+摘要) | ~1.3GB | +3 年标题级 ~1.5GB | 日 ~5400;回补 ~11 万 |
| news_fulltext | ~10.6GB | 3 年 ~32GB | 日 ~1 万;回补 ~1000 万(慢) |
| ann_meta | ~1.3GB | 2000 起 ~15GB | 日 ~5400;回补 ~19 万 |
| ann_pdf(定期+业绩) | ~45GB | ~300GB(带容量闸门) | 日 ~100-400;回补 ~34 万 |
| 非 PDF 合计 | ~13GB/年 | <60GB | — |
18.5 验收标准(实施完成的定义)
- daily lane: T+1 晨抽查 5 股(超热/热/中/冷/ST)——show_time/ann_time∈[T-1,T] 的条目 全在且 id 无重复;日志限速合规(平均间隔≥设定值,零 429/403 连击)。
- ann_meta 回补: 600519 年报 2001 起逐年可查;announcement_id 全局无重;year×count 曲线 单调合理(早年稀疏→近年 ~130 万/年)。
- news 回补: 600519 最早条目落 2023-09±1 月(实测硬顶对齐);depth_summary.json 全量产出。
- PDF: 抽 20 份跨年份可打开(%PDF 魔数+size>0+meta 可反查路径);索引行数=文件数。
- 边界: /volume1/stock/corpus 之外零写入;VPS 零改动(git diff 触及面仅 scripts+tests+docs);
容量闸门演练一次(临时阈值)证明会停;主容器 restart(nas-deploy)不影响在跑的 corpus 容器
(一次性容器与主容器互不相干,5m 已实证同款);手动
docker stop sanguo-corpus即停, 再触发从断点续跑。 5b. 断点续传: 回补中途docker stop sanguo-corpus→重启后从未完成 unit 续跑,已完成 unit 零重拉(marker 核对);某日整个任务停跑一天→次日单次执行把漏日补齐(T-1~T 窗+recent-100 覆盖);单实例锁实证:DSM 定时在跑时手动触发→让路退出(退出码=2/3 类),双进程零竞写。 - 测试: tests/data_platform/ 新增 CI 测试(fetch 全 mock 零网络)——失败语义/短窗去重/ 两天窗自愈/墙钟自停/unit marker,全套本地绿+CI 绿。
18.6 非目标(明确不做)
公告 PDF 全量(用户排除);因子加工层(factor session 职责,消费接口=18.2 的 parquet 契约); 新浪任何接口;VPS 侧任何东西;正文 NLP 解析/向量化;provider 出口(消费层稳定后再议,先直读 parquet);月度 compaction(数据量小,YAGNI)。
18.7 实施步骤概要(验收通过后,TDD)
T1 wrapper+连通金丝雀(run_corpus.sh 按 5m 同款结构编写;docker run --rm --user <uid> 跑通
镜像 python+每域 1 发出网验证+目录骨架)→ T2 corpus_download.py daily lane 四段+断点续传
state 机制+单实例锁+测试 → T3 DSM 任务注册(admin 身份)+首周人工盯跑 → T4 backfill lane ①②
→ T5 ③④+容量闸门 → T6 验收清单执行+活文档本节补「实施终态」小节。每步一个 commit,标签
[nas](VPS 零触及)。时长预期(用户知悉):T1–T3≈1–2 个 session 工作日;ann_meta 回补
~1 周后即可供 factor 做事件因子回测;全文/PDF 为月级慢车道自然推进。用户已批开工
(2026-09-06「都按你说的来吧」)。
18.8 全局下载方案与存放位置总表(回应「不想搞好几套」——本节=现势唯一完整说明)
一条规则,不是几套方案:每类数据唯一权威源+唯一权威位置(§14.2 既定原则),采集发起位置 跟随权威位置——数值类(行情/估值/报表/事件面板)权威=VPS,既有任务家族不变;文本语料类(新闻/ 公告)权威=NAS(本节新增,用户三约束唯一决定:不上VPS+东财IP限流冲突+不绑docker)。两域方法论 同款:单脚本注册表红线/慢爬防封/断点 marker/schtask 语义/容量闸门。「数值类权威=VPS」有 一个在跑的例外=5min,其权威在 NAS 副本库(见下表 sanguo-5m 行)。§14.5 为 07-22 历史快照, 采集任务现势以本表为准(08-20 起 bs-eod+bs-fund 已并 sanguo-bs-daily、akshare 已拆 daily/weekly/monthly/events 三频率+ak-vintage 自检):
| 任务 | 机器 | 时刻 | 内容 | 权威落点 |
|---|---|---|---|---|
| sanguo-bs-daily | VPS | 18:05 | baostock 日线/15m/估值/财务 fund | dbbardata + valuation_baostock/ |
| sanguo-xt-eod | VPS | 18:40 | xtdata ETF+个股当日实时 | dbbardata |
| sanguo-idx-eod | VPS | 每日 | 指数点位 | SSE 表 |
| sanguo-ak-daily | VPS | 07:35 | akshare 低频日更 | static/ |
| sanguo-ak-events | VPS | 19:30 | A 档 15 类事件面板(时间守卫) | static/ |
| sanguo-ak-weekly | VPS | 周六 03:00 | gdhs/share_capital/top_holders/northbound | static/ |
| sanguo-ak-monthly | VPS | 首周六 | 三表全量马拉松(55h 跑道) | static/ |
| ak-vintage 自检 | VPS | 09:00 | 缺日/错标防线 | vintage_status.json |
| NAS sync 链(DSM id=2,root) | NAS | 03:00 | VPS→NAS 副本拉取(7 域) | /volume1/stock/… |
| sanguo-5m(DSM id=7,root) | NAS | 00:05 | baostock 5min 增量+全量回补(独立一次性容器 docker run --rm 跑 lock-aligned 镜像,08-22 治「CI 重启主容器杀在跑任务」;窗口 2020 起,含退市 5547 只,runner=/volume1/stock/sanguo_5m) |
NAS 副本库 dbbardata('5m')=5m 唯一权威 |
| sanguo-corpus-daily(DSM,admin) | NAS | 06:00 | 巨潮公告+东财新闻(本设计,一次性容器同 5m 模式) | /volume1/stock/corpus/ |
存放位置全景:数值权威=VPS data/(dbbardata 26G+static/+valuation_baostock/),
两个例外在 NAS:①5min——权威=NAS 副本库/volume1/stock/sanguo_vnpy_v2/data_backup/ quant_trading.db 的 dbbardata('5m')(VPS 侧 '5m' 是空占位;§14.2「5min 占位/不设 schtask」
为 07-22 历史快照,08-20 起由 DSM 00:05 任务实际落地,当时未回写本文档=文档债,本表现补
——用户 09-06 验收总表时点名找回);②语料=NAS /volume1/stock/corpus/(本设计)。
NAS 其余=数值副本(sync 链产物)+大体积历史(minute_kline/ 2.1G=cfdaily 时代外部 1min/5min/
15min,无任务在跑,其中 1min 为全体系唯一 1 分钟粒度;A股数据/;LLM-Models 等非本项目)。
Mac=开发 fixture 无生产数据。corpus 不是第三种根——就是既有 /volume1/stock 数据根下的
新子目录,与 CLAUDE.md「NAS 部署目录」表一致。
18.9 实施记录(2026-09-06/07 开工夜,T1/T2/T4/T5+T6 可自主项已验)
commit 链 62a3a65→308d493(全 [nas],CI 绿,终版已部署 NAS /app)。两 lane 真数据冒烟 rc=0: daily 431s/205 unit(news +100×2 股、全文 199 篇均值 3584 字、复合键零重、 --limit 零 marker);backfill 13s/8 unit(①2026 层真公告 59+125、④真 PDF 1.09MB+索引)。 verify_corpus.py(只读验收器,晨检一条命令)真数据 PASS:三域 dups=0、账本=唯一键数、 PDF 索引=文件数。文件全 admin 属主;容器时区 CST 与 NAS 对齐。
与 §18.3 字面的四项实施偏差(均为实测倒逼,语义不劣化):
- 股票池源=巨潮
szse_stock.json(6247 含退市 000003+北交 920001→A 前缀过滤 6168), 非 NAS 副本库 distinct symbol——orgId 是按股查询硬前提且退市覆盖实测更全。 - 单实例锁=flock(非 5m 的 pid 活性同款)——docker run --rm 各容器独立 PID namespace, pid 检测跨容器失效;flock 内核级经 bind mount 同 inode 跨容器互斥,进程死自动释放 无陈旧锁(让路契约同款,实测二实例 EXIT=3)。
- 业绩快报无服务端类别码(category_yjkb_* 无效码被服务端静默忽略返回全量,官方 history-notice.js 码表无此项,单股对照实测)——PDF 六类=五服务端码+客户端标题谓词 「业绩快报」(announcementType 数字码 012111 仅作参考);announcementTypeName 恒 null, ann_meta.ann_type 存原始数字码串。
- backfill ①年序=新→旧(字面「2000→今」与 §18.7「回补~1周后即可供 factor」自相矛盾, 翻转后 day1 即近年数据;全量完结不受影响)。
§18.5 验收进度: 5/5b/6 已过——主容器 restart 期间 corpus 容器存活且 marker 在涨 (实测);docker stop 断点冻结 27 unit→重启从 000028_2026 精确接续零重拉(实测);单实例 锁二实例让路 EXIT=3(实测);容量闸门真卷演练(临时阈值 99999G>free 644G→段首暂停 零下载+capacity_paused.json,工件即清);测试 270 绿+CI 绿。待数据累积后补: 验收 1(5 股抽查)/2(600519 2001 起)/3(news 2023-09 硬顶)/4(PDF 抽 20 份)+限速 合规 stats 复核——依赖 DSM 任务注册后数日运行。
运维要点: wrapper=repo scripts/nas_sync/run_corpus_standalone.sh→NAS /volume1/ stock/corpus/run_corpus.sh(scp -O 手动同步);容器必带 --user 1024:100 --group-add 101
(Synology ACL 只授权 administrators 组,漏组=Permission denied)+--name sanguo-corpus
(杀=docker stop);东财 search-api 无 UA 返 200 空 body(全 fetcher 统一带 UA);
--until 语义=完成当前 unit 后停(首 unit 必跑);day-1 全文洪峰由 daily --until 10:30
墙钟+backfill ③账本反扫兜底。
首跑日实录(2026-09-07): daily 全量(ann/news 各 6168/6168 unit+fulltext 2478 洪峰
墙钟截断)→backfill ①ann 到 5542/6168 时巨潮 502 连击(15:45~15:47,服务端故障
rate_limited=False)触发域冷却——fail-closed 不标 done,无缝切 ②news(eastmoney 不受
波及)跑至 17:30 墙钟,rc=1 由次日自愈(设计内行为)。当日落库:ann_meta 43.0 万行/
news_meta 87.8 万行/news_fulltext 2673 行/PDF 2 份;news depth 已见 2015-05-11(np-listapi
实际可达远深于 2023-09 预估)。首跑揪出并修复第五项偏差: 巨潮单次响应同
announcementId 可挂两条(整行相同或 ann_time 差 1 秒),_filter_new 批内不比对→双双
落盘成重键行(3 行,verify FAIL)——修=批内 seen 截留(a889b2f)+存量 3 part 原子去重,
修后 verify_corpus 全域 PASS(rows=uniq=ledger)。
T3 注册收口(2026-09-07 晚): 用户 GUI 完成 DSM 任务 sanguo-corpus-daily 注册
(每日 06:00/admin/bash /volume1/stock/corpus/run_corpus.sh;esynoscheduler.db mtime
18:47 佐证,admin 无权限直读 root 属主 db 属预期)。至此 T1-T5 全部落地+部署(终版
16f00ff,CI #1134 全绿),采集进入生产节律: 次日 06:00 首班自愈接力——首跑日 backfill
遗留(ann ①缺口 626/6168 unit+news ②余量)由断点机制自动续拉,502 域冷却随新进程解除。
T6 剩余=多日累积后验收 1-4(5 股抽查/600519 2001 起/news 硬顶/PDF 抽 20 份)+限速 stats
复核+本节完结行。
首班前夜第六修正(52756e3, day-2 致命坑): 复查发现 daily ann/news 增量 marker 无
日期维度——首跑日已写满 6168+6168,次日 06:00 首班将整段跳过增量采集(backfill 仍在
跑会掩盖症状,静默断供)。修=增量段 unit 名挂 dt=YYYY-MM-DD/ 子目录(断点续传只保护
当日)+日初清旧日目录与历史平铺 marker;fulltext/pdf 段键=内容 id(公告/文章不可变,
一次永逸)保持平铺。契约测试三连: 次日重新拉窗承接新数据/当日断点续传语义不变/旧日
目录日初清(274 绿)。教训: 增量型 marker 必须带日期维度,且要在「首个完整周期结束
前」推演第二天行为——同日幂等测试全绿掩盖了跨日语义。
首班实录(2026-09-08, 第六修正的实战验证): DSM 06:00:01 自动起(功能确认)。
①day-2 修复生效: ann/news 增量真实拉窗, 新 marker 全落 dt=2026-09-08/ 下, 昨日平铺
marker 日初清理零残留; ②news 6168/6168 全量扫完(含北交 920 尾段); 全文段 +985 篇
(article 域静默无逐篇日志, 进度信号=marker 数); ③ann 2564/6168+150 失败=巨潮 cninfo
连续第二日服务端抖动(昨 502 连击/今 504×150), 触发域冷却 fail-closed, PDF 段随之
跳过; daily rc=1 → backfill 让路(设计内)。零永久丢失双兜底: 未标 done unit 明晨
重拉, 窗内漏掉的公告由 backfill ①(股,年) 全年扫终会收; ④同晨 dmsk(07:33)与 corpus
(06:00-10:14)并行无扰=东财端点分域假设实证。观察项: 巨潮抖动若持续数日→升级源端
健康度问题(备选: ann 增量段错峰避开其故障高峰)。
19. 增补 2026-09-07:财务数据域(财务136)——存量搬运+同步增量架构(本节为最新,覆盖本节初版「全 NAS 自采」方向)
19.0 背景与方向修正
factor session goal「完成财务136,部署在nas上,并验证成功」(用户 2026-09-07 设),数据层归数据 session。初版方向「全 NAS 自采」被用户当晚纠偏推翻:原话要点「这些内容数据 session 已经下载 过了,先问清楚哪些下载过了哪些没下载过,不要上去就全量下载新的数据」——VPS static 七域 本就是本 session 建的 akshare 体系。「零 VPS」重定义=运行时形态(NAS 本地 parquet 独立 可用,策略/因子读 NAS 不经 VPS),不否定存量复用与 VPS 作为上游采集器。
19.1 存量盘点(2026-09-07 只读实测,VPS C:\sanguo_vnpy_v2\data\static)
| 域 | 覆盖 | 最新 | 质量 |
|---|---|---|---|
| balance | 沪深 5215 只(319 列,银行 221 模板)回溯 1989 | 2026-06-30 ✓ | 北交 340 文件全空 (0,0)=09-01 空 dump 残留 |
| income | 同 5215(203 列) | 2026-06-30 ✓ | 北交同采集器同命运(搬运时逐文件过滤) |
| cashflow | 同 5215(254 列) | 2026-06-30 ✓ | 同上 |
| financial_abstract | 5559 含北交 343 有数据(80 指标×期宽表,回溯 1998) | 20260630 ✓ | 无 |
| valuation | 5559 含北交 343 有数据(13 列中文名,日频~2100 行/股) | 日更(ak-daily 19:00 喂) | akshare 改名列,非 raw 22 列,原样搬 |
| forecast | 26 期按期全市场文件(2020Q1→2026Q2) | 2026-06-30 ✓ | 2020 前无(可选补) |
| express | 同 26 期 | ✓ | 同上 |
采集机制现状: valuation/abstract/事件域=sanguo-ak-daily 每日 19:00;三表+forecast/
express=sanguo-ak-monthly 首个周六全量洗库(下次 11/7 02:00,55h 跑道=09-01 事故根治)
→ 三表季频新鲜度=披露后最多~5 周(Q3 数据 11/7 入库)。若因子批需披露周可用,VPS 侧
加密(10 月底补跑/改 NOTICE_DATE 增量)——挂起决策,因子侧与用户定,本 session 不擅动
VPS 调度。
真缺口清单(对 corpus 池 6168=沪深 5570+北交 598,差 613 拆解):
- 沪深退市 355 只全周期缺(F10 实测拉 000003 也空,按期接口是唯一源);
- 北交退市 258 只同缺;
- 北交现役 340 只三表=空文件(数据在按期接口可取);
- forecast/express 2020 前历史(可选,按期接口顺手)。
19.2 接口契约(11 发实测保留,定位重排)
| 域 | 接口 | 实测要点 | 新定位 |
|---|---|---|---|
| dmsk 按期 | datacenter RPT_DMSK_FN_{BALANCE,INCOME,CASHFLOW} filter=(REPORT_DATE='单期') |
全市场单期≈5223 行,pageSize500≈12页;2009 年报 2520 行(akshare docstring「2010 起」过时);57 列含 NOTICE_DATE;含彼时在市后退市股 | 补缺层(§19.4) |
| f10 按股 | emweb PC_HSF10 | 319/203/254 列全史;dates=5 期/发服务端硬顶;回溯 1992;老退市股空 | 全量回补作废(VPS 存量已有,增量走同步) |
| valuation | datacenter RPT_VALUEANALYSIS_DET |
按股全史 1 发+全市场单日快照~5556 行 | 不采集(VPS 日更存量+同步) |
| abstract | 新浪 CompanyFinanceService |
按股 1 发全史 | 不采集(VPS 日更存量+同步) |
| forecast/express | datacenter 按期全市场(ak yjyg/yjkb 契约) | 26 期形态已按期 | 2020 前可选补(同 dmsk 族) |
19.3 架构定稿:存量搬运+phase3 同步增量+按期补缺
VPS(上游采集器,ak-daily/ak-monthly 继续喂,零改动)
│ ①一次性搬运 4.22GB(跳过北交空文件)
│ ②phase3 03:00 链扩域:七域增量 rsync(月度洗库整文件重写天然被 mtime 增量捕获)
▼
NAS /volume1/stock/fundamentals/ ← 运行时 NAS 独立可用
static 原形态: {balance,income,cashflow,financial_abstract,forecast,express,valuation}/
<code>.<EXCH>_<domain>.parquet (文件名/列名原样,零转换)
补缺层: dmsk/{balance,income,cashflow,forecast,express}/dt=<REPORT_DATE>/part-*.parquet
state/ (补缺层 marker+账本)
增量分工三线: ①VPS 侧零改动(ak-daily/monthly 继续喂全列基线,月度洗库 5 周延迟=
因子验证零影响,factor 需求方已确认);②phase3 03:00 链扩域=基线层同步(七域 rsync,月度
洗库整文件重写天然被 mtime 增量捕获);③dmsk daily 重扫=新鲜度补丁层(见 §19.4,DSM
sanguo-fundamentals-daily 07:10,错峰 corpus 06:00——东财端点分域+各自限速,并发重叠
安全依据同 corpus)。北交空文件在搬运时过滤(shape==(0,0) 跳过,防下游误读)。「VPS 零参与」
让位于「VPS 零新增负担」:miniQMT 09-18 停服不影响 akshare 线,ak-daily/monthly 健康
运行(事故均已根治)。下游读法: 基线层(全列,≤5 周延迟)为主,dmsk 层(57 列核心科目,
披露次日)做新鲜度补丁与退市/北交覆盖。
19.4 dmsk 层双用途(fundamentals_dmsk_download.py,corpus 骨架复用)
用途一·补缺(一次性 backfill lane): 全期回补 2009→今 ~66 期×3 表(≈2200 发≈1.5h, 可断点续跑)——补沪深退市 355+北交退市 258+北交现役三表 340 空档;forecast/express 2020 前历史=可选 backlog 不阻塞 goal。北交所含性实施首日验证(filter 的 SECURITY_TYPE_CODE 集合,不含则北交补缺单列说明)。
用途二·新鲜度(daily lane,DSM 07:10): 近 3 期重扫+NOTICE_DATE>=T-7 增量行(~40 发
/日,季报月自然加密)——披露次日即可用(57 列核心科目够选股),不等 VPS 月度洗库。增量
unit=REPORT_DATE 一次永逸按期 marker;行键 (SECURITY_CODE,REPORT_DATE) 幂等去重;
批内去重/失败不写不标/账本+marker 次序等 corpus 六修正全带入。
19.5 验证三维(factor 持 goal 验收,锚点=factor session fund136-acceptance-anchors.md)
①覆盖: NAS 侧七域文件数/期数分布/NAS 与 VPS 逐域 count 对账(搬运完整性)+dmsk 补缺后 corpus 池 6168 覆盖率(北交三表从空→有,退市股从缺→有);②正确性: 600519 锚点(balance 103 期/2024 归母权益 2331.06 亿/归母净利 862.28 亿)+VPS 存量抽样只读对照(派单已约定 豁免);③可用性: NAS 容器内单股全历史读取秒级(7 域各抽 1 股)。
19.6 实施步骤(每步一 commit 标 [nas])
W1 搬运通道: VPS→NAS 一次性 rsync 七域(跳空文件)+逐域 count 对账 → W2 phase3 扩域: 同步链加七域增量(每日 03:00) → W3 dmsk 脚本双 lane+测试(全 mock 零网络)+wrapper+DSM 07:10 注册 → W4 dmsk backfill 全期回补(1.5h)+北交所含性验证+daily lane 首跑 → W5 三维 验证+factor NAS 实测验收+本节实施记录。预期: W1-W2 当日完成=NAS 立即可用;W3-W4 一日 内;总量级 4.22GB 搬运+2200 发一次性+40 发/日,无 2-3 周长尾(初版 f10 全量回补 21 万发 已作废)。语料库首班(09-08 06:00)全程绝对优先,财务 W1 起步于首班巡检绿之后。
19.7 基准反转补丁(2026-09-07 深夜,用户二次纠偏「假设 NAS 最全,盘点 NAS 看差多少」)
NAS 全景实测(只读): ①data/static/ 16.5 万 parquet=phase3 镜像树(04:00 链,
valuation 今日刚同步/三表 09-06 全量),七域覆盖≡VPS(沪深 5215 有效+北交 340 空+零退市)
——§19.3 的「一次性搬运」与「phase3 扩域」两项取消(镜像已在且日更,搬运本来就
免费发生在链上); ②**data/valuation_baostock/ 按年 1990→2026 日频估值=NAS 独有深度**
(10 列 peTTM/psTTM/pcfNcfTTM/pbMRQ/turn/pctChg/isST;含退市股——000003 存活年份
478 行/年实测;新鲜到 T-1,bs-daily 日喂)=用户「NAS 比 VPS 全」直觉的真实来源,纳为
第 8 验证域; ③data/fundamentals_baostock/ profit+dupont 季频指标 5357 股
2015Q1→2023Q4 断更(七域外,数据 session 单列待查,不动本 goal scope); ④A股数据/ 财务数据/=v1 死残留(1438 深市估值+年度空骨架),不采信;#recycle/ 排除。
修订后唯一新工作=dmsk 补缺层(§19.4 不变)+三维验证(§19.5 改在 NAS 镜像路径
/volume1/stock/sanguo_vnpy_v2/data/static/ 验,+valuation_baostock 第 8 域)。
缺口结论不变: 沪深退市 355+北交退市 258 三表缺(其日频估值已被 baostock 树覆盖)+
北交现役 340 空+forecast/express 2020 前可选。
19.8 实施记录(2026-09-08 凌晨)
- W1' 镜像对账全绿: 七域 count(三表各 5555=5215 沪深有效+340 北交 920xxx 零行空档,挂 .SZ 后缀=09-01 空 dump 残留;abstract/valuation 5557;forecast/ express 26 期)+600519 四锚点容器内复验逐位一致+读取 0.99s。第 8 域 valuation_baostock: 1990→2025 完整(2025 实测 1.25M 行/243 天/5211 股,含退市); 2026 文件仅 08-13 起(bs 日喂起点)→ 2026 H1 估值缺口由基线层 valuation 覆盖,H1 回补列可选 backlog。
- W3' dmsk 双 lane 落地:
fundamentals_dmsk_download.py(单脚本红线,corpus 骨架复用+六修正全带入)+21 测全 mock 绿+run_dmsk_standalone.sh(DSMsanguo-fundamentals-daily07:10,一次性容器 sanguo-fund-dmsk,corpus 同款 --user 1024:100 --group-add 101)+verify_dmsk.py(键唯一硬门只读验收)。 落库=/volume1/stock/fundamentals/dmsk/{域}/dt=期/part-*.parquet,绝不写镜像树。 - §19.4 marker 语义修正: 原文「daily 增量 unit=REPORT_DATE 一次永逸按期
marker」有 day-2 同款坑(次日重扫被跳过漏新披露行,corpus
52756e3教训)——实施 改为 daily marker 按日折叠(dt=子目录+日初清理);backfill 期 marker 才是一次 永逸(期内容历史不可变)。marker 键=域+期(域缺席会让后续域被首域 marker 连带 跳过,首测抓出)。 - 次新期金丝雀: 东财把「filter 契约失效」与「合法空期」都回 result=None 无法区分→次新期(全市场已披露 3+ 月)空=契约漂移按失败处理不标 done,防整段 静默空跑标 done。
- profit/dupont「断更」系误诊,09-08 晨撤回: 09-07 深夜读到 NAS 副本止于 2023Q4 判为「一次性回补从未接日喂」——错。实况=bs_fundamentals.py P2 按季回灌 在行军中(state next_quarter 逐夜推进,昨夜至 2024Q3 指针, NAS 副本随 04:00 链日同步滞后一拍),剩 2024Q3→2026Q2 共 10 季 ≈5 晚(≈09-13)自愈,之后 P1 增量 (当季+上一季每晚 sweep, 幂等 keep-last)自动接管。教训: 判「断更」前必须先读 生产脚本的续喂设计与 state 文件 mtime——「数据末端=快照」≠「管线已死」。 原批「5.2 万发季度追赶」取消(重复采集+并发撞 baostock 双连接红线,有害无益)。
W4' 完成终态(2026-09-08 02:18): backfill 210 unit/1771 发/5680s/零失败
rc=0,70 期×3 表全落库(27.1万/28.0万/28.0万行);verify PASS=键唯一 0 重键
(硬门),BJ 行 1.04万-1.15万/域(北交所含性实证);净新增 383 只镜像外代码
(dmsk_codes=5598 vs 镜像有效 5215)=2009 年后退市+镜像空档股,补缺目标达成。
daily lane 首跑(00:42)符合设计: 近3期重扫 2 分钟,+10/+7/+7 晚披露入账,
NOTICE_DATE 5569/5569 非空最新至当日。已知边界: 2009 年前退市股(如
000003, 2002 年退)dmsk(2009 起)与 F10(拉老退市也空)双源皆无=源头缺失,
无免费方案,如实记档。翻页坑: 东财 datacenter 用 pageNumber(cninfo 才是
pageNum),误用被静默忽略=12 页全回第一页,冒烟 +500/6000 实锤后修(d71ee55)。
DSM sanguo-fundamentals-daily 07:10 已由用户 GUI 注册(09-08 晨)并手动首跑验证:
07:33 start → daily units=0 rc=0(昨夜 00:42 手动 wrapper 已采过当日, 按日幂等跳过
语义正确)→ backfill units=0 rc=0(210 期 marker 全 done 纯 no-op)→ 容器干净退出。
明起 07:10 自动班。
19.9 基本面数据链运行节律总览(2026-09-08 终态速查,细节见各节)
| 层 | 源/接口 | 下载方式 | 增量机制 | 新鲜度 | 自愈/兜底 |
|---|---|---|---|---|---|
| 三表基线层 §19.1/19.3 |
akshare f10(emweb)按股全史 (319/203/254 列,沪深 5215) |
VPS ak-monthly 首个周六全量洗库(55h 跑道) |
月度整文件重写;phase3 04:00 链按 mtime 增量同步 NAS 镜像树 | 季频≤5 周(验证场景可接受) | 洗库失败返 None 不写不标(09-01 事故根治);valuation/abstract 另有 ak-daily 19:00 日更 |
| 三表补缺/新鲜层 §19.4 |
东财 datacenter RPT_DMSK_FN_* 按期全市场(57 列含 NOTICE_DATE,含退市+北交) |
NAS 一次性 backfill≈2200 发(09-08 完成:210 unit/1771 发/零失败) | daily(07:10):近 3 期重扫+NOTICE_DATE>=T-7 客户端过滤,账本键幂等 |
披露次日 | marker 按日折叠(daily)/一次永逸(backfill 期);批内去重;次新期金丝雀防契约漂移(都回 result=None 不分) |
| forecast/express | datacenter 按期 | 26 期按期文件(2020Q1 起) | 随 ak-monthly 洗库 | 同三表 | 2020 前历史=可选 backlog(dmsk 族同接口可补) |
| profit/dupont (baostock) |
bs query_profit/dupont_data 按股按季 |
VPS bs-daily 18:05 fund 腿:P2 按季回灌(state 逐夜推进,~2 季/晚,≈09-13 跑完)→P1 接管 |
P1=每晚拉当季+上一季 sweep;幂等键 (code,pubDate,statDate) keep-last(重述后写胜) | 季频次日 | DAILY_CAP=30000(与 eod 合计≤41k<48k 铁律);P3 forecast/express 月首周日全区间 |
| valuation_baostock §19.7 第 8 域 |
bs 日频估值(peTTM/psTTM/pcf/pbMRQ/turn/isST,1990 起含退市) | bs-daily fund 腿日喂 | 每日追加当年按年 parquet | T-1 | 2026 文件 08-13 起(日喂起点,H1 缺口由基线层 valuation 覆盖;回补列可选) |
| 语料库 §18 |
巨潮公告+东财新闻 | 首跑+backfill 四段(ann 43 万/news 88 万/PDF 六类) | daily 四段:ann T-1~T 窗/news recent-100/全文(当日新稿)/PDF(五服务端码+快报标题谓词) | 当日/次日 | 按日 marker+域冷却 fail-closed 其他域继续+backfill (股,年) 全年扫终兜;flock 单实例 |
层间读法(双层口径, §19.7 写死): 回测全历史=基线层为主(全列)+dmsk 补退市/北交段; 季频选股要新鲜=dmsk 层近 3 期优先,基线层兜全列。已知边界: 2009 年前退市股(000003 等) 三表 dmsk 与 F10 双源皆无=源头缺失(其日频估值仍被 baostock 树覆盖)。采集纪律: 东财 datacenter 1.5s/巨潮 1.0s/东财 search 1.0s/article 2.0s 慢爬,直连不走代理, 日间带 00:30-17:30 语义,baostock 同 IP 单连接 48000 次/天。
19.10 因子 P1 批五域支持(2026-09-08,factor 派单回执)
P1 二批 5 因子所需 5 域读取契约(真文件勘测 VPS+NAS,容器复验读通)。NAS 运行时根
/volume1/stock/sanguo_vnpy_v2/data/(static 树即 P0 --fund-data-dir 所指):
| 域 | 路径/命名 | 主键 | PIT 列 | 覆盖与坑 |
|---|---|---|---|---|
| dividend | static/dividend/{code}.{SH|SZ}_dividend.parquet(5538 只) |
(code,分红事件行) | dividPlanAnnounceDate(可空,回退链 PreNotice→AgmPum→Plan,全空丢行) | baostock 静态快照 2020→2026-07,无增量 lane(2027 前开);code 列=sh.600519 小写格式;沪深含退市,无北交 |
| gdhs | static/gdhs/{YYYYMMDD}_gdhs.parquet(53 期) |
(代码,统计截止日-本次) | 公告日期 | 2013Q1→2026Q1(09-08 补史 44 期/15.4 万行,源头边界 2013Q1 实测钉死,2012Q4 前东财无数据);「本次/上次」截止日不规则→增减比例≠统一季环比,消费方自建事件表自算 Δln;ak-weekly 滚动 3 年窗喂新期(披露守卫 90 天) |
| top_holders | static/top_holders/{code}.{EXC}_{期}_top_holders.parquet(10.9 万文件) |
(code,期,名次) | 无公告日列→法定披露截止近似(Q1→04-30/H1→08-31/Q3→10-31/年报→次年04-30) | 2021Q3→2026Q2(09-09 修订:原 2020Q1 契约口径与 NAS 镜像实测不符——108,610 文件首期 20210930,5431 文件/期整齐步进;后果=fund_topholder_chg 首期无差分 2022 年中才生效,合成层 v1 已剔该源);增减列混「不变」字符串;占比=%单位;北交排除 |
| financial_abstract | static/financial_abstract/{code}.{EXC}_*.parquet(5559 只) |
(指标,报告期)——转置宽表(行=80 指标,列=报告期) | 无 NOTICE_DATE,直接用有前视风险 | 1998→2026Q2;E08 已定改三表自算 CCC(复用 NOTICE_DATE PIT),本域只作对账源;ak-daily 19:00 日更 |
| valuation_baostock | data/valuation_baostock/{year}.parquet(static 兄弟目录) |
(symbol,date) | 日频即点时 | 1990→2026 含退市(000003 实测在);2026 仅 08-13 起,H1 缺口=基线层 em valuation 补;亏损/净资负 peTTM、pbMRQ=NaN;date 为字符串 |
gdhs 补史实施: akshare_static_download.py --gdhs-start 20130331(040a39e,枚举外扩+marker
幂等,TDD 23 测绿),VPS 一趟 44/44 ok/154031 行/104s,VPS+NAS 双侧 53 期对齐。同步链同日
两修一加固: ①dir /b 枚举 CRLF 清洗(a37d324——此前 6 天文件名尾粘回车符 scp 静默失败,
NAS 空目录) ②257bd3b 引入注释断行语法死(裸引号未闭合致整脚本 parse 失败,bash -n 抓出,
7195aa6 修回)——shell 改完必跑 bash -n,CI 只覆盖 pytest 救不了 shell ③skip-if-exists
(期文件 write-once,53 文件无需每日重拉)。
19.11 P1 支持决策记录 + 可选 backlog 设计(2026-09-08 晚,用户拍板 compact 后执行)
决策记录(factor×data 双方落定):
- gdhs 补史=做,已落地(§19.10);源头边界 2013Q1 实测钉死,更早无免费方案,如实记档
- dividend 2027 增量=当期不做(YAGNI),方案留 backlog-c
- E08 CCC=三表自算(DSO+DIO−DPO,复用 NOTICE_DATE PIT);financial_abstract 不作因子源 (转置宽表无披露日,直接用有前视风险),降级为对账源
- E12 gdhs=消费方自建事件表 (代码,统计截止日-本次)→股东户数-本次,PIT=公告日期,自算相邻 Δln——现成「增减比例」列因本次/上次截止日不规则(每股不同)不能当统一季环比
- 派生聚合边界: static 树只由采集层写;下游预聚合(如 top_holders 十大占比)一律落消费方 独立目录(factor_cache 类),绝不写 static 树
- parquet 日线 lane(data/{raw,qfq},daily_update_xtdata.py)07-22 方案A 定稿日退役: dbbardata 唯一行情表;脚本保留作工具、无 schtask(09-08 勘误定性,迁移文档 §6.5 同步)
可选 backlog(已设计,执行序 a→b,c 轻量收编):
a. valuation_baostock 2026 H1 回补: 2026.parquet 仅 08-13 起(bs 日喂起点),H1 靠基线层 em valuation 覆盖(异源口径)。方案=baostock query_history_k_data_plus 按 (股, 2026-01-01→08-12) 拉 10 列估值字段→与现有 2026.parquet concat+drop_duplicates(symbol,date) →原子写回(窗止 08-12 与现有段零重叠,不用 keep-last 仲裁);股票名单=当前全列表∪ query_all_stock(2026-06-30) 时点列表(保 H1 退市股)。成本≈5200 发(48000/天预算内, 单连接单线程≈2-3h)。验收=行数≈5211×H1 交易日+600519 抽锚+(symbol,date) 键唯一。 价值=D14 长史 EP/BP 的 baostock 统一口径跨 2026 连续。
b. forecast/express 2020 前历史: 现状 26 期(2020Q1 起)。方案=fundamentals_dmsk_download.py DOMAINS 扩 forecast/express 两域(同 datacenter 骨架:pageNumber 翻页+按期 marker+账本, 族内扩展不破单脚本红线),backfill 补可得最早期→2019Q4。先探源头边界再定回补深度 (同 gdhs 2013Q1 探法);早期预告披露规则不同(主板触线才强制)行数天然少=正常,空期判定 走次新期金丝雀同款(空≠契约漂移须区分)。成本≈50 期×3-5 页≈250 发。验收=有货期行数>0+ 键唯一+披露日列非空;落 NAS dmsk 树(forecast/express 子域)与基线层按期文件并存,读法 =基线层为主、dmsk 层补缺(与三表同款双层口径)。
c. dividend 增量收编(轻量): legacy Day2b 快照(2020→2026-07)继续用;分红事件低频且 年度集中(4-7 月),年度刷新比每日增量合身——2027-01 再议把年度刷新挂进 baostock 年度任务;当期零动作。
19.11.1 backlog 执行记录(2026-09-09,三项闭环)
- a. valuation_baostock 2026 H1 回补 ✅ (
150465a):bs_eod.py --backfill-valuation START END——只拉估值 9 列(无 OHLCV,不动 dbbardata);名单=全A含退市∪query_all_stock (窗口中点日)时点快照;断点序=buffer 落盘先、done 后写(崩=整批重拉幂等);终局 merge_valuation_frames(keep='last' 同 upsert_daily 语义)+os.replace 原子写回;中间产物 落data/_backfill_valuation/{tag}/(独立目录,避开 sync_valuation_daily 的 scp -r 整目录拉取面)。09-09 09:35 schtask 一趟 7545 发零失败 82min,merge 93,678→1,131,834 行键唯一;验收=600519 锚 165 行 peTTM≈20.2 对公开口径/H1 日均 7062 行(含退市名单, 大于现存 5216 属预期)/10 列 schema 不变。一次性 schtask 已删,buffer 已清;NAS 由 03:09 链自动传播(09-10 晨到)。 - b. forecast/express 补史 ✅ (
f78e8f1): DOMAINS 扩两域;边界探针实测 forecast 2003 年报起(458 行)/express 2005 年报起(133 行),2002 及更早东财返空——per-domainBACKFILL_FROM{balance:2009,forecast:2003,express:2005}+backfill_from_year()(--start-year 显式覆盖优先)。键分域: forecast 4 键 (SECURITY_CODE,REPORT_DATE, NOTICE_DATE,PREDICT_FINANCE_CODE)——同股同期同披露日多指标行(EPS 003+净利 004 并存)+多次修正史全保留,2019 年报 3646 行实测唯一;express 3 键(含 NOTICE_DATE, 2528 行实测唯一);两域 NOTICE_DATE 全期实测非空。verify_dmsk 同步五域键唯一。 09-09 11:51 手动触发 NAS run_dmsk.sh(日常 07:10 DSM 班次日自动接续);daily lane 识别 forecast 4897 行与探针精确一致。读法不变:基线层为主、dmsk 层补缺。 - c. dividend 收编 ✅零动作备案: legacy Day2b 快照继续用;2027-01 再议年度刷新挂 baostock 年度任务。
- 晨间三验收(09-09): xt_eod 09-07 缺口自愈绿(3353/4012/39 对齐 09-04 形态); 09-08 只补 30%(1040/1122/39)由 LOOKBACK=30 窗口当晚再扫自愈;dmsk 07:10 首个全自动 班绿(daily 178s/9 unit/108 发零失败);巨潮 504 连续三日抖动(failed 18→150→113, 全 ann 单元网关 504,<1%,不标 done 次日重试不丢数据)——已升级报用户待拍板。
20. 增补 2026-09-12:四域扩展(两融/申万/龙虎榜席位/北向)——用户拍板「本地数据越全越好」
20.0 拍板与勘测依据
用户 09-12 拍板(最高指令):「不用管因子,本地数据越全越好,怎么消费是其他 session 的事」—— factor 排序作废,四域全部融合进现有数据体系;北向做二次探针看能做到多细(已完成,见 20.4)。 实施顺序按 data 侧性价比:两融 > 申万 > 龙虎榜席位 > 北向。
勘测实测结论(2026-09-11/12 探针,venv310 直连清代理):
| 域 | 渠道(实测) | 深度 | 单夜请求量 |
|---|---|---|---|
| 两融个股明细 | 东财 datacenter RPTA_WEB_RZRQ_GGMX(filter SCODE 600519 实测 3,979 行=2010-03-31→今 16 年日度;filter DATE 单日全市场 ~3,300 行/7 页) |
2010-03-31 起 | 日采 7 页;16 年回补 ~3,900 交易日×7≈27k 发 |
| 申万行业 | akshare sw_index_first_info(31 一级)+index_component_sw(31 发)(成分+最新权重+计入日期=部分变更史) |
仅当前快照(计入日期带部分史) | 32 发 |
| 龙虎榜席位 | 东财 RPT_BILLBOARD_DAILYDETAILSBUY/SELL(每日上榜股×买卖席位明细);主表 2020-01-01 起 1,748 日文件已在库 |
增量(全史席位=~50 万发不可行) | ~120-200 发 |
| 北向 | 见 20.4 粒度极限 | 官方=季度频/12 个月窗 | 3 发 |
20.1 架构红线延续(对齐 §15)
- §15.1 单脚本注册表零新采集脚本(用户钦定):四域全部注册进
akshare_static_download.pyTYPES + fetch 函数,不新建任何脚本。 - 全部落
data/static/<type>/per-date parquet+marker → §16 泛型底座get_event_panel零改动自动可读(消费出口现成)。 - 不碰 dbbardata(非行情,事件/截面族);不碰 constituent_unified(不动守护库; 申万走快照域模式,变更史由逐日快照+计入日期列承担)。
- 东财直连纪律:RPTA/RPT_BILLBOARD datacenter 家族串行、复用 session、 间隔 ≥1.2s+抖动(§15.3 墙模型:5 分钟 ≥300 发触发封禁,1.2s 间隔≈250 发/5min 在线下)。
- 僵尸退役备案:PER_STOCK_TYPES 的
northbound(aksharestock_hsgt_individual_em, EM 已下线)——ak_eod wrapper 早已不跑该类型,零运行时影响,仅注册表注释标记 deprecated(2024-08 后 EM 个股级北向历史已无,见 20.4)。
20.2 新域清单(全挂 ak_events 19:30 夜班,快照域语义对齐 §15.2)
| type | 模式 | 来源 | 节律 | 文件 |
|---|---|---|---|---|
margin |
per-date | EM RPTA_WEB_RZRQ_GGMX filter DATE,7 页×500 |
T-1~T 窗(margin_sse 同款;EM 两融 T 日晚间供应,当天失败不写不标次夜补) | {date}_margin.parquet |
sw_industry |
per-date 快照 | sw_index_first_info+index_component_sw×31 |
T~T(快照,§15.2 快照语义:无历史无回补,date 仅命名) | {date}_sw_industry.parquet |
dragon_tiger_seats |
per-date | EM RPT_BILLBOARD_DAILYDETAILSBUY/SELL 每上榜股 2 发 |
T-1 |
{date}_dragon_tiger_seats.parquet |
nb_hold |
快照(季度实频) | HKEX www3.hkexnews.hk/sdw/search/mutualmarket_c.aspx 两步 POST(沪默认/深 ?t=sz),全表单请求 |
每夜 2 发查询;内容 hash 与已存快照不同才写,文件名=数据所属季度末日 | {quarter_end}_nb_hold.parquet |
nb_daily |
per-date | HKEX data_tab_daily_{date}c.js(成交总额/额度/十大活跃股) |
T-1 拉(当日 js 盘后才出) | {date}_nb_daily.parquet |
20.3 各域 schema(列名随 EM/HKEX 原字段直存,双层读法写死)
- margin: 行=两融标的×日(~3,300/日,非全A=数据属性);列 DATE/SCODE/SECURITY_NAME_ABBR/ RZYE(融资余额)/RZMRE(融资买入)/RZCHE(融资偿还)/RQYE(融券余额)/RQMCL(融券卖出)/ RQCHL(融券偿还)/RZRQYE(两融余额)。16 年回补总量级 ~1,300 万行(~400MB parquet)。
- sw_industry: 行=股票×一级行业(全市场 ~5,400);列 行业代码/行业名/股票代码/股票名/ 权重/计入日期。变更史消费法:逐日快照 diff + 计入日期列(2021-12-13 大搬迁类事件可考)。
- dragon_tiger_seats: 行=股票×席位×方向(当日上榜股 ~60-100 只×top5 席位×买/卖); 列 SIDE/TRADE_DATE/SECURITY_CODE/OPERATEDEPT_NAME/BUY/SELL/NET(EM 原字段直存)。
- nb_hold: 行=沪深股通标的(沪 2,039+深 ~1,700);列 MARKET(sh/sz)/股份代号/名称/ CCASS 持股量/占 A 股总数%/SNAPSHOT_DATE(=文件名季度末日)。
- nb_daily: 市场合计行(成交总额/买入/卖出/额度)+十大活跃股行(代码/名称/买入/卖出/成交), 从 js tabData 解析,列 MARKET/ITEM/CODE/NAME/VALUE 原样长表。
20.4 北向粒度极限备案(二次探针终审,后续 session 勿再勘测)
- 制度天花板(HKEX 官方页面原文):「由 2024年8月19日開始,滬港通及深港通下北向交易 (即滬股通和深股通)的市場信息披露…將調整於每季度第五個滬深股通交易日公布上季度末數據」 +「僅提供自 2017年3月17日 的持股紀錄,資料將按持股日期起計保留12個月」。
- 实测证据:POST
txtShareholdingDate=2026/09/11→ 单请求全沪股通 2,039 行 (工商銀行 91398=1,500,902,770 股/0.55%);查 2026/09/04 与 09/11 返回完全相同数值 → 任意日期查询均返回最近季度末快照(当前=2026Q2),日频个股明细 2024-08-16 起永久停发。 - EM 通道:个股级
RPT_MUTUAL_STOCK_NORTHSTA三连「服务器繁忙」+akshare 全系 hsgt 持股函数 NoneType → 已下线;参与者级RPT_MUTUAL_HOLD_DET存孤段 2024-05-16→09-30(61,777 行/日×~95 日,行粒度=标的×日×CCASS 参与者)。 - 深股通:同端点
mutualmarket_c.aspx?t=sz(Northbound-SZ 页表单 action 实测)。 - 回补窗:12 个月滚动=最近 4 个季度末快照(2025Q3/Q4/2026Q1/Q2,各查 1 个 窗内日期即可取到,共 8 发);更早历史无免费渠道。
- 可选 backlog(按「越全越好」原则择机,排最末):EM 参与者级孤段全收 (95 日×124 页≈11.8k 发≈5h 周六马拉松,~587 万行)。
20.5 验收锚点
- margin: 回补后 600519 首行=2010-03-31、行数 3,979±10;单日文件行数 ~3,300; 与既有 margin_sse(上交所官方)同日茅台 RZYE 量级一致(±5%,口径差在东财含深市)。
- sw_industry: 31 行业、Σ成分 ~5,000±500;600519 所属一级=食品饮料 (代码实施时以 index_component_sw 实测为准写入测试锚)。
- dragon_tiger_seats: 当日股票集⊆dragon_tiger 主表股票集;每股票 buy+sell 各 ≤5 席位。
- nb_hold: 沪 2,039±50/深 ~1,700±100;工行锚 1,500,902,770(2026Q2 快照)。
- nb_daily: 解析行数>10 且含十大活跃代码。
20.6 实施顺序与记录
顺序(用户拍板):margin(日采+16 年回补) > sw_industry > dragon_tiger_seats > nb_hold/nb_daily(含 4 快照回补)。全走 TDD(./venv310/bin/python)+worktree 协议+ [vps] 标签(schtask 挂载位在 VPS);回补马拉松周六窗口执行。
实施记录:
- 2026-09-12 全四域当日落地 (用户拍板当日开工):
- spec §20 定稿 (
96e373a)。 - margin (f7fb7b7/f80ca2f/8f3ce48): 关键实测修正——DATE 视图服务端 universe 锁沪市 2,000 只 (深市被排除, TMC×DATE 组合查询被服务端拒), 深北走 TMC 段码 (精确匹配: 股票 12 位/ETF 9 位, 七段全集≈570 万行)。 日增量=沪 DATE 直查+深北 TMC 倒序最近两日块 (实测深段 T+1 供应); wrapper T-2~T 三天窗; --margin-backfill 全史回补 (七段倒序整段翻页 流式按日切块+断点 state+合并去重幂等), 每周六 ak-weekly 兜底重跑; 16 年回补 09-12 09:03 VPS 启动 (深主板段 3,517 页起翻, 完成态见 后续巡查记录)。
- sw_industry (
b24f72d): 实测 5,214 行/31 行业/37s; 锚点 600519∈ 801120 食品饮料 (权重 39.8866/计入 2021-12-13) 写入测试。 - dragon_tiger_seats (
55339fe): 实测 680 行/58 股/190s (榜列表 68 行 =同股多上榜原因去重 58); 逐股逐侧各自 30s 预算 (整日期 3 分钟超 AK_TIMEOUT); filter 日期必须单引号。 - nb_daily + nb_hold (
d979c90): nb_daily 长表化实测通; nb_hold 季度 快照检查器实测 0630 快照 4,308 行/19s; --nb-hold-backfill 当日 完成 12 个月窗 4 季回补: 0630=4,308/0331=4,108/1231=4,014/0930= 3,820 行 (VPS data/static/nb_hold/)。 - 僵尸退役: northbound (EM 个股北向持股, 2024-08 下线) 从 ak-weekly --types 移除 (原每周六 2,883 空跑单位); PER_STOCK_TYPES 注册表保留 仅注释级。
- 测试: 新增 33 测试 (margin 14+sw 6+seats 4+nb 9), 全量 349 绿。
- spec §20 定稿 (
- margin 全史回补通道改判 (09-12 上午, 三启三修复): TMC 整段翻页实测
服务端 5.7→20s/页递增惩罚 + 「服务器繁忙」限流 (全程≈70h 不可行) →
终态=per-stock 快速通道
--margin-backfill-ps(SCODE 视图 0.2s/页, universe 读本地 valuation markers 5,563 码零网络, 逐股包 retry+重试耗尽 跳过不杀马拉松, 19-24 点避让夜班, 股级断点; ~2.5s/股≈4h); TMC 慢通道 降级退市史专用; 周六兜底改--margin-backfill-gapsgapsonly 连续 5 完整 日早停 (分钟级)。过程中根除两个存量真 bug: ①call_ak_with_timeout 的 with 块 exit 隐式 join 挂死线程 (瞬态挂起变永久卡死, 威胁全部 akshare 调用); ②EM 无数据双形态 (result=None+「返回数据为空」=合法空)。8446098部署后第 4 次启动巡航 (09-12 10:37 idx=14 推进中)。 - 首夜观察 (2026-09-12 19:30 ak-events): margin/seats/nb_daily/nb_hold 四域首航 + sw_industry 首夜; 09-13 晨锚点=五域文件行数验收。
20.7 增补 2026-09-13:数据实体抽查修正(覆盖 §20.2/§20.6 相关结论)
用户质询「看 log 还是抽查了数据」触发实体抽查(读 parquet + EM 活体 3 发对账),三项修正:
- 「DATE 视图服务端锁沪 2,000」系结算时序假象,非宇宙锁:已结算日(09-08)实测
count=4443全市场(SCODE 升序首页 000001/000002…全深主板);未结算当晚同视图只回 沪段 2,000。深段 EM 侧 T+1 且跨周末顺延(000002 周日夜最新仅 09-10)。 → 日采无需 TMC 段舞步,结算后 DATE 单查即全市场。 - 日采窗口修正(09-11 洞的机制):原 T-2
T 当晚拉 T → 沪半截落盘即标 marker → 深段永久洞(09-11 实例:文件沪2000/深0)。修=ak_events_wrapper margin 段改 **T-3T-1 仅工作日**(拉的全是已结算日),周六 gaps 兜底保留;09-11 marker 待 重跑 flush 后删除,周一晚窗口自愈。 - ps 马拉松半场事故(记录):10:31 手动实例 18:32 挂死(475 万行困内存未 flush)+ once 任务 23:59 计划时刻二次触发(手动 /run 不消费计划)续完后段 1,746 股/140 万行 → 磁盘一度只有半场。09-13 08:05 全量重跑(两段:白天 ~9s/股 + 避让窗睡眠), ~01:45 收口。验收锚点:09-08 文件 ~4,400 行、000002/300750/600519 在档、dup=0。
抽查实录(数据非日志):000001@09-08 RZYE 46.26 亿(值 sane,EM 对账 000002 22.77 亿 一致);flush dedup 实证 dup=0(TMC 883→502 即重复行吸收);16 年抽样 000001/600519 命中 0/10 = 半场实锤;nb_hold 4,308=sz2269+sh2039;seats 680=68 股×10 席位(buy/sell 各 340)。
20.8 增补 2026-09-14:margin-ps 马拉松 OOM 根因与分段落盘修复
09-13 08:05 全量重跑「~01:45 收口」预期未发生——进程 16:17:59 即被系统强杀(昨晚
22:03 巡检读 idx=4272 误判「避让窗睡眠」,实为尸体;教训:判推进必看 state mtime 是否
随墙钟走)。事件日志铁证(Resource-Exhaustion-Detector 2004):马拉松 python(pid
19552)commit 达 32.6GB(16G 内存机)→「页面文件太小」→ WER 自身停止 + sanguo-frps
句柄错误 crashloop(系统级窘迫连带)→ schtask 记录 0xC00000FD。两次「8 小时死」非时间
规律,是内存累积曲线(都死在 ~4272 股/510 万行):by_date 分桶存 1 行 DataFrame
≈510 万个 pandas 对象 ×~6KB ≈ 32GB。docstring「570 万行 16G 实测可行」评估作废。
修复(commit 同日):①行 dict 替代 1 行 df 分桶(同信息量内存 ~1/5);②每
PS_FLUSH_EVERY=300 股分段调 _flush_margin_by_date 落盘(与 TMC/日增通道同键
DATE,SCODE merge+dedup keep-last,幂等可重复吸收);③state 只在段 flush 成功后推进
(crash 最多重做 ≤300 股;旧版每股写 state 是半场事故的共因)。TDD 3 例钉死:
段边界后强杀 → 前段在盘+state 停边界;crash 后续跑全量落齐;段 merge keep-last。
验收锚点随修复重设:重跑完成 = 全史日文件行数恢复(09-08 ~4,400)、000002/300750/ 600519 在档、dup=0、且 python commit 峰值 < 2GB(事件查看器无 2004)。09-11 自愈 改由重跑覆盖(marker 删除因远端删除被权限拦,改待用户点头的窗口自愈或重跑吸收)。
20.9 增补 2026-09-16:五新域首两晚生产四病五修(用户拍板全批)
09-14(周一)起五新域进入生产首跑,09-16 联合巡检+诊断探针实测定性四病 (margin_sse 窗口缺陷为第五项),用户全批修复(infra 转达口令批次):
- margin 深段 TMC 代码级必然超时(09-14/15/16 三晚全灭,从未成功过):
原实现把沪 DATE 直查+4 段 TMC 翻页整体包一个
AK_TIMEOUT=30s预算,而 VPS 实测单段两日块 26.3s(883×2 行/4 页)→ 整体必超时。修=逐层各自预算 (dragon_tiger_seats 同款):沪直查AK_TIMEOUT+ 每 TMC 段MARGIN_TMC_SEG_TIMEOUT=60s,任一层 failed → 整体 None 不写残缺; 段成功但请求日不在最近两块 → 跳过(旧日语义不变,backfill 兜底)。 09-11 自愈(仍 3,896 行缺前段股)被此病挡住,修复后由 T-3~T-1 窗重拉。 - sw_industry 一级清单源被反爬:akshare
sw_index_first_info走乐咕乐股 legulegu.com,VPS IP 被其反爬(带 UA=200 JS 挑战页/裸 403,两晚'NoneType' find_all)。修=一级 31 行业清单改SW_FIRST_LEVEL_STATIC静态表(2021-12 版,Mac 出口实测校准;清单变更频率=年级,下次申万 一级大改需同步此表——Mac 出口仍可拉权威清单);成份源index_component_sw走申万宏源官网 API(swsresearch.com)不受影响, 保留网络拉取(Mac 实测 801120 食品饮料 122 行/600519 在档)。 VPS 出口对 swsresearch 可达性=部署后首跑验证项。 - nb_hold 日增查当天必空(与 margin_sse T 日同构的窗口 bug):HKEX
持股记录 T+1 供应,
run_nb_hold_snapshot原查d_today当天永远空页 → 09-13 起每晚 raise 出码 2 拍 ak-events rc=1。修=查询基准日改 T-1 (显式 today 参数仍可覆盖);_hkex_hold_query加strict参数—— 日增路径strict=False(无数据行返 [],走既有 skip 分支不抛), 回补路径保持默认strict=Trueraise 语义(查询日=q_end+45 必有数据)。 - financial_abstract 新浪源每晚 5.5k 连发撞限流:源=新浪 quotes.sina.cn(非 EM),09-14/15 断路器 30 连败 FATAL rc=2;单发实测 通(200/2.6MB JSON)→ 非持续封禁是批量频率触发。fa 是 ak-daily 最后 一个类型,断路器无后续连坐。修=fa 从 ak-eod 每日挪 ak-weekly 周六 03:00(季度频数据周更足够,sina 风控面 -87% + 错峰;schema/路径 不变仅频率降)。
- margin_sse 窗口含 T 日每晚必 1 failed:EM 沪 DATE 视图 T+1 供应
(本条与 §20.7 09-13 修正同源——TMC 深段已改 T-3
T-1,margin_sse 漏改)。 修=wrapper 窗口 T-1T → T-2~T-1(每晚全 settled 数据全绿;窗内 重试自愈保留——漏掉的 T-1 次晚变 T-2 仍在窗内)。
监控口径坑(09-16 备案):ak-events 类型级 failed 不抬出码(margin 两晚 failed 各自日志仍「全部完成 出码 0」),只有未捕获异常/断路器才抬 rc—— 判健康必须看每类型统计行 ok/failed,不能看 schtask rc 或「出码 0」。
验收锚点(部署后首个 19:30/周六):margin 深段 09-14/15 双日文件落盘 (各自 ~4,400 行全市场)+09-11 补至 ~4,443;sw_industry 首落 (20260917_sw_industry.parquet ~5,200 行/31 行业/600519∈801120);nb_hold rc 不再抬 1(T-1 查询或 skip);ak-events schtask rc=0;fa 下个周六 (09-19)ak-weekly 段绿。
20.10 增补 2026-09-17:数据面全景定稿(口径四原则+管线清单+归属表)——本节为数据面唯一权威查询入口
背景:09-17 双机全量盘点(NAS du/DSM 调度/VPS 探针三源交叉)。目的=此后查 「有什么数据/在哪/谁更新/多大」直接读本节,不再用代码/探针回溯。
20.10.1 口径四原则(用户 2026-09-17 拍板,覆盖此前所有归属表述)
- LLM-Models 639G 忽略:NAS 上 cfdaily 账号 2026-05-12 的 ModelScope 批量 下载(6 模型仅 GLM-5.1-Int4 有内容,目录内有 download_log.txt/教程取证), 非本项目资产。
- VPS 采集 → NAS 必须同步(统一铁律):VPS=下载主体(公网出口直连各源), NAS 每日定时同步=原始设计常态,「双份」不是差异;活的采集面在 NAS 缺 同步=缺口必须修正(当日修正两例见 20.10.4)。停更归档层除外(原则 3)。
- 搁置不管清单:分钟线分置(NAS 5m 独有腿在 90G 库/VPS 15m 在主库)=已知 问题先搁置;归档件不管(qfq 0.81G/raw 0.77G=07-22 方案A 定稿日退役、VPS minute_kline 2.98G/minute_15 1.01G 散文件=07-18/20 退役尸体、_deprecated 3.94G、csindex_raw/constituent_baostock=停更采集中间层、cfdaily 旁路三件= A股数据 3.0G+minute_kline 2.1G+LLM-Models,均非我方管线)。
- 消费不跨机:NAS 因子读 NAS 镜像,VPS 消费(实盘/回测)读 VPS 本地。 (09-17 拍板)NAS 独有域迁移定案:corpus/dmsk 建 NAS→VPS 每日镜像=§20.11 (VPS 侧消费届时读 VPS 副本,本原则自动满足);5m 留 NAS 分置(原则 3)。
20.10.2 活跃管线全景(14 条,2026-09-17 实测+§20.11 镜像链新增)
VPS 夜班(Windows schtask,9 条):
| 任务 | 时间 | 内容 | 源 | 落点 |
|---|---|---|---|---|
| sanguo-bs-daily | 18:05 日 | 个股日线+15m 增量→dbbardata;拆估值列→年 parquet;fund 腿回灌 | baostock | quant_trading.db 39.85G+valuation_baostock 0.68G+fundamentals_baostock 21M |
| sanguo-idx-daily | 18:30 日 | 9 指数日线 | 新浪 | dbbardata |
| sanguo-ak-daily | 19:00 日 | valuation 5,565 股逐股 --force | akshare/EM | static/valuation(5,565 文件) |
| sanguo-ak-events | 19:30 日 | 21 类 per-date:dragon_tiger/block_trade/restricted(2020 起 1,751 日)/zt_pool×3(09-02 起)/fund_flow×2/ths×2/xueqiu/sina_sector/hot_rank/sw_industry+margin(T-3 |
EM/新浪/同花顺/雪球/HKEX/申万宏源 | static/ 各域 |
| sanguo-xt-daily | 21:00 日 | ETF/基金日线+个股补缺 | xt 桥 | dbbardata |
| sanguo-ak-vintage | 09:00 日 | vintage 一致性自检(防线,不下载) | — | vintage_status.json |
| sanguo-ak-weekly | 周六 03:00 | gdhs(53 期,2013Q1 源头边界)/share_capital/top_holders(10.9 万文件)/financial_abstract(09-16 挪入,新浪限流对策)+margin 缺口回补 | EM/新浪 | static/ |
| sanguo-ak-monthly | 财报季首周六 02:00(下次 11-07) | 三表+forecast/express 全量洗库(balance/income/cashflow 各 5,555 股,Q2=2026-06-30) | EM datacenter | static/ |
| sanguo-index+idx-monthly | 每月 16 日 19:50 | 成份股 merge→constituent_unified(14,496 行)+index_const_hist(44 文件) | baostock+EM | dbbardata+data/index_const_hist |
NAS 侧(DSM 调度,5 条+周日):
| 任务 | 时间 | 内容 | 源 | 落点 |
|---|---|---|---|---|
| sanguo-5m 容器 | 00:05 日 | 5 分钟线全市场 5,558 股(94min 完赛) | baostock | data_backup/quant_trading.db 90G(=VPS dbbardata 日增量+5m 独有腿合库,已超 VPS 主库) |
| 03:00 同步链 | 03:00 日 | 五段:①dbbardata 增量(sync_dbbardata)②constituent_unified+bs_adjust_factor 两表 REPLACE ③per-date 18 类 7 天窗单文件拉(sync_parquet_daily)④valuation/financial_abstract 两整目录+valuation_baostock/fundamentals_baostock/index_const_hist 三根级目录 scp -r(sync_valuation_daily) | 从 VPS 拉(NAS→VPS SSH 22 出站通,光猫只拦 80/443) | 90G 库+sanguo_vnpy_v2/data 镜像树 |
| sanguo-corpus 容器 | 06:00 日 | 新闻标题/正文+公告元数据+业绩 PDF | 东财/巨潮 | corpus/ 302M(news_meta 116M/ann_meta 37M/state 131M…) |
| run_dmsk | 07:10 日 | 按期财务五域(balance/income/cashflow/forecast/express,披露次日新鲜度补丁层+退市/北交覆盖) | EM datacenter | fundamentals/dmsk 222M(dt=期分区,最新 2026-06-30) |
| 周日全量 | 周日 04:00 | static+valuation_baostock+fundamentals_baostock 整树 scp -r 6.24G/70min(慢变 per-stock 域兜底) | 从 VPS 拉 | static 镜像 |
| sanguo-vps-mirror(§20.11 新增,随实施上线) | 16:00 日 | corpus 四子域+dmsk 分区粒度增量推送(journal 指纹 diff,只增不删) | 推 VPS | C:\sanguo_vnpy_v2\data{corpus,fundamentals\dmsk} |
同步新鲜度分级(修正后):per-date 18 类+两表+dbbardata 增量+valuation/ financial_abstract/vb/fb/index_const_hist=日级;三表/forecast/express(月更 洗库)/share_capital/top_holders/gdhs(周六产)=周级(周日全量+gdhs 日级段); corpus/dmsk 的 VPS 镜像=日级(§20.11,16:00 推)。
20.10.3 数据归属与体量总表
| 数据 | 位置 | 体量 | 性质 |
|---|---|---|---|
| dbbardata 行情主库(日线+15m,含 ETF/指数/退市) | VPS+NAS | 39.85G / 90G | 双份日级(原则 2 常态) |
| 5m 分钟线 | 仅 NAS | 并在 90G 库 | 独有腿(原则 3 搁置) |
| corpus 语料四件套 | NAS 权威+VPS 日镜像(§20.11 随实施上线) | 302M(载荷 171M) | §18 采集+§20.11 镜像 |
| dmsk 五域 | NAS 权威+VPS 日镜像(同上) | 222M | §19 采集+§20.11 镜像 |
| factor 产物(topn_results/cross_section/eval_fundamental) | 仅 NAS | ~450M | 因子批产物(NAS 消费) |
| static 33 域 | VPS 原始+NAS 镜像 | 6.85G / 6.7G | 原则 2 常态 |
| valuation_baostock/fundamentals_baostock/index_const_hist | 双份 | 0.68G/21M/MB 级 | 原则 2 常态 |
| quant_trading.db 本体/universe_cache 0.23G/backtest_files/strategy_code_versions | 仅 VPS | — | 生产运行时(实盘+VPS 回测读,原则 4) |
| qfq/raw/分钟散文件/_deprecated/csindex_raw/constituent_baostock | 仅 VPS | ~5.6G+3.94G | 原则 3 归档不管 |
| cfdaily 旁路(A股数据/minute_kline/LLM-Models) | 仅 NAS | 3.0G/2.1G/639G | 原则 1/3 忽略 |
20.10.4 当日修正两例(缺口实例,模式备案)
- sync_parquet_daily TYPES 13→18 类+nb_hold 季度段(e0f5730):09-12 四域 扩展与 09-04 hot_rank 挂载后清单未跟上,margin/sw_industry/nb_daily/seats/ hot_rank 在 NAS 仅周日全量兜底周级滞后(NAS margin 停 0911 实锤)。教训: 新增 per-date 域必须同步扩 sync_parquet_daily TYPES,纳入域上线检查单。
- index_const_hist 补入 sync_valuation_daily 根级目录段:每月 16 日整文件 重写(44 文件 MB 级),此前 NAS 完全没有,按统一铁律补链。
20.10.5 半截文件防线(用户点名「别总出现半截文件」)
- margin 0911 案根因链(已闭环):旧代码沪 DATE 直查成功+TMC 段超时仍部分 concat 写盘(3,896 行、深段缺)+marker 锁死永不重拉。修复=新代码任一层 失败整体返 None 不写不标(75af7f2 五修①)+marker 只在完整写入后落——半截 写入通道已从语义上关闭。
- 提前补齐前提=根因已闭环:0911 补齐走
--margin-backfill-gaps(gapsonly 早停,分钟级),09-17 晚 ak-events 跑完后手动触发(不等 09-19 周六自愈)。 - 同族防线既有:ak-quarter 洗库撕裂=ak-vintage 09:00 自检+ALERT rc3(09-01 事故防线④);快照族节假日拉上一交易日态=消费方按交易日历过滤(§15.2)。
五修首跑验收(09-17 晚)+新病六修(TMC 块翻页漂移 dup):首跑四看全过
(ak-events rc=0 首次、margin_sse 新窗 T-2~T-1 全绿无 T 日 failed、nb_hold
「已是 20260630 期跳过」不再抬 rc、sw_industry 首落 5,217 行/31 行业/
600519∈801120 权重 39.9007 计入 2021-12-13 与锚点一致、seats 620 行、
nb_daily 62 行、valuation 5,565 股满贯)。但 margin 0915/0916 行数 6,890
(预期 4,443)——探针解剖实锤:fetch_em_tmc_recent_blocks 翻页在 EM
sortColumns=DATE 同日内排序不稳定时页边界行漂移,同一 (DATE,SCODE) 行进
两页(069001002001 块内 883 行 dupSCODE=382;四段 universe 跨段 overlap=0
排除段重叠假说;0914 干净=漂移是页边界概率性)。by_date 通道自 2,445 行/日(消费端两融余额会翻倍,
勿在修复前消费)。处置终态(09-17 晚更新):六修 44d3ab9 有
(DATE,SCODE) merge dedup 防线,五修①重构 recent_blocks 通道漏抄。修复=
_fetch_tmc_block 块出口 drop_duplicates(容错键列),TDD +1 例 372 绿。
存量脏数据:0915/0916 文件 dupd94936c 已上 VPS(run#1265,
21:43 生效);直接洗文件被本机分类器拦(写生产数据),改由 09-19 周六
gapsonly(七修版)merge keep-last 自动重写洗净——0917 在 09-18 晚 19:30
两日窗内也会被新代码重拉洗净。代价=NAS 副本 dup 躺到周日晚 03:00 同步
(margin 零消费方,无实害)。0917 当晚文件同为部署前旧代码所写,同病同治。
七修(gapsonly p101 服务墙,09-17):0911 半截补齐首跑两次同点挂
[backfill TMC 069001002001 p101]: 服务器繁忙——非短暂限流(同点复现=
确定性),根因三病:① 早停「行数相等」判定(旧文件该段行数==新块行数)在
新块带翻页漂移 dup(len 虚高)/旧文件 ps 通道行数微差时恒 False → 连续 5
完整日永不触发 → 一路裸翻;② EM 对单 TMC 段深翻页存在 ~100 页/5 万行确定性
服务墙(p101 起 result 缺失),且 TMC×DATE 组合过滤被服务端拒(§20 实测),
无法换锚深翻——此墙同时宣告 full 模式 TMC 整段翻页对 176 万行大段永不可达,
深史回补只能走 per-stock 通道(已为主力);③ gapsonly 复用 full 模式
state 断点,挂死残留 state(page=100) 毒化下次续跑(从 p100 起立即再撞墙),
且单段早停跨段 break 跳过其余六段(各段夜间失败模式独立)。修复=四件:
键集判定(旧文件该段 SCODE 键集 ⊇ 新块去重键集=完整)+ 日期下界
MARGIN_GAP_LOOKBACK_DAYS=35 自然日(≈24 交易日≈深主板 ~55 页,远离墙;更深
缺口归 ps 通道)+ 翻页硬上限 MARGIN_GAP_MAX_PAGES=90(到顶停段不 raise,
03:00 无人值守不炸)+ gapsonly 无视 state 恒从 p1(重翻由 merge 去重吸收,
段末清 state)+ 删跨段 break(七段全查)。TDD +5 例(键集扛行数差/下界+stale
state/硬上限不 raise/缺口日 merge 补齐/段间独立),376 绿。
20.10.6 已知问题登记簿(观察中,勿重复排查)
| 问题 | 状态 |
|---|---|
| hot_rank 采集成率 <50%(挂载 9 交易日落 4 文件,emappdata 夜间开墙断续) | 用户已知晓,观察;单 unit 失败不触断路器次夜重试 |
| margin_sse 曾停 0911(在 TYPES 内) | 09-17 手动触发后直达 0916,定性=VPS 侧文件产出节奏非链路故障;持续观察 03:00 班新鲜度 |
| 快照族上线日恰逢周末=连续多夜零落盘无告警 | §20 坑备案:看目录前先看日志「工作日N天」行 |
| 三表季频新鲜度=披露后最多 ~5 周(ak-monthly 月度洗库) | 设计内,dmsk 层披露次日补新鲜度(§19.3 双层) |
| NAS 独有三域(corpus/dmsk/5m)VPS 侧消费 | 已拍板(09-17):corpus/dmsk 迁 VPS 日镜像+通用分区读取接口(§20.11.2/20.11.3,双机各读各的);5m 留 NAS;语义层(PIT 合并/情绪因子)留因子线消费方 |
20.11 增补 2026-09-17:corpus/dmsk NAS→VPS 每日镜像链(迁移评估落地,用户拍板)
拍板背景:用户问「当初因数据量巨大只放 NAS 的,现在评估哪些可上 VPS,1 年内 不撑爆盘(一年内会扩容)」。实测评估后拍板:corpus+dmsk 两族迁(本节), 5m/factor 产物/LLM/停更尸体不迁。本节修正 §18.1 硬约束 1 的「零存储」(采集 仍 100% NAS、VPS 零 schtask/零采集进程不变,仅新增只读镜像副本)并关闭 §20.10.1 原则 4 挂起项。
20.11.1 评估底数(09-17 深夜实测)
- VPS 预算:C: 180G 总盘剩 63.9G(D: 无盘),主库 39.85G;主库年增保守 估 5-15G(常态 15m+日线增量 ~12MB/天;今年夏天 26G→39.85G 的大头是一次性 历史回灌,已完成)。
- corpus 有效载荷 171M(news_meta 116M/ann_meta 37M/news_fulltext 17M/ ann_pdf 1.2M;state 131M+logs=管线内部件不迁),日增 ~4MB(3 天实测 12.1MB)→ 1 年 ~1.7G。
- dmsk 211M(五域按期分区,最新 dt=2026-06-30),年增 ~20M(季度补分区)。
- 不迁四项:① 5m 库 89.4G>63.9G 放不下且 VPS 无日内消费(原则 3 分置, 扩容后也留 NAS);② factor 产物=派生数据各算各的(NAS 调研产物 450M/VPS 自有 factor_eval.db,拷贝=两份互相漂移说不清权威;研究结论走代码晋升不走 数据搬运——用户 09-17 原话确认);③ LLM-Models 639G(原则 1);④ A股数据 3.0G+minute_kline 2.1G 停更尸体(原则 3)。
- 结论:迁移集 1 年总占用 ~2G ≪ 64G 预算(3%),撑爆风险零;VPS 盘的主 导增长项是主库自身有机增长,扩容主要为它。
20.11.2 镜像链设计
| 维度 | 设计 |
|---|---|
| 方向/通道 | NAS→VPS 推送(SSH 22 出站通=03:00 链每天在用的反向;复用同账号同 key) |
| 载荷 | corpus 四子域(news_meta/news_fulltext/ann_meta/ann_pdf)+ fundamentals/dmsk 五域;排除 state/logs/cron.log/run_*.sh(管线内部件) |
| VPS 落点 | C:\sanguo_vnpy_v2\data\corpus\{四子域} + C:\sanguo_vnpy_v2\data\fundamentals\dmsk\(镜像 NAS 目录结构,消费方按 dt= 分区直读) |
| 调度 | 新 DSM 任务 sanguo-vps-mirror 每日 16:00(corpus 06:00 班典型 10:1x 完赛、dmsk 07:10 早完;16:00 避开交易时段与收盘对账窗、在 18:05 夜班前;当天没赶上的增量次日 diff 自愈) |
| 增量策略 | 分区粒度(dt= 目录/ann_pdf 年目录):本地 journal 记每分区指纹(聚合 bytes+max mtime,/volume1/stock/vps-mirror/journal.tsv),diff 出新增/变化分区→scp -r 整分区覆写推送。幂等可重跑;journal 删除=全量重建;语义=只增不删(远端不镜像本地删除,分区重写靠指纹变化触发重推吸收) |
| 脚本 | repo scripts/nas_sync/push_vps_mirror_daily.sh(基建线→runbook 同步登记;支持 --dry-run 打印将推送清单不传输) |
| 水位线 | 每次推送成功后在 VPS 两族根写 _mirror_watermark.json(last_push 时刻+各 domain max_dt);读取器 get_watermark() 暴露,消费方晨检对表(策略线 09-17 要求,回执见 20.11.5) |
| 日志/监控 | append /volume1/stock/vps-mirror/push.log(每次一行摘要:日期/推送分区数/字节数/耗时);独立任务失败不伤采集本体,无断路器需求(次日 diff 自愈) |
通道细节备案(09-18 首推实测):Windows OpenSSH 作 scp 目标直接可用(正斜杠
C:/... 路径,无需 -O);远端建目录用 PowerShell New-Item -Force(cmd 无
mkdir -p 且逐级链有解析坑);重推已存在分区必须替换语义(先 Remove-Item
再 scp 显式全路径目标——scp -r 依赖 basename 推断,重推落父级散文件)。
任务账号=admin(key 同 03:00 链;避开 root 属主坑,journal/push.log
admin 属主)。
20.11.3 消费接口(用户 09-17 补充拍板:和其他数据一样,双机各有数据和接口)
原则:同一套读取代码,双机各读各的本地副本——代码随 repo 部署两机,路径 经 config 解析后各喂各的本地数据;与 dbbardata/static 的消费模式(口径 4)完全 一致。现状勘测:repo 内尚无任何 corpus/dmsk 读取器(grep 零命中;因子侧 fundamental_pit 读的是 static 基线层镜像),本节为新件。
| 件 | 设计 |
|---|---|
| 路径解析 | 两族独立根+env 覆盖(同 SANGUO_DATA_ROOT 模式,不改部署态配置):SANGUO_CORPUS_ROOT(默认 posix=/volume1/stock/corpus,win=C:\sanguo_vnpy_v2\data\corpus)、SANGUO_FUND_DMSK_ROOT(默认 posix=/volume1/stock/fundamentals/dmsk,win=C:\sanguo_vnpy_v2\data\fundamentals\dmsk) |
| 读取核 | corpus 与 dmsk 同构(dt= 分区 parquet 直存,§19.3)→ 抽通用分区读取核 sanguo_data/partition_reader.py:list_dates(domain) / read_partitions(root, domain, start, end)(扫描分区内 *.parquet 拼接);ann_pdf 按年目录特例只给路径定位不拼 DataFrame。核内零语义(因子线 09-17 契约):不做 as-of/PIT(因子侧 fundamental_pit=唯一正确性模型,两处实现会漂且 PIT 错是静默错);零静默去重(幂等去重是写路径职责,镜像重放/分区重写出重复行消费方要看得见,取哪行=语义决策);dmsk 可选 noticed_by=None 纯过滤参数(文档写明 filter 非 merge) |
| corpus 薄封装 | sanguo_data/corpus_reader.py:get_news_meta(start,end,symbols=None) / get_ann_meta(start,end,symbols=None)(符号过滤下推,事件因子逐股截面;news↔股票若多对多则映射表一并暴露——实施时勘测)/ get_news_fulltext(ids)(按 id 批量:因子回访高信号条目+LLM 分块天然按 id;meta↔fulltext join 键契约落文档)/ ann_pdf_dir(year);ann_meta 透传公告类型/标题(源有页数更好——消费方选择性抽取不盲抽)——列名随源直存零转换(§15.2 双层读法惯例) |
| 容错语义 | 根/分区缺失→空 DataFrame 带 schema 返还,绝不 raise(同 akshare top_holders 空 df 带 schema 惯例;「数据失败≠交易信号」——消费方沿用上次快照,策略线生产铁律);get_watermark() 无水位线文件时返 None。失败分级:缺数据→空 df;数据在但形状错(schema 漂移)→fail loud(见数据契约④) |
| 数据契约(因子线 09-17 四条,文档级) | ① dmsk 五域每行 NOTICE_DATE 必在——实施时逐域实测落 reader docstring,系统性缺域明示(因子侧对缺 NOTICE_DATE 期整期弃用=宁缺毋假红线);② corpus 稳定去重 id(内容 hash)——meta+fulltext 保证或给文档配方,因子幂等计算依赖;若现数据无 id 由 corpus 采集侧补=另一工序,不进镜像链;③ 每域 schema 契约落文档:列名/类型/单位(万元 vs 元)/代码格式(600519 vs 600519.SH)——无文档的零转换逼消费方逆向猜;④ schema 冻结+fail loud:跨分区列集缺失/类型漂移读取核报错不静默 coerce |
| dmsk 薄封装 | sanguo_data/fund_dmsk_reader.py:get_domain(domain, start, end) 五域原始分区读取。语义层留白:「static 基线为主+dmsk 新鲜度补丁」的 PIT 合并(§19.3 下游读法)与情绪/事件因子加工=因子线消费方业务,届时基于本读取核演进,不进数据线;as-of 截断(按 NOTICE_DATE/披露时刻防前视)=消费方语义,读取核只保证 NOTICE_DATE 等源列直存+水位线可查 |
| 测试 | fixture 造 dt= 分区 tmp 树(env 覆盖 root),TDD 覆盖:日期过滤/跨分区拼接/空分区容忍/ann_pdf 年目录/缺根缺分区返空不 raise/水位线读取与缺失返 None/symbols 过滤/ids 批取/noticed_by 过滤/重复行直通(零去重实证)/跨分区类型漂移 fail loud |
仍不做:5m/factor 产物不迁(20.11.1 备案,不再议)。
20.11.4 实施与验收锚点(实施时回填记录)
- TDD:journal 指纹/diff 抽纯函数进 pytest(新增/变化/不变三态+ann_pdf 年
目录粒度);shell 改完必
bash -n。 - 消费接口(§20.11.3):config 根解析+partition_reader+两薄封装+数据契约四条 落 reader docstring(NOTICE_DATE 逐域实测/schema 表/id 配方),fixture TDD(Mac ./venv310);默认根即双机各读各的,零部署配置。
- 部署:先探针确认 03:00 链脚本在 NAS 的实际生效位(homes/admin 安装树 vs
/volume1/stock),新脚本放同位同款分发;DSM 建
sanguo-vps-mirror16:00 (与 03:00 链同账号)。 - 验收:①首推后对账=VPS 侧四子域+dmsk 分区数与总 bytes 逐项对齐 NAS;
②紧接着
--dry-run清单为空(收敛证明);③次晨 16:00 后新 dt= 分区自动 到 VPS;④journal 与 push.log 各就位;⑤双机读取冒烟=NAS 容器内与 VPS venv 各跑get_news_meta/get_domain最近 1 日非空+get_watermark()返到昨夜 16:00 水位。 - 收尾:runbook 登记任务(调度全景+非代码资产清单)+ CLAUDE.md「VPS 零参与」 表述补镜像注记。
20.11.6 实施记录(2026-09-18 凌晨首推战役回填)
commit 链:7e5e720(runner+lib+runbook 登记,TDD 15 例)→ 1b942c0(读取器 三件,TDD 23 例,全套 414 绿)→ 1900be2/8095404/66d450f/efe883b(首推四修) → e97f845(类型兼容精化,416 绿)。
首推五 bug 战役(一夜全踩全修,daily 增量路径从此全部踩实):
① bash 循环 case 守卫把协议 tag=PUSH 误当 fam 全部跳过(bash -n 不验行为——
部署侧必须先 --dry-run 全链);② mkdir 预扫 while-read 管道内 ssh 不带 -n
吃光 stdin(仅首条链执行);③ scp -r basename 推断在重推已存在分区时落父级
散文件(对账解剖实锤 4 stray)→ 替换语义(Remove-Item+显式全路径目标);
④ EM 源全空列写 arrow null 型、同域 part 文件 null↔double 漂移合法 → 读取核
类型兼容类精化(全空列通配/数值族互通,真冲突收窄 text↔num+列集增删);
⑤ ${DRY:+--dry-run} 恒展开(:+ 判非空不判真值)→ plan 永远 dry → journal
永不落 → 显式 DRY_FLAG。
验收终态(09-18 00:39):424 分区 / 393,217,524 字节分毫不差(VPS=
NAS 载荷 corpus 173,003,124+dmsk 220,214,578,另 +2 个 _mirror_watermark.json);
域级散文件归零;瞬时连接超时 1 次被 3 重试吸收;收敛证明=修复后重跑
PLAN push=0 bytes=0 → DONE pushed=0 fail=0(2 秒),journal 落位
/volume1/stock/vps-mirror/journal.json;NAS 真数据读取冒烟绿(news_meta
0917=5,077 行 / fulltext 按 ids 3/3 命中 / dmsk balance dt=2026-06-30 含
noticed_by 过滤 5,572 行、NOTICE_DATE max=披露当日)。
遗留:①每日调度待接——用户倾向复用现有 DSM 任务(评估定稿=挂 corpus
任务尾部:容器完赛 ~10:1x 即推,同日新鲜度优于独立 16:00;dmsk 07:15 早已
完成;失败域用「推送 rc 只记日志不进 corpus 聚合」隔离;03:00 链/dmsk 尾部
=方向/时段/新鲜度全错不可选),待用户确认后改 run_corpus_standalone.sh
尾部+scp 部署;②VPS 侧读取冒烟待 vps-deploy 后(读取器代码随 promote 到
VPS);③CLAUDE.md 注记随下次触达补;④backlog:fulltext(ids) 大载荷时加
分区定位;稳定 id 内容 hash 若现数据无则采集侧补(另一工序)。
20.11.5 消费方征询回执(09-17,讨论制:按合理性采用)
- 策略线(回执入 session 档):硬阻塞诉求=无。真实增益两条——① dmsk T+1 对 value 月度调仓有实质意义(月初 09:30 开火撞财报密集披露期末尾,现最长 5 周延迟=滞后截面;ROE 配对公共报告期交集直接受益;非阻塞,value 一直带 现延迟在跑);② 新闻/公告事件过滤当前零消费方,未来若做=买入前负面黑名单 剔除、候选池级日终粒度即可,现不加策略逻辑(YAGNI,与 20.11.3 留白一致)。 读取形态=日终批量 DataFrame(16:00 推+次日盘前读=天然快照,无需盘前快照 通道)。三点工程要求全部采纳:水位线可查(→20.11.2 水位线行)/断供 降级不 raise 沿用上次快照(→20.11.3 容错语义行,「数据失败≠清仓信号」生产 铁律)/数据截止时点暴露(水位线+NOTICE_DATE 等源列直存;as-of 截断本身留 消费方按各自 PIT 语义做——与因子线分工一致)。另:9-18 miniQMT 停服在即, 语料/财务全落 VPS 本地=交易时点零跨机依赖,方向赞成。
- 因子线(回执入 session 档,先读 spec+自家 fundamental_pit 再答):总评=
方向对不动骨架。a) dmsk 保持原始区间扫描,读取核不内置 as-of——as-of
合并已活在因子侧 fundamental_pit.py 且有测试(NOTICE_DATE≤决策日 asof 前向
填充,NOTICE_DATE 缺失整期跳过=宁缺毋假红线),读取核再做一份 PIT=两处实现
漂移、PIT 错是静默错(前视偏差旧案在档);且 dmsk 按 REPORT_DATE 分区,
「as of D」无法靠分区剪枝、必须行级 NOTICE_DATE 过滤,内置反而掩盖双日期
语义→采纳:核内零语义。两契约级保证(文档非逻辑)NOTICE_DATE 必在/
零静默去重→采纳:数据契约①②;noticed_by 纯过滤参数→纳(标注 filter
非 merge)。b) corpus 三诉求→全纳:fulltext 按 id 批量(接口改
get_news_fulltext(ids))/meta 符号过滤下推(symbols 参数,多对多映射表 实施时勘定)/稳定去重 id(内容 hash,无则采集侧补=边界限定:另一工序 不进镜像链);ann_pdf 路径定位够+ann_meta 透传类型/标题,文本抽取/缓存 归因子算力域。c) 零转换 OK 但要 schema 契约文档(列/类型/单位/代码格式, 历史吃亏多次)+跨分区 schema 冻结或 fail loud→采纳:数据契约③④ (选 fail loud 并入失败分级;实施精化=全空列通配/数值族互通,见 20.11.6 ④)。镜像链本身无异议。
实施版 review 回执(09-18,双线闭环):策略线通过(三点工程要求逐项 核验落地;两条非阻塞观察入 backlog:get_news_fulltext(ids) 全分区扫描随语料 增长线性变贵→量大时加 start/end 或按 meta 定位分区;列序漂移误报→已顺势改 按列名比对不再误报)。因子线精化认+必修 1+记录 2:契约④精化认可(按原 字面执行会拒掉全部合法数据);必修#1 null 桥接洞(因子线实测复现:首文件 全空列把 num 与 text 桥接,两具体类型从未直接对撞→concat 静默混装零 raise, 恰是契约④要防的静默 coerce 被绕过)→已修:每列维护 resolved=首个非空具体 类型、null 永不推进 resolved、后续非空类型冲突即 raise、列集按名比对(列序 漂移不误报),+3 测试(三段桥 raise/null 隔离后续冲突仍 raise/列序漂移 tolerated)共 419 绿;记录②NOTICE_DATE 空值行被 noticed_by 滤除=有意 宁缺毋假语义(docstring 已写明勿当 bug 修);记录③fulltext 扫描成本同策略 线观察,入 backlog。
参考(调查来源)
- xtdata 官方:https://dict.thinktrader.net/nativeApi/xtdata.html
- akshare 指数:https://akshare.akfamily.xyz/data/index/index.html
- akshare 基金:https://akshare.akfamily.xyz/data/fund/fund_public.html
- akshare 债券:https://akshare.akfamily.xyz/data/bond/bond.html
- baostock API:https://www.baostock.com/mainContent?file=pythonAPI.md
- 国证指数网(深证历史):http://www.cnindex.com.cn/module/index-detail.html?indexCode=399001
- 新浪历史成份:http://vip.stock.finance.sina.com.cn/corp/go.php/vII_HistoryComponent/indexid/000852.phtml
- HKEX 沪深港通持股记录查询(季度快照):https://www3.hkexnews.hk/sdw/search/mutualmarket_c.aspx (深股通加 ?t=sz)
- HKEX 沪深港通每日统计(十大活跃股):https://www.hkex.com.hk/chi/csm/DailyStat/data_tab_daily_{YYYYMMDD}c.js
- 东财数据中心(两融/龙虎榜席位):https://datacenter-web.eastmoney.com/api/data/v1/get (reportName=RPTA_WEB_RZRQ_GGMX / RPT_BILLBOARD_DAILYDETAILSBUY)
- QLib 数据层:https://qlib.readthedocs.io/en/latest/component/data.html
- 现有缺口设计:
docs/static_data_gaps_design.md