tradingSystem/HANDOFF_2026-08-07.md

166 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 交接:三系统量化交易 · 2026-08-07 开盘前
> 这份是给下一个对话窗口用的。详细节点在 `tradingSystem/DEVLOG.md`,那里按时间记着每一条
> 「做了什么 / 动了哪些文件 / 部署方式 / 真机判收 / 还欠着什么」。**这份只写坐标、状态和待办,
> 需要细节就去翻 DEVLOG不要凭这份文件的概括去改代码。**
>
> 另一条更要紧的:**以项目代码为准,不要迷信文档。** 上一轮交接文档里有大量上一个对话
> 汇总时产生的幻觉(例如把已经存在的 `A_OPEN` 说成不存在)。读代码,不读文档的结论。
---
## 一、三系统与部署方式(改错部署方式等于白改)
| 系统 | 位置 | 改码怎么生效 |
|---|---|---|
| **tradingSystemPMS仓位管理** | `factor@factorevaluation` | 源码**打进镜像**,必须 `make deploy`;跑 `make test``ALL SUITES PASS`(当前 469 例);盯盘 `make watch` |
| **bionic_trader决策系统** | `192.168.16.188:38000` | 挂载卷,`git pull` 后 `docker compose restart backend-api worker-brain`**新增 env 必须 `docker compose up -d --force-recreate`**restart 不重读 env |
| **akg-factor-bridge因子桥** | `factorevaluation`,容器 `akg_factor_bridge`API 8300 | 常驻 API 改码要 compose restart |
**时区08-06 查实、08-07 再证一次,按「哪种时间」分,不能按「哪个系统」一刀切)**
- **容器时钟与容器日志正文** —— 北京时间,**不加八小时**。证据bionic 容器内 `date` = `15:37 CST`
- **数据库时间列**`strategy_audit_log.created_at`、`strategy_daily_results.updated_at`)—— **UTC要加八小时**。证据08-07 北京 09:03 时该库 `SELECT NOW()` = `2026-08-07 01:03:32`
- **日期列**`audit_date`、`trade_date`)—— 北京日期,不换算。
- `docker logs -t` 前缀是 UTC跟正文里 Python logging 的时间不是一个口径,别混读。
> 上一轮交接文档写的是「bionic 容器时钟是 UTC先加八小时」**错的**,已在 DEVLOG 头部改正。
---
## 二、规矩(不变,逐条都被真实事故验证过)
1. **先出方案再动手。** 不要边想边改。
2. **中文可读性第一**:写完整自然句、不自造缩写、不发明术语。(我发明过「干跑」,项目自己的词是「试算」,被当场纠正。)
3. **只做加法。** 动线上系统只加不改,改既有行为要单独提、单独拍板。
4. **宁可空池。** 数据不干净就交空的,不要凑。
5. **关键路径禁止丢弃返回值**(静默失败是这个项目的头号 bug 模式,有 48 例专项单测盯着)。
6. **全程 Docker**,不给宿主机直跑 pip / python / psql。
7. **每条命令必须标注运行在哪台机器,一块代码里只放一台机器。**
8. **判收标准是真机各见一次**,不写「应该没问题」。
9. **写回 Mac 的文件以 written 回执加 md5 为准。**
10. **测试脚本由用户在实机上跑**,跑完把结果贴回来;不要自己跑复杂测试。
11. **里程碑要提示用户及时创建/上传到项目目录。**
12. **动 tradingSystem 以外的系统之前先答三题**,第一题是「是否影响了原有业务系统」。决策系统本来就不管仓位,要加仓位信息只能单独处理 PMS 那部分逻辑。
**三个不许重犯的误判**(外加这轮新增的第四个)
1. 把巧合当证据。
2. 时间不换算就下判断。
3. 推理没落地就当结论。(这轮又犯了一次:我推断「新建仓没部署,所以那些 `PMS_REJECT` 不可能来自它」,而用户当时已经盘中部署了。)
4. **新增:把「我没改过这个字符串」当成结论交付。** 今早那个「【手动重跑AKG_PLAN】」正确做法是全仓库检索出唯一写入点、把调用链一行行走通、再用落库时刻查实而不是止步于「不是我改的」。
---
## 三、当前系统状态2026-08-07 开盘前)
- **新建仓OPEN自主提议已上线并跑过实盘**`PMS_OPEN_AUTONOMY = full`QMT 是模拟池。
- **研判闸已真正接通**`PMS_JUDGE_API_BASE` 之前一直是空的08-06 才第一次真发请求)。
- 决策系统的盘中买入信号已接进 PMS此前一直被丢在门口
- 两个 bug 已修:研判请求体的 `Decimal` 序列化、运维口径文本污染股票评述。
**最近提交**
| 仓库 | 最新提交 | 部署状态 |
|---|---|---|
| tradingSystem | `bcf9ff0 08-07 09:13 处理评述问题` | ✅ 已 `make deploy` + `make test` 通过(用户确认) |
| bionic_trader | `6e82dcb 08-07 09:14 处理评述问题` | ⚠️ **未部署**,等收盘后 `docker compose restart worker-brain` |
| akg-factor-bridge | `d076c96 08-05` | 本轮未动 |
---
## 四、08-06 → 08-07 做完的事(细节见 DEVLOG 同名节点)
1. **新建仓动作,两侧代码写完**。PMS 侧动了 `action_engine`(新增 `eval_open` / `scan_open`)、`proposal_service``_scan_open` / `_route_one` 的 OPEN 分支)、`judge`OPEN 硬数字裁剪,只送定性材料不送仓位数字)、`exec_advisor`(参照位漂移保护)、`exec_timing`(窗口末日强制完成只对命令生效)、`signal_rules` / `signal_service`(新增 `NOTE_BUY`)、`param_store` / `settings`。新增 `test_batch12_units.py` 44 例,全量 469 例通过。bionic 侧只动 `tasks_intraday.py` 的两个 `PMS_JUDGE`48 增 4 删),不加 env 所以 restart 即可。
2. **决策系统买入信号接进 PMS**:并入既有 Redis 信号链,不轮询。
3. **窗口末日追高修正**`hard_gate` 的 `is_command` 改成必填无默认值,自主买入在窗口末日不强制完成、到期作废(可以接受买不上);卖出侧故意不动。
4. **跳过原因分得开**`skip` 从集合改成带原因的字典,四种处境(在途提议 / 在途指令 / 规则闸拒过 / 研判闸驳回)各有各的话。
5. **研判闸的 `Decimal` 崩溃**(危害渐进,值得记住):`_recent_ledger()` 把 `price_at`DECIMAL 列)塞进请求体,`requests.post(json=)` 序列化不了。只要一只票的评审账本里有过任何一行,它的研判就必然失败,而账本只会越积越多——过几天几乎所有票的研判都会失败并降级人工确认,而每一条看起来都只是「研判不可用,降级人工确认」这种系统里天天有的正常降级。修法是在请求出口统一做 `jsonable()` 递归转换,不是修单个字段。
6. **运维口径护栏(今早)**:见下节。
---
## 五、今早这条单独说【手动重跑AKG_PLAN】
**现象**页面上部分股票的评述里冒出「【手动重跑AKG_PLAN】」这种看不懂的字段。
**根因**(全部源码验证,非推测):`bionic_trader/scripts/rerun_pool.py:237-238` 拼出
`【手动重跑】手动重跑池 AKG_PLAN`,然后 `delay(c, reason, None, target_date)` ——
**第二个位置参数不是留痕字段,是 `reviewer_feedback`,风控官质询通道**
文本不带「【盘中」前缀,`IntradayClassifier` 返回 None于是掉进 `elif reviewer_feedback:`
被拼进提示词的 `[📢 CRITICAL CHALLENGE FROM RISK OFFICER]` 段,后面跟着
`You MUST address this in your analysis`。那是命令,大脑照办写进 `analysis`
再经 `save_to_database` 覆盖进 `strategy_daily_results.analysis_summary`
**比字段本身重要得多的收获——悬项二从推测变成实证。** `rerun_pool` 落库是
`ON DUPLICATE KEY UPDATE`,把 `signal_type / support_level / pressure_level /
analysis_summary` 一起就地覆盖。查实的落库时刻(库时钟 UTC下表已换算北京时间
| trade_date | 行数 | 落库时刻(北京) | 当时是什么时候 |
|---|---|---|---|
| 20260806 | 16 | 08-06 22:32 → 22:45 | 收盘后,安全 |
| 20260805 | 18 | 08-05 22:30 → **08-06 11:04** | **盘中**,改写的是当时正被读的昨夜结论 |
| 20260804 | 11 | **08-05 13:04** → 08-07 00:50 | **盘中**,补录历史日 |
这张表下游有两个读者bionic `pms_advisor`(支撑压力位算 PMS 买卖区间、`signal_type` 走
`BAD_Y_SIGNALS` 闸)与桥 `pool.py``BAD_SIGNALS`(决定把哪只票请出候选池)。
所以「盘中不跑 push-pool」这条纪律不只针对桥**`rerun_pool` 同样在内**。
**改法(两处,缺一不可)**`rerun_pool.py` 下发固定传 `None`(根治),`--reason` 保留但只印在
脚本输出里;`tasks_brain.py` 加 `_is_ops_note()` 前缀护栏认
`【手动重跑】/【运维】/【回补】`,先打日志再置空(兜底)。只做根治不做兜底不行——脚本用法
示例明写着鼓励人手填 `--reason "调整X因子后重跑"`。新增
`scripts/selftest_ops_note_guard.py` 24 项,做过三次变异验证确认它真会失败。
**已污染的评述救不回来**:就地覆盖,没有历史表。
---
## 六、待办(按优先级)
**P0 — 收盘后第一件事**
- bionic`git pull` → `docker exec trader_worker_brain python scripts/selftest_ops_note_guard.py`(见「全部通过」)→ `docker compose restart worker-brain`。没有新增 env不用 `--force-recreate``backend-api` 没动,不用重启它。
- 判收第二步:收盘后跑 `rerun_pool.py --group AKG_PLAN --limit 1 --reason "护栏验证"`,确认 worker 日志有「🛡️ 运维口径说明已从提示词中剔除」,且该票新落库的 `analysis_summary` 不含「手动重跑」。
**P1**
- 队列里那三条 `PRP_..._OPEN` 提议要在页面上驳回(它们的研判从来没成功过,留着会挡住这三只票的重新评估)。**08-07 早上是否已驳回,未确认。**
- 第一周要盯的五个数:每天有几只候选落在买入区间内、研判驳回率、**研判 UNAVAILABLE 率**Decimal 事故后新加的第五个)、`intraday_exec` 一跳的耗时分布、评审账本每天的行数。
- OPEN 的研判驳回率要连着看几天。08-06 是 11 条全 REJECT14:0714:38理由都在谈开新仓框架是对的零 PASS。理由引用宏观空头/熊市共振,当天 100% 驳回可能是对的,但 OPEN 的判据里有**双重保守**(「标准应当比加仓类更严」+「宁可错杀不可错放」),要盯几天看是不是压得过死。
**P2 — 需要用户拍板**
- **口径三**:信号票是否可以放宽「不追高」或择时闸。背景:信号池与候选池重叠只有 1/67唯一重叠的 `300570.SZ` 倒在 `NO_CHASE_MA5: 距 MA5 12.22% > 上限 6%`。而那 67 条信号理由全是「放量突破 / 量比 8.55 / 站上关键位」——**按定义就是离 MA5 远的票**。所以口径一(信号只重排序、不放宽任何闸)结构上注定拿不到增量,只有口径三才有真增量。但它动的是「不追高、接受买不上」这条纪律,必须用户决定。
- `SZ000800` 有两行打架的定性:`trade_date=20260806` 是 `SELL`08-06 22:38 写入),`trade_date=20260804` 是 `DROPPED`08-07 00:50 写入,**晚了两个多小时**)。补录历史日会写出「时间更新、日期更旧」的行,取数方按 `trade_date` 排还是按 `updated_at` 排会拿到不同答案。`pms_advisor` 与桥 `pool.py` 两处口径要对一遍。
- 已污染的三批评述16/18/11 行)要不要收盘后洗一遍。洗=再跑一次全量重算,支撑压力位会再动,只能收盘后做。
**P3**
-`industry.get_many``gp_stock_category` 分支加按日缓存(每跳省几十次库查询,但改的是既有函数的时序行为,单独提、单独拍板)。
- `rerun_pool.py``--dry-run` 的中文说明写的是「干跑」,项目里同类东西叫「试算」,措辞不统一。
- 文档补账:`WS_INTEGRATION_STATUS.md` 停在 07-30`BIONIC_PMS_INTERFACE.md` 要补新建仓这一路(研判闸第五类动作、硬数字裁剪、择时侧零改动)。
---
## 七、悬而未决
| # | 事 | 状态 |
|---|---|---|
| 二 | 盘中改写 `strategy_daily_results` 顶掉昨夜结论 | **已从推测变实证**08-05 / 08-06 各发生一次。PMS 侧有 `PMS_OPEN_REF_DRIFT_MAX` 漂移保护,但那是止损不是免疫 |
| 四 | 总资产与持仓市值的差额 | 已结56408-05→ 5108-06 盘中)→ **4.00 元**(收盘后),是时点与价格精度差,不是口径差。**但 `+ sell_return_today` 双算的假设没测过**(当天零卖出),仍开着 |
| 八 | `trade_no` 幂等键 | `trade_no` 是随机串(`T-SHADOW-420911c4b8`),不是确定性的 `SHADOW-xxxx#1`。回放到底按 `trade_no` 还是按单调的 `seq` 去重,未确认 |
| — | `trading_buy_plan` | 死枝:最新一行停在 07-30ENTRY_GATE 已关(`ENTRY_GATE_ENABLED=False`),无重复买入风险 |
---
## 八、速查
**关键参数**`PMS_AUTONOMY`、`PMS_OPEN_AUTONOMY`(新,默认 `full`)、`PMS_JUDGE_ACTIONS`(默认 `FILL,ADD,DCA,SWITCH,OPEN`)、`PMS_JUDGE_TIMEOUT=90`、bionic 侧 `PMS_JUDGE_TASK_TIMEOUT=75`、`PMS_OPEN_REF_DRIFT_MAX=0.03`、`PMS_JUDGE_TICK_BUDGET_SEC=150`、`PMS_OPEN_REQUIRE_WS_CASH=True`、`PMS_OPEN_SIGNAL_PRIORITY=True`、`PMS_PLAN_TOP_N=30`、`PMS_PLAN_TOP=300`。
**两道闸**:规则闸(`rule_gate.check`,纯代码,所有指令都要过)→ 研判闸(`judge.request` → bionic `POST /api/intraday/pms_judge`LLM3090 秒,只管自主提议,命令驱动不过)→ 自主档位路由(`full` / `propose_only` / `off`)。
**择时**实现A = bionic `POST /api/intraday/pms_exec`读昨夜支撑压力位推买卖区间秒级实现B = PMS 内置保守择时(`exec_timing.decide`)。
**文档**`DEVLOG.md`(节点日志,**最先读这个**)、`NEW_POSITION_ACTION_PLAN.md`(新建仓方案 V3 + 八步判收)、`BIONIC_PMS_INTERFACE.md`(欠更新)、`README.md`。