修复okx

This commit is contained in:
dekun
2026-05-24 10:24:33 +08:00
parent 77a0861801
commit 134173be24
2 changed files with 89 additions and 48 deletions
+88 -47
View File
@@ -268,7 +268,9 @@ ACCOUNT_BALANCE_CACHE = {
} }
LIQUIDITY_RANK_CACHE = { LIQUIDITY_RANK_CACHE = {
"updated_at": 0.0, "updated_at": 0.0,
"version": 0,
"ranks": {}, "ranks": {},
"volumes": {},
"total": 0, "total": 0,
} }
@@ -3165,13 +3167,36 @@ def _status_by_ema55(symbol, timeframe):
return "横盘", None, None return "横盘", None, None
def _daily_volume_rank(symbol): def _okx_usdt_swap_volume_by_base() -> dict[str, float]:
""" """
返回(symbol_rank, total_count)OKX USDT 永续 24h 成交额(USDT) 在全市场币种中的排名本月 OKX 网页24小时成交额一致走官方 /market/tickers?instType=SWAP volCcy24hUSDT
同一 base 多合约取成交额最大的一条不用 vol24h张数参与排序 ccxt quoteVolume OKX 上常不可靠会导致 ZEC 等币种排名严重偏低
""" """
sym_norm = normalize_symbol_input(symbol) by_base: dict[str, float] = {}
target_base = journal_coin_from_symbol(sym_norm) try:
ensure_markets_loaded()
if hasattr(exchange, "publicGetMarketTickers"):
resp = exchange.publicGetMarketTickers({"instType": "SWAP"})
rows = (resp or {}).get("data") or []
for row in rows:
if not isinstance(row, dict):
continue
inst = str(row.get("instId") or "").upper()
# 仅 USDT 本位永续:BTC-USDT-SWAP
parts = inst.split("-")
if len(parts) < 3 or parts[-1] != "SWAP" or parts[1] != "USDT":
continue
base = parts[0].strip()
if not base:
continue
qv = _safe_float(row.get("volCcy24h"))
if qv is None or qv <= 0:
continue
by_base[base] = max(by_base.get(base, 0), float(qv))
if by_base:
return by_base
except Exception:
pass
def _ticker_base(sym_text): def _ticker_base(sym_text):
s = str(sym_text or "").upper().strip() s = str(sym_text or "").upper().strip()
@@ -3184,57 +3209,69 @@ def _daily_volume_rank(symbol):
if s.endswith("USDT"): if s.endswith("USDT"):
return s[:-4].strip() return s[:-4].strip()
return s return s
try:
ensure_markets_loaded()
try:
tickers = exchange.fetch_tickers(params={"instType": "SWAP"})
except Exception:
tickers = exchange.fetch_tickers()
for s, t in (tickers or {}).items():
try:
mk = exchange.markets.get(s) if exchange.markets else None
if mk is not None:
if not mk.get("swap"):
continue
if str(mk.get("quote") or "").upper() != "USDT":
continue
if mk.get("linear") is False:
continue
if mk.get("active") is False:
continue
else:
su = str(s).upper()
if "USDT" not in su or ":USDT" not in su:
continue
base = _ticker_base(s)
if not base:
continue
info = (t or {}).get("info") if isinstance((t or {}).get("info"), dict) else {}
qv = _safe_float(info.get("volCcy24h"))
if qv is None:
qv = _safe_float((t or {}).get("quoteVolume"))
if qv is None or qv <= 0:
continue
by_base[base] = max(by_base.get(base, 0), float(qv))
except Exception:
continue
except Exception:
pass
return by_base
def _daily_volume_rank(symbol):
"""
返回(symbol_rank, total_count)OKX USDT 永续 24h 成交额(USDT) 在全市场币种中的排名本月
数据与 OKX App24小时成交额同源字段 volCcy24h
"""
sym_norm = normalize_symbol_input(symbol)
target_base = journal_coin_from_symbol(sym_norm)
now_ts = time.time() now_ts = time.time()
cache_ver = 3
cached_ok = ( cached_ok = (
LIQUIDITY_RANK_CACHE["updated_at"] LIQUIDITY_RANK_CACHE.get("version") == cache_ver
and LIQUIDITY_RANK_CACHE["updated_at"]
and now_ts - float(LIQUIDITY_RANK_CACHE["updated_at"]) < max(30, BALANCE_REFRESH_SECONDS) and now_ts - float(LIQUIDITY_RANK_CACHE["updated_at"]) < max(30, BALANCE_REFRESH_SECONDS)
) )
if not cached_ok: if not cached_ok:
try: try:
ensure_markets_loaded() by_base = _okx_usdt_swap_volume_by_base()
try:
tickers = exchange.fetch_tickers(params={"instType": "SWAP"})
except Exception:
tickers = exchange.fetch_tickers()
by_base: dict[str, float] = {}
for s, t in (tickers or {}).items():
try:
mk = exchange.markets.get(s) if exchange.markets else None
if mk is not None:
if not mk.get("swap"):
continue
if str(mk.get("quote") or "").upper() != "USDT":
continue
if mk.get("active") is False:
continue
else:
su = str(s).upper()
if "USDT" not in su or ":USDT" not in su:
continue
base = _ticker_base(s)
if not base:
continue
qv = _safe_float((t or {}).get("quoteVolume"))
if qv is None:
info = (t or {}).get("info") if isinstance((t or {}).get("info"), dict) else {}
# OKXvolCcy24h = 24h 成交额(USDT)vol24h 多为张数,不能参与排名
qv = _safe_float(info.get("volCcy24h"))
if qv is None:
bv = _safe_float((t or {}).get("baseVolume"))
lp = _safe_float((t or {}).get("last"))
if bv is not None and lp is not None:
qv = bv * lp
if qv is None or qv <= 0:
continue
prev = by_base.get(base)
if prev is None or float(qv) > prev:
by_base[base] = float(qv)
except Exception:
continue
scored = sorted(by_base.items(), key=lambda x: x[1], reverse=True) scored = sorted(by_base.items(), key=lambda x: x[1], reverse=True)
ranks = {base: idx for idx, (base, _) in enumerate(scored, 1)} ranks = {base: idx for idx, (base, _) in enumerate(scored, 1)}
LIQUIDITY_RANK_CACHE["ranks"] = ranks LIQUIDITY_RANK_CACHE["ranks"] = ranks
LIQUIDITY_RANK_CACHE["volumes"] = dict(by_base)
LIQUIDITY_RANK_CACHE["total"] = len(scored) LIQUIDITY_RANK_CACHE["total"] = len(scored)
LIQUIDITY_RANK_CACHE["version"] = cache_ver
LIQUIDITY_RANK_CACHE["updated_at"] = now_ts LIQUIDITY_RANK_CACHE["updated_at"] = now_ts
except Exception: except Exception:
pass pass
@@ -4910,8 +4947,10 @@ def api_symbol_liquidity_rank():
if not symbol: if not symbol:
return jsonify({"ok": False, "msg": "symbol 不能为空"}), 400 return jsonify({"ok": False, "msg": "symbol 不能为空"}), 400
rank, total = _daily_volume_rank(symbol) rank, total = _daily_volume_rank(symbol)
base = journal_coin_from_symbol(symbol)
vol_24h = (LIQUIDITY_RANK_CACHE.get("volumes") or {}).get(base)
if total <= 0: if total <= 0:
return jsonify({"ok": False, "msg": "成交排名读取失败"}), 502 return jsonify({"ok": False, "msg": "24h成交排名读取失败"}), 502
if rank is None: if rank is None:
return jsonify( return jsonify(
{ {
@@ -4919,6 +4958,7 @@ def api_symbol_liquidity_rank():
"symbol": symbol, "symbol": symbol,
"rank": None, "rank": None,
"total": int(total), "total": int(total),
"vol_usdt_24h": vol_24h,
"in_top30": False, "in_top30": False,
"rank_max": KEY_DAILY_VOLUME_RANK_MAX, "rank_max": KEY_DAILY_VOLUME_RANK_MAX,
} }
@@ -4930,6 +4970,7 @@ def api_symbol_liquidity_rank():
"symbol": symbol, "symbol": symbol,
"rank": int(rank), "rank": int(rank),
"total": int(total), "total": int(total),
"vol_usdt_24h": vol_24h,
"in_top30": in_top, "in_top30": in_top,
"in_top": in_top, "in_top": in_top,
"rank_max": KEY_DAILY_VOLUME_RANK_MAX, "rank_max": KEY_DAILY_VOLUME_RANK_MAX,
+1 -1
View File
@@ -1461,7 +1461,7 @@ if(keyForm){
const rankMax = data.rank_max || 30; const rankMax = data.rank_max || 30;
const inTop = data.in_top != null ? data.in_top : data.in_top30; const inTop = data.in_top != null ? data.in_top : data.in_top30;
if(data.rank == null || !inTop){ if(data.rank == null || !inTop){
alert(`${data.symbol} 当前成交排名 ${data.rank == null ? "—" : data.rank}/${data.total},不在前${rankMax},已拦截。`); alert(`${data.symbol} 当前24h成交排名 ${data.rank == null ? "—" : data.rank}/${data.total},不在前${rankMax},已拦截。`);
return; return;
} }
keyForm.submit(); keyForm.submit();