From ea1d41b04caf56e612a593b432dd1309d3e13e19 Mon Sep 17 00:00:00 2001 From: claude_dev Date: Sun, 30 Aug 2026 11:54:03 +0800 Subject: [PATCH] =?UTF-8?q?fix(live):=20day=5Fcount=E9=9A=94=E6=97=A5?= =?UTF-8?q?=E6=81=A2=E5=A4=8D+1=E5=8F=8C=E8=AE=A1=E4=BF=AE=E6=AD=A3(?= =?UTF-8?q?=E8=90=BD=E7=9B=98=E5=80=BC=E5=B7=B2=E5=90=AB=E8=87=AA=E5=A2=9E?= =?UTF-8?q?,=E6=81=A2=E5=A4=8D=E7=9B=B4=E5=8F=96saved=5Fcount)=20[vps]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sanguo_portfolio/strategies/all_weather.py | 6 +++--- sanguo_portfolio/strategies/small_cap.py | 6 ++++-- sanguo_portfolio/strategies/small_cap_ex.py | 6 ++++-- tests/portfolio/test_small_cap.py | 10 +++++++--- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/sanguo_portfolio/strategies/all_weather.py b/sanguo_portfolio/strategies/all_weather.py index 060578d..19863a7 100644 --- a/sanguo_portfolio/strategies/all_weather.py +++ b/sanguo_portfolio/strategies/all_weather.py @@ -696,9 +696,9 @@ def _shift_date(date_str: str, days: int) -> str: # 08-24~08-28 实锤:small_cap 的 day_count 只在内存,引擎每晚部署/修账重启即 # 归零 → 连续 5 个交易日 day=0 全量调仓,tc=5 从未生效(每天 ~1k 换仓摩擦)。 # 状态文件按实例 env 隔离(live_20 与 shadow_61 互不串);回测/单测无实例 -# env → 不落盘不恢复,保持原内存语义。恢复口径:上次运行日≠今天 → +1(该 -# 交易日 handle_data 未跑),同日多次重启不重复加;停摆跨多交易日只 +1 -# (计数偏低=调仓延后,自洽不放大)。 +# env → 不落盘不恢复,保持原内存语义。恢复口径:直接取落盘值 saved_count +# ——落盘发生在 handle_data 末尾、已是当日自增后的终值,当日 day_count 由 +# 当日 handle_data 再 +1;隔日恢复若额外 +1 会当日双计,把 tc 周期压缩。 def _live_instance_key() -> str: """live/影子实例标识(持久化按实例隔离);回测/单测无实例 env → 空。""" import os diff --git a/sanguo_portfolio/strategies/small_cap.py b/sanguo_portfolio/strategies/small_cap.py index cdfaa57..723a8e8 100644 --- a/sanguo_portfolio/strategies/small_cap.py +++ b/sanguo_portfolio/strategies/small_cap.py @@ -117,10 +117,12 @@ class SmallCapStrategy: # day_count 跨重启持久化恢复(2026-08-28:08-24~08-28 连续 5 交易日 # day=0 全量调仓根治——重启不再归零,tc=5 周期跨重启保持)。回测无 # 实例 env → _load_day_state 返回 (0,"") 等价旧内存语义。 + # 落盘值已是上个运行日 handle_data 自增后的终值,恢复直接取 + # saved_count:今日 day_count 由今日 handle_data 再 +1,隔日恢复 + # 不额外 +1(否则当日双计,tc=5 周期被重启压缩)。 saved_count, saved_date = _load_day_state("small_cap") if saved_date: - today = datetime.datetime.now().strftime("%Y-%m-%d") - self.day_count = saved_count + (0 if saved_date == today else 1) + self.day_count = saved_count logger.info( "[day-restore] day_count=%d (saved=%d @%s)", self.day_count, saved_count, saved_date) diff --git a/sanguo_portfolio/strategies/small_cap_ex.py b/sanguo_portfolio/strategies/small_cap_ex.py index 7695df0..12e40af 100644 --- a/sanguo_portfolio/strategies/small_cap_ex.py +++ b/sanguo_portfolio/strategies/small_cap_ex.py @@ -119,10 +119,12 @@ class SmallCapExStrategy: # day_count 跨重启持久化恢复(2026-08-28:08-24~08-28 连续 5 交易日 # day=0 全量调仓根治——重启不再归零,tc=5 周期跨重启保持)。回测无 # 实例 env → _load_day_state 返回 (0,"") 等价旧内存语义。 + # 落盘值已是上个运行日 handle_data 自增后的终值,恢复直接取 + # saved_count:今日 day_count 由今日 handle_data 再 +1,隔日恢复 + # 不额外 +1(否则当日双计,tc=5 周期被重启压缩)。 saved_count, saved_date = _load_day_state("small_cap") if saved_date: - today = datetime.datetime.now().strftime("%Y-%m-%d") - self.day_count = saved_count + (0 if saved_date == today else 1) + self.day_count = saved_count logger.info( "[day-restore] day_count=%d (saved=%d @%s)", self.day_count, saved_count, saved_date) diff --git a/tests/portfolio/test_small_cap.py b/tests/portfolio/test_small_cap.py index 95c027e..6402fb3 100644 --- a/tests/portfolio/test_small_cap.py +++ b/tests/portfolio/test_small_cap.py @@ -477,15 +477,19 @@ class TestDayCountPersistence: d.mkdir(parents=True, exist_ok=True) return d / "small_cap_day.json" - def test_overnight_restore_increments(self, tmp_path, monkeypatch): - """隔日重启:恢复值 +1(该交易日 handle_data 尚未跑)——重启日不再是 day=0。""" + def test_overnight_restore_takes_saved_value(self, tmp_path, monkeypatch): + """隔日重启:恢复=落盘值(已是上个运行日自增后终值),不加 1。 + + 当日 day_count 由当日 handle_data 再 +1;若恢复再 +1 会当日双计, + 把 tc=5 周期压缩(08-30 自查修正,旧断言 ==5 即双计产物)。 + """ import json monkeypatch.chdir(tmp_path) monkeypatch.setenv("SANGUO_LIVE_ACCOUNT_ID", "20") self._state_file(tmp_path).write_text( json.dumps({"day_count": 4, "date": "2020-01-01"}), encoding="utf-8") s = make_strategy(config=SmallCapConfig(tc=5)) - assert s.day_count == 5 + assert s.day_count == 4 def test_same_day_restart_no_double_count(self, tmp_path, monkeypatch): """同日多次重启:恢复值不加(handle_data 当日已跑过/不再跑)。"""