Count roll groups as one position slot and protect monitors during roll.

Include active roll groups in deduped position slots; normalize CTP position keys in reconcile; skip closing monitors tied to active roll groups.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-02 23:04:34 +08:00
parent 93bdce3568
commit ae28bc6273
2 changed files with 23 additions and 4 deletions
+9
View File
@@ -289,6 +289,15 @@ def active_position_slots_from_monitors(conn) -> set[tuple[str, str]]:
sym = (r["symbol"] or "").strip() sym = (r["symbol"] or "").strip()
if sym: if sym:
keys.add(_position_slot_key(sym, r["direction"] or "long")) keys.add(_position_slot_key(sym, r["direction"] or "long"))
for r in conn.execute(
"""SELECT m.symbol, m.direction
FROM roll_groups g
JOIN trade_order_monitors m ON m.id = g.order_monitor_id
WHERE g.status='active'"""
):
sym = (r["symbol"] or "").strip()
if sym:
keys.add(_position_slot_key(sym, r["direction"] or "long"))
except Exception: except Exception:
pass pass
return keys return keys
+14 -4
View File
@@ -647,9 +647,11 @@ def reconcile_monitors_without_position(conn, mode: str, *, grace_sec: int = 120
for p in positions: for p in positions:
if int(p.get("lots") or 0) <= 0: if int(p.get("lots") or 0) <= 0:
continue continue
sym = (p.get("symbol") or "").lower() sym = (p.get("symbol") or "").strip()
direction = p.get("direction") or "long" direction = p.get("direction") or "long"
position_keys.add((sym, direction)) if sym:
base = sym.lower().split(".")[0]
position_keys.add((base, (direction or "long").strip().lower()))
try: try:
from modules.ctp.ctp_trading_state import trading_state from modules.ctp.ctp_trading_state import trading_state
@@ -657,9 +659,11 @@ def reconcile_monitors_without_position(conn, mode: str, *, grace_sec: int = 120
lots = int(p.get("lots") or 0) lots = int(p.get("lots") or 0)
if lots <= 0: if lots <= 0:
continue continue
sym = (p.get("symbol") or "").lower() sym = (p.get("symbol") or "").strip()
direction = p.get("direction") or "long" direction = p.get("direction") or "long"
position_keys.add((sym, direction)) if sym:
base = sym.lower().split(".")[0]
position_keys.add((base, (direction or "long").strip().lower()))
except Exception: except Exception:
pass pass
@@ -709,6 +713,12 @@ def reconcile_monitors_without_position(conn, mode: str, *, grace_sec: int = 120
break break
if matched: if matched:
continue continue
mid = mon.get("id")
if conn.execute(
"SELECT 1 FROM roll_groups WHERE order_monitor_id=? AND status='active' LIMIT 1",
(mid,),
).fetchone():
continue
try: try:
cancel_monitor_exit_orders(conn, mon, mode=mode) cancel_monitor_exit_orders(conn, mon, mode=mode)
except Exception as exc: except Exception as exc: