Files
ProStock/AGENTS.md

561 lines
18 KiB
Markdown
Raw Normal View History

# ProStock 代理指南
A股量化投资框架 - Python 项目,用于量化股票投资分析。
## 交流语言要求
**⚠️ 强制要求:所有沟通和思考过程必须使用中文。**
所有与 AI Agent 的交流必须使用中文
代码中的注释和文档字符串使用中文
禁止使用英文进行思考或沟通
## 构建/检查/测试命令
**⚠️ 重要:本项目强制使用 uv 作为 Python 包管理器和运行工具。禁止直接使用 `python``pip` 命令。**
```bash
# 安装依赖(必须使用 uv
uv pip install -e .
# 运行所有测试
uv run pytest
# 运行单个测试文件
uv run pytest tests/test_sync.py
# 运行单个测试类
uv run pytest tests/test_sync.py::TestDataSync
# 运行单个测试方法
uv run pytest tests/test_sync.py::TestDataSync::test_get_all_stock_codes_from_daily
# 使用详细输出运行
uv run pytest -v
# 运行覆盖率测试(如果安装了 pytest-cov
uv run pytest --cov=src --cov-report=term-missing
```
### 禁止的命令 ❌
以下命令在本项目中**严格禁止**
```bash
# 禁止直接使用 python
python -c "..." # 禁止!
python script.py # 禁止!
python -m pytest # 禁止!
python -m pip install # 禁止!
# 禁止直接使用 pip
pip install -e . # 禁止!
pip install package # 禁止!
pip list # 禁止!
```
### 正确的 uv 用法 ✅
```bash
# 运行 Python 代码
uv run python -c "..." # ✅ 正确
uv run python script.py # ✅ 正确
# 安装依赖
uv pip install -e . # ✅ 正确
uv pip install package # ✅ 正确
# 运行测试
uv run pytest # ✅ 正确
uv run pytest tests/test_sync.py # ✅ 正确
```
## 项目结构
```
ProStock/
├── src/ # 源代码
│ ├── config/ # 配置管理
│ │ ├── __init__.py
│ │ └── settings.py # pydantic-settings 配置
│ │
│ ├── data/ # 数据获取与存储
│ │ ├── api_wrappers/ # Tushare API 封装
│ │ │ ├── base_sync.py # 同步基础抽象类(BaseDataSync/StockBasedSync/DateBasedSync)
│ │ │ ├── api_daily.py # 日线数据接口(DailySync)
│ │ │ ├── api_pro_bar.py # Pro Bar 数据接口(ProBarSync)
│ │ │ ├── api_stock_basic.py # 股票基础信息接口
│ │ │ ├── api_trade_cal.py # 交易日历接口
│ │ │ ├── api_bak_basic.py # 历史股票列表接口(BakBasicSync)
│ │ │ ├── api_namechange.py # 股票名称变更接口
│ │ │ ├── financial_data/ # 财务数据接口
│ │ │ │ ├── api_income.py # 利润表接口
│ │ │ │ └── api_financial_sync.py # 财务数据同步
│ │ │ └── __init__.py
│ │ ├── __init__.py
│ │ ├── client.py # Tushare API 客户端(带速率限制)
│ │ ├── config.py # 数据模块配置
│ │ ├── db_inspector.py # 数据库信息查看工具
│ │ ├── db_manager.py # DuckDB 表管理和同步
│ │ ├── rate_limiter.py # 令牌桶速率限制器
│ │ ├── storage.py # 数据存储核心
│ │ ├── sync.py # 数据同步调度中心
│ │ └── utils.py # 数据模块工具函数
│ │
│ ├── factors/ # 因子计算框架DSL 表达式驱动)
│ │ ├── __init__.py # 导出所有公开 API
│ │ ├── dsl.py # DSL 表达式层 - 节点定义和运算符重载
│ │ ├── api.py # API 层 - 常用符号(close/open等)和函数(ts_mean/cs_rank等)
│ │ ├── compiler.py # AST 编译器 - 依赖提取
│ │ ├── translator.py # Polars 表达式翻译器
│ │ └── engine.py # 因子执行引擎 - 统一入口
│ │
│ ├── pipeline/ # 模型训练管道
│ │ ├── __init__.py
│ │ ├── pipeline.py # 处理流水线
│ │ ├── registry.py # 插件注册中心
│ │ ├── core/ # 核心抽象
│ │ │ ├── __init__.py
│ │ │ ├── base.py # 基类定义
│ │ │ └── splitter.py # 时间序列划分策略
│ │ ├── models/ # 模型实现
│ │ │ ├── __init__.py
│ │ │ └── models.py # LightGBM、CatBoost 等
│ │ └── processors/ # 数据处理器
│ │ ├── __init__.py
│ │ └── processors.py # 标准化、缩尾、中性化等
│ │
│ └── training/ # 训练入口
│ ├── __init__.py
│ ├── main.py # 训练主程序
│ ├── pipeline.py # 训练流程配置
│ └── output/ # 训练输出
│ └── top_stocks.tsv # 推荐股票结果
├── tests/ # 测试文件
│ ├── test_sync.py
│ └── test_daily.py
├── config/ # 配置文件
│ └── .env.local # 环境变量(不在 git 中)
├── data/ # 数据存储DuckDB
├── docs/ # 文档
├── pyproject.toml # 项目配置
└── README.md
```
## 代码风格指南
### Python 版本
- **需要 Python 3.10+**
- 使用现代 Python 特性match/case、海象运算符、类型提示
### 导入
```python
# 标准库优先
import os
import time
from datetime import datetime, timedelta
from pathlib import Path
from typing import Optional, Dict, Callable
from concurrent.futures import ThreadPoolExecutor
import threading
# 第三方包
import pandas as pd
import numpy as np
from tqdm import tqdm
from pydantic_settings import BaseSettings
# 本地模块(使用来自 src 的绝对导入)
from src.data.client import TushareClient
from src.data.storage import Storage
from src.config.settings import get_settings
```
### 类型提示
- **始终使用类型提示** 用于函数参数和返回值
- 对可空类型使用 `Optional[X]`
- 当可用时使用现代联合语法 `X | Y`Python 3.10+
-`typing` 导入类型:`Optional``Dict``Callable`
```python
def sync_single_stock(
self,
ts_code: str,
start_date: str,
end_date: str,
) -> pd.DataFrame:
...
```
### 文档字符串
- 使用 **Google 风格文档字符串**
- 包含 Args、Returns 部分
- 第一行保持简短摘要
```python
def get_next_date(date_str: str) -> str:
"""获取给定日期之后的下一天。
Args:
date_str: YYYYMMDD 格式的日期
Returns:
YYYYMMDD 格式的下一天日期
"""
...
```
### 命名约定
- 变量、函数、方法使用 `snake_case`
- 类使用 `PascalCase`
- 常量使用 `UPPER_CASE`
- 私有方法:`_leading_underscore`
- 受保护属性:`_single_underscore`
### 错误处理
- 使用特定的异常,不要使用裸 `except:`
- 使用上下文记录错误:`print(f"[ERROR] 上下文: {e}")`
- 对 API 调用使用指数退避重试逻辑
- 在关键错误时立即停止(设置停止标志)
```python
try:
data = api.query(...)
except Exception as e:
print(f"[ERROR] 获取 {ts_code} 失败: {e}")
raise # 记录后重新抛出
```
### 配置
- 对所有配置使用 **pydantic-settings**
-`config/.env.local` 文件加载
- 环境变量自动转换:`tushare_token``TUSHARE_TOKEN`
- 对配置单例使用 `@lru_cache()`
### 数据存储
- 使用 **DuckDB** 嵌入式 OLAP 数据库进行持久化
- 存储在 `data/` 目录中(通过 `DATA_PATH` 环境变量配置)
- 使用 UPSERT 模式(`INSERT OR REPLACE`)处理重复数据
- 多线程场景使用 `ThreadSafeStorage.queue_save()` + `flush()` 模式
### 线程与并发
- 对 I/O 密集型任务API 调用)使用 `ThreadPoolExecutor`
- 实现停止标志以实现优雅关闭:`threading.Event()`
- 数据同步默认工作线程数10
- 出错时始终使用 `executor.shutdown(wait=False, cancel_futures=True)`
### 日志记录
- 使用带前缀的 print 语句:`[模块名] 消息`
- 错误格式:`[ERROR] 上下文: 异常`
- 进度:循环中使用 `tqdm`
### 测试
- 使用 **pytest** 框架
- 模拟外部依赖Tushare API
- 使用 `@pytest.fixture` 进行测试设置
- 在导入位置打补丁:`patch('src.data.sync.Storage')`
- 测试成功和错误两种情况
### 日期格式
- 使用 `YYYYMMDD` 字符串格式表示日期
- 辅助函数:`get_today_date()``get_next_date()`
- 完全同步的默认开始日期:`20180101`
### 依赖项
关键包:
- `pandas>=2.0.0` - 数据处理
- `numpy>=1.24.0` - 数值计算
- `tushare>=2.0.0` - A股数据 API
- `pydantic>=2.0.0``pydantic-settings>=2.0.0` - 配置
- `tqdm>=4.65.0` - 进度条
- `pytest` - 测试(开发)
### 环境变量
创建 `config/.env.local`
```bash
TUSHARE_TOKEN=your_token_here
DATA_PATH=data
RATE_LIMIT=100
THREADS=10
```
## 常见任务
```bash
# 同步所有股票(增量)
uv run python -c "from src.data.sync import sync_all; sync_all()"
# 强制完全同步
uv run python -c "from src.data.sync import sync_all; sync_all(force_full=True)"
# 自定义线程数
uv run python -c "from src.data.sync import sync_all; sync_all(max_workers=20)"
```
## 架构变更历史
### v2.2 (2026-03-01) - 因子框架 DSL 化重构
#### 因子计算框架重构
**变更**: 从基类继承方式迁移到 DSL 表达式方式
**原因**:
- 提供更直观的数学公式表达方式
- 支持因子表达式的组合和嵌套
- 更好的类型安全和编译期检查
**架构变化**:
- 新增 `dsl.py`: 表达式节点基类和运算符重载Symbol、FunctionNode等
- 新增 `api.py`: 常用符号close/open/volume等和函数ts_mean/cs_rank等
- 新增 `compiler.py`: AST 编译器,提取表达式依赖
- 新增 `translator.py`: 将 DSL 表达式翻译为 Polars 表达式
- 重构 `engine.py`: 统一执行引擎入口,整合 DataRouter、ExecutionPlanner、ComputeEngine
- 移除: `base.py``composite.py``data_loader.py``data_spec.py`
- 移除: `factors/momentum/``factors/financial/` 子目录
**使用方式对比**:
```python
# 旧方式(基类继承)
class MA20Factor(TimeSeriesFactor):
name = "ma20"
data_specs = [DataSpec("daily", ["close"], 20)]
def compute(self, data):
return data.get_column("close").rolling_mean(20)
# 新方式DSL 表达式)
from src.factors.api import close, ts_mean
ma20 = ts_mean(close, 20) # 直接编写数学表达式
engine = FactorEngine()
engine.register("ma20", ma20)
result = engine.compute(["ma20"], "20240101", "20240131")
```
#### data 模块补充完善
**新增文件**:
- `api_wrappers/base_sync.py`: 数据同步基础抽象类BaseDataSync、StockBasedSync、DateBasedSync
- `data_router.py`: 数据路由器(已集成到 factors/engine.py 中的 DataRouter
- `utils.py`: 日期工具函数get_today_date、get_next_date、is_quarter_end等
**影响**: 数据同步逻辑更加规范化,支持按股票和按日期两种同步模式
### v2.1 (2026-02-28) - 同步模块规范更新
**变更**: 明确 `sync.py` 只包含每日更新的数据同步
**原因**: 区分高频(每日)和低频(季度/年度)数据,避免不必要的 API 调用
**规范**:
- `sync.py` / `sync_all_data()`: **仅包含每日更新的数据**
- 日线数据 (`api_daily`)
- Pro Bar 数据 (`api_pro_bar`)
- 交易日历 (`api_trade_cal`)
- 股票基本信息 (`api_stock_basic`)
- 历史股票列表 (`api_bak_basic`)
- **不应放入 `sync.py` 的季度/低频数据**:
- 财务数据 (`financial_data/` 目录): 利润表、资产负债表、现金流量表等
- 名称变更 (`api_namechange`): 已移除自动同步,建议手动定期同步
- **季度数据同步方式**:
```python
# 财务数据单独同步(不在 sync_all_data 中)
from src.data.api_wrappers.financial_data.api_financial_sync import sync_financial
sync_financial() # 增量同步利润表
# 名称变更手动同步
from src.data.api_wrappers import sync_namechange
sync_namechange(force=True)
```
### v2.0 (2026-02-23) - 重要更新
#### 存储层重构
**变更**: 从 HDF5 迁移到 DuckDB
**原因**: DuckDB 提供更好的查询性能、SQL 下推能力、并发支持
**影响**: 所有数据表现在使用 DuckDB 存储,旧 HDF5 文件可手动迁移
#### Sync 类迁移
**变更**: `DataSync` 类从 `sync.py` 迁移到 `api_daily.py`
**原因**: 实现代码职责分离,每个 API 文件包含自己的同步逻辑
**影响**:
- `sync.py` 保留为调度中心
- `api_daily.py` 包含 `DailySync` 类和 `sync_daily` 函数
#### 新增模块
**pipeline 模块**: 机器学习流水线组件(处理器、模型、划分策略)
**training 模块**: 训练入口程序
**factors/momentum**: 动量因子MA、收益率排名
**factors/financial**: 财务因子框架
**data/utils.py**: 日期工具函数集中管理
#### 新增 API 接口
`api_namechange.py`: 股票曾用名接口(手动同步)
`api_bak_basic.py`: 历史股票列表接口
#### 工具函数统一
`get_today_date()``get_next_date()``DEFAULT_START_DATE` 等函数统一在 `src/data/utils.py` 中管理
其他模块应从 `utils.py` 导入这些函数,避免重复定义
其他模块应从 `utils.py` 导入这些函数,避免重复定义
## Factors 框架设计说明
### 架构层次
因子框架采用分层设计,从上到下依次是:
```
API 层 (api.py)
|
v
DSL 层 (dsl.py) <- 因子表达式 (Node)
|
v
Compiler (compiler.py) <- AST 依赖提取
|
v
Translator (translator.py) <- 翻译为 Polars 表达式
|
v
Engine (engine.py) <- 执行引擎 (DataRouter/ExecutionPlanner/ComputeEngine)
|
v
数据层 (data_router.py + DuckDB) <- 数据获取和存储
```
### 使用方式
#### 1. 基础表达式
```python
from src.factors.api import close, open, ts_mean, cs_rank
# 定义因子表达式(惰性计算)
ma20 = ts_mean(close, 20) # 20日移动平均
price_rank = cs_rank(close) # 收盘价截面排名
# 组合运算
alpha = ma20 * 0.6 + price_rank * 0.4
```
#### 2. 注册和执行
```python
from src.factors import FactorEngine
engine = FactorEngine()
engine.register("ma20", ma20)
engine.register("price_rank", price_rank)
# 执行计算
result = engine.compute(
factor_names=["ma20", "price_rank"],
start_date="20240101",
end_date="20240131",
)
```
### 支持的函数
**时间序列函数 (ts_*)**
- `ts_mean(x, window)` - 滚动均值
- `ts_std(x, window)` - 滚动标准差
- `ts_max(x, window)` - 滚动最大值
- `ts_min(x, window)` - 滚动最小值
- `ts_sum(x, window)` - 滚动求和
- `ts_delay(x, periods)` - 滞后 N 期
- `ts_delta(x, periods)` - 差分 N 期
- `ts_corr(x, y, window)` - 滚动相关系数
- `ts_cov(x, y, window)` - 滚动协方差
- `ts_rank(x, window)` - 滚动排名
**截面函数 (cs_*)**
- `cs_rank(x)` - 截面排名(分位数)
- `cs_zscore(x)` - Z-Score 标准化
- `cs_neutralize(x, group)` - 行业/市值中性化
- `cs_winsorize(x, lower, upper)` - 缩尾处理
- `cs_demean(x)` - 去均值
**数学函数**
- `log(x)` - 自然对数
- `exp(x)` - 指数函数
- `sqrt(x)` - 平方根
- `sign(x)` - 符号函数
- `abs(x)` - 绝对值
- `max_(x, y)` / `min_(x, y)` - 逐元素最值
- `clip(x, lower, upper)` - 数值裁剪
**条件函数**
- `if_(condition, true_val, false_val)` - 条件选择
- `where(condition, true_val, false_val)` - if_ 的别名
### 运算符支持
DSL 表达式支持完整的 Python 运算符:
```python
# 算术运算: +, -, *, /, //, %, **
expr1 = (close - open) / open * 100 # 涨跌幅
# 比较运算: ==, !=, <, <=, >, >=
expr2 = close > open # 是否上涨
# 一元运算: -, +, abs()
expr3 = -change # 涨跌额取反
# 链式调用
expr4 = ts_mean(cs_rank(close), 20) # 排名后的20日平滑
```
## AI 行为准则
## AI 行为准则
### LSP 检测报错处理
**⚠️ 强制要求:当进行 LSP 检测时报错,必定是代码格式问题。**
如果 LSP 检测报错,必须按照以下流程处理:
1. **问题定位**
- 报错必定是由基础格式错误引起:缩进错误、引号括号不匹配、代码格式错误等
- 必须读取对应的代码行,精确定位错误
2. **修复方式**
-**必须**:读取报错文件,检查具体代码行
-**必须**:修复格式错误(缩进、括号匹配、引号闭合等)
-**禁止**:删除文件重新修改
-**禁止**:自行 rollback 文件
-**禁止**:新建文件重新修改
-**禁止**:忽略错误继续执行
3. **验证要求**
- 修复后必须重新运行 LSP 检测确认无错误
- 确保修改仅针对格式问题,不改变代码逻辑
**示例场景**
```
LSP 报错Syntax error on line 45
✅ 正确做法:读取文件第 45 行,发现少了一个右括号,添加后重新检测
❌ 错误做法:删除文件重新写、或者忽略错误继续
```
### Emoji 表情禁用规则
**⚠️ 强制要求:代码和测试文件中禁止出现 emoji 表情。**
1. **禁止范围**
- 所有 `.py` 源代码文件
- 所有测试文件 (`tests/` 目录)
- 配置文件、脚本文件
2. **替代方案**
- ❌ 禁止使用:`print("✅ 成功")``print("❌ 失败")``# 📝 注释`
- ✅ 应使用:`print("[成功]")``print("[失败]")``# 注释`
- 使用方括号 `[成功]``[警告]``[错误]` 等文字标记代替 emoji
3. **唯一例外**
- AGENTS.md 文件本身可以使用 emoji 进行文档强调(如本文件中的 ⚠️)
- 项目文档、README 等对外展示文件可以酌情使用
4. **检查方法**
- 使用正则表达式搜索 emoji`[\U0001F600-\U0001F64F\U0001F300-\U0001F5FF\U0001F680-\U0001F6FF\U0001F1E0-\U0001F1FF\u2600-\u26FF\u2700-\u27BF]`
- 提交前自查,确保无 emoji 混入代码