fix(risk): trigger cooldown only on user-initiated closes

Remove external-close risk hooks; register user_instance, user_hub, and user_trend_stop via hub API and trend stop; update docs and tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-17 19:14:05 +08:00
parent 850ffcd7d2
commit b6acbf4b2c
14 changed files with 423 additions and 131 deletions
+36 -2
View File
@@ -1177,6 +1177,21 @@ async def _fetch_flask_json(
return {"ok": False, "error": str(e)}
async def _notify_instance_user_close(
client: httpx.AsyncClient, ex: dict, *, count: int = 1
) -> dict | None:
"""登记实例侧用户主动平仓风控(中控点平仓/全平)。"""
if count <= 0 or not (ex.get("flask_url") or "").strip():
return None
return await _fetch_flask_json(
client,
ex,
"/api/hub/account-risk/user-close",
method="POST",
json_body={"source": "user_hub", "count": int(count)},
)
def _flask_error_from_hub_mon(hub_mon: dict | None) -> str | None:
if not isinstance(hub_mon, dict) or hub_mon.get("ok") is not False:
return None
@@ -1936,6 +1951,9 @@ async def api_close_position(exchange_id: str, body: ClosePositionBody):
)
if isinstance(sync_parsed, dict):
out["trend_sync"] = sync_parsed
risk_sync = await _notify_instance_user_close(flask_client, ex, count=1)
if isinstance(risk_sync, dict):
out["risk_sync"] = risk_sync
_schedule_board_refresh()
return out
@@ -1985,7 +2003,15 @@ async def api_close_exchange(exchange_id: str):
body = r.json()
except Exception:
body = {"raw": (r.text or "")[:2000]}
out = {"exchange": ex, "status_code": r.status_code, "payload": body}
ok = bool(isinstance(body, dict) and body.get("ok"))
out = {"exchange": ex, "status_code": r.status_code, "payload": body, "ok": ok}
if ok and isinstance(body, dict):
closed = body.get("closed") or []
n = len(closed) if isinstance(closed, list) else 0
if n > 0:
risk_sync = await _notify_instance_user_close(client, ex, count=n)
if isinstance(risk_sync, dict):
out["risk_sync"] = risk_sync
_schedule_board_refresh()
return out
@@ -2005,7 +2031,15 @@ async def api_close_all(body: CloseAllBody | None = Body(default=None)):
payload = r.json()
except Exception:
payload = {"raw": (r.text or "")[:2000]}
return {"id": ex["id"], "name": ex["name"], "status_code": r.status_code, "payload": payload}
row = {"id": ex["id"], "name": ex["name"], "status_code": r.status_code, "payload": payload}
if isinstance(payload, dict) and payload.get("ok"):
closed = payload.get("closed") or []
n = len(closed) if isinstance(closed, list) else 0
if n > 0:
risk_sync = await _notify_instance_user_close(client, ex, count=n)
if isinstance(risk_sync, dict):
row["risk_sync"] = risk_sync
return row
except Exception as e:
return {"id": ex["id"], "name": ex["name"], "status_code": None, "error": str(e)}