Add daily loss-count freeze for account risk cooldown.

RISK_DAILY_LOSS_LIMIT (default 2, 0 disables) freezes new opens after N losing closes in the trading day.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-21 22:13:38 +08:00
parent a4be294c06
commit 301a464f29
13 changed files with 166 additions and 3 deletions
+37
View File
@@ -20,6 +20,7 @@ from lib.trade.account_risk_lib import (
enrich_risk_status_countdown,
ensure_account_risk_schema,
max_active_positions_from_env,
on_closed_trade_pnl,
on_journal_saved,
on_manual_close,
on_user_initiated_close,
@@ -58,6 +59,7 @@ class AccountRiskLibTests(unittest.TestCase):
os.environ["RISK_COOLING_HOURS_MANUAL"] = "4"
os.environ["RISK_COOLING_HOURS_MANUAL_JOURNAL"] = "1"
os.environ["RISK_MANUAL_CLOSE_DAILY_LIMIT"] = "2"
os.environ["RISK_DAILY_LOSS_LIMIT"] = "2"
os.environ["RISK_MOOD_ISSUES_DAILY_FREEZE"] = "1"
os.environ["APP_TIMEZONE"] = "Asia/Shanghai"
@@ -521,6 +523,41 @@ class AccountRiskLibTests(unittest.TestCase):
os.environ["MAX_ACTIVE_POSITIONS"] = "3"
self.assertEqual(max_active_positions_from_env(), 3)
def test_daily_loss_limit_freezes_on_second_loss(self):
conn = _mem_conn()
now = datetime(2026, 6, 14, 12, 0, 0)
on_closed_trade_pnl(conn, pnl_amount=-1.5, trading_day="2026-06-14", now=now)
st = compute_account_risk_status(conn, trading_day="2026-06-14", now=now)
self.assertEqual(st["daily_loss_count"], 1)
self.assertEqual(st["status"], STATUS_NORMAL)
on_closed_trade_pnl(conn, pnl_amount=-0.2, trading_day="2026-06-14", now=now)
st2 = compute_account_risk_status(conn, trading_day="2026-06-14", now=now)
self.assertEqual(st2["daily_loss_count"], 2)
self.assertEqual(st2["status"], STATUS_DAILY)
self.assertFalse(st2["can_trade"])
self.assertIn("日亏损", st2["reason"])
def test_daily_loss_limit_zero_disables(self):
os.environ["RISK_DAILY_LOSS_LIMIT"] = "0"
conn = _mem_conn()
now = datetime(2026, 6, 14, 12, 0, 0)
on_closed_trade_pnl(conn, pnl_amount=-10, trading_day="2026-06-14", now=now)
on_closed_trade_pnl(conn, pnl_amount=-10, trading_day="2026-06-14", now=now)
st = compute_account_risk_status(conn, trading_day="2026-06-14", now=now)
self.assertEqual(st["daily_loss_count"], 0)
self.assertEqual(st["daily_loss_limit"], 0)
self.assertEqual(st["status"], STATUS_NORMAL)
self.assertTrue(st["can_trade"])
def test_profitable_close_does_not_count_loss(self):
conn = _mem_conn()
now = datetime(2026, 6, 14, 12, 0, 0)
on_closed_trade_pnl(conn, pnl_amount=3.2, trading_day="2026-06-14", now=now)
on_closed_trade_pnl(conn, pnl_amount=0, trading_day="2026-06-14", now=now)
st = compute_account_risk_status(conn, trading_day="2026-06-14", now=now)
self.assertEqual(st["daily_loss_count"], 0)
self.assertEqual(st["status"], STATUS_NORMAL)
if __name__ == "__main__":
unittest.main()