Fix position flicker, drop futures cooloff, prioritize startup display.

Preserve trading state when CTP memory is empty, bootstrap equity/positions on page load, stabilize risk status from DB monitors, and remove app-layer manual close cooling periods.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-30 23:17:18 +08:00
parent 2386eca324
commit 1b3a7f1bdc
9 changed files with 218 additions and 153 deletions
+16 -45
View File
@@ -51,17 +51,12 @@ def risk_control_enabled() -> bool:
def cooling_hours_manual() -> float:
try:
return max(0.0, float(os.getenv("RISK_COOLING_HOURS_MANUAL", "4")))
except (TypeError, ValueError):
return 4.0
"""期货版不使用应用层冷静期(交易所自有规则),恒为 0。"""
return 0.0
def cooling_hours_manual_journal() -> float:
try:
return max(0.0, float(os.getenv("RISK_COOLING_HOURS_MANUAL_JOURNAL", "1")))
except (TypeError, ValueError):
return 1.0
return 0.0
def manual_close_daily_limit() -> int:
@@ -286,15 +281,16 @@ def on_user_initiated_close(conn, *, trading_day: str, now: Optional[datetime] =
if count >= manual_close_daily_limit():
conn.execute(
"""UPDATE account_risk_state SET trading_day=?, manual_close_count=?,
daily_frozen=1, cooloff_until_ms=NULL, last_close_at_ms=?, updated_at=? WHERE id=1""",
daily_frozen=1, cooloff_until_ms=NULL, cooloff_hours=NULL,
last_close_at_ms=?, updated_at=? WHERE id=1""",
(td, count, close_ms, datetime.now().strftime("%Y-%m-%d %H:%M:%S")),
)
return
until = close_ms + int(cooling_hours_manual() * 3600 * 1000)
conn.execute(
"""UPDATE account_risk_state SET trading_day=?, manual_close_count=?,
daily_frozen=0, cooloff_until_ms=?, cooloff_hours=?, last_close_at_ms=?, updated_at=? WHERE id=1""",
(td, count, until, int(cooling_hours_manual()), close_ms, datetime.now().strftime("%Y-%m-%d %H:%M:%S")),
daily_frozen=0, cooloff_until_ms=NULL, cooloff_hours=NULL,
last_close_at_ms=?, updated_at=? WHERE id=1""",
(td, count, close_ms, datetime.now().strftime("%Y-%m-%d %H:%M:%S")),
)
@@ -310,26 +306,9 @@ def on_mood_journal_freeze(conn, *, trading_day: str) -> None:
def reduce_cooloff_after_journal(conn, *, trading_day: str, now: Optional[datetime] = None) -> None:
"""复盘手动平仓说明后,4h 冷静期降为 1h"""
if not risk_control_enabled():
return
ensure_account_risk_schema(conn)
row = conn.execute("SELECT * FROM account_risk_state WHERE id=1").fetchone()
if int(_row_get(row, "daily_frozen") or 0):
return
until = _row_get(row, "cooloff_until_ms")
if not until:
return
now_ms = _now_ms(now)
if int(until) <= now_ms:
return
last = int(_row_get(row, "last_close_at_ms") or now_ms)
journal_ms = int(cooling_hours_manual_journal() * 3600 * 1000)
new_until = max(now_ms, last + journal_ms)
conn.execute(
"""UPDATE account_risk_state SET cooloff_until_ms=?, cooloff_hours=?, updated_at=? WHERE id=1""",
(new_until, int(cooling_hours_manual_journal()), datetime.now().strftime("%Y-%m-%d %H:%M:%S")),
)
"""期货版无应用层冷静期,保留空实现兼容旧复盘钩子"""
del conn, trading_day, now
return
def get_risk_status(
@@ -355,6 +334,11 @@ def get_risk_status(
now_ms = _now_ms(now)
daily = int(_row_get(row, "daily_frozen") or 0) == 1
until = _row_get(row, "cooloff_until_ms")
if until:
conn.execute(
"UPDATE account_risk_state SET cooloff_until_ms=NULL, cooloff_hours=NULL WHERE id=1"
)
conn.commit()
active = count_active_trade_monitors(conn) if active_count is None else int(active_count)
mx = max_active_positions()
pos_limit = active >= mx
@@ -387,19 +371,6 @@ def get_risk_status(
"can_roll": False,
"reason": "当日日冻结,禁止新开仓",
}
if until and int(until) > now_ms:
rem = int((int(until) - now_ms) / 1000)
hours = float(_row_get(row, "cooloff_hours") or cooling_hours_manual())
st = STATUS_FREEZE_1H if hours <= cooling_hours_manual_journal() + 0.01 else STATUS_FREEZE_4H
return {
**base,
"status": st,
"status_label": STATUS_LABELS[st],
"can_trade": False,
"can_roll": pos_limit,
"reason": f"冷静期中,剩余约 {rem // 3600}h {(rem % 3600) // 60}m",
"freeze_remaining_sec": rem,
}
if daily_risk_limit_hit:
return {
**base,