Files
sanguo_vnpy_v2/docs/superpowers/specs/2026-07-21-data-source-fusion-design.md
T

119 KiB
Raw Blame History

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 格式:600519 vs sh.600000 vs 600519.SH
  • exchange 命名:SSE vs SH
  • 复权口径: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 处)

  1. 日线 OHLCV:dbbardata ∩ daily_baostock_full ∩ parquet raw(三处)
  2. 估值 PE/PB:akshare valuation ∩ daily_baostock_full(peTTM/pbMRQ)
  3. 15min:dbbardata ∩ parquet minute_15
  4. 基本面:akshare 三表 ∩ miniQMT PershareIndex ∩ baostock 季频
  5. 成份股: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 — 治幸存者偏差 + 策略核心缺口

  1. 历史成份股:深证/国证(index_detail_hist_cni)+ 中证1000/2000(新浪 vII_HistoryComponent)+ 300/500/50(baostock 已有)
  2. ETF 全市场日线:xtdata universe 改 沪深A股∪沪深ETF∪沪深基金 + dividend_type='front'(改 build_daily_from_xtdata.py:40 + daily_update_xtdata.py:114)
  3. 退市股 K 线:baostock query_all_stock 筛 status=0 + query_stock_basic 退市日期 + 逐只 K → daily_baostock_full

P1 — 策略增强

  1. 申万行业 SW1/2/3(xtdata get_sector_list)+ 历史变动
  2. 龙虎榜(xtdata get_longhubang)
  3. 合约信息涨跌停/ST(xtdata get_instrument_detail)全 A 入库
  4. 可转债(akshare bond_zh_hs_cov_min + 转股价调整)
  5. 研报/一致预期 EPS(akshare stock_research_info_em)

P2 — 按需

  1. 股东户数 / 除权明细 / 业绩快报 / 大宗交易 / 宏观 / 期货

融合层(贯穿)

  1. 归一化库(vt_symbol/exchange/factor/volume 映射)
  2. LocalUnifiedProvider(读权威表 + 归一化 + 网络兜底)
  3. 完整度监控报表(每类覆盖率/缺口,源退化早发现)

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 复权走 xtdata dividend_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+可回滚+审计日志)

  1. 存量垃圾清理(_staging_xtdata 14万文件 / _xtdata.tar 1.4G / 归拢 cta_* dbg_* → backtest_files/)
  2. config 统一 VPS 路径(NAS 仅备份)
  3. 成份股合并(bs_index_constituent + index_const_hist union → constituent_unified,按指数代码去重,新浪300/50丢弃)
  4. daily_baostock_full 拆分(OHLCV→dbbardata('d') 含退市;pe/pb→valuation_baostock/.parquet;旧表 rename _old)
  5. 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 / tushare limit_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.sh TYPES 原写死老 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 硬约束(用户原话级)

  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 侧调度。
  2. 采集进程=一次性容器,与 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 链(内部搬运)。
  3. 时间带:全部采集限于 00:30–17:30,避开 18:05–23:45 傍晚带(VPS 夜任务密集+家宽使用)。 唯一日窗=每日 06:00 起(见 18.3)。
  4. 慢爬纪律:单进程单线程、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 晨拉零损失):

  1. 公告增量(巨潮,5400 req @1/s≈1.5h):每股 seDate=T-1T 两天窗+announcement_id 短窗去重 (同 margin_sse 两天窗自愈模式,漏一天次日自动补上);
  2. 新闻增量(东财 search-api=akshare stock_news_em 同款端点,~5400 req @1/s≈1.5h):带摘要, 每股最近100条,新 art_code 入 news_meta;
  3. 新闻全文(东财文章页,@2/s,~1万 req≈1.5h):仅下载昨日新发现的 art_code 正文;
  4. 当日 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 验收标准(实施完成的定义)

  1. daily lane: T+1 晨抽查 5 股(超热/热/中/冷/ST)——show_time/ann_time∈[T-1,T] 的条目 全在且 id 无重复;日志限速合规(平均间隔≥设定值,零 429/403 连击)。
  2. ann_meta 回补: 600519 年报 2001 起逐年可查;announcement_id 全局无重;year×count 曲线 单调合理(早年稀疏→近年 ~130 万/年)。
  3. news 回补: 600519 最早条目落 2023-09±1 月(实测硬顶对齐);depth_summary.json 全量产出。
  4. PDF: 抽 20 份跨年份可打开(%PDF 魔数+size>0+meta 可反查路径);索引行数=文件数。
  5. 边界: /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 类),双进程零竞写。
  6. 测试: 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 字面的四项实施偏差(均为实测倒逼,语义不劣化):

  1. 股票池源=巨潮 szse_stock.json(6247 含退市 000003+北交 920001→A 前缀过滤 6168), 非 NAS 副本库 distinct symbol——orgId 是按股查询硬前提且退市覆盖实测更全。
  2. 单实例锁=flock(非 5m 的 pid 活性同款)——docker run --rm 各容器独立 PID namespace, pid 检测跨容器失效;flock 内核级经 bind mount 同 inode 跨容器互斥,进程死自动释放 无陈旧锁(让路契约同款,实测二实例 EXIT=3)。
  3. 业绩快报无服务端类别码(category_yjkb_* 无效码被服务端静默忽略返回全量,官方 history-notice.js 码表无此项,单股对照实测)——PDF 六类=五服务端码+客户端标题谓词 「业绩快报」(announcementType 数字码 012111 仅作参考);announcementTypeName 恒 null, ann_meta.ann_type 存原始数字码串。
  4. 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 拆解):

  1. 沪深退市 355 只全周期缺(F10 实测拉 000003 也空,按期接口是唯一源);
  2. 北交退市 258 只同缺;
  3. 北交现役 340 只三表=空文件(数据在按期接口可取);
  4. 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(DSM sanguo-fundamentals-daily 07: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-domain BACKFILL_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.py TYPES + 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(akshare stock_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-1T(与主表 dragon_tiger 的 TT 并存:席位供应晚,保守窗) {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 绿。
  • 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-gaps gapsonly 连续 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 发对账),三项修正:

  1. 「DATE 视图服务端锁沪 2,000」系结算时序假象,非宇宙锁:已结算日(09-08)实测 count=4443 全市场(SCODE 升序首页 000001/000002…全深主板);未结算当晚同视图只回 沪段 2,000。深段 EM 侧 T+1 且跨周末顺延(000002 周日夜最新仅 09-10)。 → 日采无需 TMC 段舞步,结算后 DATE 单查即全市场。
  2. 日采窗口修正(09-11 洞的机制):原 T-2T 当晚拉 T → 沪半截落盘即标 marker → 深段永久洞(09-11 实例:文件沪2000/深0)。修=ak_events_wrapper margin 段改 **T-3T-1 仅工作日**(拉的全是已结算日),周六 gaps 兜底保留;09-11 marker 待 重跑 flush 后删除,周一晚窗口自愈。
  3. 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 转达口令批次):

  1. 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 窗重拉。
  2. 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 可达性=部署后首跑验证项。
  3. 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=True raise 语义(查询日=q_end+45 必有数据)。
  4. 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/路径 不变仅频率降)。
  5. margin_sse 窗口含 T 日每晚必 1 failed:EM 沪 DATE 视图 T+1 供应 (本条与 §20.7 09-13 修正同源——TMC 深段已改 T-3T-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 拍板,覆盖此前所有归属表述)

  1. LLM-Models 639G 忽略:NAS 上 cfdaily 账号 2026-05-12 的 ModelScope 批量 下载(6 模型仅 GLM-5.1-Int4 有内容,目录内有 download_log.txt/教程取证), 非本项目资产。
  2. VPS 采集 → NAS 必须同步(统一铁律):VPS=下载主体(公网出口直连各源), NAS 每日定时同步=原始设计常态,「双份」不是差异;活的采集面在 NAS 缺 同步=缺口必须修正(当日修正两例见 20.10.4)。停更归档层除外(原则 3)。
  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,均非我方管线)。
  4. 消费不跨机: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-3T-1)+margin_sse(T-2T-1)+dragon_tiger_seats(T-1T)+nb_daily(T-1T)+nb_hold(季) 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 当日修正两例(缺口实例,模式备案)

  1. 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,纳入域上线检查单。
  2. 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 通道自 44d3ab9 有 (DATE,SCODE) merge dedup 防线,五修①重构 recent_blocks 通道漏抄。修复= _fetch_tmc_block 块出口 drop_duplicates(容错键列),TDD +1 例 372 绿。 存量脏数据:0915/0916 文件 dup2,445 行/日(消费端两融余额会翻倍, 勿在修复前消费)。处置终态(09-17 晚更新):六修 d94936c 已上 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 实施与验收锚点(实施时回填记录)

  1. TDD:journal 指纹/diff 抽纯函数进 pytest(新增/变化/不变三态+ann_pdf 年 目录粒度);shell 改完必 bash -n。
  2. 消费接口(§20.11.3):config 根解析+partition_reader+两薄封装+数据契约四条 落 reader docstring(NOTICE_DATE 逐域实测/schema 表/id 配方),fixture TDD(Mac ./venv310);默认根即双机各读各的,零部署配置。
  3. 部署:先探针确认 03:00 链脚本在 NAS 的实际生效位(homes/admin 安装树 vs /volume1/stock),新脚本放同位同款分发;DSM 建 sanguo-vps-mirror 16:00 (与 03:00 链同账号)。
  4. 验收:①首推后对账=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 水位。
  5. 收尾: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。

参考(调查来源)