fix(risk): stop stale 4h cooloff after 1h journal expires
Anchor last_close on journal save, ignore leftover stored until when 1h window ended, and clear expired cooloff on trading-day rollover. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -236,6 +236,66 @@ class AccountRiskLibTests(unittest.TestCase):
|
||||
self.assertEqual(st["status"], STATUS_FREEZE_1H)
|
||||
self.assertAlmostEqual(st["freeze_remaining_sec"], 54 * 60, delta=3)
|
||||
|
||||
def test_stale_4h_ignored_after_1h_journal_expired(self):
|
||||
"""复盘已降为 1h 且窗口结束后,不应再读库内旧 4h until。"""
|
||||
conn = _mem_conn()
|
||||
close_at = datetime(2026, 6, 18, 17, 56, 0)
|
||||
now = datetime(2026, 6, 18, 21, 50, 0)
|
||||
close_ms = _local_ms(close_at)
|
||||
stale_4h_until = close_ms + 4 * 3600 * 1000
|
||||
conn.execute(
|
||||
"""UPDATE account_risk_state SET
|
||||
trading_day='2026-06-18',
|
||||
manual_close_count=1,
|
||||
cooloff_until_ms=?,
|
||||
cooloff_hours=1,
|
||||
last_close_at_ms=?,
|
||||
daily_frozen=0
|
||||
WHERE id=1""",
|
||||
(stale_4h_until, close_ms),
|
||||
)
|
||||
st = compute_account_risk_status(conn, trading_day="2026-06-18", now=now)
|
||||
self.assertEqual(st["status"], STATUS_NORMAL)
|
||||
self.assertTrue(st["can_trade"])
|
||||
|
||||
def test_active_4h_countdown_matches_tier(self):
|
||||
conn = _mem_conn()
|
||||
close_at = datetime(2026, 6, 18, 21, 46, 0)
|
||||
now = datetime(2026, 6, 18, 21, 52, 0)
|
||||
close_ms = _local_ms(close_at)
|
||||
on_user_initiated_close(
|
||||
conn,
|
||||
source=CLOSE_SOURCE_USER_INSTANCE,
|
||||
closed_at_ms=close_ms,
|
||||
trading_day="2026-06-18",
|
||||
now=close_at,
|
||||
)
|
||||
st = compute_account_risk_status(conn, trading_day="2026-06-18", now=now)
|
||||
self.assertEqual(st["status"], STATUS_FREEZE_4H)
|
||||
self.assertAlmostEqual(st["freeze_remaining_sec"], 3 * 3600 + 54 * 60, delta=5)
|
||||
|
||||
def test_trading_day_reset_clears_expired_stale_cooloff(self):
|
||||
conn = _mem_conn()
|
||||
close_at = datetime(2026, 6, 18, 17, 56, 0)
|
||||
close_ms = _local_ms(close_at)
|
||||
stale_4h_until = close_ms + 4 * 3600 * 1000
|
||||
conn.execute(
|
||||
"""UPDATE account_risk_state SET
|
||||
trading_day='2026-06-18',
|
||||
manual_close_count=1,
|
||||
cooloff_until_ms=?,
|
||||
cooloff_hours=1,
|
||||
last_close_at_ms=?,
|
||||
daily_frozen=0
|
||||
WHERE id=1""",
|
||||
(stale_4h_until, close_ms),
|
||||
)
|
||||
next_day = datetime(2026, 6, 19, 9, 0, 0)
|
||||
st = compute_account_risk_status(conn, trading_day="2026-06-19", now=next_day)
|
||||
self.assertEqual(st["status"], STATUS_NORMAL)
|
||||
row = conn.execute("SELECT cooloff_until_ms FROM account_risk_state WHERE id=1").fetchone()
|
||||
self.assertIsNone(row["cooloff_until_ms"])
|
||||
|
||||
def test_legacy_naive_utc_ms_countdown_normalized(self):
|
||||
conn = _mem_conn()
|
||||
now = datetime(2026, 6, 14, 12, 0, 0)
|
||||
|
||||
Reference in New Issue
Block a user