# 知行 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` 并进入实现阶段。