根因三层(全案=audit/20261005_qmt_identity_env_plan.md): schtask 无 per-task env+机器级 env 未设→wrapper 被迫字面量;「部署身份」无单一权威源(env 名分裂三个);模拟号零安全压力致 32 文件 88 处 copy-paste 扩散。 - qmt_gate_common.load_identity 正典装载器(:14-59): env SANGUO_QMT_ACCOUNT/BIGQMT_ACCOUNT_ID(兼容别名)>json>RuntimeError fail-loud;SANGUO_IDENTITY_JSON 显式指路不存在=立即报错;查找=repo 相对>C:\sanguo_vnpy_v2\config\(生产副本回退位) - 灾备腿同源: relogin/qmt_bridge_probe/setclip 改 from qmt_gate_common import ACCOUNT - 桥腿镜像同链: xt_gateway._qmt_account/qmt_gateway_client._identity_default_account/is_price_source_vps/bridge_switch_ops(3 处 env 注入+1 处内嵌探针串)/check_xtquant——env 带默认的硬编码默认值全数退役 - xt_eod_wrapper.ps1 改 Get-Content identity json(保持 ASCII);码内 docstring 字面量→占位符(engine/runner/runner_live/live.yaml 注释/README) - .gitignore 白名单 !config/qmt_identity.json(全局 *.json 曾吞之,git check-ignore 实证) - tests/trader/test_qmt_identity.py 五钉: 装载链语义(env 双名覆盖/显式指路 fail)+单源一致性(identity≡live.yaml≡watch_accounts≡gate_common≡各腿镜像,休市表 CI 同步测先例)+码面字面量 grep-pin(生产码面零 66639661,只 config 三件套可含) - 监控 spec: §3.2 账号来源 bullet/§9.A-18 坑条/§12 行数+行号勘正(插入块致 bridge_ping/calendar_probe/relogin_running 引用行号推移);runbook: 非代码资产两行(副本回退路径+生产 wrapper 待改清单=10-08 窗口后 §五③) 生产 wrapper(C:\sanguo_bigqmt 库外)字面量收尾=10-08 复市验证窗口后非代码资产流程;VPS 班车同窗口(护 10-08 07:50 relogin 首班旧码纯净)。trader+api 620 绿。 Co-Authored-By: Claude Code <noreply@anthropic.com>
55 KiB
VPS 生产运维 Runbook(大QMT 桥栈)
sanguo 实盘交易栈生产运维手册(infra session 维护的活文档;上次全面更新 2026-09-14)。 2026-09-08 全量切桥(miniQMT → 大QMT RPC 桥)后本文为权威运维文档;旧 FastAPI bridge(:8765)+Caddy+miniQMT 直连架构已退役(文末历史节)。
相关文档:
- 发布流程与发布关联性检查清单:
../three-env-code-promote.md(唯二主文档之「发布」)- 提交纪律(环境标签 + 三线设计档同步闸门):promote §12/§12.1 —— 触及基建域(含本工具箱
scripts/qmt_relogin/)须同 push 更新本档或发布档,纯实现打[no-doc];CI 强制,档随码走- 大QMT 无人值守登录:
../qmt-headless-login-runbook.md- 本档=唯二主文档之「运维」。旧
vps-unified-deploy.md(web/回测/数据面)已收编进本档 §7 并归档。安全约定:本文进 git 不含任何凭证。登录凭证=DPAPI
C:\sanguo_bigqmt\creds\qmt_login.enc(进程内解密,never in argv / never on disk / never logged);redis 密码运行时读C:\redis\redis.conf。
1. 生产栈架构(2026-09 实态)
┌────────────────────────── Windows VPS 49.232.102.198 ──────────────────────────┐
│ │
│ XtItClient.exe(大QMT 客户端 GUI,唯一) │
│ └─ 模型交易实例(自动运行)= 桥 server 宿主 │
│ BIGQMT_REDIS_DRYRUN.py + bigqmt_signal_trader(含本地归一化补丁) │
│ │ Redis RPC(127.0.0.1,queue=bigqmt:rpc:queue:<acc>) │
│ ▼ │
│ C:\sanguo_bigqmt\xtquant_bridge\xtquant\(glue shim,接口兼容旧 miniQMT 语法) │
│ ▲ ▲ │
│ │ │ │
│ 引擎树(09-28 对账) 21:00 xt_eod(数据腿,同一 shim) │
│ ├─ live_17~22 全stopped(影子化迁移存量,live desk 空,supervisor 空转) │
│ └─ shadow_57~63 ×7 sanguo_trader.shadow --account ← sanguo-shadow-desk(--auto) │
│ │
│ 三层防御 schtask:07:50 relogin / 30min 哨兵 / 09:15 盘前探针 │
│ 采集 schtask 群:bs-daily 18:05 / idx 18:30 / ak 19:00+ / xt-daily 21:00 │
└────────────────────────────────────────────────────────────────────────────────┘
关键事实(新接手必读):
- XtItClient.exe = 大QMT 客户端本体 + 桥 server 宿主。它是 GUI 程序、无 headless 登录路径、 登录窗无「记住密码/自动登录」,登录会话不随柜台日切刷新 → 必须每日晨间重登(07:50 自动链)。
- miniQMT(XtMiniQmt.exe/miniquote.exe)零生产依赖(2026-09-10 数据腿切桥后),09-18 券商停服无感。 判活指标已不含 mini 栈;旧探针里 mini 相关 WARN 属遗留口径。
- 引擎断桥有 with_connect_retry 重试环,但 36h+ 长断桥后重试环会死(09-14 实例)→ 桥恢复后 若引擎日志无「📅 新交易日」,需收割重启(策略域工序)。
- 基线锚点:
TRADE_PROBE GREEN cash=7846164.67(恒等式基线,分毫不动即健康;变了先怀疑未对账成交)。恒等式语义(2026-10-01 老账调查定案):Σ实例市值只算**在册(status≠stopped)**实例——stopped 实例的书=冻结史(09-25 停机冻结 vs 快照随行就市=慢性假红 H1 分量),全 stopped → no_instances 绿;09-17 清算回滚残留(幻影 002088 −20100/300059 −9000、孤儿 002415/159915/510050/513030 等,−2127 万 811%)=H2 分量,归修账/留痕不归语义门,账本已在案(audit/20261001 代读包)。 - 引擎数期望以 DB 实查为准,勿按上图背数(09-28 联合巡检实证:live_accounts 17
22 全 stopped=影子化迁移存量, live desk 已空;生产引擎=shadow_5763 ×7,含挑战者 63szneul等权v1挑战者影子#69_v202609280)。vps_count_engines.py expected本就查 DB,晨查口径=当日 DB running 数对 wmic 实扫数。
1.5 桥 RPC 接口与更新流程(2026-09-19 起)
查接口一律先查桥仓库的接口参考:xtquant_big_convert repo docs/RPC_API_REFERENCE.md(全量 119 只读 + 2 下单,含参数/返回/语义;桥代码与接口文档同仓,改接口必须同步改这份)。运维高频入口:
| 需求 | RPC 方法 | 说明 |
|---|---|---|
| 当日成交/委托 | query_stock_trades / query_stock_orders |
空 strategy_name=全账户;当日会话语义,隔日查不到 |
| 历史成交/委托(任意日) | get_history_trade_detail |
组合入口(0.3.26 起):先终端原生函数(实盘注入)→ 模拟端/失败自动落本地 XtClient 日志扫描;返回 {source: client|local|none, rows} |
| 柜台持仓快照对账 | get_position_snapshots_local |
每次登录柜台全量下发持仓表,按登录批次切快照(一日约 3 张);A(晨初)/B(盘后)/C(次日晨初) 对齐法 = 09-17 清算回滚案的破案工具:C==A 而 B!=A 即当夜清算回滚签名 |
| 桥能力探测 | probe_capabilities |
qmt_globals 报每个终端注入函数的可用性(如模拟端 get_history_trade_detail_data: false) |
| 热重载 | reload_deployment |
下个 adjust tick 重导入部署包,不重启 QMT |
- 调用模板:
scripts/qmt_relogin/qmt_bridge_probe.py(redis127.0.0.1:6379 db=5,密码运行时读C:\redis\redis.conf;call_redis_rpc(rc, ACCOUNT, method, params);注意返回是 rpc 信封,handler 结果在data里)。 - 桥代码更新流程(源码=
xtquant_big_convertreposrc/bigqmt_signal_trader/,部署树=C:\国金QMT交易端模拟\python\bigqmt_signal_trader\,二者无自动同步):repo 改+测试 → scp 到 VPSC:\tmp\→ 远程 python(glob 定位中文路径)落部署树(先备份.bak_日期)→ RPCreload_deployment→ping的version字段核对生效。09-19 实例:0.3.26 = commit583e219。 - 取证原则:柜台侧疑案(持仓/清算对不上)先拉快照对齐,再看 deal 回放——
source=none是「没证据」不是「没成交」(回放只在终端当晚重连时写入,个别日子缺)。 - 快照留痕协议(2026-09-21 起,用户令「复发直接定罪 QMT,不再靠推断」):
C:\tmp\snap_archive.py(Mac 侧母本/tmp/snap_archive.py,滚动 3 日窗start_date/end_date必传、空串=空结果)经 RPCget_position_snapshots_local拉快照,归档C:\sanguo_vnpy_v2\logs\position_snapshots\snap_<ts>.json;节奏=盘前基线(随 09:20 例查)/盘后 B(21:05)/次晨 C(08:05,07:50 重登后),由 infra 的 claude-cron 唤醒执行;复发判定=C==B 且当日成交消失=柜台自身数据定罪,零推断(对齐表盯 002088/002415/159915/300059/510050 五票)。
2. schtask 全景表
| 任务 | 频率 | 动作 | 域 |
|---|---|---|---|
| sanguo-qmt-relogin | MON-FRI 07:50 | 杀+拉起+物理键入登录+验桥(v2 两阶段 exe→login;10-05 上机核实=周一~五,周末不开盘不重登,spec §8.1 同口径) | infra |
| sanguo-qmt-sentinel | 00:10 起每 30min | 进程+RPC ping+日历探针+cash 留痕;RED→自动触发 relogin | infra |
| sanguo-qmt-probe0915 | 工作日 09:15 | 盘前主动探针(510050×100@0.01 FIX 必不成交+即撤)=会话当日金标准 | infra |
| sanguo-live-supervisor | 开机/手动 | run_live_bridge.ps1 → sanguo_live --supervisor → 6×runner_live | 任务=infra,进程=策略域 |
| sanguo-shadow-desk | 开机/手动 | run_shadow_bridge.ps1 → sanguo_trader.shadow --auto → 6×shadow | 同上 |
| sanguo-api | 开机 | run_api.ps1 :8000(web/回测 API) | infra |
| sanguo-bs-daily | 18:05 | baostock eod→fund 串行 | 数据 |
| sanguo-xt-daily | 21:00 | xt_eod(ETF/基金/北交 EOD,走桥 shim) | 数据 |
| sanguo-idx-* / sanguo-ak-* / sanguo-margin-ps / sanguo-dsa / sanguo-factor-full | 各时段 | 指数/akshare 域/融资/截面/因子 | 数据(注:sanguo-dsa=用户侧独立调研项目 C:\sanguo_dsa\ --serve 常驻,sanguo_vnpy_v2 零引用、无监控;2026-10-03 用户拍板保留,勿当故障/退役候选重问) |
| sanguo-ak-events-retry | 周一至五 20:30 起每小时×4 发 | 重跑 ak-events wrapper(marker 幂等,兜 EM 当日未出数时序失败;09-25 重建=weekly 版,首版 hourly 被建成一次性跑完即死,§7.5 终态) | 数据 |
| sanguo-caddy | 开机 | mysanguo.online HTTPS 直 serve | infra |
| sanguo-ui / sanguo-shot | 按需 | console session UI 原语/截屏通道(ssh=session 0 不可用) | infra |
| sanguo-data-monitor-eve | 每日 23:50 | data_monitor_wrapper.ps1 -Shift evening(数据面监控终检:注册表 42 项四层证据链→data/monitor/health_*.json+alerts.db,spec §20.15) | 数据监控 |
| sanguo-data-monitor-morn | 每日 08:05 | 同 wrapper -Shift morning(晨间全量+前夜自愈回看+NAS inbox 摄取;08:10 晨检 agent 首读 health_latest.json) | 数据监控 |
| sanguo-strategy-monitor-morn | 每日 08:05 | strategy_monitor_wrapper.ps1 -Shift morn(盘前引擎面:期望数/进程数/会话日零重启§11.0/报错风暴/日志新鲜度;开盘前 85min=relogin 7:50 后 15min) |
策略监控 |
| sanguo-strategy-monitor-eve | 每日 21:30 | 同 wrapper -Shift eve(盘后产物+订单链:IS 日报出跑/恒等式 resid/订单残留/成交 vs 台账/周报出跑;错峰 20:45 日报+21:00 xt_eod 之后、23:50 data-eve 之前;infra 09-28 核批无碰撞) | 策略监控 |
监控注记:监控设计唯一权威源=
docs/superpowers/specs/2026-10-03-monitoring-design.md(2026-10-03 用户钦定统一档挂 CLAUDE.md;注册表 42 项/四层证据链/日历与三态容忍/休市表/row-band 滚动带/在岗互盯/坑全集/值班手册=其 §5/§6/§7/§9.B/§10)。此处只留调度分诊事实:监控 wrapper 恒 exit 0(例外=sanguo-xt-dailyETF/基金清单空时 rc=1 抬码防静默漏采,分诊=last_result=1+日志「FATAL ETF/基金 universe 异常(…)」(10-05 勘正实串:xt_eod.py:190 原文含「异常(…)」非「EMPTY」,grep EMPTY 零命中会误判无信号));NAS 监控 v2 挂sanguo-vps-mirror16:00 班尾(runner 属宿主生效位,CI 不覆盖——改 repo 副本后须scp -O同步/volume1/stock/monitor_nas/);告警消费入口=前端「运维告警」页/ops-alerts(APIGET /api/v1/alerts)。
策略面监控注记(2026-09-28 v1 上线):设计细节(v1.3 十一检五件套/§11.0 盘窗零重启口径/fills 逐对账/setpoint 7→3 翻转工序/连休值班预期/坑)唯一权威源=monitoring-design spec §4+§9.A;方案史档=
docs/superpowers/plans/2026-09-28-strategy-ops-monitor.md(已收编标注)。部署事实:scripts/strategy_monitor/三件套 schtask 本机跑(不经 ssh)+只读体检+wrapper 恒 exit 0+source="strategy"写同一 alerts.db(前端 /ops-alerts 类别=数据/策略);health 落health_strategy_{date}_{shift}.json+health_strategy_latest.json(health_latest.json 是数据域的,永不写);schtask 注册=register_strategy_monitor_schtasks.ps1随 promote 上 VPS 后由 infra 执行一次(工法照 factor_monthly register 先例)。
3. 三层防御 + 每日节律
| 时点 | 动作 | 判据 |
|---|---|---|
| 07:50 | relogin 自动重登 | EXIT=0 + trade-probe GREEN |
| 08:05 | 策略 session 晨查 | |
| 09:15 | 盘前探针 | order status=50 已报=会话当日 |
| 09:25 | infra 五件套闸门 | 对钟/引擎/RPC+allow_order/09:15 结果/日历探针(max 入历)+锚 |
| 全天 :10/:40 | 哨兵 | GREEN 留痕 C:\sanguo_bigqmt\gate\ |
| 15:10 | 恒等式(策略域) | 柜台 vs 台账逐票,前置=fresh trade-probe GREEN |
| 21:00 | xt_eod | DONE ok≈2303 fail=0 |
防御设计原则(用户 09-09 拍板,勿擅改):报警只记 log 不加通道;哨兵 30min;09:15 探针做; 失败不退避;脚本验可用性、agent 验正确性。被动查询测不出会话陈旧——主动探针是唯一金标准。
4. 非代码资产清单(promote.sh 推不到,发版/重装时人工核对)
git 不是 VPS 生产全貌。以下资产只存在 VPS(或需手动 scp),代码晋升流程管不到它们:
| 资产 | 位置 | 说明 |
|---|---|---|
| 桥工具箱+防御脚本 | C:\sanguo_bigqmt\(源码=repo scripts/qmt_relogin/) |
哨兵/探针/relogin/gate/wintree/ui_act/dsp_reset/minall/setclip 等;改 repo 后必须手动 scp 到 VPS 才生效;10-05 起账号读部署身份单一权威源 C:\sanguo_vnpy_v2\config\qmt_identity.json(随 promote 走,P2-18 根治——C:\sanguo_bigqmt 副本经回退路径自动取到,无需在此目录另放;方案=audit/20261005_qmt_identity_env_plan.md) |
| glue shim | C:\sanguo_bigqmt\xtquant_bridge\xtquant\ |
引擎+xt_eod 共用的接口兼容层;改动=双侧部署+relogin |
| 桥 server 部署位 | C:\国金QMT交易端模拟\python\bigqmt_signal_trader\ |
含本地补丁(market_bigqmt.py 归一化等);⚠️ 客户端升级会重装此树=补丁丢失须重打;同名包在安装树内有多份拷贝,打补丁先确认运行时 sys.path 实际加载的那份 |
| 桥策略第三方包 | ...\bin.x64\Lib\site-packages\ |
QMT 策略进程 sys.path 特殊,第三方包放这里(redis-py 用 3.5.3,4.x 不兼容 py3.6) |
| redis | C:\redis\(Windows 服务) |
requirepass;密码运行时读 redis.conf 零落盘 |
| frps(FRP 服务端) | C:\frp\frps.exe -c C:\frp\frps.json(nssm 服务 sanguo-frps,:7000) |
家里 Mac frpc-beijing 反连:13000=家Gitea 代码通道 / 13001=claude.mysanguo.online(北京 Caddy 反代)/ 18789=OpenClaw;token 看 frps.json(⚠️同目录 frps.toml 是 07-30 旧文件,勿混);nssm 崩溃放弃后不自愈,须手动 sc start sanguo-frps;验活=sc query sanguo-frps+`netstat -ano |
| 登录凭证 | C:\sanguo_bigqmt\creds\qmt_login.enc |
DPAPI hex blob;换机/换用户即失效 |
| wrapper ps1 ×5 | C:\sanguo_bigqmt\run_live_bridge.ps1 / run_shadow_bridge.ps1 / qmt_relogin_run.ps1 / xt_eod wrapper / C:\sanguo_vnpy_v2\run_api.ps1 |
必须 ASCII-only(PS5.1 无 BOM 按 GBK 解析中文注释可吃掉语句行);重定向已改追加式 *>>(保 stdout 证据);run_shadow_bridge.ps1 等账号字面量待改读 identity json(P2-18 §五③,10-08 复市验证窗口后、改前报备——repo 侧 xt_eod_wrapper.ps1 已改,生产生效位随 promote+班车) |
| 引擎运行时状态 | C:\sanguo_vnpy_v2\runtime\<inst>\live_state.json |
含锚(strategy_start_date),策略域所有,重启语义敏感 |
| gate 留痕 | C:\sanguo_bigqmt\gate\ |
每日 log + latest.json |
| schtask 注册本身 | 注册表 | XML 定义各任务;重建任务须原样(SYSTEM/HighestAvailable/频率) |
5. 运维命令速查(Mac 出发)
# 对钟(VPS 有漂移前科,任何时序排查先做)
ssh 49.232.102.198 "powershell -Command \"Get-Date -Format 'yyyy-MM-dd HH:mm:ss'\""; date '+本地: %Y-%m-%d %H:%M:%S'
# 桥健康(交易腿真数据)
ssh 49.232.102.198 "python C:\\sanguo_bigqmt\\bridge_switch_ops.py trade-probe"
# 期望: TRADE_PROBE GREEN cash=7846164.67
# 引擎/进程计数(supervisor+子进程)
ssh 49.232.102.198 "python C:\\sanguo_bigqmt\\bridge_switch_ops.py count"
# 期望: 以 DB 实查为准勿背数(§1 引擎树铁律)——现役 LIVE=0(live_17~22 全 stopped)+ SHADOW_CHILD=7(shadow_57~63 含挑战者63);晨查口径=当日 DB running 数对 wmic 实扫数
# 哨兵最新判据
ssh 49.232.102.198 "type C:\sanguo_bigqmt\gate\qmt_gate_latest.json"
# 引擎日志推进(进程在≠活,日志推进才是活)
ssh 49.232.102.198 "powershell -Command \"Get-Content C:\sanguo_vnpy_v2\logs\shadow_63.log -Tail 5\""
# relogin 末轮全链日志(登录链取证)
ssh 49.232.102.198 "powershell -Command \"Get-Content C:\sanguo_bigqmt\qmt_relogin.log -Tail 30\""
引擎收割/重启工序(⚠️ 顺序错误会触发重拉赛跑杀树):
- 先
/end整个 desk(sanguo-shadow-desk或sanguo-live-supervisor)让 supervisor 优雅退场; - 再收割残留子进程(若有);
/run重新拉起。 直接 terminate auto-respawn supervisor 的子进程=触发 supervisor 立即重拉,TerminateProcess 不走清理、 锁残留可致新子 8 秒全灭(09-14 shadow 事故实证)。rc=15=psutil terminate 指纹,发现时刻≠击杀时刻。
6. 已知问题库(09-08 切桥以来 35 起提炼,2026-09-18)
6.1 五波大事故(影响/差点影响交易)
| 日期 | 事故 | 根因 | 解法/防御 |
|---|---|---|---|
| 09-08 | pip 装桥 client 污染官方 xtquant → xt_eod 炸 | wheel src/xtquant 与 site-packages 同名 | force-reinstall;缺口 LOOKBACK 自愈 |
| 09-08 | 全舰队交易腿瘫痪全天 | 切档重启桥策略挤掉引擎连接;重连只在 boot | 轮换重启引擎;切档前预告策略域 |
| 09-09 | 26 单全拒 证券交易未初始化 |
客户端会话不随柜台日切 | 07:50 每日重登(三层防御第一层) |
| 09-11 | 12 引擎调度器全天停摆 | 桥 native 日历返字符串≠毫秒契约;四件套闸门无日历探针=盲区 | server+shim 双归一化;第五探针=日历类型断言 |
| 09-12~14 | 崩溃循环 16+ 轮(周末) | 客户端写日线缓存撕裂 7 DAT,启动重载即崩 | 隔离 DAT(move 不删自动重下)+WER 对话框 PostMessage;黑屏 CDS 重置;哨兵 30min 自愈实证 |
| 09-14 | shadow 六实例整树死 | 收割波触发旧 supervisor 重拉竞态 | 收割前先 /end desk(§5 工序);三信号监控 |
6.2 长尾坑分类(同类复发先查这里)
| 类别 | 要点 |
|---|---|
| A. QMT 是 GUI 不是服务(最大类) | 重登后 ~30min 持仓/资产查询空窗(不报错只返空,引擎不得在此窗读仓);周日夜柜台拒登(等开门自愈勿通宵折腾);WER 对话框盖登录窗;无人接入截屏全黑(dsp_reset);FG 抢占(minall);键盘错位暂态;1x 截图坐标幻觉(只信像素扫描+wintree+UIA);UI 自动化必须 console session(ssh=session 0 死) |
| B. 桥契约差异 | get_trading_dates 必须 int 毫秒(日历探针钉死);get_market_data 返 DataFrame;安装树同名包多拷贝(部署位陷阱);QMT 策略 py3.6+特殊 sys.path |
| C. 双腿架构 | XtItClient=交易腿勿与 mini 栈混淆;mini 栈现为闲置,重启会拉起登录窗=噪声 |
| D. 编排/进程生命周期 | 长断桥后引擎重试环会死(桥活也不重连→收割重启);supervisor 树杀顺序(§5);session-only cron 随 session 死(系统 schtask 是底座);时钟漂移先对钟;EOD 对账在 server 死时=伪干净(恒等式前置=fresh trade-probe);盘外 vps-deploy 收尾必滚动重启双树(vps_restart_resident.sh:taskkill→/end×2→sleep 30→/run×2 连发→引擎核验;盘中 09:15-15:30 自动跳过)——遇「无署名双 desk 重启」先对表 Gitea vps-deploy run 起止窗再谈悬案(09-14 23:13:13=run#1243、09-16 20:30:54/55=run#1256,两案悬三天实为授权部署的收尾步;infra 汇报部署必提此副作用;boot 时间戳可直接对表 CI run);09-13 16:16 frps OOM 饿死 5 天(Resource-Exhaustion 2004 点名 30.7GB 失控 python 吃光 commit→frps 被 nssm 拉起必崩 fatal error: out of memory→16:17 放弃 exit 1066 永不自愈→claude.mysanguo.online 502+13000 断;09-18 手动拉活)——同机失控计算会殃及交易栈,commit>90% 告警/回测内存上限待立项;09-19 真凶钉死=一周末两案两凶(2004 事件×8+文件 mtime 咬合取证):09-12(周六)18:05-18:31 六连 2004=ak 静态表周六马拉松 30.7GB(akshare_static_20260912_103200.log 10:32 写到 18:32,XtItClient 同场 980MB 侥幸未死);09-13(周日)16:11/16:16=margin TMC 回填 33GB(margin_backfill_20260913_075540.txt 07:55 跑到 16:17:59,深段翻页战争累积 8.3h)——两凶均已在代码层修根(margin=75af7f2 逐层预算+3cce22a 键集早停/翻页硬上限 90/per-stock 通道;ak-quarter=挪周六+vintage 自检),残余风险=未来任一新回填/回测类长跑再犯,防御三件 09-19 第一波已落地(用户拍板「先探着」):①哨兵第六探针+②commit>90% 告警=qmt_sentinel.py infra_probe()(frps:7000+claude 200+commit%≥90 三查,每 30min 全天候随哨兵 schtask,RED/AMBER 只记录不自愈;首跑 21:37 GREEN commit=28.8%;已部署 VPS+repo 同步);③回测/回填内存上限=第二波待统一监控设计时一并做(用户定位=现有探针是未来监控系统地基) |
| E. 环境/footgun | PS wrapper 必须 ASCII-only;裸跑 xt_eod 无 PYTHONPATH 回落旧腿(必须 schtask 或 wrapper);中文经 ssh/GBK 必坏(匹配用 ASCII 子串) |
细节与时间线:记忆 miniqmt-shutdown-migration-20260918 / qmt-ui-automation-toolchain /
qmt-sentinel-gate-plan-20260909 / xt-eod-bridge-leg-switch-20260910;登录处置全流程=
../qmt-headless-login-runbook.md。
7. web/回测/数据面(2026-09-14 自 vps-unified-deploy.md 收编)
7.1 三机角色与网络入口
| 机器 | 角色 | 跑什么 |
|---|---|---|
北京 VPS 49.232.102.198 |
生产 | sanguo_api :8000 + 前端 dist + 大QMT 桥栈(§1) + 权威 DB + 采集 schtask 群 |
NAS 192.168.2.154 |
test/备份 | Docker 容器(运维见 three-env-code-promote §9/§10) |
| Mac mini | 开发 | 改码/构建/部署(runner 是 Mac,睡眠时 CI 不跑) |
- 对外入口:
https://vnpy.mysanguo.online(北京 Caddy :443 直 serve,BootTrigger,ICP 已备案);老vnpy.mysanguo.top首尔入口 502=历史残留勿用。
7.2 VPS 安装清单与 sanguo_api
- Python
C:\Python310;vnpy 4.4.0 = 源码 PYTHONPATH 引用(不 pip install);pip 走阿里镜像。 sanguo-apischtask →C:\sanguo_vnpy_v2\run_api.ps1:env 定死(SANGUO_DATA_ROOT/SANGUO_DB_PATH/SANGUO_FILE_DIR/SANGUO_LIVE_ENABLED/SANGUO_QMT_ACCOUNT等)= 保 git 真相、三机共用 config;API 日志=C:\Users\Administrator\sanguo_api.log(worker traceback 看这里)。- 回测入口=runner_backtest 独占(VPS 不走 ProcessPool;runner≠orchestrator 的 runner 易混)。
7.3 已知坑(web/回测面,事故实锤)
| 坑 | 现象 | 解法 |
|---|---|---|
| empyrical×numpy2.0 | 结果页垃圾值(3305%)+无图 | metrics.py 导入前补回 np 别名(NINF/Inf 等) |
| 回测静默吞异常 | 显示垃圾不报错 | cta_engine 已加 traceback 到 warning(见 api log) |
| ProcessPool worker 缓存旧代码 | 改 .py 行为没变 | 重启 sanguo-api(/end+/run) |
| SSH 密集连接触发限连 | Connection closed ... port 22 |
等 30-60s 冷却;长脚本 detached + 轮询文件 |
| 复杂引号 ssh 命令拆坏 | PS 管道报「不是内部或外部命令」 | powershell -Command - + stdin heredoc 喂脚本 |
7.4 NAS 同步链(03:00 root 班+周日全量;2026-09-17 定稿)
链脚本=repo
scripts/nas_sync/,执行位=NAS/volume1/stock/sanguo_vnpy_v2/scripts/nas_sync/(root 班实跑这份,手动 scp 部署,CI 不覆盖;homes/admin 下同名目录=CI 仓副本非执行位,2026-09-18 实证勘误:09-17 两修只落 repo 未 scp 执行位,03:00 连跑两晚旧 13 类版,NAS margin 停 0911 而 VPS 已 0916);调度=DSM id=2 每日 03:00(root 身份执行)+周日 04:00 全量。方向=NAS 主动 ssh VPS 拉(SSH 22 出站通,光猫只拦 80/443)。 防漂移(09-18 加,两连咬后):改scripts/nas_sync/任一脚本 push 后,必须scp -O五.sh全量到执行位并diff执行位↔repo 逐个 SAME 收口(曾发生:repo 缺 parquet/valuation 两钩子、执行位带 NAS 本地热修的反向漂移,盲目推 repo 会静默停跑日同步)。
| 段 | 脚本 | 内容 | 频率 |
|---|---|---|---|
| dbbardata 增量 | sync_dbbardata.sh+export/merge_increment.py | 行情库增量 | 日 |
| 两表 | sync_tables.sh | constituent_unified+bs_adjust_factor REPLACE | 日 |
| per-date 18 类 | sync_parquet_daily.sh | 7 天窗单文件拉+gdhs/nb_hold 季度段+§20.13 三域 listing 段(09-22:pledge_ratio/research_report 周五锚+pledge_detail 月桶,skip-if-exists,滞后任意天必追上) | 日 |
| 根级目录 | sync_valuation_daily.sh | valuation/financial_abstract+vb/fb/index_const_hist scp -r | 日 |
| 周全量 | sync_parquet.sh | static+vb+fb 整树 6.24G/70min | 周日 |
-
运维规矩(09-17 实锤坑):①03:00 班以 root 跑,写的文件 root:root 644——admin 手动重跑链会撞 Permission Denied(盖不掉 root 属主文件,~60 个/晚);手动验证只用只读探针,写操作交给 03:00 班。②新增 per-date 数据域必须同步扩 sync_parquet_daily 覆盖(09-17 教训:四域+hot_rank 漏扩=NAS 周级滞后一周才实锤;形态二选一=TYPES 滚动窗[日更域]或 listing 段[周频/月桶 write-once 域,09-22 起 §20.13 三域先例——周五锚文件若首班失败次周补落,文件龄 8 天滚出 7 天窗,listing 才追得上])。
-
ak-weekly 三新域(融合 spec §20.13,2026-09-22 挂载):
ak_stock_wrapper.ps1追加两条独立命令(不带 --force,marker 幂等增量):--types pledge_ratio,pledge_detail --start 20210108+--types research_report --start 20210701。pledge_ratio 仅枚举周五(非周五 EM result=None 必失败),未发布周五 failed 不写 marker 次周自愈;pledge_detail=RPTA_APP_ACCUMDETAILS 254 页走 fetch_em_dc_pages 节流通道(1.2s/页≈6 分钟)月桶留存;research_report=reportapi 直连周窗 anchor=周五。 -
反向镜像链(融合 spec §20.11,2026-09-17 新增):
push_vps_mirror_daily.sh+vps_mirror_lib.py(纯逻辑,宿主 python3.8 stdlib)——corpus 五子域(09-22 起 +flash_meta 快讯域)+dmsk 五域 NAS→VPS 推送(09-18 起挂sanguo-corpus-dailyDSM 任务尾部=run_corpus_standalone.shEXIT trap 完赛即推,典型 ~10:1x/backfill 日 ~17:3x;rc 隔离=corpus rc∈0/1/3 才推[09-19 首验勘误:rc() 把「墙停+噪声 failed」报 1,旧 0/3 闸门 11 天只推 1 天,仅 rc=2 限流不推]、推送失败只记日志不进聚合 rc;admin 账号=避开 root 属主坑;原独立 16:00 DSM 方案作废),分区粒度 journal 指纹 diff 只增不删;部署位/volume1/stock/vps-mirror/(宿主文件,改 repo 副本后 scp -O 同步,同 corpus/dmsk runner 纪律),journal/watermark_*.json/push.log 同目录;VPS 落data\corpus+data\fundamentals\dmsk+族根_mirror_watermark.json(消费方get_watermark()晨检对表);任一失败不 commit journal/不落水位线=次日 diff 自愈;--dry-run打印将推送清单=验收收敛证明。设计与消费契约=融合 spec §20.11。09-20 增独立 static manifest lane(spec §20.11.7):data_backup/static_overlay/manifests/*.list(补洗变更清单,每行<domain>/<file>)文件级幂等推送、整单成功归档 pushed/、失败只 WARN 不影响 corpus/dmsk 聚合——三表 per-stock 文件由此 lane 推 VPS(不进 journal 指纹体系)。 -
flash 快讯 lane+xcheck 对账 lane(融合 spec §20.12.3/§20.12.4,09-22 上线):①
run_corpus_standalone.sh第三 lane--lane flash(金十快照+东财 kuaixun 翻页 T-1 边界,秒级完赛,rc 隔离不进聚合、独立跑不 gate 于 daily/backfill)→ corpus/flash_meta/ 落盘,镜像车五子域自动携带;②run_corpus_standalone.sh第四 lanexcheck.py --lane corpus_side(ann_em 拉取+公告披露日对照+腾讯 qt 全市场估值快照对照,rc 隔离);③run_dmsk.sh第四 lanexcheck.py --lane fund_side(读 wash manifests 当日命中股→新浪三表近 12 期+两源 NOTICE_DATE 对照)。xcheck 域落corpus/xcheck/不推 VPS(NAS 侧质检设施);findings 报告+trace 追溯=融合 spec §20.12.4;容器名 sanguo-xcheck(杀=docker stop sanguo-xcheck)。首跑锚点:corpus cron.logflash lane exit=0(隔离)行 +xcheck corpus_side exit=0行 + dmsk cron.logxcheck fund_side exit=0行 + 次日 push.log 出现 flash_meta 分区计数。 -
funnel 漏斗 lane+integrity gate lane(融合 spec §20.16/流水线 spec §4.8 P4-3,10-02 上线):
run_corpus_standalone.sh第五/六段——⑤corpus_funnel.py --until 23:00 --llm-cap 200 --token-budget 3000000(第一层词表八类事件零成本全量→events_llm 直落;第二层 LLM 只碰词表 miss:候选入state/funnel_pending.jsonl队列、串行慢爬、token 预算断路 rc=3 次夜续——10-05 审计 P2-16 前该断路仅文档宣称未接线,现已实接 3M=每夜费用上界(≈整夜墙钟吞吐量级,正常夜 <0.5M 不触;backlog 夜 checkpoint 次夜续);水位state/funnel_watermark.json只前向,历史回填--start按预算分批)⑥integrity_gate.py --profile default(三层门 crit exit1/warn exit2)。两段 rc 隔离不进聚合。LLM env 三件与 P4-1 向导同款(§运维表 288 行):DSM 任务环境或 run_corpus.sh 头 export 后由 wrapper 条件传递进容器;缺 key 且当晚有候选 → funnel rc=1(fail loud,非故障面=未配 env)。冒烟:corpus cron.logfunnel exit=0行+integrity gate exit=0行+corpus/events_llm/dt=*/分区出现;--no-llm可只验第一层。容器名 sanguo-funnel/sanguo-igate(杀=docker stop)。 -
因子月度批评·先批后评四段链(流水线 spec §4.2 决议 H+§12.4 决议 J,09-23 上线;09-27 加 stage4 归因批 10-04 首班起):双机同评——NAS+VPS 每月第一个周日 09:30 各跑同一批评链(①②③段),JSON 对拍件(
{host}_{asof}.json)落各自报告目录,人工/VPS 侧 scp 汇集到 NAS 后python -m sanguo_factor.review_compare nas_*.json vps_*.json对拍(一致=落档进告警流程;分歧 exit 2=只开排查 issue 不出降权告警)。ⓐNAS 侧:run_factor_monthly.sh(源码=reposcripts/nas_sync/run_factor_monthly_standalone.sh,改后 scp -O 同步生效位/volume1/stock/sanguo_vnpy_v2/)——一次性容器四段串行monthly_batch(注册表全量 12M 窗重评批,重活)→monthly_review --host nas(判定报告,JSON append-only)→data_gap_check→attribution_batch(归因批: 15 截面增量[12 源+size_log+在位者+挑战者,daily_section 幂等 merge,as_of 撞周末模块内归一最近 bar 日]→归因双跑[#69 影子 A/B 归因侧供给,挑战者落 challenger/ 子目录]→cp 双投递生效位[在位者件→admin 家data/attribution/根 glob 取最新;挑战者件带因子名;生效位目录容器挂 rw/effective-data,代码卷恒 :ro];工作区/volume1/stock/factor_cross_section/attribution/留全历史);as_of=上月末脚本头自算;rc 语义=①非零停链、②③ exit 2 是有效信号按 0 聚合、④非零=真失败(截面断供/归因挂/投递缺)进 final;容器金丝雀坑=必须-e HOME=/tmp -e MPLCONFIGDIR=/tmp/mpl(--user 1024 下 HOME=/ → vnpy import 建不了/.vntrader)。报告目录/volume1/stock/sanguo_vnpy_v2/reports/factor_monthly/;日志=factor_monthly_cron.log。DSM 任务sanguo-factor-monthly=每周日 09:30 admin(UI 手建)+脚本头日号闸——DSM 计划任务月度档只有「每月几号」没有「第一个周日」原生选项,调度只能建每周日,「是不是第一个周日」由脚本头dom>7 静默退出兜住。ⓑVPS 侧:wrapper=scripts/factor_research/factor_monthly_wrapper.ps1(三段同链批评部分,--host vps,eval_db=C:\sanguo_vnpy_v2\data\factor_eval.db,报告/日志=C:\sanguo_vnpy_v2\reports\factor_monthly\;ASCII-only 纪律;stage4 归因批不镜像——归因双跑落 NAS 工作区+生效位,VPS 侧归因件走 infra 偏差日报链另行供给);schtask 注册=scripts/factor_research/register_factor_monthly_task.ps1(XML ScheduleByMonthDayOfWeek 原生「每月第一个周日」,无需日号闸——zh-CN schtasks 不吃星期名组合走 ak-monthly 同款 XML 路线;SYSTEM/不限时,monthly_batch 重活首班实测耗时后再定是否拆任务错时)——vps-deploy 把两文件推上 VPS 后 ssh 跑一次注册脚本即成。首班=部署后第一个周日人工盯全程。 -
static 三表事件驱动补洗(融合 spec §20.11.7,2026-09-20 上线):
run_dmsk.sh第三 lanestatic_overlay_wash.py(dmsk daily/backfill 后 ~07:2x 起跑,--until 15:00 墙停,rc 隔离)——dmsk NOTICE_DATE 雷达命中股逐股 F10(emweb) 近 12 期 upsert 重写static/{income,balance,cashflow}/per-stock 文件;pending 重试队列(F10 落库滞后/网络失败次日自愈,30 天老化);周日 sync_parquet 全量回冲=雷达窗内自愈、更深归月度全量洗兜底;变更清单→晚间镜像车 manifest lane 推 VPS。 -
数据归属口径四原则与 14 条管线全景=融合 spec §20.10(数据面唯一权威查询入口)。
-
数据读取口径/灌库/备份不在本档:见数据设计活文档
docs/superpowers/specs/2026-07-21-data-source-fusion-design.md与 provider 文档。
7.5 数据源间歇断供档案(复发时判因用;2026-09-22 开档)
目的=病因留痕:断供事件证据位+未定论假说+复发判别树(下次复发照树走三探针即判因,不用重新勘测)。
事件 #1:hot_rank(东财 emappdata 人气榜)2026-09-17~21 三晚断供
- 症状:
ak-events19:30 班hot_rank/{date}3/3 retry 全烧,签名=('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))=服务端掐连接(非 timeout 非 403)。09-16 及 09-22 晚均正常(0.2s/100 行)。 - 证据位:VPS
data\static\logs\akshare_static_YYYYMMDD_193*.log(grephot_rank);数据面=data\static\hot_rank\文件名=最后成功日(快照型一晚一文件,断了就缺,无告警——类型级 failed 不抬 rc,巡检看目录新鲜度 vs 最后交易日)。 - 前科:
ak_events_wrapper.ps1头部 09-04 注释「emappdata 夜间开关,19:30 失败/22:28 实测 OK」——但 09-22 19:30 成功反证非固定时段开关。 - 病因未定论(恢复后无法回溯):假说 A=emappdata 服务端间歇故障(全国性);假说 B=针对 VPS IP(腾讯云段)的间歇风控。断供窗口内没做第二 IP 对照是本案取证缺口。
- 缺口口径:快照型端点无 date 参数,断供晚=该日快照永久丢(fetch 永远返当前榜,补跑老日期会拿今天的榜写老文件=数据污染;wrapper
--start today无自愈窗是防污染正确设计,margin 族滚动窗自愈不适用于快照族)。 - 复发判别树(核心,照抄执行):
- VPS 探针看签名:
ssh 49.232.102.198 'C:\Python310\python.exe -X utf8 -c "import requests;s=requests.Session();s.trust_env=False;r=s.post(\"https://emappdata.eastmoney.com/stockrank/getAllCurrentList\",json={\"appId\":\"appId01\",\"globalId\":\"786e4c21-70dc-435a-93bb-38\",\"marketType\":\"\",\"pageNo\":1,\"pageSize\":100},timeout=15);print(r.status_code,len(r.content))"'—— RemoteDisconnected=服务端掐;timeout=IP 黑洞型;403/429=风控明示。 - Mac/NAS 同命令对照(第二 IP):双侧同挂→假说 A 服务端故障(等恢复+评估换源);仅 VPS 挂→假说 B IP 风控(换源或深夜错峰重试)。
- 当晚 22:30 同探针再打一次:恢复→间歇型(记录窗口即可);仍挂→持续性(触发换源决策)。
- VPS 探针看签名:
- 换源/加固备选(连续≥3 晚才动,动前报用户):①wrapper 尾加 22:30 二次重试今日 unit(marker 幂等,治间歇型;改 VPS 生效位须口令)②同花顺 ths_hot_list 备份源(零鉴权)③xueqiu_hot 已每晚并行在采(语义邻近:关注热度 vs 人气榜)。
事件 #2:hot_rank 2026-09-23 晚第 4 次断供(晨检 09-24 发现,判别树已执行)
- 签名同 #1:193003.log
RemoteDisconnected 3/3(19:30:17~24),同班 sina_sector/sw_industry 全绿=仅 emappdata 域挂。 - 判别树执行结果(09-24 08:2x):探针②Mac=200/4476 ✓、探针③VPS=200/4476 ✓——双侧已自愈,窗口已过,A/B 假说仍不可判(几小时自愈窗口略偏假说 A 服务端间歇,不定论);探针①昨晚签名档在案。
- 序列:交易日 17断/18断/21断/22通/23断=4 断/6 交易日(频率较开档时 3/5 上升),但非连续≥3 晚,换源决策线未触发。
- 取证缺口持续:断供总在 19:30 窗口内、晨检 08:10 才发现,Mac 对照永远迟到。根治=备选①22:30 二次重试(重试成功=记录恢复窗口;仍挂=可当场跑 Mac 对照抓现行)——频率已 4/6,是否提前上待用户拍板(改 VPS wrapper 生效位须口令)。
哨兵方案(09-24 用户拍板「下猛药」:每小时重试+双 IP 同频对照)
- 社区调研结论(09-24):①GitHub issue 2026-01 同签名案例「服务器上总是 RemoteDisconnected、本地正常」=云服务器 IP 段被检测的社区实证 ②东财服务端静默断连机制(空闲超时
15s/单连接20 次限制,超限不发 FIN 直接掐=本案签名) ③「IP 列观察名单而非硬封」解释同 IP 间歇通断 ④云 IP 段(腾讯云等)更易被限。假说 B(IP 维度灰度限制)证据加权但未定论,A/B 判定仍靠双 IP 同频对照。 - VPS 侧(零代码改动,✅09-24 已注册生效,用户授权):每小时重试班=schtask
sanguo-ak-events-retry重跑与 19:30 主班完全相同的 wrapper(marker 幂等:已成功类型秒级 skip,只有断供的 hot_rank 真跑;时间护栏 19:00-23:59 天然覆盖)。窗口 20:30/21:30/22:30/23:30 四发(前科 22:28 恢复≈3 发内覆盖;跑通宵无增量信息且早榜漂移过大)。重试 log 行自带时刻+尝试签名=恢复窗口量化。 - 注记(09-27 审计 🟢-8):hot_rank 已迁 NAS 采集(§7.5 本节),VPS
static/hot_rank/内 NAS 时代推送件(0925 起)无 .akshare marker(与 VPS 自采时代不对称)——现无消费方依赖 marker,备案防未来复用时误判「未完成」重拉。注册命令(留档备用,重装/迁移用):schtasks /create /tn sanguo-ak-events-retry /tr "powershell -ExecutionPolicy Bypass -File C:\sanguo_vnpy_v2\scripts\data_platform\ak_events_wrapper.ps1" /sc hourly /mo 1 /st 20:30 /du 003:30 /f。 - Mac 侧(✅09-24 已上线):
~/bin/hot_rank_probe.py+crontab30 19,20,21,22,23 * * *(与 VPS 同频五发:19:30 主班时刻+四个重试时刻),只读探针恒 exit 0,log=~/logs/hot_rank_probe.log一行/发(时刻 ok/FAIL+签名)。 - 判读法(自动出结论):断供夜两侧 log 按时间轴对齐——VPS 挂 Mac 通=假说 B(云 IP);双挂=假说 A(服务端);VPS 重试第 N 发成功=恢复窗口分布。跑 1-2 周自然分晓,无需晨检手工对照。
- 快照语义注记:重试成功时刻≠19:30 定档时刻(人气榜盘中后仍有散户行为漂移),文件仍按当日名落盘,实际成功时刻以 log/文件 mtime 为准,消费方按需知悉。
终态定论(09-25 晚,哨兵首夜即出结论+迁移收口,本案闭档)
- 哨兵首夜判读(09-24 夜):时间轴完美对齐——Mac 探针五发全绿(19:30~23:30 全 200)vs VPS 主班+四发重试全断(20:30:00 Mac ok / 20:30:09 VPS
RemoteDisconnected 3/3,四发重试 log 实证真跑过 hot_rank 非 marker skip)。假说 A 排除、B 定论:emappdata 对 VPS 云 IP 针对性断连(家宽同分钟全通)。0923/24/25 三连断触发「连续≥3 晚」换源决策线。 - 处置(09-25 用户拍板):采集迁 NAS 家宽出口(spec §20.14)——corpus 班尾
run_hot_rank_nas.sh(17:35 一次性容器采 emappdata+腾讯 join,scp 推回0925 三天快照型不可回补(消费方零现役因子,接受)。static/hot_rank/,.pushed marker 补推);ak_events_wrapper.ps1同批摘除 hot_rank 类型(防双写);数据只维护 NAS/VPS 双机,Mac probe 留纯观测不留数据。缺口 0923 - 东财全景勘定(同晚实证):断连精确锁定 emappdata 一域——datacenter(龙虎榜/大宗/解禁)当晚 NoneType=EM 周五当日数据未出(Mac 直连同空对照,良性时序)非断连;push2ex/push2(涨停池/资金流)VPS 正常但对家宽出口恒空响应(hot_rank 迁移件 join 源因此弃 push2 用腾讯);reportapi 周域正常。
- retry 班坑与修复:
/sc hourly /st /du被 Windows 建成「一次性+每小时重复」→ 跑完注册当晚即死(下次运行 N/A,09-25 晚发现当晚 20:30/21:30 两发漏跑)。已重注册/sc weekly /d MON,TUE,WED,THU,FRI /st 20:30 /ri 60 /du 003:30(每周一至五四发;保留价值=兜 dragon_tiger 等 EM 当日未出数的时序失败,hot_rank 摘除后与 IP 断连无关)。 - 连带发现(同晚巡检):①
xueqiu_hot09-21 起静默断供 5 晚——雪球上线 TLS 指纹反爬(requests 恒 418 空体、curl 放行,Mac/VPS/akshare 1.18.88 三方实测),修复=fetch 改 curl 子进程(spec §20.14,同批推 VPS);②ak-weekly 09-19 班 share_capital 新浪源 85 只失败触发断路器跳过后续类型(rc=1),当班 pledge/研报增量被连累跳过靠 09-22 回填兜底——下一班(周六 03:00)若再熔断三新域增量会缺一周,晨检重点盯,被跳过当天手动补拉。
7.6 P2 孵化梯运行件(2026-09-24 起,spec §4.5 决议 L)
| 件 | 位置 | 说明 |
|---|---|---|
| 周报重算 job | APScheduler pipeline_weekly_report(常驻 sanguo-api 内,每日 20:45,晚于 20:30 live_step) |
双机各跑各的(B');注册在 sanguo_trader/scheduler.py:register_pipeline_weekly_job,失败不影响 api 启动(try/except 兜底);手动重算=PYTHONPATH=. python -m sanguo_portfolio.weekly_report --as-of <date>(--db 缺省 data/backtest_results.db=影子/paper 实走同库,即正确值;⚠️勿指 quant_trading.db——09-25 VPS 冒烟实证影子 supervisor 落库=backtest_results.db) |
| 毕业口令 | env SANGUO_PROMOTION_PASSPHRASE |
首班由用户设定后写进 api 启动环境(C:\sanguo_vnpy_v2\run_api.ps1 或系统 env);未配置→graduate 端点 503;口令不符→403 |
| Gitea 开 issue | env SANGUO_GITEA_BASE_URL(缺省 http://192.168.2.154:3000) |
--gitea-open/verdict 开 issue 的 API 地址;VPS=http://127.0.0.1:13000(FRP 映射家 Gitea,仅 VPS 可达);不设则 VPS 侧开 issue 静默降级=模板落盘 |
| 每机阈值库 | data/pipeline.db(env SANGUO_PIPELINE_DB 可改) |
gate 运行值+审计行+周报三表;连接即幂等自建 schema(首跑自举);控制台「闸门阈值」页可改(PUT 落审计) |
| 研判卡回放 | CLI PYTHONPATH=. python -m sanguo_factor.verdict_replay --as-of <同月度批评>(月度批评链后跟一条,同机同 as-of;10-04 首班双机首跑) |
产物 <monthly_dir>/verdict_replay.json(派生件可重建);触发点普查+七档事后成绩(近似估算,spec §4.7 P3 第一刀);GET /pipeline/research-card 读月报+此件出卡 |
| 研判裁决留痕 | env SANGUO_VERDICT_RECORDS(缺省 data/verdict_records.jsonl) |
POST /pipeline/research-card/verdict 落档(月键一条,重复 409);七档全人工触点零自动执行(决议 C) |
| 偏差日报(IS四分解) | CLI PYTHONPATH=. python -m sanguo_portfolio.ishortfall_daily --as-of <今日>(每日 20:45 后、周报 job 之后跟跑,避开 20:30 paper 回放与 21:00 xt_eod;价格源=scripts/pipeline/is_price_source_vps.py 桥 xtdata shim 分钟 bar+dbbardata 日线;首跑/部署后必跑其 probe(<day>) fail-loud 自检) |
产物 data/ishortfall/<day>.json+pipeline_store is_daily 表(GET /pipeline/attribution IS 四行+价格移动参考行数据源=latest_is());事件表 order_events 主库幂等自建(FIX 七态 append-only,老 backlog 委托入库就此闭环);回放=--from 2026-09-14 --to <日> 出首份真日报(幂等可重跑);⚠️回执缺供的'filled'终态单 cum 按快照兜不住→整腿按未全额计机会成本(identity_resid 非零可见,缺数非错算);spec §4.7 P3 第二刀 |
| 假设卡向导(P4-1) | env 三件:SANGUO_LLM_PROVIDER(缺省 glm_cn)/SANGUO_LLM_MODEL(缺省 glm-5.3-flash)/SANGUO_LLM_API_KEY(必配,仅 env 不入库);可选 SANGUO_LLM_BASE_URL 覆盖端点。配好后 run_api.ps1 加 env→重启 sanguo-api 生效 |
冒烟:登录后 curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:8000/api/v1/pipeline/hypotheses/draft -H "Content-Type: application/json" -d '{"sentence":"高管增持之后股价会涨"}' 期望 200 五字段 draft;未配 key 期望 503(这是 NAS 测试台默认形态);spec §4.8 P4 第一刀;向导依赖 api cwd 下 config/data_manifest.yaml(白名单来源),缺失/坏 YAML=正常降级空白名单非故障 |
| 策略注册表 | 运行副本=data/strategy_registry.yaml+data/strategy_events.jsonl(env SANGUO_STRATEGY_REGISTRY/SANGUO_STRATEGY_EVENTS 名不变);git 种子=config/strategy_registry.yaml 首触自举+缺失条目自动 merge(运行副本缺失时从种子拷贝;已存在时种子新登记条目由 ensure_runtime_registry 每次 touch 自动补入,同名条目运行态为准——2026-09-27 挑战者双机漏登记、周报点名跳过实证后治本) |
promote.sh 每次 push 都 rsync config/——运行期转移(毕业/退回/延长)若写 config/ 会被下次部署静默回滚,故运行态一律落 data/(部署不覆盖;merge 只补缺、绝不覆盖同名运行态);因子 verdict 端点同款:data/factor_registry.yaml+data/registry_events.jsonl(种子 config/factor_registry.yaml,factors 容器同走 merge);跨机同步=人工 git 收编(运行副本改动抄回 config/ 种子后 commit;转移事件同时落 reports/registry_events/ 毕业模板,防丢) |
| 存量补录 | PYTHONPATH=. python -m sanguo_portfolio.strategy_registry register <name> --hypothesis <H-x> --composite-version <v> --backfilled [--paper-account-id <id>] [--stage <s>] |
逐条补录在跑实例(gate 快照留空);现在写 data/ 运行副本(缺则从 config/ 种子自举;--stage 直落初档,如 --stage live);其余 CLI 子命令=transition(--stage/--gate-json/--capital-json/--cause)与 extend-shadow(--extra-weeks --note) |
| 回测 gate 判定 | PYTHONPATH=. python -m sanguo_portfolio.promotion_gate backtest --task-id <run> --db <主库>(或 --sharpe X --max-dd Y) |
打印 gate JSON,喂 strategy_registry transition --gate-json |
| VPS 控制台 | schtask sanguo-api(开机自启,run_api.ps1→run_web.py→uvicorn 8000,vnpy.mysanguo.top 外网绑定) |
B' 生产控制台;09-25 勘误:本就常驻跑纯 API(旧文「VPS 无常驻 web」过时);09-25 起挂前端 dist(frontend/dist,CI 只推 NAS 故 VPS 前端需手动 scp)+PASSPHRASE/GITEA_BASE_URL env 进 run_api.ps1;改代码后须 schtasks /end /tn sanguo-api && schtasks /run /tn sanguo-api 重启加载;env 优先级=SANGUO_DB_PATH env > config/backtest.yaml(yaml 里 db_path 是 NAS 容器路径,promote 种子直推,勿被误导) |
部署班次台账(tag
vps-deployed=部署真相,随班前移):70e7678(09-26 首)→ 16641f0(09-26 深夜)→ c97f449(09-27 审计修复波 10 条班车:影子A/B 2+偏差日报接线 1+factor 3+data 4;run 2104 success;影子 A/B 挑战者 id=63 当班落位,09-28 09:30 首跑)→ b3fe69a(09-27 深夜 P3 控制台班车 5 条[vps]:55bcde7 可读化波族切换器+归因页重构 /3a938ecregistry 种子缺失条目自动 merge /b7fc69e断言对齐 /fdbbb48归因页崩修+composite 接真 /b7ce364归因批 stage4;+2 条 spec doc 顺风;run 2125 success;VPS 冒烟=attribution 新契约/composite 接真 families+shadowCompare 0/4/ladder 含挑战者 shadow 三脸全绿;引擎未重启=11.0 铁律,registry merge 对已补行副本幂等 no-op)。
VPS 周报:过渡期 CLI schtask 已终结(09-25)——sanguo-api 常驻重启后 20:45 APScheduler job 自动跑(首班 09-25 晚);手动重算=CLI python -m sanguo_portfolio.weekly_report(不设 SANGUO_DB_PATH 即用缺省 data/backtest_results.db(正确库))。
P3 偏差日报批次(2026-09-26,回放毕/上 VPS 毕):已随 vps-deploy
16641f0班车全量上 VPS(首班 70e7678,10-04 前各波次顺延);历史回放(09-14→09-25)已完成出首份真日报(幂等可重跑);此后每日 20:45 后随周报链跑。接线(routes_pipeline IS 五行+factorContribution 读真)已毕;09-27 补调度接线:ishortfall 日跑挂库内 APScheduler 20:50 job(register_ishortfall_daily_job,随 sanguo-api 常驻,审计终裁落地)。⚠️手动跑 ishortfall_daily/probe 必预置全链 PYTHONPATH(09-26 VPS 冒烟实证)——
_ensure_bridge_env()运行时改 env 只利 spawn 子进程,不动当前进程 sys.path;缺此步import xtdata落到 site-packages 原生 xtquant 直连本机客户端,报「无法连接xtquant服务」。cmd 配方:cd /d C:\sanguo_vnpy_v2 set PYTHONPATH=C:\sanguo_bigqmt\xtquant_bridge;C:\sanguo_vnpy_v2;C:\sanguo_vnpy_v2\vnpy_v4.4.0;C:\sanguo_vnpy_v2\vnpy_qmt_v0.3.3 python -m sanguo_portfolio.ishortfall_daily --from 2026-09-14 --to <日> python -c "import sys; sys.path.insert(0,'.'); from scripts.pipeline.is_price_source_vps import probe; probe('<日>')"(probe 是函数非 CLI 子命令,python -c 直调;env 其余件 DEFAULT_DATA_PROVIDER/REDIS 口令由
_ensure_bridge_env运行时自设。)非交易日桥断连定性(09-26 周六实证):客户端在跑但行情断连时 bridge 连 1d 都返空 DataFrame(shim 返空不报错)——probe 分钟空≠代码错。日线锚走 dbbardata 不受影响,分钟缺腿=legs_no_anchor 如实可见;数据自愈(下个交易日 xt_eod 21:00 班)后幂等重跑回放覆盖 no_anchor 腿。
基准延伸节律(te/vs 保真,09-25 定):策略挂的回测基准 equity 停在其 end_date;周报对齐窗(近 4 周)随 as_of 前移会滑出回测段 → te/vs 掉 None。每 ≤4 周重跑一次基准:同参数 POST /portfolio/backtest(end_date=最新交易日)→ done 后 strategy_registry register <name> --backtest-run <新tid>(upsert 换挂,te/vs 自动对齐新段)。锚点=月度批评首班前一天晚捎带(10-04 起);重跑占 orchestrator 回测池(max_workers=2),避开批评链与当日回测高峰。
部署尾节清单(首班用户在场时执行,不自动):①推 vps(口令)②VPS 设 SANGUO_PROMOTION_PASSPHRASE ③VPS 存量补录 CLI 逐条跑(live/shadow 实例挂 paper_account_id;backfill CLI 现在写 data/ 运行副本,--stage 可用,如 --stage live)④VPS 控制台起法定型⑤NAS 侧无需新动作(api 容器随 CI 自动部署,20:45 job 自动注册)。
7.7 NAS 长批模式(一次性容器,2026-09-26 定型)
铁律:多小时批一律跑一次性容器,禁常驻容器 docker exec——nas-deploy 每次 push 重启 sanguo_vnpy_v2 常驻容器=当时在跑的 docker exec 批静默死(SIGKILL 无 traceback+| tail 管道掩退出码;09-25/26 累计 6 撞实证,撞杀窗口=活跃 session 的 push 频率,无协调可依赖)。
标准命令(corpus 一次性容器先例转正):
DOCKER=/var/packages/Docker/target/usr/bin/docker
$DOCKER run --rm -d --name sanguo-<批名> \
--user 1024:100 --group-add 101 \
--entrypoint python \
-e PYTHONPATH=/app:/app/vnpy_v4.4.0 -e HOME=/tmp -e MPLCONFIGDIR=/tmp/mpl \
-e TZ=Asia/Shanghai \
-v /volume1/homes/admin/.sanguo_projects/sanguo_vnpy_v2:/app \
-v /volume1/stock:/volume1/stock -w /app \
sanguo_vnpy_v2:lock-aligned -u <脚本.py>
三个 env 都是坑换来的:PYTHONPATH(entrypoint.sh 里设的会被 --entrypoint 覆写绕掉;脚本目录≠cwd,sanguo_*/vnpy import 不到)/HOME=/tmp(vnpy 导入要写 $HOME/.vntrader,uid 1024 下 HOME=/ 不可写→PermissionError 秒死)/MPLCONFIGDIR(matplotlib 缓存同因,警告级)。
配套纪律:①批脚本自带 append 日志(落 /volume1/stock 可跨容器重启存活)+分片+skip-if-exists(撞杀只丢在飞一片,重放即续)②判活=docker top <容器> -o pid,stat,time,cmd(容器内 busybox ps 截断 cmdline 假阴性;/proc 扫描自匹配模式字面量——判活一律 docker top)③批前查 CI 无 in_progress(窗口纪律,锦上添花非依赖)。
8. 在案遗留(观察项)
8. 在案遗留(观察项)
- 探针撤单在集合竞价段不确认(0.01 永不成交+日切自愈,无害)
- 冒烟 2 笔 ETF(510050+159915×100,残差 637.40)待用户手平
- mini 栈闲置:09-18 停服后建议彻底清除引用(避免假 WARN)
- upstream(xtquant_big_convert)归一化贡献 backlog
9. 历史:已退役架构(2026-07 时代,勿参照执行)
本 runbook 旧版描述的 FastAPI bridge(:8765) + Caddy 反代 + BRIDGE_TOKEN + miniQMT 进程内直连
已于 2026-09-08 全量切桥后退役:交易腿→Redis RPC 桥(本档 §1),数据腿→桥 shim(09-10),
BRIDGE_SESSION_ID 换号、/health 三端点、Mac SSH 隧道等内容全部作废。
仍有效的通用内容(Windows ssh 跑命令三坑:GBK 编码/引号嵌套用 stdin/中文路径用搜索)已并入
本档 §7.3 与 §6.2E。git 历史可查旧版全文。