From 8c6a3f90d0d09110ab403e59cabddc991d4fdbe1 Mon Sep 17 00:00:00 2001 From: claude_dev Date: Wed, 2 Sep 2026 10:25:36 +0800 Subject: [PATCH] =?UTF-8?q?fix(strategy):=20channel=5Ftest=E7=9B=98?= =?UTF-8?q?=E5=A4=96=E8=BD=AE=E6=8D=A2=E6=94=B9=E9=94=9A=E5=9B=BA=E5=AE=9A?= =?UTF-8?q?9:35=E2=80=94=E2=80=9409-02=20dev=E5=B7=A1=E6=A3=80=E5=AE=9E?= =?UTF-8?q?=E9=94=A45d0a0bf=E5=89=AF=E4=BD=9C=E7=94=A8:=E9=9A=8F=E5=90=AF?= =?UTF-8?q?=E9=9A=8F=E9=AA=8C=E3=80=8C=E7=9B=98=E5=A4=96=E4=B8=8D=E6=B3=A8?= =?UTF-8?q?=E5=86=8C=E3=80=8D=C3=97=E8=BF=90=E7=BB=B4=E8=A7=84=E5=88=99?= =?UTF-8?q?=E3=80=8C=E8=BD=AE=E6=8D=A2=E6=94=BE23:05=E5=90=8E=E3=80=8D=3D?= =?UTF-8?q?=E6=AF=8F=E6=AC=A1boot=E9=83=BD=E7=9B=98=E5=A4=96=E2=86=92?= =?UTF-8?q?=E6=B0=B8=E4=B8=8D=E6=B3=A8=E5=86=8C=E2=86=92=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E9=80=9A=E9=81=93=E5=81=9C=E6=91=86(live=5F18/22=E9=9B=B6?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1,=E8=B0=83=E5=BA=A6=E6=81=A2=E5=A4=8D?= =?UTF-8?q?=E5=8F=88=E5=9B=A0=E5=AD=98=E6=A1=A3=E6=A8=A1=E5=9D=97=E8=B7=AF?= =?UTF-8?q?=E5=BE=84vs=20runtime=E5=89=AF=E6=9C=AC=E9=94=99=E9=85=8D?= =?UTF-8?q?=E6=81=92=E5=A4=B1=E8=B4=A5,=E5=AE=88=E5=8D=AB=E5=86=8D?= =?UTF-8?q?=E6=8B=A6=E5=9B=9E=E9=80=80=E6=B3=A8=E5=86=8C,=E4=B8=89?= =?UTF-8?q?=E9=87=8D=E5=8F=A0=E5=8A=A0=E6=B8=85=E7=A9=BA);=E8=80=83?= =?UTF-8?q?=E5=8F=A4=E6=BE=84=E6=B8=85:=E5=9B=9B=E5=9B=BA=E5=AE=9A?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E8=87=AA08-20=20147a49d=E9=9A=8F=E5=90=AF?= =?UTF-8?q?=E9=9A=8F=E9=AA=8C=E4=B8=8A=E7=BA=BF=E5=8D=B3=E6=9C=89=E6=84=8F?= =?UTF-8?q?=E9=80=80=E5=87=BAlive(probe=5Fall=E4=B8=80=E8=BD=AE=E8=A6=86?= =?UTF-8?q?=E7=9B=96rotate/T1/swap),=E9=9D=9E=E6=9C=AC=E6=AC=A1=E5=9B=9E?= =?UTF-8?q?=E5=BD=92;=E4=BF=AE=3D=E7=9B=98=E5=A4=96boot=E6=94=B9=E9=94=9A?= =?UTF-8?q?=E5=9B=BA=E5=AE=9A9:35(=E5=8E=86=E5=8F=B2=E4=B8=BB=E8=B0=83?= =?UTF-8?q?=E4=BB=93=E6=97=B6=E5=88=BB,=E7=9B=98=E4=B8=AD=E7=94=B1?= =?UTF-8?q?=E6=9E=84=E9=80=A0=E4=BF=9D=E8=AF=81),=E7=9B=98=E4=B8=ADboot?= =?UTF-8?q?=E4=BB=8Dnow+90s=E5=BF=AB=E9=AA=8C=E4=B8=8D=E5=8F=98,=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E4=BE=A7=E5=AE=88=E5=8D=AB=E4=BF=9D=E7=95=99=E4=B8=BA?= =?UTF-8?q?=E6=9C=AB=E9=81=93=E9=98=B2=E7=BA=BF;=E5=8E=9F=E3=80=8C?= =?UTF-8?q?=E7=9B=98=E5=A4=96=E4=B8=8D=E6=B3=A8=E5=86=8C=E3=80=8D=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E6=8C=89=E6=96=B0=E8=A7=84=E6=A0=BC=E6=94=B9=E5=86=99?= =?UTF-8?q?=E4=B8=BA=E6=96=AD=E8=A8=80=E6=B3=A8=E5=86=8C9:35;25/25+557?= =?UTF-8?q?=E7=BB=BF=20[vps]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sanguo_portfolio/strategies/channel_test.py | 15 ++++++++++----- tests/portfolio/test_channel_test.py | 13 +++++++++---- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/sanguo_portfolio/strategies/channel_test.py b/sanguo_portfolio/strategies/channel_test.py index a6e09b0..2506745 100644 --- a/sanguo_portfolio/strategies/channel_test.py +++ b/sanguo_portfolio/strategies/channel_test.py @@ -97,16 +97,21 @@ class ChannelTestStrategy: b.set_option("use_real_price", True) b.set_option("avoid_future_data", True) if self._on_demand(): - # 随启随验:只注册一个"启动后约90秒"的探针任务。必须经 facade.run_daily - # 注册而非直接调用——回调才会收到 B2 包装的代理 context(实例预算视图), + # 随启随验:只注册一个探针任务。必须经 facade.run_daily 注册而非 + # 直接调用——回调才会收到 B2 包装的代理 context(实例预算视图), # 绕过它探针就测不到定寸虚拟化。重启实例(停止→启动)即再验一轮。 - # 盘前/盘后/周末重启不注册(锚点在时段外=盘后真单挂柜台,09-01 实锤)。 + # 锚点策略:盘中重启锚 now+90s(快验);盘外重启锚固定 9:35—— + # 09-01 实锤 now+90s 落盘外=16 笔真单挂柜台,而 5d0a0bf 初版 + # 「盘外不注册」在 09-02 被 dev 巡检实锤副作用:轮换按运维规则放 + # 23:05 后 → 每次 boot 都盘外 → 永不注册 → 测试通道停摆 + # (live_18/22 零任务,四场景至少停一天)。 probe_at = _now() + timedelta(seconds=90) if not _in_trading_session(probe_at): logger.warning( - "[PROBE] 重启于非交易时段(探针锚定 %s),跳过随启随验注册" - "——防盘后挂单排队次日集合竞价;下次盘中重启再验", + "[PROBE] 重启于非交易时段(探针锚定 %s),改锚固定时刻 9:35" + "——防盘后挂单排队次日集合竞价,同时保住测试通道每日在验", probe_at.strftime("%H:%M")) + b.run_daily(self.probe_all, "9:35") return b.run_daily(self.probe_all, probe_at.strftime("%H:%M")) diff --git a/tests/portfolio/test_channel_test.py b/tests/portfolio/test_channel_test.py index 368f199..2080ec0 100644 --- a/tests/portfolio/test_channel_test.py +++ b/tests/portfolio/test_channel_test.py @@ -237,9 +237,14 @@ def test_probe_all_skips_out_of_session(monkeypatch, caplog): assert any("非交易时段" in r.message for r in caplog.records) -def test_initialize_on_demand_after_hours_skips_registration(monkeypatch, caplog): - """盘后重启(live env)不注册随启随验——run_daily 锚点落在时段外必跳过, - 否则 16 笔真单挂柜台排队次日集合竞价(09-01 18:48 轮换实锤)。""" +def test_initialize_on_demand_after_hours_registers_fixed_anchor(monkeypatch, caplog): + """盘后重启(live env)改锚固定盘中时刻 9:35,而非放弃注册。 + + 09-01 18:48 轮换实锤「now+90s 落盘外=16 笔真单挂柜台」后,5d0a0bf 修成 + 盘外不注册;09-02 dev 巡检实锤其副作用:运维规则轮换放 23:05 后 → 每次 + boot 都盘外 → 永不注册 → 测试通道四场景停摆(live_18/22 零任务)。修=盘外 + boot 锚定固定 9:35(历史主调仓时刻,probe_all 一轮覆盖 rotate/T1/swap), + 既有盘后挂单风险由锚点固定+执行侧守卫双重消除。""" monkeypatch.setenv("SANGUO_LIVE_STRATEGY", "channel_test") ct._now = lambda: datetime(2026, 9, 1, 18, 48) # type: ignore[assignment] registered: list = [] @@ -254,7 +259,7 @@ def test_initialize_on_demand_after_hours_skips_registration(monkeypatch, caplog config=ChannelTestConfig(on_demand=True)) with caplog.at_level("WARNING"): s.initialize(object()) - assert registered == [] # 不注册 + assert registered == [("probe_all", "9:35")] # 改锚固定盘中时刻 assert any("非交易时段" in r.message for r in caplog.records)