中控可下发买一全平:客户端新增 /api/hub/options/close,由本地执行并拒绝无效买一。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -76,8 +76,13 @@ def _register_options_hub_bridge(app: Flask, cfg: dict[str, Any]) -> None:
|
||||
def snapshot_fn():
|
||||
return build_options_hub_snapshot(cfg)
|
||||
|
||||
def close_fn(inst_id: str) -> dict[str, Any]:
|
||||
# 中控总览只全平(不改张数);无效买一在执行层拒绝
|
||||
return _run_manual_bid_close(cfg, inst_id, sheets=None, reason="中控平仓")
|
||||
|
||||
hub_ctx = dict(app.config.get("HUB_CTX") or {})
|
||||
hub_ctx["options_snapshot_fn"] = snapshot_fn
|
||||
hub_ctx["options_close_fn"] = close_fn
|
||||
app.config["HUB_CTX"] = hub_ctx
|
||||
|
||||
|
||||
@@ -169,6 +174,78 @@ def _require_options_ex(cfg: dict[str, Any]):
|
||||
return ex, ""
|
||||
|
||||
|
||||
def _run_manual_bid_close(
|
||||
cfg: dict[str, Any],
|
||||
inst_id: str,
|
||||
*,
|
||||
sheets: int | None = None,
|
||||
reason: str = "手动平仓",
|
||||
) -> dict[str, Any]:
|
||||
"""手动买一限价平仓(全平或指定张数);残档/无效买一由 close_option_by_bid1 拒绝."""
|
||||
ex, err = _require_options_ex(cfg)
|
||||
if ex is None:
|
||||
return {"ok": False, "msg": err}
|
||||
inst_id = (inst_id or "").strip()
|
||||
if not inst_id:
|
||||
return {"ok": False, "msg": "缺少 inst_id"}
|
||||
from lib.options.options_close_exec_lib import close_option_by_bid1
|
||||
|
||||
result = close_option_by_bid1(
|
||||
cfg,
|
||||
ex,
|
||||
inst_id,
|
||||
sheets=sheets,
|
||||
require_recycle_gate=False,
|
||||
)
|
||||
if not result.get("ok"):
|
||||
return result
|
||||
from lib.exchange.okx_options_lib import invalidate_option_positions_cache
|
||||
|
||||
invalidate_option_positions_cache()
|
||||
_sync_options_trades(cfg, force=True)
|
||||
try:
|
||||
from lib.options.options_notify_lib import notify_options_close
|
||||
from lib.options.options_target_lib import cancel_target_monitor
|
||||
|
||||
conn2 = cfg["get_db"]()
|
||||
try:
|
||||
if result.get("fully_closed"):
|
||||
cancel_target_monitor(conn2, inst_id=inst_id)
|
||||
conn2.commit()
|
||||
note = reason if result.get("fully_closed") else f"{reason}(部分)"
|
||||
notify_options_close(
|
||||
cfg,
|
||||
conn2,
|
||||
inst_id=inst_id,
|
||||
reason=note,
|
||||
sheets=result.get("submitted_sheets"),
|
||||
premium_received=result.get("premium_received"),
|
||||
close_quote=result.get("locked_bid_px") or result.get("bid"),
|
||||
)
|
||||
finally:
|
||||
conn2.close()
|
||||
except Exception:
|
||||
pass
|
||||
if result.get("fully_closed"):
|
||||
try:
|
||||
from lib.options.options_coin_open_lib import maybe_sell_spot_after_close
|
||||
|
||||
spot_sell = maybe_sell_spot_after_close(cfg, ex, inst_id=inst_id, close_result=result)
|
||||
if spot_sell is not None:
|
||||
result = dict(result)
|
||||
result["spot_sell"] = spot_sell
|
||||
if spot_sell.get("bridge_status") == "pending_sell_spot":
|
||||
result["msg"] = (
|
||||
str(result.get("msg") or "平仓成功")
|
||||
+ ";但卖回 USDT 失败,请点「重试卖回」"
|
||||
)
|
||||
except Exception as e:
|
||||
result = dict(result)
|
||||
result["spot_sell"] = {"ok": False, "msg": str(e)}
|
||||
_mark_balances_stale(cfg)
|
||||
return result
|
||||
|
||||
|
||||
def _budget_full_usdc(cfg: dict[str, Any], ex: Any) -> tuple[float | None, str]:
|
||||
"""打满可用额度 = min(交易户可用 USDC, 单笔预算);calc_order_size 再乘 budget_buffer."""
|
||||
from lib.exchange.okx_options_lib import fetch_options_trading_usdc
|
||||
@@ -1538,9 +1615,6 @@ def register_options_routes(app: Flask, cfg: dict[str, Any]) -> None:
|
||||
@app.route("/api/options/close", methods=["POST"])
|
||||
@lr
|
||||
def api_options_close():
|
||||
ex, err = _require_options_ex(cfg)
|
||||
if ex is None:
|
||||
return jsonify({"ok": False, "msg": err})
|
||||
data = request.get_json(silent=True) or {}
|
||||
inst_id = (data.get("inst_id") or "").strip()
|
||||
if not inst_id:
|
||||
@@ -1552,62 +1626,8 @@ def register_options_routes(app: Flask, cfg: dict[str, Any]) -> None:
|
||||
sheets_i = int(sheets) if sheets is not None and str(sheets).strip() != "" else None
|
||||
except (TypeError, ValueError):
|
||||
return jsonify({"ok": False, "msg": "张数无效"})
|
||||
from lib.options.options_close_exec_lib import close_option_by_bid1
|
||||
|
||||
# 手动买一平仓:只验有效流动性;2×门控仅用于自动/目标位平仓
|
||||
result = close_option_by_bid1(
|
||||
cfg,
|
||||
ex,
|
||||
inst_id,
|
||||
sheets=sheets_i,
|
||||
require_recycle_gate=False,
|
||||
)
|
||||
if result.get("ok"):
|
||||
from lib.exchange.okx_options_lib import invalidate_option_positions_cache
|
||||
|
||||
invalidate_option_positions_cache()
|
||||
_sync_options_trades(cfg, force=True)
|
||||
try:
|
||||
from lib.options.options_target_lib import cancel_target_monitor
|
||||
from lib.options.options_notify_lib import notify_options_close
|
||||
|
||||
conn2 = cfg["get_db"]()
|
||||
try:
|
||||
if result.get("fully_closed"):
|
||||
cancel_target_monitor(conn2, inst_id=inst_id)
|
||||
conn2.commit()
|
||||
reason = "手动平仓" if result.get("fully_closed") else "手动平仓(部分)"
|
||||
notify_options_close(
|
||||
cfg,
|
||||
conn2,
|
||||
inst_id=inst_id,
|
||||
reason=reason,
|
||||
sheets=result.get("submitted_sheets"),
|
||||
premium_received=result.get("premium_received"),
|
||||
close_quote=result.get("locked_bid_px") or result.get("bid"),
|
||||
)
|
||||
finally:
|
||||
conn2.close()
|
||||
except Exception:
|
||||
pass
|
||||
if result.get("fully_closed"):
|
||||
try:
|
||||
from lib.options.options_coin_open_lib import maybe_sell_spot_after_close
|
||||
|
||||
spot_sell = maybe_sell_spot_after_close(cfg, ex, inst_id=inst_id, close_result=result)
|
||||
if spot_sell is not None:
|
||||
result = dict(result)
|
||||
result["spot_sell"] = spot_sell
|
||||
if spot_sell.get("bridge_status") == "pending_sell_spot":
|
||||
result["msg"] = (
|
||||
str(result.get("msg") or "平仓成功")
|
||||
+ ";但卖回 USDT 失败,请点「重试卖回」"
|
||||
)
|
||||
except Exception as e:
|
||||
result = dict(result)
|
||||
result["spot_sell"] = {"ok": False, "msg": str(e)}
|
||||
_mark_balances_stale(cfg)
|
||||
return jsonify(result)
|
||||
return jsonify(_run_manual_bid_close(cfg, inst_id, sheets=sheets_i, reason="手动平仓"))
|
||||
|
||||
@app.route("/api/options/spot-bridge/retry-sell", methods=["POST"])
|
||||
@lr
|
||||
|
||||
Reference in New Issue
Block a user