Files
CoinOX/lib/hub/hub_options_funds_lib.py
T
dekun 88b7fb7a0a Initial CoinOX instance: coin-margined options + USDT hedge.
Forked from crypto_monitor OKX instance (copy-only). Keeps standalone options, perp-options and options-options hedge; drops standalone perp entrypoints; forces coin margin; adds sim wallets; default port 5010.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 00:18:40 +08:00

220 lines
8.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""中控资金统计:期权 USDC/USDT 按 1:1 计入 USDT 合计."""
from __future__ import annotations
from typing import Any, Optional
def _safe_float(value: Any) -> Optional[float]:
try:
if value is None or value == "":
return None
v = float(value)
return v if v >= 0 else None
except (TypeError, ValueError):
return None
def _account_total_usdt(funding: Any, trading: Any) -> Optional[float]:
fu = _safe_float(funding)
tu = _safe_float(trading)
if fu is None or tu is None:
return None
return round(fu + tu, 4)
def stablecoin_usdt_equiv(value: Any) -> Optional[float]:
"""USDC / USDT 按 1:1 折算为 USDT 统计口径."""
return _safe_float(value)
def _sum_optional(*values: Any) -> Optional[float]:
parts = [_safe_float(v) for v in values]
present = [p for p in parts if p is not None]
if not present:
return None
return round(sum(present), 4)
def options_balances_usdt_equiv(options_snap: dict[str, Any] | None) -> dict[str, Any]:
"""从期权 snapshot 提取资金户/交易户 USDT 等价余额.
- funding_usdt / trading_usdt: USDT+USDC(+USDG) 全账户(勿与永续 USDT 再加总)
- funding_usdc_equiv / trading_usdc_equiv: 仅非 USDT 稳定币,可安全加到永续 USDT 上
"""
snap = options_snap if isinstance(options_snap, dict) else {}
if snap.get("enabled") is False:
return {
"ok": False,
"funding_usdt": None,
"trading_usdt": None,
"funding_usdc_equiv": None,
"trading_usdc_equiv": None,
}
if snap.get("ok") is False:
return {
"ok": False,
"funding_usdt": None,
"trading_usdt": None,
"funding_usdc_equiv": None,
"trading_usdc_equiv": None,
}
bal = snap.get("balances") if isinstance(snap.get("balances"), dict) else snap
funding_usdc_equiv = _sum_optional(bal.get("funding_usdc"), bal.get("funding_usdg"))
trading_usdc_equiv = _sum_optional(bal.get("trading_usdc"), bal.get("trading_usdg"))
funding = _sum_optional(bal.get("funding_usdt"), funding_usdc_equiv)
trading = _sum_optional(bal.get("trading_usdt"), trading_usdc_equiv)
ok = funding is not None and trading is not None
return {
"ok": ok,
"funding_usdt": funding,
"trading_usdt": trading,
"funding_usdc_equiv": funding_usdc_equiv,
"trading_usdc_equiv": trading_usdc_equiv,
}
def options_float_pnl_usdt(options_snap: dict[str, Any] | None) -> Optional[float]:
"""期权浮盈合计(USDT).币本位按指数换算,勿把 ETH/BTC 数量当 U.
优先逐仓 display_pnl_usdt_from_option_row(已含 BTC/ETH × 指数);
回退 upl_total_usdc 时按「已是 USDT」处理——实例 hub 快照合计已折 U,
不可再 × 指数,否则币本位会双计.
"""
snap = options_snap if isinstance(options_snap, dict) else {}
if snap.get("enabled") is False or snap.get("ok") is False:
return None
try:
from lib.options.options_positions_lib import display_pnl_usdt_from_option_row
total_u = 0.0
found = False
for p in snap.get("positions") or []:
if not isinstance(p, dict):
continue
pnl = display_pnl_usdt_from_option_row(p)
if pnl is None:
continue
found = True
total_u += float(pnl)
if found:
return round(total_u, 4)
except Exception:
pass
upl = snap.get("upl_total_usdc")
if upl is not None:
try:
return round(float(upl), 4)
except (TypeError, ValueError):
return None
return None
def options_open_position_count(options_snap: dict[str, Any] | None) -> int:
snap = options_snap if isinstance(options_snap, dict) else {}
if snap.get("enabled") is False or snap.get("ok") is False:
return 0
if snap.get("position_count") is not None:
try:
return max(0, int(snap.get("position_count")))
except (TypeError, ValueError):
pass
pos = snap.get("positions")
return len(pos) if isinstance(pos, list) else 0
def merge_perp_options_balances(
perpetual_funding_usdt: Any,
perpetual_trading_usdt: Any,
options_snap: dict[str, Any] | None,
) -> dict[str, Any]:
"""永续 USDT + 期权非 USDT 稳定币合并为中控总资金(避免 OKX 同账户 USDT 双计).
与实例顶栏 total_funds_usdt(..., options_usdc, None, None) 口径一致:
期权 snapshot 里的 USDT 与永续资金/交易户是同一钱包,只把 USDC/USDG 加上.
"""
opt = options_balances_usdt_equiv(options_snap)
# 展示用期权户:优先非 USDT 稳定币;若仅有 USDT 则仍给出全量以便辨识
opt_fund_disp = opt.get("funding_usdc_equiv")
opt_trade_disp = opt.get("trading_usdc_equiv")
if opt_fund_disp is None and opt_trade_disp is None and opt.get("ok"):
opt_fund_disp = opt.get("funding_usdt")
opt_trade_disp = opt.get("trading_usdt")
if opt.get("ok"):
if perpetual_funding_usdt is None and perpetual_trading_usdt is None:
# 永续账户未取到时,期权 snapshot 已含同账户 USDT+USDC,直接用全量
funding = opt.get("funding_usdt")
trading = opt.get("trading_usdt")
else:
funding = _sum_optional(perpetual_funding_usdt, opt.get("funding_usdc_equiv"))
trading = _sum_optional(perpetual_trading_usdt, opt.get("trading_usdc_equiv"))
else:
funding = _safe_float(perpetual_funding_usdt)
trading = _safe_float(perpetual_trading_usdt)
total = _account_total_usdt(funding, trading)
# 任一侧齐全即可展示;永续缺一侧但有期权 USDC 时仍尽量给出合计
if total is None:
total = _sum_optional(funding, trading)
perp_total = _account_total_usdt(perpetual_funding_usdt, perpetual_trading_usdt)
opt_total = _account_total_usdt(opt.get("funding_usdt"), opt.get("trading_usdt"))
data_ok = total is not None
return {
"perpetual_funding_usdt": _safe_float(perpetual_funding_usdt),
"perpetual_trading_usdt": _safe_float(perpetual_trading_usdt),
"options_funding_usdt": opt_fund_disp,
"options_trading_usdt": opt_trade_disp,
"options_funding_full_usdt": opt.get("funding_usdt"),
"options_trading_full_usdt": opt.get("trading_usdt"),
"options_ok": bool(opt.get("ok")),
"funding_usdt": funding,
"trading_usdt": trading,
"total_usdt": total,
"perpetual_total_usdt": perp_total,
"options_total_usdt": opt_total,
"data_ok": data_ok,
}
def repair_double_counted_fund_entry(ac: dict[str, Any]) -> dict[str, Any]:
"""识别并修复历史快照中「永续 USDT + 期权(USDT+USDC)」的双计.
旧口径 options_* 存的是 USDT+USDC 全量,且 funding≈2×期权资金户 USDT 部分.
新口径 options_* 多为纯 USDC,不会误伤.
"""
if not isinstance(ac, dict):
return {}
out = dict(ac)
ofu = _safe_float(ac.get("options_funding_usdt"))
otu = _safe_float(ac.get("options_trading_usdt"))
fu = _safe_float(ac.get("funding_usdt"))
tu = _safe_float(ac.get("trading_usdt"))
if ofu is None or otu is None or fu is None or tu is None:
return out
if ofu < 1.0:
return out
ratio = fu / ofu if ofu > 0 else 0.0
# 经典双计:合并资金户 ≈ 2 × 期权资金户(同钱包 USDT 加了两遍)
if 1.8 <= ratio <= 2.25:
out["funding_usdt"] = ofu
out["trading_usdt"] = otu
out["total_usdt"] = round(ofu + otu, 4)
out["repaired_double_count"] = True
return out
def merge_board_row_balances(row: dict[str, Any]) -> dict[str, Any]:
"""监控板行 → 含期权的资金统计."""
caps = row.get("capabilities") or []
options_snap = row.get("options") if "options" in caps else None
merged = merge_perp_options_balances(
row.get("funding_usdt") if row.get("account_ok") else None,
row.get("trading_usdt") if row.get("account_ok") else None,
options_snap,
)
merged["options_float_pnl_u"] = options_float_pnl_usdt(options_snap)
merged["options_open_position_count"] = options_open_position_count(options_snap)
return merged