自建 A 股全市场量化分析系统(
/opt/quant-screener),经历 v0 → v3 三代模型演进,从「因子打分」走向「全互联预测」。本文详解数据管道与模型架构,配套 skill 为quant-data-pipeline与quant-ml-pipeline。
一、项目概述
- 位置:
/opt/quant-screener(132 个 Python 文件,git 全程留痕) - 目标:全市场 5000+ 标的的端到端股票收益预测
- 架构:三层 —— Raw(原始数据)→ Preprocess(特征工程)→ AI Analysis(模型/报告)
- 现状:v3 全互联模型,IC=0.329 / RankIC=0.350 / IR=2.01,8 层互联特征
二、数据管道
2.1 数据源
| 数据 | 规模 | 说明 |
|---|---|---|
| A股日线 | 8,488 标的(1972-08 ~ 2026-08-28) | AKShare 主采,kline_cache.db(3.9G) |
| 新闻库 | 11 万+ 条 | 新闻联播/百度经济/同花顺/东财/财新 6 源 |
| 宏观因子 | USDCNY / CN10Y / SSE50 | 837 天 |
| 期货主连 | 33 品种 | 股指/商品/国债 |
| 走势模式 PCA | 58,831 样本 → 10 维 | 20 日走势压缩 |
2.2 采集自动化
- 每日收盘采集:15:30(峰谷后 18:30)AKShare 全市场快照,约 5500 只,5min cache
- 新闻增量:每小时实时采集,v2 每 30 分钟 collect_daily()
- 新浪限流重试:fetch_spot_daily.py 内置 canonical 重试——限流 2 次 180s 自动重试后第 3 次成功(08-27 实战生效)
- 断点续传 + 幂等去重:防重复采集
2.3 数据存储
- SQLite 单文件:
kline_cache.db(3.9G 行情)、news_db_v2.db(新闻全文 + 情感特征) - OSS 多桶备份:备份桶 / 资料桶 / 量化数据专用桶
- 本地 SQLite 作为 24h 缓存,daemon 启动时从 OSS 拉取,分析完推送回 OSS
2.4 配套 skill:quant-data-pipeline
核心原则(skill 内固化的经验):
- 数据优先:「方法不是问题,获取数据才是主要要求。不因工具限制放弃数据源——urllib 不行就用 CloakBrowser,CloakBrowser 超时就加重试机制,最终目标是数据完整」
- 条数不设上限:每个采集源尽可能多拉取,默认目标 1000 条/平台/次
- 主动报告进度:长任务每一步完成后立即输出耗时和里程碑
- 网络搜索备选:DuckDuckGo 超时后必须尝试 CloakBrowser/Playwright 再放弃
三、模型演进路线
3.1 v0 基线(IC 0.090)
154 因子简单打分,验证可行性。Ridge 回归基线。
3.2 v1(IC 0.145)
加入交互项,因子间关联性显性建模。
3.3 v2(IC 0.238)
200 因子,引入横截面 + 板块 + 宏观维度。
3.4 v3 全互联(IC 0.329 / RIC 0.350 / IR 2.01)
核心哲学:世界是互联的
「分析股票不能只分析股票。世界是相互关联的。」——用户 (2026-07-29)
关键纠正案例(skill 内记录):
「我给你的思想不是只在新闻上。」——用户 (2026-07-29)
最初拿到「世界互联」思想后只应用到了新闻情感上,用户当场纠正。教训:拿到高层次思想,要问每个方面是否都符合,而不是挑一个最明显的特征加上去就交差。
互联性检查清单(每次应用新思想时必须过):
- 所有 154 个技术因子 → 是否都是孤立计算的? → 应该做 PCA/横截面
- 板块划分 → 是否只是标签? → 应该反映相互影响
- 新闻 → 是否只是个列特征? → 应该有个股/板块/市场三级传导
- 期货 → 是否只是数据? → 应该映射到相关股票的板块
- 目标变量 → 是否是绝对的? → 应该考虑相对排名
8 层互联架构
1 | 因子PCA(154→15个主成分) + 横截面PC(百分位排名) |
- 横截面因子 PCA:跨股票 PCA 而非逐股算——每只股票相对全体股票的排位
- 走势模式 PCA:验证「股价走势只有有限种形态」——10 个 PC 分(趋势延续/均值回复/突破等)
- Ridge 回归:64 原始特征 → IC 筛选(>0.005)→ 去相关(≤0.85)→ 40 有效特征
核心发现:横截面相对排位比绝对数值更具预测持续性——「股票的相对强弱决定未来收益」在回测中持续成立。
3.5 训练管道
- 训练窗口:滚动至最新交易日(2024-01 至 2026-08,样本 127,993)
- 样本构成:股票 5,195 + 期货 33
- 耗时:约 8.5-20 分钟(1.8G 内存机器,特征构建占大头)
- 每日迭代:工作日 19:00 自动训练新模型
四、工程挑战与解决
4.1 1.8G 小内存机上的训练 OOM
全量 12 万样本训练多次 OOM。解法组合拳:
- 子进程隔离(_pred_worker.py)
- 循环内定期 gc + 训练后释放大结构(commit 6dbabd6「训练内存卫生」)
- 窗口错开(训练 19:00 与采集 18:30 分开,避免内存叠加)
- 08-26 起 OOM 连续多日未复发
4.2 走势特征缺失断崖
预测期 9 个 PATTERN_PC 特征全 0(20 日采样点对齐问题——pattern_pcs_update 是 20 日采样,预测日非采样点时 0 填充)。解法:二分查找最近可用采样点(commit db8a7a8),覆盖至 4,958 只。
4.3 停牌脏数据崩溃
OHLC=0 占位行导致 SVD 不收敛。解法:训练前过滤停牌行(commit 25307d0)。
4.4 报告假预测问题
早期 market_report 用 np.random.randn 造假预测。修复:接入真实 v3 模型子进程 worker,失败回退 picks.json 快照(commit 489a846)。教训:绝不假装成功,失败要报告原因。
4.5 新闻特征停更
fix_news_v2 日期解析 bug(时间戳被当字符串比较),新闻特征停更 07-29→恢复至 08-11(commit 3d32dc2)。
4.6 期货数据静默停更
2026-08-27 反思发现:期货数据 fut_* 停在 07-29 约一个月未更新——任务在跑、无报错、退出码 0,但上游数据源停更导致特征悄悄变 0。「静默失败」不止任务不跑一种形态。教训:验证步骤的核对范围要覆盖全部特征源。
4.7 +inf% 数据质量修复
2026-08-28 修复:market_report.py 三处 20 日涨跌幅除零,4 只停牌复牌股 20 天前 close=0 → numpy inf 进领涨榜和板块均值。处置:新增 pct20 助手排除无效值 → 隔离验证 → 全量跑 0 处 inf(创业板均值 +inf→+9.25%、中小板 +inf→+8.41%)→ git 提交 7b02380。验证脚本 11/11 断言 PASS(详见量化系统二篇)。
五、模型管理
5.1 文件规范
- 模型带时间戳:
v3_20260828_1931.pkl,每日收盘后训练新版本 registry.json记录部署历史:IC / RankIC / IR / 特征数全透明- 文件管理铁律(用户 2026-07-30 明确下达):
「以后不要把这些文件放在 tmp 里面,是哪个项目就放进对应文件夹,没有就创建,全部加上 git,所有代码要注释,记牢了」
- 每次创建/修改脚本必须检查:项目目录?分类正确?硬编码 /tmp 改 data/?git commit?docstring?
5.2 门控逻辑
- BEST_VALID_IC=0.327 阈值:新模型 Valid IC 必须超过线上才替换 registry
- 08-24~08-27 的 pkl 都在但全部 <0.327 未进 registry——这是设计行为,不是静默丢失
- 教训:交付核对必须查 pkl 文件本身,registry 只是门控结果不是证据
5.3 版本历史
| 版本 | 特征 | IC | 说明 |
|---|---|---|---|
| v0 | 154因子 | 0.090 | 基线模型 |
| v1 | 154+交互 | 0.145 | 加入交互项 |
| v2 | 200因子 | 0.238 | 横截面+板块+宏观 |
| v3 | 64→40 | 0.329 | 全互联+模式PCA+期货 |
六、配套 skill:quant-ml-pipeline
端到端管道 skill,包含:
- 触发词:train pipeline / factor expansion / stock prediction / v3 model / improve ic 等
- 架构文档:8 层互联的完整实现说明
- 用户思想记录:世界互联哲学的两次纠正案例
- 文件管理铁律:目录规范 + git 纪律
- 经验教训:OOM 处理、特征断崖修复、门控逻辑
这个 skill 的价值在于:它把「用户的高层思想 → 具体实现」的转化过程完整记录下来,包括踩过的坑和用户的纠正,后续训练/调优直接复用,不用重新探索。