修复okx
This commit is contained in:
+88
-47
@@ -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 的 volCcy24h(USDT)。
|
||||||
同一 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 App「24小时成交额」同源字段 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 {}
|
|
||||||
# OKX:volCcy24h = 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,
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user