Appearance
量化研究项目设计文档
- 日期: 2026-06-11
- 作者: someu
- 状态: 已批准设计,待生成实现计划
1. 目标
搭建一个个人 A股日频因子/策略研究项目骨架。重点是研究迭代速度与可复现性:能快速验证因子/策略想法,做 IC/分层分析,并用 qlib 做回测;暂不接实盘。
2. 范围与非目标
范围(In scope)
- A股(沪深)日频数据的采集、清洗、存储
- 因子计算、因子评价(IC / RankIC / ICIR / 分层 / 相关性)
- 基于 qlib 的模型训练(因子合成,可选)与回测
- 配置驱动的可复现实验 + Notebook 探索
- 报告与可视化(净值、回撤、IC 衰减、分层)
非目标(Out of scope,本期不做)
- 实盘交易、下单执行、券商对接
- 分钟/Tick 等更高频数据(架构预留,不实现)
- 多市场(港股/美股/期货/crypto)——架构上 adapter 可扩展,本期只做 A股
- 多人协作的中心化数据库(本期本地文件即可)
3. 技术选型
| 维度 | 选型 | 理由 |
|---|---|---|
| 语言 | Python | 量化研究生态成熟 |
| 数据存储 | 本地 Parquet/CSV + pandas | 中小数据量,轻量免运维 |
| 数据源 | tushare + 已有本地数据 | tushare 质量好;本地数据走统一适配 |
| 回测/模型引擎 | qlib(微软) | 专为 A股 ML 因子研究设计,数据+因子+模型+回测全家桶 |
| 工作流 | Notebook 探索 + src/ 库 + 配置驱动 pipeline | 兼顾探索灵活度与可复现性 |
关键约束:qlib 使用自有二进制格式(.bin)和 workflow 范式(yaml + recorder),不直接读 parquet。因此需要一个 parquet → qlib .bin 的转换层;同一份 parquet 数据湖同时服务 pandas 探索与 qlib 回测。
4. 架构:分层设计(方案 B)
qlib 作为回测/模型引擎,藏在薄接口之后。src/quant/ 包按职责显式分七层,每层通过定义良好的接口通信、可独立理解与测试:
- data/ 采集层 — adapter 模式封装数据源(tushare/local),统一接口;交易日历、股票池(剔 ST/停牌/次新)。
- storage/ 存储层 — parquet 数据湖读写;
parquet → qlib .bin转换。 - factors/ 因子层 —
Factor抽象(compute(df) -> Series)、因子库、注册表、预处理(去极值/标准化/中性化)。 - research/ 因子评价层 — pandas 侧的 IC/分层/相关性分析。
- models/ 模型层(可选) — 封装 qlib 模型(LightGBM/线性)做因子合成。
- backtest/ 回测策略层 — 封装 qlib 引擎;选股/调仓策略;A股交易成本。
- reports/ 报告层 — 绩效指标与绘图。
qlib 隔离原则:qlib 仅出现在 storage/qlib_dump.py、backtest/engine.py、models/trainer.py 三处,其余层零依赖 qlib,便于测试与将来替换引擎。
5. 目录结构
text
quant/
├── README.md
├── pyproject.toml # 依赖 + 把 src/quant 装成可 import 的包
├── .gitignore
├── .env.example # tushare token(不入库)
├── Makefile # make data / factor / backtest 快捷入口
│
├── configs/ # 配置驱动 → 可复现实验
│ ├── data.yaml # 数据源、股票池、时间区间
│ ├── factors/momentum_20d.yaml
│ ├── qlib_workflow/lgb_alpha158.yaml
│ └── backtest/topk_dropout.yaml
│
├── src/quant/ # 核心库(pip install -e .)
│ ├── config.py # 配置加载/校验(pydantic)
│ ├── data/ # ① 采集层(adapter 模式)
│ │ ├── sources/
│ │ │ ├── base.py # DataSource 抽象基类
│ │ │ ├── tushare_source.py
│ │ │ └── local_source.py
│ │ ├── download.py # 拉取 → 原始 parquet(按交易日增量)
│ │ ├── calendar.py # 交易日历
│ │ └── universe.py # 股票池(剔 ST/停牌/次新)
│ ├── storage/ # ② 存储层
│ │ ├── parquet_store.py # parquet 数据湖读写
│ │ └── qlib_dump.py # parquet → qlib .bin 转换
│ ├── factors/ # ③ 因子层
│ │ ├── base.py # Factor 抽象 compute(df)->Series
│ │ ├── library/{momentum,value,volatility}.py
│ │ ├── registry.py # 因子注册表,按名取用
│ │ └── preprocess.py # 去极值/标准化/中性化
│ ├── research/ # ④ 因子评价(pandas 侧)
│ │ ├── ic.py # IC / RankIC / ICIR
│ │ ├── layering.py # 分层回测 / 单调性
│ │ └── correlation.py # 因子相关性 / 拥挤度
│ ├── models/ # ⑤ 模型层(封装 qlib 模型,可选)
│ │ └── trainer.py # LightGBM/线性,因子合成
│ ├── backtest/ # ⑥ 回测/策略层(封装 qlib 引擎)
│ │ ├── engine.py # 薄封装:调 qlib workflow
│ │ ├── strategy.py # 选股/调仓策略
│ │ └── cost.py # A股成本:印花税/佣金/滑点/涨跌停
│ ├── reports/ # ⑦ 报告层
│ │ ├── metrics.py # 年化/夏普/回撤/换手
│ │ └── plots.py # 净值/IC衰减/分层图
│ └── utils/{logging,io}.py
│
├── pipelines/ # 可复现入口(配置驱动,串各层)
│ ├── run_download.py # configs/data.yaml → 原始 parquet
│ ├── run_dump_qlib.py # parquet → qlib .bin
│ ├── run_factor.py # 算因子 → 落盘
│ ├── run_research.py # 因子评价(IC/分层)→ 报告
│ └── run_backtest.py # qlib 回测 → 报告
│
├── notebooks/ # 探索(import quant 复用 src)
│ ├── 00_data_explore.ipynb
│ ├── 01_factor_idea.ipynb
│ └── 02_strategy_review.ipynb
│
├── data/ # .gitignore
│ ├── raw/ # 原始下载
│ ├── processed/ # 清洗后 parquet 数据湖
│ ├── qlib_cn_data/ # qlib 二进制
│ └── factors/ # 因子值落盘
│
├── results/{reports,figures}/ # 实验产出
├── mlruns/ # qlib recorder(.gitignore)
└── tests/ # 关键单测
├── test_factors.py
├── test_cost.py
└── test_universe.py6. 数据流(端到端)
text
tushare / 本地
│ run_download.py (configs/data.yaml)
▼
data/raw ──清洗──▶ data/processed (parquet 数据湖)
│ │
│ run_dump_qlib.py ├─(pandas) factors/library ─▶ data/factors
▼ │ │
data/qlib_cn_data(.bin) │ ▼ research/ (IC/分层) ─▶ results/reports
│ │
└──────┬───────────────┘
▼ configs/qlib_workflow
models/trainer (因子合成, 可选) ─▶ backtest/engine (qlib) ─▶ results + mlruns ─▶ reports/plots7. 关键设计决策
- 因子双轨:
Factor.compute(df) -> Series同一份实现,既供research/用 pandas 算 IC/分层,也能注册成 qlib 特征进回测——避免一个因子写两遍、两边口径不一致。 - qlib 隔离:见第 4 节,qlib 仅限三处文件,其余层零依赖。
- 配置驱动可复现:每个
pipelines/run_*.py只接受一个 config 路径,用 pydantic 校验;configs/入库,data/ results/ mlruns/全.gitignore。实验 = 一份配置 + 一条命令。 - A股特殊规则集中处理:交易日历、涨跌停(涨跌停价位不可成交)、停牌/ST 过滤、复权、印花税单边、T+1 限制——集中在
data/universe.py+backtest/cost.py,不散落各处。 - 数据与代码分离:原始/中间/产出数据全部本地化并
.gitignore;唯有configs/与代码入库,保证仓库轻量且实验可复现。
8. 错误处理与边界
- 数据源适配:
DataSource基类统一异常类型;tushare 限频 → 重试 + 退避。 - 增量更新:
run_download按交易日增量拉取,避免重复全量请求。 - 数据校验:落盘前校验缺失值、重复行、字段类型;显式防护前视偏差(因子只用 T 日及之前信息)。
- 配置校验:pydantic 在 pipeline 入口处对 config 做强校验,早失败。
9. 测试策略
不追求覆盖率,只锁关键正确性:
- 成本模型
test_cost.py:涨跌停价位不可成交、印花税单边、佣金/滑点计算。 - 因子计算
test_factors.py:用构造的小样本对拍预期值;防前视偏差。 - 股票池
test_universe.py:ST/停牌/次新正确剔除。
10. 依赖(初步)
python>=3.10、pandas、pyarrow、numpy、pyqlib、tushare、pydantic、pyyaml、matplotlib、pytest、lightgbm(模型层)。具体版本在实现计划阶段锁定。
11. 后续扩展(架构已预留,非本期)
- 接 alphaear-stock skill 作为一个额外
DataSourceadapter。 - 扩展到分钟频/多市场(新增 source adapter + 存储分区)。
- 接入实盘信号/执行层(在
backtest/之外新增live/层)。