# 交接:三系统量化交易 · 2026-08-06 收盘前 > 这份东西是写给下一个对话开头的。可以整段贴过去,也可以留在仓库里当阶段存档。 我们在推进三个相互衔接的量化交易系统。请先读项目记忆里的 **tradingsystem-bionic-bridge**、 **clock-and-timezones**、**tradingsystem-silent-failure** 三篇(都在 08-06 更新过), 背景需要时再读 tradingsystem-ws-channel 和 quant-factor-synthesis,工作方式看 feedback-plan-first 和 writing-style-readability。读完再看下文,然后等我给任务,不要自行开工。 --- ## 一、三系统与部署方式(改错部署方式等于白改) **tradingSystem(PMS,持仓管理)** 跑在 `factor@factorevaluation`。源码是打进镜像的, 所以改码必须 `make deploy`,跑完再 `make test` 看到 ALL SUITES PASS;盯盘用 `make watch`。 **容器时钟是北京时间。** **bionic_trader(决策系统)** 跑在 `192.168.16.188:38000`(tlaipro 机)。挂载卷, `git pull` 之后 `docker compose restart backend-api worker-brain` 即可生效; 但**新增 env 必须 `docker compose up -d --force-recreate`,`restart` 不重读 env**。 **容器时钟是 UTC。** **akg-factor-bridge(因子桥)** 在桥机 `factorevaluation`,容器名 `akg_factor_bridge`, API 在 8300。常驻 API 改码要 compose restart。**容器时钟是 UTC。** 线上运行中的系统只做加法。 ## 二、规矩(不变) 先出方案再动手;中文可读性第一,写完整自然句、不自造缩写;只做加法;宁可空池; 关键路径禁止丢弃返回值;全程 Docker,不给宿主机直跑 pip/python/psql;每条命令必须标注 运行在哪台机器,一块代码里只放一台机器;判收的标准是真机各见一次;写回 Mac 的文件以 written 回执加 md5 为准;**看桥和 bionic 的任何时间戳,先加八小时再和对话里的时间对齐。** 测试脚本由我在实机上运行,跑完把结果发给你,你不用跑复杂测试。里程碑的代码和文档 请提示我及时创建或上传到项目目录。 ## 三、下一个任务:给动作引擎加「新建仓」动作 **要解决的问题**:不能每天靠人手工走一遍下命令、排方案那一串。正常应该是上游选股计划 出现之后,PMS 按规则自己执行。 **已经查清的现状,不用重查**:整条链除了「下命令」这一步,其余全是自动的。调度表里 08:40 拉候选池,08:50 盘前准备,**每分钟**跑命令轮询(把已下达的命令排成方案)、盘中执行 (方案转指令 + 自主提议扫描 + 择时出手)、成交入账加轻对账、消化决策系统的盘中信号, 14:50 T 仓平回,15:10 日终结算加窗口收口,15:30 日报。`make t-*` 只是这些调度位的手动 等价物,是排查用的,不是日常流程。 **唯一要人的就是下命令,而且是刻意的**:计划回答「能买哪些」,命令回答「今天打算投多少」。 **三条路,性质完全不同**: 一是把下命令挂成定时,每天自动下一条升仓命令。改动最小,加一个调度位;代价是仓位单向 增长到撞上组合上限,而且不看市场状态。 二是把自主档位调到 full。**这条解决不了问题**——它只让已有持仓的增持类提议不用人确认, 而动作引擎产出的只有补足底仓、回踩补仓、盈利加仓、减持这四类,**根本没有「新建仓」 这个动作**。 三是给动作引擎加新建仓动作,让自主提议除了管已有持仓,也能从候选池里挑新票,走同样的 规则闸、研判闸、档位分流。这才对得上要解决的问题,是新逻辑不是新调度位。 **我选第三条。先出方案,我拍板之后再动手。** **开工前要知道的约束**:择时读的那张 `strategy_daily_results` 表,在盘中跑 push-pool 触发补扫时会被就地改写(详见第六节)。开发期靠「盘中不跑 push-pool」这条纪律规避, 没有改代码。设计新建仓动作时要把这件事放进考虑,别让无人值守的建仓建在会漂移的输入上。 ## 四、当前系统状态(2026-08-06 盘中,约 11:15) 账户总资产 2,000,288.86,可用 1,881,764.86,组合仓位 5.92%。参数:总规模 200 万, 自主档位 propose_only,下发模式 ws,择时档位 A,组合上限 70%,单股上限 8%,最多 20 只, 执行窗口默认 3 个交易日。 **持仓三只**:600150.SH 一千七百股、可卖一千二、摊薄成本 34.625、安全垫 +0.16%,参考位 支撑 34 压力 37 止损 34(来源 bionic);002335.SZ 一千九百股、可卖零、摊薄成本 30.984、 安全垫 +0.41%;000035.SZ 一百股、可卖零、摊薄成本 5.028、安全垫 -1.55%,**决策系统对它 的定性是 SELL**。 **在途四条**:000035 的减持一百股(来源自主提议,11:13 我在页面人工放行);002335 的清仓 一千九百股(来源决策系统风控信号,置信度 95%);002518 的买入九百股(**被新装的定性闸 拦着**,窗口今天到期);000063 的买入一千七百股(现价高于买入区间上沿,不追,窗口今天到期)。 前两条都要等明天 T+1 才能出手。 ## 五、08-05 到 08-06 做完的事 **买入侧补上了一道闸,两侧都已部署,真机判收成立。** 起因是发现候选层的结论对执行层 完全不可见:桥用 `strategy_daily_results.signal_type` 落在 SELL、AVOID、DROPPED 就把票请出 候选池,而决策系统的择时应答读同一个字段、放进 `observed.y_signal` 原样回传却从不用它判断, PMS 又只解析 verdict、limit_price、reason。同一条结论一边当判决一边当摆设。 600841 就差一根 3.3% 的阴线会被买进来。 改动:决策系统 `app/services/pms_advisor.py` 加 `BAD_Y_SIGNALS` 常量和买入分支的闸, `config/settings.py` 加开关 `PMS_EXEC_BLOCK_BAD_Y_SIGNAL`;PMS 侧 `app/core/rule_gate.py` 加 `BAD_SIGNAL` 检查项并把定性无条件写进 hard_numbers,`app/services/exec_advisor.py` 把 `observed.y_signal` 存进 advice 并挂到决策上,`app/services/executor.py` 传进规则闸 flags, `scripts/test_batch3_units.py` 加一条用例。**08-06 真机拦下第一笔:002518 停在 PROPOSED、 成交 0、理由是新写的那句。** PMS 那道 `BAD_SIGNAL` 至今没真的触发过(决策系统先回 WAIT 就走不到规则闸),符合当初「第二道闸平时空转、只为留痕」的预期。 其余:600841 的在途买入指令已撤(回执是 `cancelled:0` 加「仅本地置撤销」,PROPOSED 从没 下发过子单时走的就是这个分支);freeze 的 manifest.json 判收通过,08-03 和 08-04 两天 都在;XXL 例行调度的根因查实——从来没有自动拉起过,日志里只有手动触发的行,配置已重新设计。 ## 六、悬而未决(按优先级) 1. **主线**:动作引擎加新建仓动作,见第三节。 2. **昨夜结论会被盘中补扫就地改写**。push-pool 跑完触发增量补扫,补扫用 `trade_date=昨日` 就地覆盖已有那行,而 `fetch_yesterday_strategy` 是取最新一行、不按日期过滤。实证: 000035 在 09:53 成交时定性是 WATCH、压力 5.2,补扫之后变 SELL、压力 5.15;002335 的支撑 从 31.27 变成 29.00,差 7.3%。**开发期靠「盘中不跑 push-pool」规避,代码未改。** 真要修,最小加法是给 `fetch_yesterday_strategy` 加「只取今天之前」的过滤,但那样盘中 补扫的产出就完全用不上了,是不是想要的要先拍板。 3. **卖出侧的镜像缺口**。桥对「持仓且形态恶化」只警示、明确不出池,而 PMS 没有任何机制 会因为决策系统的定性去减仓——研判闸只管买入侧的补足、加仓、补仓,规则闸的冻结和黑名单 只挡增持。买入侧补上了,卖出侧还是空的。000035 现在就是这个状态。 4. **总资产与持仓市值的口径**。总资产来自 QMT 的 ws 资金快照,被组合刹车当权益基准用 (高水位与回撤,15:10 跑);持仓市值是 PMS 拿 Redis 分钟线自算的。08-05 两边差 564 元, 08-06 盘中只差 51 元。倾向是取数时点差不是口径差,收盘后价格静止时再对一次才能定案。 5. **时区显示错位八小时**。`_today_exit_verdict` 把 created_at 直接截成「01:35」拼进理由, 传到 PMS 页面和北京时间戳并排显示。给 bionic 容器设 `TZ=Asia/Shanghai`(新增 env, 必须 force-recreate)或者格式化时显式转。低优先。 6. **600150 最后五百股买在区间上沿**。区间连续四个交易日都是 [33.66, 34.9] 没变过, 今天现价正好等于上沿,闭区间判定放行,成交在 34.89,摊薄成本被从 34.514 抬到 34.625、 安全垫从峰值 +1.99% 压到 +0.01%。这是分批建仓遇上区间长期不变的固有副作用。 要不要改(现价等于上沿时不买,或者区间连续 N 天不变时降档)是策略取舍,未拍板。 7. **XXL 例行调度已重新配置**,验证点是看桥的 `data/xxl_build.log` 有没有在北京时间 07:10 自动长出新行(日志是 UTC,会写成前一天的 23:10)。 8. `trade_no` 格式核验(关系 S3 收尾函第一节的阻断项): `docker compose run --rm --no-deps pms-web python scripts/ws_smoke.py inbox --type trade --width 600`。 是 `SHADOW-xxxx#1` 这种确定式就闭环,还是 T-SHADOW 随机串就继续追。这条一直没做。 9. 命令目录里 `FREEZE_STOCK` 的说明写着「在途买入撤销」,与实现不符(它是参数类命令、 没有 planner,只让规则闸的冻结项拦),文案要补账。 10. 文档补账:`WS_INTEGRATION_STATUS.md` 停在 07-30;`BIONIC_PMS_INTERFACE.md` 第三节要 加一句新闸;README 待办 9 和 10 标判收。 11. 老悬项不变:分歧票候选层拦截未拍板;AKG_PLAN 并入 TECH_POOL 的共管规矩未拍板; 07-29 那 19 条 SIG_INVALID 未查明。 ## 七、这轮我犯过的三个误判,别重犯 **一是看见巧合就当线索。** 600150 的现价 34.900 恰好等于两笔委托的限价,我据此断定取价 有问题,还推出「安全垫其实是负的」。实际行情源是活的、分钟线连续,34.900 就是当时的 真实价。**先验证数据源是否在更新,再怀疑取值。** **二是没换算时区。** 审计行写着 01:35,我当成北京时间,于是把一个正常的四分钟赛跑 (09:31 咨询干净、09:32 成交、09:35:51 结论落库、09:36 信号到达)判成了「老闸漏读」的 bug, 差点去改代码。**桥和 bionic 的时间戳一律先加八小时。** **三是推理没落地就当结论。** 我推定 `audit_date` 会因为容器在 UTC 而错位一天,实际写入侧 用的是北京日期,洞根本不存在。**时间相关的猜测必须先查实际数据再下判断。**