Files
zhixing-system/.trellis/tasks/08-08-migrate-zhixing-b1/implement.md
T

154 lines
5.8 KiB
Markdown
Raw Normal View History

2026-08-08 22:41:45 +08:00
# 知行 B1 选股策略实施计划
## 实施原则
- 只修改 `zhixing-system`;旧项目只读,不回写、不重命名、不提交旧项目数据。
- 先写行为测试,再补最小实现;每一步保持 `uv run pytest` 可定位失败范围。
- `zhixing_b1` 是新策略身份;不要把 `xg_composite` 作为新模块的对外名称。
- 公式语义优先于旧 Python 的偶然行为;每个有意差异都要在 fixture 或测试名中
留下证据。
- 不启动 HTTP、前端、信号持久化或全市场批次编排;它们属于后续任务。
## 1. 依赖与模块骨架
- 在 `zhixing-server/pyproject.toml` 声明直接依赖 `pandas` 和 `numpy`,执行
`uv lock`,确认锁文件与 Python 3.12 环境一致。
- 创建 `modules/selection/{domain,application,infrastructure,presentation}`
包和上下文 README,保持 domain 不导入 FastAPI/Psycopg。
- 先新增领域模型、端口和评估状态类型,再接入基础设施。
验证:
```bash
cd zhixing-server
uv lock --check
uv run python -c "import numpy, pandas; print(numpy.__version__, pandas.__version__)"
```
回滚点:依赖或包骨架若无法通过 Ruff/Pyright,先撤销骨架,不触碰
`modules/market_data`。
## 2. 迁移公式原语
- 从旧项目 `shared/indicators.py`、`kdj.py`、`rsi.py`、`zhixing.py` 和
`market_type.py` 提取必要实现到 `selection/domain/indicators.py`。
- 先覆盖 `MA/EMA/LLV/HHV/SMA/REF/EXIST/EVERY/COUNT/HHVBARS/BARSLAST/CROSS`,
再实现 KDJ、RSI、知行线和板块幅度参数。
- 每个公共函数增加完整类型、参数/返回值/边界说明;NaN、除零和不足窗口行为
用测试锁定。
- 不引入 Numba、SciPy 或其他旧项目专用依赖;首期 Pandas/NumPy 足够保持公式
计算的向量化和数值接近。
验证:
```bash
cd zhixing-server
uv run pytest tests/unit/selection/test_indicators.py
```
## 3. 实现 `ZhixingB1Strategy`
- 将旧 `prepare_xg_indicators()` 拆成可读的领域计算步骤:基础线、振幅、KDJ/RSI、
缩量、大绿棒、异动、趋势、距离/回踩、7 个子信号。
- 策略类固定 `name = "zhixing_b1"`,公开入口显式接收 `StockHistory` 和
`target_trade_date`。
- 对目标交易日定位使用日期索引,不使用 DataFrame 最后一行猜测目标日期。
- 保留 7 个 mask 的全部命中,按公式顺序产生多个 `SelectionSignal`,不可使用
旧代码中的 `break`。
- 详情只写可序列化、与目标行相关的关键指标;不要保存整张 DataFrame。
- 对目标日缺失、历史不足、无信号分别返回评估状态;公式计算异常向上暴露,
不静默转换为空结果。
验证:
```bash
cd zhixing-server
uv run pytest tests/unit/selection/test_zhixing_b1.py
```
回滚点:若结果数量明显偏离 golden,保留公式原语测试和差异报告,回滚策略
编排层,不回退到旧 `xg_composite` 命名。
## 4. 建立市场数据读取端口与 PostgreSQL 适配器
- 在 `selection/domain/ports.py` 定义只读 `MarketDataReader`。
- 在 `selection/infrastructure/postgres_reader.py` 实现参数化查询,读取 qfq
`market_daily_bar`,左连接同日 `market_daily_basic`,按日期升序映射为
`StockHistory`。
- 从 `Settings` 注入连接串;不直接读取环境变量,不调用 Tushare,不回退 CSV。
- 使用数据库事实表的 `source_adj = 'qfq'` 过滤,拒绝目标日之后的行。
- 连接失败转换为带股票和目标日上下文的基础设施错误;目标日无 bar 属于可识别
的业务状态。
验证:
```bash
cd zhixing-server
uv run pytest tests/unit/selection/test_postgres_reader.py
```
若增加 PostgreSQL 集成覆盖:
```bash
cd zhixing-server
uv run pytest -m integration tests/integration/test_selection_reader.py
```
回滚点:只读适配器失败时删除 selection 适配器即可;不得修改已有市场数据表、
同步事务或 Alembic migration。
## 5. 应用用例与 Fake reader
- 实现 `EvaluateZhixingB1`,输入 `ts_code`、`target_trade_date` 和 reader,输出
`SelectionEvaluation`。
- 用例只负责读取、调用领域策略和映射错误;不负责全市场循环、保存信号或 HTTP
响应。
- 提供 Fake reader 测试目标日期截断、缺失目标行、历史不足、无信号、选中多分类
和基础设施错误。
验证:
```bash
cd zhixing-server
uv run pytest tests/unit/selection/test_evaluate.py
```
## 6. 固定 fixture 与 golden 对比
- 从旧项目现有 `data/raw` 中选取少量股票和目标日期,抽取最小 OHLCV CSV,放入
`zhixing-server/tests/fixtures/selection/zhixing_b1/`。
- 将旧实现或人工确认结果固化为 JSON,包含目标日期、命中分类集合和关键详情的
容差范围;测试运行时不导入旧项目。
- 至少包含普通代码和宽幅代码,并加入一个人工构造的同日多信号样本。
- 明确记录旧实现“只保留第一个分类”与新实现“保留全部分类”的差异。
验证:
```bash
cd zhixing-server
uv run pytest tests/integration/test_zhixing_b1_golden.py
```
## 7. 完整质量检查与规划复核
实现结束后运行:
```bash
cd zhixing-server
uv run ruff format --check .
uv run ruff check .
uv run pyright
uv run pytest
```
并检查:
- `rg -n "xg_composite|zgnb\." src/zhixing_server/modules/selection tests` 只在
迁移说明或兼容性测试中出现,不成为新领域运行时依赖;
- 旧项目工作区没有被修改;
- 没有新增 HTTP 路由、前端文件、信号表 migration 或调度入口;
- golden、单元测试和端口测试都能在无网络、无生产数据库条件下运行。
完成 planning 后,先向用户展示 `prd.md`、`design.md` 和本文件摘要;只有用户
明确批准最新 planning summary,才能执行 `task.py start` 并进入实现阶段。