"""期权账户内划转执行(本机设置 / 中控 Bridge 共用).""" from __future__ import annotations from typing import Any def _safe_float(v: Any) -> float | None: if v is None or v == "": return None try: return float(v) except (TypeError, ValueError): return None def _pick_stable(bal: dict[str, Any] | None, *, account: str, ccy: str) -> float | None: if not isinstance(bal, dict): return None acct = "trading" if account == "trading" else "funding" ccy_l = (ccy or "usdt").strip().lower() or "usdt" avail = _safe_float(bal.get(f"{acct}_{ccy_l}_avail")) if avail is not None: return round(float(avail), 8) total = _safe_float(bal.get(f"{acct}_{ccy_l}")) if total is not None: return round(float(total), 8) return None def execute_options_internal_transfer( cfg: dict[str, Any], *, amount: Any, from_acct: str = "funding", to_acct: str = "trading", ccy: str = "USDT", ) -> dict[str, Any]: """资金户↔交易户划转;持仓/待卖回拒绝.成功后附带最新 USDT 余额.""" from lib.options.options_account_pnl_lib import transfer_blocked_by_position_msg from lib.options.options_db import init_options_tables ex = cfg.get("exchange_options") ready_fn = cfg.get("options_api_ready") if callable(ready_fn): ok, reason = ready_fn(ex) if not ok: return {"ok": False, "msg": reason or "期权 API 未配置"} if ex is None: return {"ok": False, "msg": "交易所未就绪"} src = (from_acct or "funding").strip().lower() dst = (to_acct or "trading").strip().lower() if src not in ("funding", "trading") or dst not in ("funding", "trading"): return {"ok": False, "msg": "仅支持 funding/trading"} if src == dst: return {"ok": False, "msg": "转出与转入账户不能相同"} ccy_u = (ccy or "USDT").strip().upper() or "USDT" if ccy_u not in ("USDT", "USDC"): return {"ok": False, "msg": "仅支持 USDT/USDC"} amt = _safe_float(amount) if amt is None or amt <= 0: return {"ok": False, "msg": "数量无效"} get_db = cfg.get("get_db") if not callable(get_db): return {"ok": False, "msg": "数据库未就绪"} conn = get_db() try: block = transfer_blocked_by_position_msg(conn, ex) if block: return {"ok": False, "msg": block, "transfer_blocked": True} finally: conn.close() xfer = cfg.get("transfer_ccy") if not callable(xfer): try: import lib.exchange.okx_options_lib as _opt_lib xfer = getattr(_opt_lib, "transfer_ccy", None) except Exception: xfer = None if not callable(xfer): return {"ok": False, "msg": "划转不可用"} result = xfer(ex, ccy_u, float(amt), src, dst) if not isinstance(result, dict): return {"ok": False, "msg": "划转返回异常"} out = dict(result) if not out.get("ok"): out.setdefault("msg", "划转失败") return out conn2 = get_db() try: init_options_tables(conn2) conn2.execute( """ INSERT INTO options_transfer_log (ccy, amount, from_account, to_account, status, message) VALUES (?, ?, ?, ?, 'ok', ?) """, (ccy_u, float(amt), src, dst, ""), ) conn2.commit() except Exception: try: conn2.rollback() except Exception: pass finally: conn2.close() try: from lib.exchange.okx_options_lib import invalidate_options_balance_cache from lib.instance.instance_live_push_lib import notify_instance_balance_changed invalidate_options_balance_cache() app_mod = cfg.get("app_module") if app_mod is not None and hasattr(app_mod, "invalidate_account_balance_cache"): app_mod.invalidate_account_balance_cache() notify_instance_balance_changed() except Exception: pass bal = {} try: fetch_bal = cfg.get("fetch_options_balances") if callable(fetch_bal): bal = fetch_bal(ex) or {} except Exception: bal = {} trading_usdt = _pick_stable(bal, account="trading", ccy="USDT") funding_usdt = _pick_stable(bal, account="funding", ccy="USDT") out.update( { "ok": True, "msg": out.get("msg") or "划转成功", "ccy": ccy_u, "amount": round(float(amt), 8), "from": src, "to": dst, "trading_usdt": trading_usdt, "funding_usdt": funding_usdt, "transfer_blocked": False, } ) return out