diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..123ab28 --- /dev/null +++ b/.env.example @@ -0,0 +1,24 @@ +# ============================================================ +# 复制本文件为项目根目录 .env 并填入真实值。 +# .env 已被 .gitignore 忽略 —— 严禁把真实密钥提交进 Git。 +# 各变量用途:被根目录 config.yaml 中对应 *_env 字段引用, +# 或由后端 app.core.config 直接读取。 +# ============================================================ + +# ---- Tushare Pro token(首选数据源,Phase 1 数据管线使用)---- +TUSHARE_TOKEN= + +# ---- 数据库连接 ---- +# 留空时使用默认 SQLite:<项目根>/data/quant.db(相对路径自动解析到项目根) +DATABASE_URL= +# SQLite 示例(显式指定): +# DATABASE_URL=sqlite:///./data/quant.db +# MySQL 示例(未来切换,仅需改此值,业务代码不变): +# DATABASE_URL=mysql+pymysql://user:password@127.0.0.1:3306/quant + +# ---- AI Agent / LLM(Phase 5 接入,先留空)---- +LLM_API_KEY= +LLM_BASE_URL= + +# ---- API 应用密钥(必须修改为随机值)---- +APP_SECRET_KEY=please-change-me diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..50a148e --- /dev/null +++ b/.gitignore @@ -0,0 +1,50 @@ +# ================= Python ================= +__pycache__/ +*.py[cod] +*.egg-info/ +*.egg +.venv/ +venv/ +.pytest_cache/ +.ruff_cache/ +.mypy_cache/ +.pyright/ +htmlcov/ +.coverage +dist/ +build/ + +# ================= 密钥 / 凭证 ================= +# 真实密钥只放根目录 .env(复制自 .env.example),严禁提交 +.env +*.pem +*.key + +# ================= 前端 / Node ================= +node_modules/ +.next/ +out/ + +# ================= 本地数据(不入库) ================= +# 行情、数据库、缓存均不入库;只保留目录占位 .gitkeep +data/* +!data/**/.gitkeep +*.db +*.db-wal +*.db-shm +*.sqlite +*.sqlite3 +*.parquet +*.csv +*.h5 +*.pkl + +# ================= 实验产物 ================= +experiments/* +!experiments/**/.gitkeep + +# ================= OS / 编辑器 ================= +.DS_Store +.idea/ +.vscode/ +*.swp diff --git a/AGENT.md b/AGENT.md new file mode 100644 index 0000000..b615399 --- /dev/null +++ b/AGENT.md @@ -0,0 +1,1201 @@ +# AGENT.md + +## AI Agent 开发约束 + +本文件是本项目所有 AI Coding Agent(Claude Code、DSH、REASONIX等)的开发约束。 + +**在修改代码前必须阅读本文件和 `ARCHITECTURE.md`。** + +**AI 回答必须使用中文** + +--- + +# 1. 项目定位 + +这是一个: + +- A股量化研究平台 +- 个人开发项目 +- 以选股、因子研究、回测为核心 +- 以低频/中低频交易研究为目标 +- Qlib 为量化研究引擎 +- Tushare 为首选数据源 +- 新浪财经为备用数据源 +- SQLite 为当前数据库 +- MySQL 为未来数据库 +- React / Next.js 为前端 +- FastAPI 为后端 +- AI Agent 为后期研究助手 + +不要把项目开发成高频交易系统。 + +--- + +# 2. 总体开发原则 + +必须遵守: + +```text +简单优先 +模块解耦 +接口稳定 +数据可追溯 +实验可复现 +禁止未来函数 +AI 可调用 +SQLite → MySQL 可迁移 +API KEY, 账号密码等敏感信息写入根目录.env文件 +可配置项统一写入根目录config.yaml 文件 +``` + +禁止为了“看起来专业”而过度微服务化。 + +--- + +# 3. 修改代码前 + +AI Agent 必须先: + +1. 阅读 `ARCHITECTURE.md` +2. 阅读相关模块代码 +3. 找到现有接口 +4. 判断是否可以复用 +5. 最小范围修改 +6. 修改后运行测试 + +禁止看到需求就直接大量重构。 + +--- + +# 4. 架构边界 + +严格遵守: + +```text +Frontend + ↓ +API + ↓ +Application Service + ↓ +Domain + ↓ +Repository / DAO + ↓ +Infrastructure +``` + +量化: + +```text +Application Service + ↓ +Quant Service + ↓ +Qlib Adapter + ↓ +Qlib +``` + +禁止: + +```text +Frontend → Qlib +Frontend → Database +Agent → Database +Agent → Qlib internal API +Service → sqlite3 +``` + +--- + +# 5. 数据源约束 + +## 5.1 Tushare 是第一数据源 + +所有已有 Tushare 能提供的数据,默认必须优先使用 Tushare。 + +禁止无理由改成新浪。 + +## 5.2 新浪是备用数据源 + +新浪财经只能作为: + +- Tushare 缺失数据 +- Tushare 暂时不可用 +- 数据交叉验证 +- 特定行情数据补充 + +必须通过: + +```text +SinaAdapter +``` + +接入。 + +业务代码不得直接 import 新浪 API 实现。 + +--- + +# 6. Data Provider 接口 + +业务层只能依赖抽象接口: + +```python +class MarketDataProvider(Protocol): + ... +``` + +例如: + +```python +provider.get_daily(...) +provider.get_stock_basic(...) +provider.get_financial(...) +``` + +不能: + +```python +from tushare import ... +``` + +散落在业务代码中。 + +正确: + +```text +MarketDataProvider + │ + ├── TushareProvider + └── SinaProvider +``` + +--- + +# 7. 数据源 Failover + +推荐: + +```text +Tushare + │ + ├── success → use + │ + └── failure / missing + ↓ + Sina +``` + +但必须记录: + +```text +source +request_time +success +failure_reason +row_count +data_date +``` + +不能静默切换导致数据来源不可追踪。 + +--- + +# 8. 数据一致性 + +任何行情数据必须至少考虑: + +```text +symbol +trade_date +open +high +low +close +volume +amount +``` + +需要复权时必须使用明确的复权因子。 + +禁止在代码中偷偷改变: + +```text +前复权 +后复权 +不复权 +``` + +必须在 API / Research Specification 中明确。 + +--- + +# 9. 未来函数是最高优先级风险 + +严禁: + +```text +回测日期 T +使用 T 之后才公布的数据 +``` + +财务数据必须区分: + +```text +report_date +announce_date +``` + +研究查询必须支持: + +```python +as_of_date +``` + +任何新增财务数据功能,都必须回答: + +> 在回测当天,这条数据是否已经公开? + +如果无法回答,不得用于回测。 + +--- + +# 10. DAO / Repository 约束 + +业务层禁止直接操作: + +```python +sqlite3 +SQLAlchemy Session +SQL +``` + +业务层只能调用: + +```text +Repository Interface +``` + +例如: + +```python +stock_repo.get_by_symbol(...) +factor_repo.list(...) +experiment_repo.save(...) +``` + +--- + +# 11. SQLite → MySQL 兼容 + +当前使用 SQLite。 + +但是: + +> 任何业务代码都不能假设数据库是 SQLite。 + +禁止: + +```python +SELECT * FROM sqlite_master +``` + +禁止 SQLite 专有 SQL。 + +禁止: + +```python +sqlite3.connect() +``` + +出现在 Service / Domain 层。 + +数据库访问统一: + +```text +SQLAlchemy +Repository +Alembic +``` + +未来切换 MySQL 时,业务层不应该修改。 + +--- + +# 12. Migration + +数据库结构必须使用: + +```text +Alembic +``` + +禁止手工修改生产数据库结构作为正式方案。 + +新增字段必须: + +```text +Model + ↓ +Migration + ↓ +Test +``` + +--- + +# 13. Parquet 使用原则 + +大量历史时序数据优先: + +```text +Parquet +``` + +SQLite 主要存: + +- metadata +- configuration +- experiment +- job +- factor definition +- strategy +- 索引/小规模业务数据 + +不要把几十年、全市场、高频明细全部塞入 SQLite。 + +--- + +# 14. Qlib 使用原则 + +Qlib 必须被 Adapter 封装。 + +例如: + +```text +QlibDatasetAdapter +QlibModelAdapter +QlibBacktestAdapter +``` + +业务层不要直接依赖 Qlib 内部实现。 + +禁止项目代码到处出现: + +```python +import qlib +``` + +尽量集中在: + +```text +quant/qlib_adapter/ +``` + +--- + +# 15. 不要修改 Qlib 源码 + +默认禁止: + +```text +修改 site-packages/qlib +``` + +如果 Qlib 功能不满足要求: + +优先: + +```text +Adapter +Wrapper +Extension +``` + +只有确实无法实现时,才考虑 fork,并必须记录原因。 + +--- + +# 16. Research Specification + +前端、Agent、后端统一通过: + +```text +Research Specification +``` + +描述研究任务。 + +不要让前端直接构造 Qlib YAML。 + +不要让 Agent 直接生成任意 Qlib 配置。 + +正确流程: + +```text +User / Agent + ↓ +Research Specification + ↓ +Schema Validation + ↓ +Strategy Builder + ↓ +Qlib Adapter +``` + +--- + +# 17. API 设计 + +API 必须面向业务对象: + +```text +/api/stocks +/api/universes +/api/factors +/api/factor-tests +/api/strategies +/api/backtests +/api/experiments +/api/jobs +/api/agent +``` + +不要设计成: + +```text +/api/qlib/xxx +``` + +除非是内部 Adapter API。 + +--- + +# 18. API 输入输出 + +API 输入必须使用: + +```text +Pydantic Schema +``` + +不要直接把 SQLAlchemy Model 暴露给前端。 + +例如: + +```text +Request DTO + ↓ +Application Service + ↓ +Domain + ↓ +Repository +``` + +输出: + +```text +Domain + ↓ +Response DTO + ↓ +Frontend +``` + +--- + +# 19. 异步任务 + +以下任务必须考虑异步执行: + +- 大量数据下载 +- 因子计算 +- 模型训练 +- 回测 +- 大规模参数搜索 +- AI Research + +API 不应该长时间阻塞 HTTP 请求。 + +返回: + +```json +{ + "job_id": "BT-001", + "status": "queued" +} +``` + +前端通过 SSE / WebSocket 获取进度。 + +--- + +# 20. Job 状态 + +统一状态: + +```text +queued +running +success +failed +cancelled +``` + +可选阶段: + +```text +data_loading +feature_calculation +model_training +prediction +backtesting +analysis +saving_result +``` + +--- + +# 21. Experiment 必须可复现 + +每次研究必须保存: + +```text +experiment_id +data_version +code_version +strategy_version +universe +factors +model +parameters +backtest_config +start_date +end_date +result +``` + +最好记录: + +```text +git commit +``` + +目标: + +> 任何一个历史实验,都应该尽可能可以重新运行。 + +--- + +# 22. 因子开发约束 + +每个因子必须明确: + +```text +name +description +formula +input data +frequency +lookback +direction +normalization +neutralization +``` + +例如: + +```text +momentum_60 + +定义: +过去60个交易日收益率 + +频率: +daily + +方向: +higher_is_better +``` + +禁止创建只有: + +```python +factor1() +factor2() +``` + +而没有定义和文档的因子。 + +--- + +# 23. 因子研究不能只看收益率 + +新增因子测试至少考虑: + +```text +IC +RankIC +ICIR +分层收益 +换手率 +稳定性 +行业暴露 +市值暴露 +不同市场阶段 +``` + +不能因为: + +```text +Sharpe > 2 +``` + +就直接认为因子有效。 + +--- + +# 24. 回测约束 + +回测必须考虑: + +```text +手续费 +印花税 +滑点 +涨跌停 +停牌 +成交约束 +调仓频率 +``` + +如果某项没有实现,必须在 UI 和结果中明确显示。 + +禁止默认假设: + +```text +永远可以买入 +永远可以卖出 +没有交易成本 +``` + +--- + +# 25. 选股策略 + +核心目标是: + +```text +低频 +选股 +组合 +回测 +``` + +默认优先: + +```text +daily data +weekly rebalance +monthly rebalance +``` + +不要默认引入: + +```text +tick +order book +HFT +``` + +除非用户明确要求。 + +--- + +# 26. 前端约束 + +前端必须: + +```text +业务导向 +参数清晰 +结果可视化 +``` + +不要直接暴露: + +```text +Qlib internal config +Python object +SQL +``` + +用户看到: + +```text +股票池 +因子 +模型 +策略 +回测 +``` + +而不是: + +```text +DatasetH +HandlerLP +SignalRecord +``` + +--- + +# 27. 前端结果统一 + +回测结果必须标准化。 + +推荐: + +```text +summary +equity_curve +drawdown +monthly_returns +yearly_returns +positions +trades +risk_metrics +factor_exposure +``` + +前端组件只依赖这个结构。 + +--- + +# 28. AI Agent 约束 + +Agent 是: + +```text +Research Assistant +``` + +不是: + +```text +System Administrator +``` + +Agent 默认只能通过 Tool: + +```text +search_stock +get_market_data +test_factor +create_strategy +run_backtest +get_experiment +compare_experiments +``` + +Agent 不得: + +```text +直接删除数据库 +直接修改数据库 +直接执行 shell +修改生产配置 +修改数据源凭证 +修改系统安全配置 +``` + +--- + +# 29. AI Agent 的研究行为 + +Agent 应优先: + +```text +提出假设 + ↓ +建立实验 + ↓ +运行测试 + ↓ +分析结果 + ↓ +提出下一步 +``` + +而不是: + +```text +看到高收益 + ↓ +宣布策略成功 +``` + +必须主动考虑: + +```text +overfitting +look-ahead bias +survivorship bias +data leakage +transaction cost +parameter sensitivity +out-of-sample +``` + +--- + +# 30. 禁止数据泄露 + +股票池也必须防止: + +```text +未来成分股 +未来行业分类 +未来财务数据 +未来退市信息 +``` + +例如不能用“2026年的沪深300成分股”回测2015年。 + +必须使用历史时点对应的成分数据。 + +--- + +# 31. 测试要求 + +每次修改至少运行相关测试。 + +重点测试: + +```text +Data Adapter +DAO +Repository +Research Specification +Future-data protection +Factor +Backtest +API +``` + +关键金融逻辑必须有单元测试。 + +--- + +# 32. 类型与代码质量 + +Python: + +```text +Python 3.11+ +``` + +推荐: + +```text +ruff +pytest +mypy / pyright +pydantic +SQLAlchemy 2.x +Alembic +``` + +代码必须尽量: + +```text +typed +small +testable +documented +``` + +--- + +# 33. 配置管理 + +禁止把: + +```text +Tushare Token +数据库密码 +LLM API Key +``` + +写进 Git。 + +使用: + +```text +.env +.env.example +``` + +`.env.example` 只提供变量名,不提供真实密钥。 + +--- + +# 34. Git 约束 + +每个功能尽量: + +```text +一个清晰 commit +``` + +Commit message 要表达实际修改: + +```text +feat: add tushare daily data provider +fix: prevent future financial data leakage +feat: add backtest job API +``` + +禁止提交: + +```text +数据库 +缓存 +大规模行情文件 +模型权重 +.env +secret +``` + +--- + +# 35. 修改现有代码的原则 + +优先: + +```text +最小修改 +``` + +而不是: + +```text +顺手重构整个项目 +``` + +如果确实需要架构调整: + +1. 说明原因 +2. 明确影响范围 +3. 分阶段修改 +4. 保证每阶段可运行 + +--- + +# 36. 新功能开发流程 + +AI Agent 应按照: + +```text +1. 阅读 ARCHITECTURE.md +2. 理解需求 +3. 定义 Domain +4. 定义 DTO +5. 定义 Repository Interface +6. 实现 Infrastructure +7. 实现 Application Service +8. 实现 API +9. 实现前端 +10. 编写测试 +11. 运行测试 +12. 更新文档 +``` + +不要倒过来从 UI 开始堆代码。 + +--- + +# 37. 数据迁移原则 + +未来 SQLite → MySQL 时: + +```text +Domain 不变 +Application 不变 +API 不变 +Frontend 不变 + +只调整: +Infrastructure / Database Configuration +``` + +这是 DAO / Repository 抽象必须保证的目标。 + +--- + +# 38. 第一阶段禁止事项 + +MVP 阶段不要主动增加: + +```text +Kubernetes +微服务集群 +Kafka +复杂消息队列 +实时交易 +高频交易 +复杂权限系统 +多租户 +GPU 集群 +``` + +除非用户明确提出。 + +--- + +# 39. 推荐 MVP 技术栈 + +```text +Frontend +React / Next.js +TypeScript +ECharts + +Backend +FastAPI +Pydantic +SQLAlchemy +Alembic + +Data +Tushare +Sina fallback +Parquet +DuckDB + +Quant +Qlib +LightGBM + +Database +SQLite + +Testing +pytest +ruff + +Deployment +Docker Compose +``` + +--- + +# 40. 最重要的开发原则 + +如果一个实现: + +```text +更简单 +更容易测试 +更容易替换 +更容易解释 +``` + +优先选择它。 + +如果一个实现: + +```text +把 Qlib +数据库 +前端 +Agent +``` + +强耦合在一起: + +> 默认拒绝。 + +最终系统必须保持: + +```text +Data + ↓ +Domain + ↓ +Research + ↓ +Qlib + ↓ +Experiment + ↓ +API + ↓ +Frontend + ↓ +Agent +``` + +每一层职责明确、接口稳定、可测试、可替换。 + +--- + +# 41. Agent 每次任务结束前必须检查 + +```text +□ 是否违反 ARCHITECTURE.md? +□ 是否绕过 DAO? +□ 是否把 SQLite 写死? +□ 是否直接依赖 Qlib 内部实现? +□ 是否可能引入未来函数? +□ 是否引入数据泄露? +□ 是否有测试? +□ 是否修改了 API 契约? +□ 是否需要更新文档? +□ 是否把 secret 提交进 Git? +□ 是否进行了不必要的大规模重构? +``` + +如果任一项为“是”,必须先处理或明确向用户报告。 + +--- + +# 42. 最终架构目标 + +本项目最终应该能够做到: + +```text +用户 + ↓ +Web UI / AI Agent + ↓ +Research Specification + ↓ +Application Service + ↓ +Data / Factor / Strategy / Backtest + ↓ +Qlib + ↓ +Experiment + ↓ +可视化结果 +``` + +并且: + +```text +Tushare → Sina +SQLite → MySQL +Qlib → 其他量化引擎 +普通研究 → AI Agent +``` + +都不应该要求推翻整个系统。 + +**这比单纯快速把功能写出来更重要。** + diff --git a/README.md b/README.md index 8733fc7..2d7a9a0 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,98 @@ -# qlib +# qlib-platform -Qlib base的选股和回测平台 \ No newline at end of file +个人 A 股量化研究平台:**选股 · 因子研究 · 回测**,面向低频 / 中低频交易研究。 + +> 核心量化引擎:[Qlib](https://github.com/microsoft/qlib) · 首选数据源:Tushare(新浪财经为备用)· 当前数据库:SQLite(未来 MySQL,业务层无感切换) + +## 定位 + +- 个人开发项目,中低频选股 / 因子 / 组合回测 +- **不做**高频交易、不做过度的微服务化 +- 以 Qlib 为研究引擎,但 Qlib 只是计算引擎而不是整个系统 +- AI Agent(Phase 5)只能通过受控 Tool 调用研究能力 + +## 架构 + +详见 [AGENT.md](./AGENT.md)(开发约束)与 [docs/ARCHITECTURE.md](./docs/ARCHITECTURE.md)(架构文档),**改代码前必须阅读**。 + +```text +Web 前端 (frontend/web) + ↓ REST / SSE +FastAPI (backend) + ↓ Research Specification +Application Service ── Quant Service ── Qlib Adapter ── Qlib + ↓ ↓ +Repository / DAO Parquet / SQLite +``` + +### 目录结构 + +```text +qlib/ +├── backend/ # FastAPI 后端(uv 管理,Python 3.12) +│ ├── app/ +│ │ ├── api/ # HTTP API 层(面向业务对象,禁止暴露 Qlib/SQL) +│ │ ├── application/ # 用例 / 应用服务(编排,不含框架细节) +│ │ ├── domain/ # 领域实体 + Repository Protocol +│ │ ├── infrastructure/ # SQLAlchemy / Alembic 等基础设施实现 +│ │ ├── quant/qlib_adapter/ # Qlib 适配层(业务禁止直接 import qlib) +│ │ ├── agent/ # AI Research Agent(Phase 5,仅 Tool 访问) +│ │ └── core/ # 配置、通用组件 +│ └── tests/ +├── frontend/web/ # React / Next.js 前端(Phase 3 初始化) +├── data/ # raw / normalized / parquet / qlib(不入库,gitignore) +├── experiments/ # 实验产物(不入库,gitignore) +├── scripts/ # 数据同步、运维脚本 +├── docker/ # 部署(Phase 后引入,第一阶段不过度工程) +├── docs/ +├── AGENT.md +├── config.yaml # 可配置项(无密钥) +└── .env.example # 密钥模板(复制为 .env,勿提交) +``` + +## 快速开始(后端) + +前置:安装 [uv](https://docs.astral.sh/uv/)(`pip install uv` 或官方脚本)。 + +```bash +# 1. 配置密钥(复制模板,填入 TUSHARE_TOKEN 等) +cp .env.example .env + +# 2. 安装依赖(自动使用 Python 3.12,见 backend/.python-version) +cd backend +uv sync + +# 3. 运行测试 +uv run pytest + +# 4. 启动开发服务 +uv run uvicorn app.main:app --reload --port 8000 +# 健康检查:http://127.0.0.1:8000/api/health +# 交互文档:http://127.0.0.1:8000/docs +``` + +### 数据库迁移(Alembic,已就位) + +```bash +cd backend +uv run alembic upgrade head # 首次运行会在 data/quant.db 建立版本表 +uv run alembic revision --autogenerate -m "add xxx table" # 修改 Model 后生成迁移 +``` + +## 开发阶段(对应架构文档 §20) + +- **Phase 1 数据**:Tushare → 标准化 → SQLite(stock / daily / 复权因子 / 交易日历 / 财务指标),Parquet 导出 +- **Phase 2 Qlib**:Parquet → Qlib Dataset → 因子(Alpha158 / 自定义)→ LightGBM → 回测 +- **Phase 3 Web**:股票池 / 因子研究 / 选股 / 回测 / 结果可视化(Next.js + ECharts) +- **Phase 4 Experiment**:所有研究自动可复现存档 +- **Phase 5 AI Agent**:自然语言 → Research Plan → 受控 Tool → Experiment + +## 约定速查 + +- 回答与文档使用中文 +- 一切时间相关数据防「未来函数」:财务数据区分 `report_date` / `announce_date`,查询支持 `as_of_date` +- 数据源必须经 `MarketDataProvider`(Tushare 优先,Sina 兜底且记录来源),业务层禁止直接 import 新浪 / Tushare 实现 +- 业务层禁止直接操作 sqlite3 / SQL / SQLAlchemy Session,只能走 Repository +- 新表:Model → Alembic Migration → Test +- 禁止修改 site-packages/qlib 源码,一律走 Adapter / Wrapper +- API 输入输出用 Pydantic DTO,禁止把 ORM Model 直接暴露给前端 diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..51b5d10 --- /dev/null +++ b/config.yaml @@ -0,0 +1,43 @@ +# ============================================================ +# 全局可配置项(可提交,不含任何密钥) +# 约定(见 AGENT.md §2 / §33): +# - 可配置项统一写入本文件(项目根 config.yaml) +# - 密钥统一放根目录 .env(见 .env.example), +# 本文件通过 *_env 字段引用对应环境变量名,不写明文 +# ============================================================ + +app: + name: "qlib-platform" + version: "0.1.0" + debug: false + # 从 .env 读取应用密钥的环境变量名 + secret_key_env: "APP_SECRET_KEY" + +api: + prefix: "/api" + +database: + # 留空 → 默认 sqlite:///./data/quant.db(相对路径自动解析到项目根 data/) + url_env: "DATABASE_URL" + echo: false + # Alembic 迁移脚本目录(相对 backend/) + migrations_dir: "app/infrastructure/persistence/migrations" + +data_source: + primary: "tushare" + fallback: "sina" + tushare_token_env: "TUSHARE_TOKEN" + +storage: + # 相对项目根目录 + raw_dir: "data/raw" + normalized_dir: "data/normalized" + parquet_dir: "data/parquet" + qlib_dir: "data/qlib" + +job: + # 第一阶段异步任务模式:local(FastAPI BackgroundTasks 级);Phase 复杂后再引入队列 + mode: "local" + +logging: + level: "INFO" diff --git a/data/.gitkeep b/data/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docker/.gitkeep b/docker/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md new file mode 100644 index 0000000..77847bf --- /dev/null +++ b/docs/ARCHITECTURE.md @@ -0,0 +1,1009 @@ +# A股个人量化选股与回测平台架构 + +> 版本:v1.0 +> 定位:个人开发、A股、中低频选股/回测、AI Agent 二次开发 +> 数据源优先级:Tushare > 新浪财经 +> 当前数据库:SQLite +> 未来数据库:MySQL +> 核心量化引擎:Qlib +> 前端:React / Next.js +> 后端:FastAPI + Python + +--- + +## 1. 项目目标 + +本项目不是简单给 Qlib 套一个 Web UI,而是构建一个独立的个人量化研究平台: + +```text +Web 前端 + ↓ +FastAPI + ↓ +Research Specification + ↓ +业务服务层 + ├── 数据服务 + ├── 股票池服务 + ├── 因子服务 + ├── 选股服务 + ├── 模型服务 + ├── 回测服务 + └── 实验服务 + ↓ +Qlib / ML + ↓ +标准化研究结果 + ↓ +SQLite / Parquet + ↓ +Web 前端 +``` + +AI Agent 作为独立能力层,通过受控 Tool 调用上述服务,而不是直接操作数据库或随意修改 Qlib 内部代码。 + +--- + +# 2. 总体架构 + +```text + ┌──────────────────────┐ + │ React / Next │ + │ │ + │ Dashboard │ + │ 股票池 │ + │ 因子研究 │ + │ 选股 │ + │ 回测 │ + │ Experiment │ + │ AI Research │ + └──────────┬───────────┘ + │ + REST / SSE + │ + ▼ + ┌──────────────────────┐ + │ FastAPI │ + │ │ + │ API / Auth / DTO │ + │ Job / Validation │ + └──────────┬───────────┘ + │ + ┌────────────┼────────────┐ + │ │ │ + ▼ ▼ ▼ + Data Service Research Agent Service + │ Service │ + │ │ │ + ▼ ▼ ▼ + DAO / Repo Qlib / ML Agent Tools + │ │ │ + └────────────┼──────────────┘ + ▼ + ┌──────────────────────┐ + │ Persistence │ + │ │ + │ SQLite │ + │ Parquet │ + │ Qlib Dataset │ + └──────────────────────┘ +``` + +--- + +# 3. 核心设计原则 + +## 3.1 Qlib 不是系统数据库 + +Qlib 负责: + +- Feature / Dataset +- 模型训练 +- Prediction +- Portfolio +- Backtest +- 部分分析工具 + +Qlib 不作为业务系统唯一数据存储。 + +系统数据分为: + +```text +业务数据 → SQLite +历史/分析型大数据 → Parquet +Qlib计算数据 → Qlib Dataset +实验结果 → SQLite +``` + +## 3.2 前端不能直接调用 Qlib + +必须经过: + +```text +Frontend + ↓ +FastAPI + ↓ +Application Service + ↓ +Qlib Adapter + ↓ +Qlib +``` + +这样未来可以替换 Qlib,而不影响前端。 + +## 3.3 DAO 必须与数据库实现解耦 + +业务代码禁止直接: + +```python +sqlite3.connect(...) +``` + +也禁止在 Service 中写 SQL。 + +必须: + +```text +Service + ↓ +Repository / DAO Interface + ↓ +SQLite Repository +``` + +未来: + +```text +Service + ↓ +Repository Interface + ├── SQLite Repository + └── MySQL Repository +``` + +业务层不感知底层数据库。 + +--- + +# 4. 数据源架构 + +## 4.1 数据源优先级 + +```text + Data Service + │ + ┌────────┴────────┐ + ▼ ▼ + Tushare Sina + Primary Secondary + │ │ + └────────┬────────┘ + ▼ + Normalization + │ + Validation + │ + Storage +``` + +### 第一优先级:Tushare + +用于: + +- 股票基本信息 +- 日线行情 +- 复权因子 +- 指数 +- 财务数据 +- 分红送转 +- 停复牌 +- 行业/概念 +- 其他可用数据 + +### 第二优先级:新浪财经 + +主要作为: + +- Tushare 数据缺失补充 +- 行情数据校验 +- 特定实时/准实时数据补充 + +新浪数据必须经过统一 Adapter,禁止业务代码直接调用新浪接口。 + +--- + +# 5. 数据采集流水线 + +```text +Scheduler + ↓ +Data Source Adapter + ↓ +Raw Response + ↓ +Schema Validation + ↓ +Normalization + ↓ +Deduplication + ↓ +Business Validation + ↓ +DAO + ↓ +SQLite + ↓ +Parquet Export + ↓ +Qlib Dataset +``` + +每个数据源都必须有独立 Adapter: + +```text +data/ +├── sources/ +│ ├── base.py +│ ├── tushare.py +│ └── sina.py +├── normalizers/ +├── validators/ +└── service.py +``` + +业务层只依赖: + +```python +MarketDataProvider +``` + +而不是: + +```python +TushareClient +``` + +--- + +# 6. 数据库设计 + +## 6.1 SQLite 定位 + +SQLite 用于: + +- 股票基础信息 +- 数据源状态 +- 数据同步记录 +- 因子定义 +- 策略定义 +- 回测配置 +- Experiment metadata +- Job +- 用户配置 +- 系统配置 + +SQLite 不建议长期承载超大规模原始行情明细。 + +历史行情和大量 Feature 优先使用 Parquet。 + +--- + +# 7. DAO / Repository 设计 + +推荐使用: + +```text +SQLAlchemy 2.x + + +Repository Pattern + + +Pydantic DTO +``` + +目录: + +```text +backend/ +├── domain/ +│ ├── entities/ +│ └── repositories/ +│ +├── infrastructure/ +│ └── persistence/ +│ ├── sqlalchemy/ +│ │ ├── models/ +│ │ ├── repositories/ +│ │ └── session.py +│ └── migrations/ +│ +└── application/ + └── services/ +``` + +Repository 接口示例: + +```python +class StockRepository(Protocol): + def get_by_symbol(self, symbol: str) -> Stock | None: ... + def list(self, filters: StockFilter) -> list[Stock]: ... + def save(self, stock: Stock) -> Stock: ... +``` + +SQLite: + +```python +class SqlAlchemyStockRepository(StockRepository): + ... +``` + +未来 MySQL: + +```python +class MySqlStockRepository(StockRepository): + ... +``` + +推荐实际上让两者都基于 SQLAlchemy,而不是分别维护两套 SQL。 + +这样数据库切换主要通过: + +```text +DATABASE_URL +``` + +完成。 + +例如: + +```text +SQLite: +sqlite:///./data/quant.db + +MySQL: +mysql+pymysql://user:password@host/quant +``` + +业务 Service 不需要修改。 + +--- + +# 8. 建议的核心数据库表 + +第一阶段至少包括: + +```text +stock +stock_daily +stock_adjust_factor + +industry +stock_industry + +index +index_daily + +trading_calendar +suspend_data +stock_st_data + +financial_indicator +income_statement +balance_sheet +cashflow_statement + +factor_definition +factor_test + +strategy +strategy_factor + +backtest +backtest_trade +backtest_position +backtest_metric + +experiment +experiment_artifact + +job +data_sync_log +``` + +注意: + +`stock_daily` 等大量时序数据如果规模变大,应逐渐迁移到: + +```text +Parquet +``` + +SQLite 保留元数据和索引。 + +--- + +# 9. 时间与未来函数防护 + +所有研究数据必须明确: + +```text +trade_date +report_date +announce_date +effective_date +``` + +财务数据必须按照 `announce_date` 控制可见性。 + +禁止: + +```text +使用未来公告的财务数据回测过去 +``` + +所有数据查询必须明确: + +```text +as_of_date +``` + +例如: + +```python +get_financial_data( + symbol="600519.SH", + as_of_date="2024-06-30" +) +``` + +只允许返回当时市场已经知道的数据。 + +--- + +# 10. Domain 层 + +建议核心领域对象: + +```text +Stock +Universe +Factor +FactorTest +Model +Strategy +Portfolio +Backtest +Experiment +Job +``` + +例如: + +```text +Universe + ↓ +Factor + ↓ +Model + ↓ +Strategy + ↓ +Backtest + ↓ +Experiment +``` + +--- + +# 11. Research Specification + +前端、AI Agent 和后端统一使用自己的研究描述对象。 + +示例: + +```json +{ + "type": "backtest", + "universe": { + "market": "CN_A", + "exclude_st": true, + "exclude_suspended": true, + "min_listing_days": 250 + }, + "factors": [ + { + "name": "momentum_60", + "weight": 0.3 + }, + { + "name": "roe_ttm", + "weight": 0.3 + }, + { + "name": "low_volatility_60", + "weight": 0.4 + } + ], + "selection": { + "top_n": 30 + }, + "rebalance": "monthly", + "period": { + "start": "2015-01-01", + "end": "2026-08-31" + } +} +``` + +然后: + +```text +Research Specification + ↓ +Validator + ↓ +Strategy Builder + ↓ +Qlib Adapter +``` + +--- + +# 12. 前端结构 + +第一阶段: + +```text +Dashboard +股票池 +因子研究 +选股 +回测 +Experiment +``` + +第二阶段: + +```text +模型研究 +Portfolio +AI Research +数据管理 +``` + +--- + +# 13. 前端输入 + +## 股票池 + +支持: + +- 市场 +- 股票类型 +- 行业 +- 市值 +- 流动性 +- 上市时间 +- ST +- 停牌 +- 指数成分 + +## 因子 + +支持: + +- 内置因子 +- 自定义表达式 +- 因子组合 +- 权重 +- 标准化 +- 中性化 + +## 选股 + +支持: + +- Top N +- Top % +- Score +- 等权 +- Score 加权 +- 行业约束 +- 单股权重上限 + +## 回测 + +支持: + +- 起止日期 +- 调仓频率 +- 初始资金 +- 手续费 +- 印花税 +- 滑点 +- 涨跌停限制 +- 停牌限制 + +--- + +# 14. 前端输出 + +回测结果统一转换为: + +```text +BacktestResult +├── summary +├── equity_curve +├── drawdown +├── monthly_returns +├── yearly_returns +├── positions +├── trades +├── turnover +├── risk_metrics +└── factor_exposure +``` + +这样前端完全不需要理解 Qlib 内部对象。 + +--- + +# 15. 异步 Job + +所有耗时任务必须异步: + +```text +POST /api/backtests + ↓ +Job Created + ↓ +Worker + ↓ +Qlib + ↓ +Result +``` + +前端通过: + +```text +SSE +``` + +接收: + +```text +queued +running +factor_calculation +model_training +backtesting +analysis +completed +failed +``` + +第一阶段可以使用: + +```text +FastAPI BackgroundTasks +``` + +或简单本地 Worker。 + +系统复杂后再引入: + +```text +Redis + Celery/RQ +``` + +不要第一版过度工程化。 + +--- + +# 16. Qlib Adapter + +Qlib 必须被封装: + +```text +quant/ +├── qlib_adapter/ +│ ├── dataset.py +│ ├── feature.py +│ ├── model.py +│ ├── backtest.py +│ └── provider.py +``` + +业务代码: + +```python +backtest_service.run(spec) +``` + +而不是: + +```python +qlib.init(...) +qlib.workflow(...) +``` + +散落在项目各处。 + +--- + +# 17. AI Agent 架构 + +Agent 只能调用 Tool: + +```text +Agent + ├── search_stocks + ├── inspect_factor + ├── test_factor + ├── create_strategy + ├── run_backtest + ├── compare_experiments + ├── get_backtest_result + └── create_experiment +``` + +Agent 禁止: + +```text +直接 SQL +直接修改数据库 +直接删除数据 +直接执行任意 shell +直接修改生产策略 +``` + +Agent: + +```text +自然语言 + ↓ +Research Plan + ↓ +Tool Calls + ↓ +Research Specification + ↓ +执行 + ↓ +Experiment + ↓ +分析 +``` + +--- + +# 18. AI Research 示例 + +用户: + +> 帮我寻找适合A股月度调仓的低频选股因子。 + +Agent: + +```text +1. 获取A股股票池 +2. 创建候选因子 +3. IC测试 +4. RankIC测试 +5. 分层测试 +6. 相关性分析 +7. 删除冗余因子 +8. 组合因子 +9. Walk Forward +10. 回测 +11. 保存 Experiment +12. 输出结论 +``` + +Agent 不能因为一次回测表现好就直接认为策略有效。 + +必须关注: + +```text +样本外 +Walk Forward +不同市场阶段 +交易成本 +换手率 +因子稳定性 +``` + +--- + +# 19. 推荐的开发目录 + +```text +quant-platform/ +│ +├── frontend/ +│ └── web/ +│ +├── backend/ +│ ├── app/ +│ │ ├── api/ +│ │ ├── application/ +│ │ ├── domain/ +│ │ ├── infrastructure/ +│ │ ├── quant/ +│ │ ├── agent/ +│ │ └── core/ +│ │ +│ └── tests/ +│ +├── data/ +│ ├── raw/ +│ ├── normalized/ +│ ├── parquet/ +│ └── qlib/ +│ +├── experiments/ +│ +├── scripts/ +│ +├── docker/ +│ +├── docs/ +│ +├── ARCHITECTURE.md +├── AGENT.md +└── README.md +``` + +--- + +# 20. 第一阶段 MVP + +不要一开始做所有功能。 + +### Phase 1:数据 + +```text +Tushare + ↓ +标准化 + ↓ +SQLite + ↓ +Parquet +``` + +完成: + +- 股票列表 +- 交易日历 +- 日线 +- 复权因子 +- 基本财务指标 + +### Phase 2:Qlib + +```text +Parquet + ↓ +Qlib Dataset + ↓ +Alpha158 / 自定义因子 + ↓ +LightGBM + ↓ +Backtest +``` + +### Phase 3:Web + +完成: + +```text +股票池 +因子 +选股 +回测 +结果 +``` + +### Phase 4:Experiment + +所有研究自动保存。 + +### Phase 5:AI Agent + +最后再接: + +```text +自然语言 + ↓ +Research Plan + ↓ +Tool + ↓ +Experiment +``` + +--- + +# 21. 数据流总图 + +```text + Tushare + │ + ▼ + Tushare Adapter + │ + │ 失败/缺失 + ▼ + Sina Adapter + │ + ▼ + Raw Data + │ + ▼ + Data Validator + │ + ▼ + Normalization + │ + ┌─────┴──────┐ + ▼ ▼ + SQLite Parquet + │ │ + │ ▼ + │ Qlib Dataset + │ │ + │ ┌─────┴─────┐ + │ ▼ ▼ + │ Factor Model + │ │ │ + │ └─────┬─────┘ + │ ▼ + │ Strategy + │ │ + │ ▼ + │ Backtest + │ │ + └────────────┤ + ▼ + Experiment + │ + ┌─────────┴─────────┐ + ▼ ▼ + Web Output AI Analysis +``` + +--- + +# 22. 最终原则 + +这个系统必须坚持: + +1. **Tushare 第一,新浪第二** +2. **数据源通过 Adapter 隔离** +3. **DAO / Repository 隔离数据库** +4. **SQLite 当前使用,SQLAlchemy 保证未来 MySQL 可切换** +5. **大量历史时序数据逐渐转 Parquet** +6. **Qlib 是计算引擎,不是整个系统** +7. **前端只面对自己的 Domain API** +8. **前后端通过 Research Specification 解耦** +9. **所有耗时任务异步化** +10. **所有研究产生 Experiment** +11. **严格防止未来函数** +12. **AI Agent 只能通过 Tool 使用研究能力** +13. **第一阶段不做实盘** +14. **第一阶段不做复杂分布式架构** +15. **每个模块都必须可以被单元测试** + +最终目标不是: + +> Qlib + Web + +而是: + +> **一个以 Qlib 为量化研究引擎、以 Tushare 为主要数据源、具备清晰 DAO 抽象和 AI Agent 接口的个人 A 股量化研究平台。** + diff --git a/experiments/.gitkeep b/experiments/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/frontend/web/README.md b/frontend/web/README.md new file mode 100644 index 0000000..a1bac31 --- /dev/null +++ b/frontend/web/README.md @@ -0,0 +1,6 @@ +# frontend/web + +React / Next.js 前端(Phase 3 初始化,当前为占位目录)。 + +按 docs/ARCHITECTURE.md §12-§14:前端只面对业务 Domain API(/api/stocks、/api/factors、 +/api/backtests ...),消费标准化 BacktestResult,禁止接触 Qlib 内部配置 / SQL / ORM 对象。 diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 0000000..32b5ca1 --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,3 @@ +# scripts + +数据同步 / 运维 / 一次性脚本(如 Tushare 拉数 CLI、Parquet 导出、Qlib Dataset 构建)。