# AGENT.md ## AI Agent 开发约束 本文件是本项目所有 AI Coding Agent(Claude Code、DSH、REASONIX等)的开发约束。 **在修改代码前必须阅读本文件和 `ARCHITECTURE.md`。** **AI 回答必须使用中文** --- # 0. 网络下载与代理规则 当网络下载(git clone、pip / uv 安装、wget、数据下载、Docker pull 等)出现**困难或超时**时, 统一使用本机局域网 HTTP 代理: ```text 192.168.1.160:3128 ``` 示例(仅在下载失败 / 超时时启用,不把代理写入代码或 Git): ```bash # git clone(仅对 GitHub 等外网 https 目标使用) git -c http.proxy=http://192.168.1.160:3128 -c https.proxy=http://192.168.1.160:3128 clone # pip / uv 安装 export http_proxy=http://192.168.1.160:3128 export https_proxy=http://192.168.1.160:3128 uv pip install # wget / curl wget -e use_proxy=yes -e http_proxy=http://192.168.1.160:3128 ``` 注意事项: - 代理只用于**外网**下载;内网资源(如 ssh git@192.168.1.10、局域网服务)不要走代理。 - 代理 IP 属于局域网配置,不写入 `.env` / `config.yaml` / 任何提交进 Git 的文件。 - 直接下载成功时不要多此一举走代理。 ### 0.1 数据库目标:只允许本机 MariaDB(硬约束) - 数据库一律指向**本机 MariaDB 10.11**(`127.0.0.1:3306/qlib`)。 - **禁止把 `192.168.1.10` 作为数据库目标**(该地址在本文档中仅作外网代理白名单/SSH 提及, 不是数据库目标)。远端旧库只作为历史数据来源,已不再写入。 - 该约束不是「靠自觉」:`app/core/config.py::assert_db_target_allowed` 在 `get_settings()` 解析出 URL 后立刻校验,命中禁用主机**直接抛错**(应用起不来),不允许「起得来但连错库」。 禁用列表默认 `192.168.1.10`,可用环境变量 `QLIB_FORBIDDEN_DB_HOSTS` 覆盖(空串=不限制)。 - 理由:连错库属于最危险的静默错误 —— 不报错、界面正常,回测/归档/策略却写到了另一台机器上。 - 新增脚本/文档/示例配置时,DB 主机一律写 `127.0.0.1`,禁止出现远端库地址作为**默认值**。 --- # 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 ``` 都不应该要求推翻整个系统。 **这比单纯快速把功能写出来更重要。**