From b377956367985b89bc36c4560413b82e16836fc6 Mon Sep 17 00:00:00 2001 From: dekun Date: Fri, 7 Aug 2026 19:28:58 +0800 Subject: [PATCH] Fix false USDC-short error while waiting for a qualified option. Use risk-sizing preview ask/qty (same as auto-convert) instead of monitor book ask. Co-authored-by: Cursor --- backend/app/strategy/auto_usdc.py | 20 +++++++++++++++++--- backend/app/strategy/engine.py | 17 +++++++++++------ 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/backend/app/strategy/auto_usdc.py b/backend/app/strategy/auto_usdc.py index 0ccf7f0..ad0b693 100644 --- a/backend/app/strategy/auto_usdc.py +++ b/backend/app/strategy/auto_usdc.py @@ -44,7 +44,9 @@ def _round_down(n: float, nd: int = 2) -> float: def preview_capacity_for_convert(db: Database | None = None) -> dict[str, Any]: """ - 用盘口预览以损定仓名义评估资金门(不写 settings)。 + 用预览以损定仓名义评估资金门(不写 settings)。 + - 选约杠杆:用定仓卖一(指数/杠杆下限),与预算/k 一致,勿用监控未达标贵卖一 + - 实际杠杆:用盘口卖一 手动仓位则直接 assess 当前账本名义。 """ database = db or get_db() @@ -53,7 +55,8 @@ def preview_capacity_for_convert(db: Database | None = None) -> dict[str, Any]: prev = preview_risk_sizing(database) if prev.get("risk_based") and prev.get("ok"): - return assess_open_capacity( + # option_ask 在 preview 里已是定仓口径(selection=隐含 / actual=盘口) + cap = assess_open_capacity( database, option_ask=float(prev["option_ask"]) if prev.get("option_ask") is not None @@ -64,10 +67,21 @@ def preview_capacity_for_convert(db: Database | None = None) -> dict[str, Any]: perp_qty_eth=float(prev["perp_qty_eth"]) if prev.get("perp_qty_eth") is not None else None, + call_ask=float(prev["call_ask"]) + if prev.get("call_ask") is not None + else None, + put_ask=float(prev["put_ask"]) + if prev.get("put_ask") is not None + else None, ) + cap["capacity_basis"] = "risk_preview" + cap["leverage_basis"] = prev.get("leverage_basis") + return cap except Exception: logger.exception("preview capacity for convert failed") - return assess_open_capacity(database) + cap = assess_open_capacity(database) + cap["capacity_basis"] = "ledger" + return cap def prepare_okx_trading_usdc(db: Database | None = None) -> dict[str, Any]: diff --git a/backend/app/strategy/engine.py b/backend/app/strategy/engine.py index dd08156..0c349c8 100644 --- a/backend/app/strategy/engine.py +++ b/backend/app/strategy/engine.py @@ -17,7 +17,7 @@ from ..env_store import live_ready from .clock import can_open_new, window_key from .exits import check_expiry_close, check_exits, resolve_exit_target from .group import next_group_id -from .open_capacity import assess_open_capacity, maybe_notify_funds_short +from .open_capacity import maybe_notify_funds_short logger = logging.getLogger(__name__) @@ -219,9 +219,12 @@ class StrategyEngine: last_error = None allow_open = can_open_new(skip_weekends=skip_weekends) try: - open_cap = assess_open_capacity(self.db) + # 以损定仓(尤其选约杠杆):用预览名义+定仓卖一,勿用监控盘口贵卖一×账本名义虚高「需USDC」 + from .auto_usdc import preview_capacity_for_convert + + open_cap = preview_capacity_for_convert(self.db) except Exception: - logger.exception("assess_open_capacity failed") + logger.exception("preview_capacity_for_convert failed") open_cap = { "perp_can_open": None, "option_can_open": None, @@ -1045,15 +1048,17 @@ class StrategyEngine: return if pick is None: try: - from .open_capacity import assess_open_capacity, funds_gate_blocks + from .auto_usdc import preview_capacity_for_convert + from .open_capacity import funds_gate_blocks - cap = assess_open_capacity(self.db) + # 与自动兑 USDC 同一口径(选约杠杆用隐含卖一估需),避免无合格约时用盘口贵卖一误报缺 USDC + cap = preview_capacity_for_convert(self.db) blocked, why = funds_gate_blocks(cap) if blocked and cap.get("option_can_open") is False: self._set_state( phase="wait_funds", last_error=( - "无合格期权;且交易账户 USDC 不够开仓" + "无合格期权;且按拟定仓估算交易账户 USDC 不够开仓" f"(需≈{cap.get('option_need_usdc')}U / 有{cap.get('option_have_usdc')}U)。" "系统会在冷却后自动市价兑 USDC。" ),