27 KiB
A股个人量化选股与回测平台架构
版本:v2.0
定位:个人开发、A股、中低频选股/回测、AI Agent 二次开发
数据源优先级:Tushare > 新浪财经
当前数据库:SQLite
未来数据库:MySQL
核心量化引擎:Qlib
前端:React / Next.js
后端:FastAPI + Python
1. 项目目标
本项目不是简单给 Qlib 套一个 Web UI,而是构建一个独立的个人 A 股量化研究平台。
核心目标是形成完整的:
数据
↓
因子
↓
因子研究
↓
复合因子 / 模型
↓
股票筛选
↓
交易信号
↓
组合构建
↓
回测
↓
Experiment
↓
实盘前候选与信号
总体业务架构:
Web / AI Agent
↓
Research Specification
↓
Application Services
├── Data Service
├── Universe Service
├── Factor Service
├── Factor Research Service
├── Selection Service
├── Signal Service
├── Portfolio Service
├── Model Service
├── Backtest Service
└── Experiment Service
↓
Quant Engine
├── Qlib
└── ML
↓
Standardized Results
↓
SQLite / Parquet / Qlib Dataset
AI Agent 作为独立能力层,通过受控 Tool 调用上述服务,而不是直接操作数据库或随意修改 Qlib 内部代码。
2. 总体架构
┌──────────────────────────┐
│ React / Next │
│ │
│ Dashboard │
│ 股票池 │
│ 因子研究 │
│ 复合因子 │
│ 股票筛选 │
│ 交易信号 │
│ 组合管理 │
│ 回测 │
│ Experiment │
│ AI Research │
└────────────┬─────────────┘
│ REST / SSE
▼
┌──────────────────────────┐
│ FastAPI │
│ │
│ API / DTO / Validation │
│ Job / Research Spec │
└────────────┬─────────────┘
│
┌───────────────────────────┼───────────────────────────┐
│ │ │
▼ ▼ ▼
Data Services Research Services Agent Service
│ │ │
│ ┌───────────┼────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ ▼
│ Factor Selection Signal Agent Tools
│ Research Engine Engine
│ │ │ │
│ └───────────┼────────────┘
│ ▼
│ Portfolio Engine
│ │
│ ▼
│ Backtest Engine
│ │
│ ▼
│ Qlib / ML
│
▼
DAO / Repository
│
├── SQLite
├── Parquet
└── Qlib Dataset
3. 核心设计原则
3.1 Qlib 是量化计算引擎,不是整个业务系统
Qlib 主要负责:
- Feature / Dataset
- 模型训练
- Prediction
- 部分 Portfolio
- Backtest
- 分析工具
本系统自己的业务层负责:
- 股票池
- 因子定义
- 因子研究
- 复合因子
- 股票筛选
- 交易信号
- 组合构建
- 策略版本
- Experiment
- AI Agent
因此:
Qlib
=
Quant Engine
本项目
=
Quant Research Platform
3.2 因子研究、股票筛选、交易信号必须分离
这是本架构的核心设计原则。
Factor Research 回答:
这个因子有没有预测能力?
Selection Engine 回答:
在某一个历史/当前时点,哪些股票符合策略条件?
Signal Engine 回答:
什么时候应该买、卖或继续持有?
Portfolio Engine 回答:
买哪些股票、买多少、什么时候调仓?
完整关系:
Factor
↓
Factor Research
↓
Composite Factor / Model
↓
Selection Engine
↓
Candidate Stocks
↓
Signal Engine
↓
BUY / SELL / HOLD
↓
Portfolio Engine
↓
Backtest
4. 数据源架构
Data Service
│
┌────────┴────────┐
▼ ▼
Tushare Sina
Primary Secondary
│ │
└────────┬────────┘
▼
Normalization
│
Validation
│
Storage
第一优先级:Tushare
用于:
- 股票基本信息
- 日线行情
- 复权因子
- 指数
- 财务数据
- 分红送转
- 停复牌
- 行业/概念
- 其他可用数据
第二优先级:新浪财经
主要作为:
- Tushare 数据缺失补充
- 行情数据校验
- 特定实时/准实时数据补充
新浪数据必须经过统一 Adapter,禁止业务代码直接调用新浪接口。
5. 数据采集流水线
Scheduler
↓
Data Source Adapter
↓
Raw Response
↓
Schema Validation
↓
Normalization
↓
Deduplication
↓
Business Validation
↓
DAO
↓
SQLite
↓
Parquet Export
↓
Qlib Dataset
目录:
data/
├── sources/
│ ├── base.py
│ ├── tushare.py
│ └── sina.py
├── normalizers/
├── validators/
└── service.py
业务层只依赖:
MarketDataProvider
而不是:
TushareClient
6. 数据存储架构
业务元数据
↓
SQLite
历史/分析型大数据
↓
Parquet
Qlib 计算数据
↓
Qlib Dataset
实验/策略/任务元数据
↓
SQLite
SQLite 用于:
- 股票基础信息
- 数据源状态
- 数据同步记录
- 因子定义
- 因子研究记录
- 策略定义
- 选股规则
- 信号规则
- 组合配置
- 回测配置
- Experiment metadata
- Job
- 用户配置
- 系统配置
SQLite 不建议长期承载超大规模原始行情明细。
7. DAO / Repository 设计
推荐:
SQLAlchemy 2.x
+
Repository Pattern
+
Pydantic DTO
业务层禁止直接:
sqlite3.connect(...)
也禁止在 Service 中直接写 SQL。
必须:
Service
↓
Repository / DAO Interface
↓
SQLite Repository
未来:
Service
↓
Repository Interface
├── SQLite Repository
└── MySQL Repository
数据库切换主要通过:
DATABASE_URL
例如:
SQLite:
sqlite:///./data/quant.db
MySQL:
mysql+pymysql://user:password@host/quant
8. 核心数据库表
stock
stock_daily
stock_adjust_factor
industry
stock_industry
index
index_daily
index_constituent_history
trading_calendar
suspend_data
stock_st_data
financial_indicator
income_statement
balance_sheet
cashflow_statement
factor_definition
factor_test
factor_composite
factor_composite_component
universe
universe_rule
selection_rule
selection_result
selection_snapshot
signal_rule
signal_event
strategy
strategy_factor
strategy_selection
strategy_signal
strategy_portfolio
portfolio
portfolio_position
backtest
backtest_trade
backtest_position
backtest_metric
experiment
experiment_artifact
experiment_factor_result
experiment_selection_result
experiment_signal_result
job
data_sync_log
selection_result 保存某个研究时点的选股结果:
selection_id
strategy_id
as_of_date
symbol
rank
score
selection_reason
signal_event 保存交易信号:
signal_id
strategy_id
symbol
signal_date
signal_type
score
trigger_reason
price
这样系统不仅能回答:
这次回测赚了多少钱?
还能够回答:
2023-08-15 为什么选择这只股票?
以及:
2026-09-08 当前有哪些股票满足策略?
9. 时间与未来函数防护
所有研究数据必须明确:
trade_date
report_date
announce_date
effective_date
as_of_date
财务数据必须按照 announce_date 控制可见性。
禁止:
使用未来公告的财务数据回测过去
所有研究数据查询必须明确:
as_of_date
只允许返回当时市场已经知道的数据。
同样,历史指数成分必须使用:
index_constituent_history
禁止直接使用今天的指数成分股回测过去。
10. Domain 层
核心领域对象:
Stock
Universe
Factor
FactorTest
CompositeFactor
Model
SelectionRule
SelectionResult
SignalRule
SignalEvent
Strategy
Portfolio
Backtest
Experiment
Job
核心关系:
Universe
↓
Factor
↓
FactorTest
↓
CompositeFactor / Model
↓
SelectionRule
↓
SelectionResult
↓
SignalRule
↓
SignalEvent
↓
Portfolio
↓
Strategy
↓
Backtest
↓
Experiment
11. Factor Engine
Factor Engine 负责:
原始数据
↓
因子计算
↓
标准化
↓
中性化
↓
因子值
支持:
- 内置因子
- 技术因子
- 财务因子
- 估值因子
- 成长因子
- 质量因子
- 动量因子
- 波动率因子
- 自定义表达式
每个因子必须具有:
name
description
formula
input_data
frequency
lookback
direction
normalization
neutralization
availability_rule
version
12. Factor Research Service
因子研究不是直接选股,而是评估因子的预测能力。
支持:
IC
RankIC
ICIR
分层收益
多空组合
累计收益
因子稳定性
因子相关性
行业暴露
市值暴露
换手率
不同市场阶段
典型流程:
Candidate Factors
↓
Data Validation
↓
IC / RankIC
↓
Layered Backtest
↓
Correlation
↓
Redundancy Removal
↓
Factor Combination
↓
Out-of-Sample Test
13. Composite Factor Engine
复合因子负责把多个单因子组合成一个可用于选股的 Score。
例如:
CompositeScore =
0.25 × ROE
+ 0.20 × RevenueGrowth
+ 0.30 × Momentum60
+ 0.10 × PE
+ 0.15 × Quality
支持:
- 固定权重
- Rank 加权
- Z-Score 加权
- IC 加权
- ICIR 加权
- 手工权重
- ML 模型输出
- 因子方向控制
- 标准化
- 行业中性化
- 市值中性化
注意:
Composite Factor
≠
Strategy
Composite Factor 只是生成:
Stock → Score
真正决定买卖的仍然是 Selection + Signal + Portfolio。
14. Selection Engine:股票筛选引擎
Selection Engine 是连接“研究”和“实际选股”的核心模块。
14.1 三种选股模式
A. 条件选股
ROE > 15%
AND
PE < 30
AND
Revenue Growth > 20%
AND
Close > MA60
B. 因子评分选股
Composite Score
↓
Rank
↓
Top N
C. 模型预测选股
Historical Data
↓
Features
↓
LightGBM / Qlib Model
↓
Predicted Return
↓
Rank
↓
Top N
14.2 Selection 输入
Universe
+
Filters
+
Factor / Composite Factor / Model
+
Ranking
+
Top N / Top %
+
Constraints
14.3 Selection 输出
SelectionResult
├── as_of_date
├── symbol
├── rank
├── score
├── factor_values
├── filter_status
├── selection_reason
└── metadata
Selection Engine 必须支持历史日期执行:
select(
strategy_id,
as_of_date="2024-06-30"
)
因此:
当前选股和历史回测选股必须使用同一套 Selection Engine。
15. Signal Engine:交易信号引擎
Selection 解决:
哪些股票值得关注?
Signal 解决:
什么时候交易?
典型输入:
SelectionResult
+
Price
+
Technical Indicators
+
Market Regime
+
Existing Position
+
Risk Rules
输出:
BUY
SELL
HOLD
WATCH
例如:
Selection Rank <= 20
AND
Close > MA60
AND
Momentum20 > 0
AND
Market Regime = Bull
→ BUY
卖出:
Rank > 50
OR
Close < MA60
OR
Risk Rule Triggered
→ SELL
SignalEvent 必须记录:
signal_date
symbol
signal_type
trigger_reason
score
price
strategy_id
这样可以解释:
为什么这一天产生买入信号?
16. Portfolio Engine:组合构建
Signal 产生以后,不直接进入回测,而是进入 Portfolio Engine。
Portfolio Engine 负责:
- 股票数量
- 仓位
- 权重
- 行业约束
- 单股上限
- 最大回撤控制
- 换手约束
- 调仓
- 现金管理
支持:
Equal Weight
Score Weight
Risk Weight
Custom Weight
例如:
Top 20
↓
过滤 BUY 信号
↓
剩余 12 只
↓
单股最大 10%
↓
行业最大 25%
↓
组合最终持仓
17. Strategy:完整策略定义
Strategy 不再只是 Factor + Model + Backtest,而是:
Strategy
├── Universe
├── Filters
├── Factors
├── Composite Factor
├── Model
├── Selection Rule
├── Signal Rule
├── Portfolio Rule
├── Rebalance Rule
└── Risk Rule
示例:
strategy:
name: "质量成长动量策略"
universe:
type: "CSI300"
filters:
- market_cap > 10000000000
- is_st = false
- suspended = false
factors:
- name: roe_ttm
weight: 0.25
- name: revenue_growth
weight: 0.20
- name: momentum_60
weight: 0.30
- name: pe
weight: 0.10
- name: quality
weight: 0.15
selection:
method: composite_score
top_n: 20
signal:
buy:
- score_rank <= 20
- close > ma60
sell:
- score_rank > 50
- close < ma60
portfolio:
weighting: equal
max_position: 0.10
max_industry_weight: 0.25
rebalance:
frequency: weekly
18. Research Specification
前端、AI Agent 和后端统一使用自己的研究描述对象。
Research Specification 是系统最重要的业务契约之一。
处理流程:
Research Specification
↓
Validator
↓
Strategy Builder
↓
Selection Builder
↓
Signal Builder
↓
Portfolio Builder
↓
Qlib / ML Adapter
↓
Backtest
前端和 Agent 不允许直接生成任意 Qlib 配置绕过这一层。
19. 前端结构
第一阶段:
Dashboard
股票池
因子研究
复合因子
股票筛选
交易信号
回测
Experiment
第二阶段:
模型研究
Portfolio
AI Research
数据管理
20. 前端输入
股票池
支持:
- 市场
- 股票类型
- 行业
- 市值
- 流动性
- 上市时间
- ST
- 停牌
- 指数成分
- 历史指数成分
因子
支持:
- 内置因子
- 自定义表达式
- 因子组合
- 权重
- 标准化
- 中性化
股票筛选
支持:
- 条件筛选
- Top N
- Top %
- Score
- Score Threshold
- 等权
- Score 加权
- 行业约束
- 市值约束
- 流动性约束
- 单股权重上限
交易信号
支持:
- 买入条件
- 卖出条件
- 持有条件
- 趋势条件
- 技术指标
- 市场环境
- 风险条件
回测
支持:
- 起止日期
- 调仓频率
- 初始资金
- 手续费
- 印花税
- 滑点
- 涨跌停限制
- 停牌限制
- 成交约束
21. 前端输出
21.1 选股结果
SelectionResult
├── as_of_date
├── universe
├── candidates
│ ├── symbol
│ ├── rank
│ ├── score
│ ├── factor_values
│ └── selection_reason
└── statistics
21.2 信号结果
SignalResult
├── symbol
├── signal
├── score
├── trigger_reason
├── price
└── risk_flags
21.3 回测结果
BacktestResult
├── summary
├── equity_curve
├── drawdown
├── monthly_returns
├── yearly_returns
├── positions
├── trades
├── turnover
├── risk_metrics
├── factor_exposure
├── selection_history
└── signal_history
前端完全不需要理解 Qlib 内部对象。
22. 异步 Job
所有耗时任务必须异步:
POST /api/backtests
↓
Job Created
↓
Worker
↓
Selection
↓
Signal
↓
Portfolio
↓
Qlib
↓
Result
前端通过 SSE 接收:
queued
running
data_loading
factor_calculation
factor_research
selection
signal_generation
portfolio_construction
model_training
backtesting
analysis
completed
failed
第一阶段:
FastAPI BackgroundTasks
复杂后再引入:
Redis + Celery/RQ
不要第一版过度工程化。
23. Qlib Adapter
Qlib 必须被封装:
quant/
├── qlib_adapter/
│ ├── dataset.py
│ ├── feature.py
│ ├── model.py
│ ├── backtest.py
│ └── provider.py
业务代码:
backtest_service.run(spec)
而不是:
qlib.init(...)
qlib.workflow(...)
散落在项目各处。
24. AI Agent 架构
Agent 只能调用受控 Tool:
Agent
├── search_stocks
├── inspect_factor
├── test_factor
├── create_composite_factor
├── screen_stocks
├── explain_selection
├── generate_signals
├── create_strategy
├── run_backtest
├── compare_experiments
├── get_backtest_result
└── create_experiment
Agent 禁止:
直接 SQL
直接修改数据库
直接删除数据
直接执行任意 shell
直接修改生产策略
直接调用 Qlib 内部 API 绕过业务层
25. 研究与回测一致性
这是本平台必须保证的关键原则:
历史回测使用的选股、信号和组合逻辑,与当前实际选股使用的逻辑必须完全相同。
正确方式:
Strategy Specification
│
┌───────────┼───────────┐
▼ ▼ ▼
Historical Current Future
Backtest Screen Signal
│ │ │
└───────────┼───────────┘
▼
Same Engine
这样可以避免:
回测一套逻辑
实际运行另一套逻辑
26. Experiment 可复现性
每次研究必须记录:
experiment_id
data_version
code_version
strategy_version
universe
factor_version
model_version
selection_rule
signal_rule
portfolio_rule
backtest_config
start_date
end_date
result
最好记录:
git commit
目标:
同一个 Experiment
+
同一个数据版本
+
同一个代码版本
+
同一个 Strategy Version
=
可以重新得到相同研究结果
27. 测试要求
必须测试:
Data Adapter
DAO
Repository
Research Specification
Future-data Protection
Factor
Factor Research
Composite Factor
Selection Engine
Signal Engine
Portfolio Engine
Backtest
API
Experiment
特别需要测试:
Future Function
announce_date > as_of_date
→ 不得进入研究数据
Survivorship Bias
历史成分股
≠
当前成分股
Selection / Backtest Consistency
历史某日 Selection
=
Backtest 当日 Selection
Signal Consistency
历史某日 Signal
=
Strategy Engine 在同一条件下重新计算的 Signal
28. 开发目录
quant-platform/
│
├── frontend/
│ └── web/
│
├── backend/
│ ├── app/
│ │ ├── api/
│ │ ├── application/
│ │ │ └── services/
│ │ │ ├── data_service.py
│ │ │ ├── universe_service.py
│ │ │ ├── factor_service.py
│ │ │ ├── factor_research_service.py
│ │ │ ├── composite_factor_service.py
│ │ │ ├── selection_service.py
│ │ │ ├── signal_service.py
│ │ │ ├── portfolio_service.py
│ │ │ ├── model_service.py
│ │ │ ├── backtest_service.py
│ │ │ └── experiment_service.py
│ │ ├── domain/
│ │ │ ├── entities/
│ │ │ └── repositories/
│ │ ├── infrastructure/
│ │ ├── quant/
│ │ │ └── qlib_adapter/
│ │ ├── agent/
│ │ └── core/
│ │
│ └── tests/
│
├── data/
│ ├── raw/
│ ├── normalized/
│ ├── parquet/
│ └── qlib/
│
├── experiments/
├── scripts/
├── docker/
├── docs/
├── ARCHITECTURE.md
├── AGENT.md
└── README.md
29. MVP 开发阶段
Phase 1:数据
Tushare
↓
标准化
↓
SQLite
↓
Parquet
完成:
- 股票列表
- 交易日历
- 日线
- 复权因子
- 基本财务指标
- 历史指数成分
Phase 2:因子
Parquet
↓
Qlib Dataset
↓
自定义因子
↓
Factor Research
完成:
- 因子计算
- IC
- RankIC
- 分层
- 因子相关性
Phase 3:股票筛选
Factor
↓
Composite Factor
↓
Selection Engine
↓
Top N
完成:
- 条件选股
- 多因子评分
- 复合因子
- Top N
- 历史选股
- 当前选股
Phase 4:交易信号
Selection
↓
Signal Engine
↓
BUY / SELL / HOLD
完成:
- 买入条件
- 卖出条件
- 技术指标
- 趋势条件
- 信号历史
Phase 5:组合与回测
Selection
↓
Signal
↓
Portfolio
↓
Qlib Backtest
完成:
- 仓位
- 调仓
- 交易成本
- 涨跌停
- 停牌
- 回撤
- Sharpe
- 换手率
Phase 6:Web
Dashboard
股票池
因子研究
复合因子
股票筛选
交易信号
回测
Experiment
Phase 7:AI Agent
自然语言
↓
Research Plan
↓
Tool
↓
Strategy
↓
Selection
↓
Signal
↓
Backtest
↓
Experiment
30. 数据流总图
Tushare
│
▼
Tushare Adapter
│
失败/缺失
▼
Sina Adapter
│
▼
Raw Data
│
▼
Data Validator
│
▼
Normalization
│
┌───────┴────────┐
▼ ▼
SQLite Parquet
│ │
│ ▼
│ Qlib Dataset
│ │
│ ┌───────┴────────┐
│ ▼ ▼
│ Factor Model
│ │ │
│ └───────┬────────┘
│ ▼
│ Composite Factor
│ │
│ ▼
│ Selection Engine
│ │
│ Candidates
│ │
│ ▼
│ Signal Engine
│ │
│ BUY/SELL
│ │
│ ▼
│ Portfolio Engine
│ │
│ ▼
│ Backtest Engine
│ │
└────────────────┤
▼
Experiment
│
┌─────────┴─────────┐
▼ ▼
Web Output AI Analysis
31. 最终核心原则
这个系统必须坚持:
- Tushare 第一,新浪第二
- 数据源通过 Adapter 隔离
- DAO / Repository 隔离数据库
- SQLite 当前使用,SQLAlchemy 保证未来 MySQL 可切换
- 大量历史时序数据逐渐转 Parquet
- Qlib 是计算引擎,不是整个系统
- 因子研究、股票筛选、交易信号、组合构建必须分层
- Selection Engine 必须支持历史日期和当前日期
- 回测与实际选股必须使用同一套 Strategy Engine
- 前端只面对自己的 Domain API
- 前后端通过 Research Specification 解耦
- 所有耗时任务异步化
- 所有研究产生 Experiment
- 严格防止未来函数
- 严格防止幸存者偏差
- AI Agent 只能通过 Tool 使用研究能力
- 第一阶段不做实盘
- 第一阶段不做复杂分布式架构
- 每个核心模块都必须可以被单元测试
- 系统最终输出不仅是回测收益,还必须能够解释“为什么选这只股票、为什么产生这个交易信号”。
最终目标不是:
Qlib + Web
而是:
一个以 Qlib 为量化计算引擎、以 Tushare 为主要数据源、以 Composite Factor + Selection + Signal + Portfolio 为策略核心、具备严格历史一致性和 AI Agent 接口的个人 A 股量化研究平台。