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:
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user