diff --git a/sanguo_factor/monthly_batch.py b/sanguo_factor/monthly_batch.py index d62ec6ba..0a73b96a 100644 --- a/sanguo_factor/monthly_batch.py +++ b/sanguo_factor/monthly_batch.py @@ -37,8 +37,8 @@ def month_end(as_of: str) -> str: def window_start(end: str, window_months: int = 12) -> str: """闭区间起点:含 end 当月共 window_months 个月的月初(起步默认 12M).""" y, m = int(end[:4]), int(end[5:7]) - total = y * 12 + m - (window_months - 1) - return f"{total // 12:04d}-{total % 12:02d}-01" + total = y * 12 + (m - 1) - (window_months - 1) + return f"{total // 12:04d}-{total % 12 + 1:02d}-01" def resolve_with_yaml(registry: dict): diff --git a/tests/factor/test_monthly_batch.py b/tests/factor/test_monthly_batch.py index 949c3dac..ba4bbb20 100644 --- a/tests/factor/test_monthly_batch.py +++ b/tests/factor/test_monthly_batch.py @@ -44,6 +44,15 @@ def test_window_start_twelve_months(): assert window_start("2026-09-30", 12) == "2025-10-01" +def test_window_start_december_month_math(): + """11 月月末回归锚:1-based 月减法 %12 归零曾产 '2026-00-01'(月=00 非法).""" + from sanguo_factor.monthly_batch import window_start + assert window_start("2026-11-30") == "2025-12-01" # 含 11 月共 12 个月 + assert window_start("2026-12-31") == "2026-01-01" + assert window_start("2026-01-31") == "2025-02-01" + assert window_start("2026-09-30") == "2025-10-01" # 既有正确值不变 + + def test_plan_batch_excludes_dead_and_labels(registry): plan = plan_batch(registry, "2026-09-30") assert plan["factor_names"] == ["vol_ma5"]