Add option close liquidity gate with 30% bid/mark cap.

Block new opens while flat legs wait; emergency close bypasses the check.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-25 09:05:04 +08:00
parent 8c14759e78
commit 9fd2a842af
11 changed files with 136 additions and 28 deletions
+17 -6
View File
@@ -88,7 +88,8 @@ class StrategyEngine:
async def emergency_close(self) -> dict[str, Any]:
async with self._lock:
r = self.matcher.close_group(reason="emergency")
# 紧急全平:绕过期权流动性/偏差校验
r = self.matcher.close_group(reason="emergency", bypass_liquidity=True)
if r.ok:
self._after_close()
return {
@@ -155,8 +156,8 @@ class StrategyEngine:
exit_pct = self.ledger.get_setting_float("exit_move_pct", s.exit_move_pct)
pos = self.matcher.current_position()
# 有未平仓:只盯平仓,绝不开下一组
if pos.get("status") == "open":
self._set_state(phase="open", last_error=None)
upl = self.matcher.unrealized()
decision = check_exits(
perp_upl=float(upl["perp_upl"]),
@@ -164,17 +165,22 @@ class StrategyEngine:
move_pct=float(upl.get("move_pct") or 0),
exit_move_pct=exit_pct,
)
if decision.should_close:
self._set_state(phase="closing")
pending_close = st["phase"] in ("liquidity_wait", "closing")
if decision.should_close or pending_close:
reason = decision.reason or "liquidity_retry"
if not pending_close:
self._set_state(phase="closing", last_error=None)
r = await asyncio.to_thread(
self.matcher.close_group, reason=decision.reason
self.matcher.close_group, reason=reason, bypass_liquidity=False
)
if r.ok:
self._after_close()
elif r.liquidity_wait:
self._set_state(phase="liquidity_wait", last_error=r.detail)
else:
self._set_state(last_error=r.detail)
self._set_state(phase="closing", last_error=r.detail)
else:
self._set_state(phase="open", last_error=None)
return
if st["phase"] == "resting" and st["rest_until_ms"]:
@@ -190,6 +196,11 @@ class StrategyEngine:
if st["phase"] in ("stopped", "outside_window"):
self._set_state(phase="idle")
# 双保险:账本仍显示有仓则不开
if self.matcher.has_open_position():
self._set_state(phase="open", last_error="有未平仓,禁止开下一组")
return
self._set_state(phase="wait_signal")
pick = await get_session().pick_for_open_async()
if pick is None: