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
+37
View File
@@ -214,6 +214,7 @@ def install_on_app(
volume_rank_fn=None,
reconcile_hub_flat_fn=None,
risk_status_fn=None,
user_close_fn=None,
):
app.config["HUB_CTX"] = {
"exchange": exchange,
@@ -228,6 +229,7 @@ def install_on_app(
"volume_rank_fn": volume_rank_fn,
"reconcile_hub_flat_fn": reconcile_hub_flat_fn,
"risk_status_fn": risk_status_fn,
"user_close_fn": user_close_fn,
}
install_hub_embed_headers(app)
configure_hub_embed_session(app)
@@ -383,6 +385,41 @@ def register_hub_routes(app):
finally:
conn.close()
@app.route("/api/hub/account-risk/user-close", methods=["POST"])
@_hub_auth_required
def api_hub_account_risk_user_close():
"""中控/实例:登记用户主动平仓(计入冷静期与日冻结)。"""
c = _ctx()
get_db = c.get("get_db")
user_close_fn = c.get("user_close_fn")
if not callable(get_db) or not callable(user_close_fn):
return jsonify({"ok": False, "msg": "未配置 user_close_fn"}), 501
body = request.get_json(silent=True) or {}
source = (body.get("source") or request.form.get("source") or "").strip()
try:
count = max(0, int(body.get("count") if body.get("count") is not None else 1))
except (TypeError, ValueError):
count = 1
trade_record_id = body.get("trade_record_id")
closed_at_ms = body.get("closed_at_ms")
if count <= 0:
return jsonify({"ok": True, "skipped": True, "count": 0})
conn = get_db()
try:
user_close_fn(
conn,
source=source,
count=count,
trade_record_id=trade_record_id,
closed_at_ms=closed_at_ms,
)
conn.commit()
return jsonify({"ok": True, "count": count, "source": source})
except Exception as e:
return jsonify({"ok": False, "msg": str(e)}), 500
finally:
conn.close()
@app.route("/api/hub/monitor")
@_hub_auth_required
def api_hub_monitor():