From 2b059d4b438380e3b939553bce345419e9a340cd Mon Sep 17 00:00:00 2001 From: kevin9327 <5299031+kevin9327@users.noreply.github.com> Date: Thu, 10 Sep 2026 19:39:36 +0900 Subject: [PATCH] =?UTF-8?q?fix(market-time):=20=E9=9D=9E=E4=BA=A4=E6=98=93?= =?UTF-8?q?=E6=97=A5=E7=9A=84=E5=B7=B2=E4=BA=A4=E6=98=93=E5=88=86=E9=92=9F?= =?UTF-8?q?=E6=95=B0=E6=8C=89=E5=85=A8=E5=A4=A9=E7=AE=97,=20=E9=87=8F?= =?UTF-8?q?=E6=AF=94=E4=B8=8D=E5=86=8D=E8=A2=AB=E6=8A=98=E7=AE=97=E6=94=BE?= =?UTF-8?q?=E5=A4=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit trading_minutes_elapsed_from_dt 的文档写明「非交易日(周末) = 240 (视作全天, 避免量比被折算成 0)」, 但实现里没有周几判断, 只按时刻分段。 compute_enriched_today 用 `time_factor = 240 / elapsed_minutes` 把盘中部分量 折算到全天量级。周末在行情页点「手动刷新」(refresh() 不过 _market_phase 门控) 且行情源不带 quote_ts 时, 兜底会走 trading_minutes_elapsed() —— 周六 9:31 得 1 分钟 → 全市场量比 ×240, 10:00 得 30 分钟 → ×8, signal_volume_surge(量比 ≥ 2) 整片误触发。 补上文档已声明的周末判定。 --- backend/app/market_time.py | 2 + backend/tests/test_trading_minutes_elapsed.py | 61 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 backend/tests/test_trading_minutes_elapsed.py diff --git a/backend/app/market_time.py b/backend/app/market_time.py index d25e212..fa38d47 100644 --- a/backend/app/market_time.py +++ b/backend/app/market_time.py @@ -44,6 +44,8 @@ def trading_minutes_elapsed_from_dt(dt: datetime) -> float: - 开盘前 = 0; 午休(11:30-13:00) = 120(保持上午累计); 收盘后 = 240。 - 非交易日(周末) = 240 (视作全天, 避免量比被折算成 0)。 """ + if dt.weekday() >= 5: + return float(_TRADING_TOTAL_MINUTES) t = dt.time() if t < _MORNING_START: return 0.0 diff --git a/backend/tests/test_trading_minutes_elapsed.py b/backend/tests/test_trading_minutes_elapsed.py new file mode 100644 index 0000000..b8dffb8 --- /dev/null +++ b/backend/tests/test_trading_minutes_elapsed.py @@ -0,0 +1,61 @@ +"""当日已交易分钟数 — 量比时间折算的分母来源。 + +compute_enriched_today 用 `time_factor = 240 / elapsed_minutes` 把盘中的部分 +成交量折算到全天量级。周末/非交易日没有"当日已交易分钟", 必须按全天 240 算, +否则手动刷新一次行情就会把全市场量比放大 240/已过分钟数 倍, 「放量」 +(vol_ratio_5d >= 2) 整片误触发。 +""" +from __future__ import annotations + +from datetime import datetime, timedelta, timezone + +import pytest + +from app.market_time import ( + trading_minutes_elapsed_from_dt, + trading_minutes_elapsed_from_ts, +) + +CN = timezone(timedelta(hours=8)) + + +def _ms(dt: datetime) -> int: + return int(dt.timestamp() * 1000) + + +@pytest.mark.parametrize( + ("moment", "label"), + [ + (datetime(2026, 9, 12, 9, 31, tzinfo=CN), "周六 开盘后 1 分钟"), + (datetime(2026, 9, 12, 10, 0, tzinfo=CN), "周六 上午"), + (datetime(2026, 9, 13, 14, 0, tzinfo=CN), "周日 下午"), + ], +) +def test_weekend_counts_as_a_full_session(moment, label): + assert trading_minutes_elapsed_from_dt(moment) == 240.0, label + + +def test_weekend_timestamp_also_counts_as_full_session(): + """行情戳落在周末 (源侧异常戳) 时同样按全天算。""" + assert trading_minutes_elapsed_from_ts(_ms(datetime(2026, 9, 12, 10, 0, tzinfo=CN))) == 240.0 + + +@pytest.mark.parametrize( + ("moment", "expected", "label"), + [ + (datetime(2026, 9, 11, 9, 0, tzinfo=CN), 0.0, "周五 开盘前"), + (datetime(2026, 9, 11, 9, 31, tzinfo=CN), 1.0, "周五 9:31"), + (datetime(2026, 9, 11, 11, 30, tzinfo=CN), 120.0, "周五 午休起点"), + (datetime(2026, 9, 11, 12, 30, tzinfo=CN), 120.0, "周五 午休中"), + (datetime(2026, 9, 11, 14, 0, tzinfo=CN), 180.0, "周五 14:00"), + (datetime(2026, 9, 11, 15, 30, tzinfo=CN), 240.0, "周五 收盘后"), + ], +) +def test_weekday_session_progress_unchanged(moment, expected, label): + """交易日的分段折算不受影响 (回归保护)。""" + assert trading_minutes_elapsed_from_dt(moment) == expected, label + + +def test_missing_timestamp_still_counts_as_full_session(): + assert trading_minutes_elapsed_from_ts(None) == 240.0 + assert trading_minutes_elapsed_from_ts(0) == 240.0