88 lines
4.9 KiB
Markdown
88 lines
4.9 KiB
Markdown
# 优化选股执行性能
|
|
|
|
## Goal
|
|
|
|
在不改变知行 B1 公式语义和结果持久化契约的前提下,降低全量选股执行的
|
|
数据库连接、查询和事务开销,并默认使用 4 个受限 worker 并发评估股票。
|
|
|
|
用户价值:执行同一目标交易日的选股策略时,系统更快完成且仍能保留完整的
|
|
逐股状态、失败原因和七类独立子信号。
|
|
|
|
## Background and Confirmed Facts
|
|
|
|
- `RunZhixingB1.execute` 当前按 `prepared.source.stocks` 串行逐股执行:
|
|
[application/run.py:76-122](../../../zhixing-server/src/zhixing_server/modules/selection/application/run.py:76)。
|
|
- `PostgresMarketDataReader.load_history` 每只股票建立一次直接 PostgreSQL
|
|
连接并读取目标日前的全部 qfq 行情:
|
|
[infrastructure/postgres_reader.py:25-163](../../../zhixing-server/src/zhixing_server/modules/selection/infrastructure/postgres_reader.py:25)。
|
|
- `PostgresSelectionRunRepository.record_item` 每只股票建立独立事务,并逐条
|
|
插入其信号:
|
|
[infrastructure/postgres_runs.py:139-197](../../../zhixing-server/src/zhixing_server/modules/selection/infrastructure/postgres_runs.py:139)。
|
|
- 市场数据模块已经有可复用的有上限 `psycopg_pool.ConnectionPool` 模式:
|
|
[market_data/infrastructure/postgres.py:34-53](../../../zhixing-server/src/zhixing_server/modules/market_data/infrastructure/postgres.py:34)。
|
|
- 知行 B1 需要保留七类独立子信号;历史 golden 和现有测试是结果兼容基线。
|
|
- 本任务不引入 Redis,不改选股公式规则,不实现独立任务队列或新的进度 API。
|
|
|
|
## Requirements
|
|
|
|
### R1. 可观测的性能基线
|
|
|
|
- 为一次运行记录可复现的阶段指标:有效股票数、历史行数、读取耗时、公式
|
|
评估耗时、持久化耗时、worker 数和批次数。
|
|
- 指标不能输出数据库 URL、密码、Tushare token 或单股完整行情。
|
|
- 运行结果、信号分类和失败状态仍以 PostgreSQL 持久化结果为准。
|
|
|
|
### R2. 连接池化
|
|
|
|
- 选股读取适配器和结果存储适配器使用应用生命周期内的有上限 PostgreSQL
|
|
连接池,不再为每只股票创建和销毁连接。
|
|
- 连接池大小必须覆盖 4 个 worker、批量写入和必要的查询余量,不能无限增长。
|
|
- 应用关闭时可靠关闭连接池;单元测试可以注入 fake pool/connection。
|
|
|
|
### R3. 批量历史读取
|
|
|
|
- 保持 qfq、目标交易日截断、升序日期和六年数据保留语义不变。
|
|
- 将逐股历史读取改为按股票批量/分块读取;分块大小可配置但必须有默认上限,
|
|
防止一次性把全市场历史全部载入内存。
|
|
- 当前 B1 公式不使用历史 `turnover_rate` 和 `total_mv`;本任务可以移除历史
|
|
查询中不必要的 daily-basic 字段/连接,但目标日数据完整性校验必须保留。
|
|
|
|
### R4. 批量结果写入
|
|
|
|
- 将逐股 `record_item` 改为按批次写入 `selection_run_item` 和
|
|
`selection_signal`,默认批次大小为 200,且保留逐股评估异常隔离。
|
|
- 批次提交失败时不能标记为成功;运行最终状态必须正确收敛为
|
|
`success`、`partial_success` 或 `failed`。
|
|
- 结果查询、重跑唯一性和七类独立信号身份不变。
|
|
|
|
### R5. 四 worker 有界并发
|
|
|
|
- 默认使用 4 个 worker;并发度必须可配置且至少为 1。
|
|
- worker 不得无限创建连接、线程或进程;数据库连接数受池上限约束。
|
|
- 同一股票只评估一次;结果顺序不作为业务契约,API 查询仍按既有稳定规则排序。
|
|
- 公式计算失败仍只影响该股票,不能丢失其他股票结果。
|
|
|
|
## Out of Scope
|
|
|
|
- Redis、Celery/RQ/Arq 等外部任务队列或独立 worker 服务。
|
|
- 前端轮询协议和执行进度接口重构。
|
|
- 公式阈值、指标定义、历史窗口、股票池范围和信号分类调整。
|
|
- 结果表结构的大规模迁移或删除历史结果。
|
|
|
|
## Acceptance Criteria
|
|
|
|
- [ ] 在固定历史 fixture 上,现有 golden、七类独立信号和选股状态全部保持一致。
|
|
- [ ] 单元测试覆盖连接池生命周期、批量历史按股票分组、批量写入、4 worker
|
|
并发上限、单股异常隔离和批次失败状态收敛。
|
|
- [ ] 一次选股运行不再产生每股一次的数据库连接;读取和写入均通过连接池。
|
|
- [ ] 一次选股运行不再为每只股票单独提交结果事务;结果按批次提交。
|
|
- [ ] 运行日志/基准输出包含 R1 指标,并能区分 read/evaluate/persist 三段耗时。
|
|
- [ ] 使用实际 PostgreSQL 数据或等价可复现 harness 验证 4 worker 下运行成功,
|
|
且没有出现超出连接池上限的连接创建。
|
|
- [ ] 选股 HTTP 契约、重跑保护、最终分页结果和失败列表相关测试通过。
|
|
- [ ] 不引入 Redis,工作区只包含本任务相关改动。
|
|
|
|
## Open Questions
|
|
|
|
无阻塞问题。批量大小默认 200,worker 默认 4;两者保持配置化,后续以基准结果调整。
|