From 4bda3b77036e6c04ccdb773f3299205b8effaa7f Mon Sep 17 00:00:00 2001 From: dekun Date: Thu, 20 Aug 2026 22:08:28 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=A4=8D=E7=9B=98=E7=9B=88?= =?UTF-8?q?=E4=BA=8F=E6=9C=AA=E6=8C=89ETH=E6=8C=87=E6=95=B0=E6=8A=98U?= =?UTF-8?q?=EF=BC=9B=E4=B9=B0=E4=B8=80=E5=B9=B3=E4=BB=93=E5=8F=96=E6=B6=88?= =?UTF-8?q?=E7=A1=AE=E8=AE=A4=EF=BC=8C=E8=87=AA=E5=8A=A8=E5=8D=96=E5=9B=9E?= =?UTF-8?q?USDT=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- lib/common/static/options_panel.js | 19 +++++------- lib/options/options_review_lib.py | 50 +++++++++++++++++++++--------- 2 files changed, 43 insertions(+), 26 deletions(-) diff --git a/lib/common/static/options_panel.js b/lib/common/static/options_panel.js index a500d9c..b434890 100644 --- a/lib/common/static/options_panel.js +++ b/lib/common/static/options_panel.js @@ -2128,24 +2128,13 @@ alert("暂无有效买一深度,请稍后重试或到 OKX App 挂限价"); return; } - const lv = (preview.levels && preview.levels[0]) || {}; const posLike = { inst_id: inst, premium_ccy: q.premium_ccy || (preview.close_gate && preview.close_gate.premium_ccy) || null, margin_mode: q.options_margin_mode || q.margin_mode || null, }; const premCcy = posPremiumCcy(posLike); - const msg = [ - "按买一限价卖出本轮可平张数?", - "合约: " + inst, - "锁定买一: " + (lv.px != null ? lv.px : "—") + " × " + (lv.sheets != null ? lv.sheets : preview.covered_sheets) + " 张", - "预计收回: " + fmtClosePreviewText(preview, posLike), - preview.estimated_pnl != null - ? ("预估盈亏: " + fmtPremiumAmtSigned(preview.estimated_pnl, premCcy)) - : "", - preview.uncovered_sheets > 0 ? "\n注意: 买一深度不足,预计仍剩 " + preview.uncovered_sheets + " 张,需下次再平。" : "" - ].filter(function (x) { return x !== ""; }).join("\n"); - if (!confirm(msg)) return; + // 买一平仓后币本位会自动卖回 ETH/BTC→USDT,不再弹确认框 if (btn) btn.disabled = true; try { const r = await apiJson("/api/options/close", { @@ -2161,6 +2150,12 @@ } if (r.remaining_sheets > 0) okMsg += "\n剩余: " + r.remaining_sheets + " 张(下次再平)"; if (r.stopped_reason) okMsg += "\n状态: " + r.stopped_reason; + const ss = r.spot_sell; + if (ss && ss.ok && !ss.skipped) { + okMsg += "\n已自动卖回 USDT"; + } else if (ss && ss.bridge_status === "pending_sell_spot") { + okMsg += "\n卖回 USDT 失败,请点「重试卖回」"; + } alert(okMsg); } else { alert(r.msg || "平仓失败"); diff --git a/lib/options/options_review_lib.py b/lib/options/options_review_lib.py index c92b7e5..73e1d5b 100644 --- a/lib/options/options_review_lib.py +++ b/lib/options/options_review_lib.py @@ -298,22 +298,44 @@ def sync_options_from_local_trades( def _index_px(underly: str) -> float | None: u = (underly or "ETH").strip().upper() or "ETH" - pub = ex - if pub is None: - try: - from lib.sim.hooks import _APP_MODULE - - pub = getattr(_APP_MODULE, "exchange", None) if _APP_MODULE else None - except Exception: - pub = None - if pub is None: - return None + inst = f"{u}-USDT" + pubs: list[Any] = [] try: - t = pub.fetch_ticker(f"{u}/USDT") or {} - last = t.get("last") or t.get("close") - return float(last) if last is not None else None + from lib.sim.hooks import _APP_MODULE, _sim_public_exchange + + pub = _sim_public_exchange(ex) if _APP_MODULE is not None else None + if pub is not None: + pubs.append(pub) except Exception: - return None + pass + if ex is not None and ex not in pubs: + pubs.append(ex) + for pub in pubs: + try: + if hasattr(pub, "public_get_market_ticker"): + rows = (pub.public_get_market_ticker({"instId": inst}) or {}).get("data") or [] + if rows: + last = rows[0].get("last") or rows[0].get("lastPx") + if last is not None and float(last) > 0: + return float(last) + except Exception: + pass + try: + from lib.exchange.okx_options_lib import fetch_index_price + + px = fetch_index_price(pub, f"{u}-USD") + if px is not None and float(px) > 0: + return float(px) + except Exception: + pass + try: + t = pub.fetch_ticker(f"{u}/USDT") or {} + last = t.get("last") or t.get("close") + if last is not None and float(last) > 0: + return float(last) + except Exception: + continue + return None def _to_usdt(amount: float | None, *, ccy: str, idx: float | None) -> float | None: if amount is None: