Fix false supervisor open events for existing holdings

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-23 20:20:33 +08:00
parent 65901c5577
commit 54ba412d1d
2 changed files with 122 additions and 16 deletions
+68 -4
View File
@@ -146,6 +146,22 @@ def is_program_event(event_type: str) -> bool:
return event_type in (EVENT_PROGRAM_TP, EVENT_PROGRAM_SL)
def _normalize_position_symbol(sym: str) -> str:
"""统一合约名,避免 ZEC/USDT 与 ZEC/USDT:USDT 被当成两笔持仓。"""
s = (sym or "").strip().upper()
if not s:
return ""
if s.endswith(":USDT") and "/" in s:
return s.rsplit(":", 1)[0]
return s
def _position_key(exchange_id: str, symbol: str, side: str) -> str:
sym = _normalize_position_symbol(symbol)
sd = (side or "long").strip().lower() or "long"
return f"{exchange_id}|{sym}|{sd}"
def _position_contracts(pos: dict) -> float:
for key in ("contracts", "contracts_signed", "size"):
try:
@@ -173,7 +189,7 @@ def collect_position_keys(board_payload: dict | None) -> dict[str, dict]:
continue
sym = str(p.get("symbol") or "")
side = str(p.get("side") or "").lower() or "long"
key = f"{ex_id}|{sym}|{side}"
key = _position_key(ex_id, sym, side)
out[key] = {
"exchange_id": ex_id,
"exchange_name": ex_name,
@@ -184,13 +200,47 @@ def collect_position_keys(board_payload: dict | None) -> dict[str, dict]:
return out
def _board_agent_snapshot_ready(board_payload: dict | None) -> bool:
"""监控板各启用账户 agent 快照已就绪(避免空板先入库导致后续持仓误判为新开)。"""
if not isinstance(board_payload, dict) or board_payload.get("ok") is False:
return False
rows = board_payload.get("rows") or []
if not rows:
return False
seen = 0
for row in rows:
if not isinstance(row, dict):
continue
if row.get("enabled") is False:
continue
ag = row.get("agent")
if not isinstance(ag, dict):
return False
seen += 1
return seen > 0
def _entry_contracts(entry: dict | None) -> float:
if not isinstance(entry, dict):
return 0.0
try:
return float(entry.get("contracts") or 0)
except (TypeError, ValueError):
return 0.0
def detect_new_opens(
prev_positions: dict[str, dict],
curr_positions: dict[str, dict],
) -> list[dict]:
"""仅当某合约从空仓变为有仓时视为新开(已有持仓不加仓不算)。"""
events = []
for key, info in curr_positions.items():
if key in prev_positions:
curr_c = _entry_contracts(info)
if curr_c < 1e-12:
continue
prev_c = _entry_contracts(prev_positions.get(key))
if prev_c >= 1e-12:
continue
events.append({"event_type": EVENT_OPEN, "event_id": f"open:{key}:{_now_str()[:16]}", **info})
return events
@@ -566,6 +616,7 @@ def process_supervisor_tick(
"processed": [],
"positions": {},
"stats": {trading_day: state.get("stats", {}).get(trading_day, {})},
"positions_baseline_ready": False,
}
processed = set(str(x) for x in (state.get("processed") or []))
@@ -573,17 +624,30 @@ def process_supervisor_tick(
prev_positions = dict(state.get("positions") or {})
curr_positions = collect_position_keys(board_payload)
closed_trades = dash.get("closed_trades") or []
board_ready = _board_agent_snapshot_ready(board_payload)
if not state.get("initialized"):
if not state.get("positions_baseline_ready"):
for trade in closed_trades:
if isinstance(trade, dict):
processed.add(f"close:{_trade_event_id(trade)}")
if not board_ready:
state["trading_day"] = trading_day
state["processed"] = list(processed)
save_supervisor_state(state)
return {"ok": True, "events": 0, "waiting_board": True, "trading_day": trading_day}
state["trading_day"] = trading_day
state["processed"] = list(processed)
state["positions"] = curr_positions
state["positions_baseline_ready"] = True
state["initialized"] = True
save_supervisor_state(state)
return {"ok": True, "events": 0, "seeded": True, "trading_day": trading_day}
return {
"ok": True,
"events": 0,
"seeded": True,
"trading_day": trading_day,
"positions": len(curr_positions),
}
raw_events = detect_new_opens(prev_positions, curr_positions) + detect_new_closes(
processed, closed_trades