diff --git a/crypto_monitor_okx/app.py b/crypto_monitor_okx/app.py index 6de0ae9..1cf9f98 100644 --- a/crypto_monitor_okx/app.py +++ b/crypto_monitor_okx/app.py @@ -3167,7 +3167,8 @@ def _status_by_ema55(symbol, timeframe): def _daily_volume_rank(symbol): """ - 返回(symbol_rank, total_count),按 quoteVolume 降序,缺失时 fallback 到 baseVolume*last。 + 返回(symbol_rank, total_count):OKX USDT 永续 24h 成交额(USDT) 在全市场币种中的排名(非「本月」)。 + 同一 base 多合约取成交额最大的一条;不用 vol24h(张数)参与排序。 """ sym_norm = normalize_symbol_input(symbol) target_base = journal_coin_from_symbol(sym_norm) @@ -3195,16 +3196,29 @@ def _daily_volume_rank(symbol): tickers = exchange.fetch_tickers(params={"instType": "SWAP"}) except Exception: tickers = exchange.fetch_tickers() - scored = [] + by_base: dict[str, float] = {} for s, t in (tickers or {}).items(): try: - su = str(s).upper() - if "USDT" not in su: + 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 {} - qv = _safe_float(info.get("volCcy24h") or info.get("vol24h")) + # 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")) @@ -3212,14 +3226,13 @@ def _daily_volume_rank(symbol): qv = bv * lp if qv is None or qv <= 0: continue - scored.append((_ticker_base(s), float(qv))) + prev = by_base.get(base) + if prev is None or float(qv) > prev: + by_base[base] = float(qv) except Exception: continue - scored.sort(key=lambda x: x[1], reverse=True) - ranks = {} - for idx, (base, _) in enumerate(scored, 1): - if base and base not in ranks: - ranks[base] = idx + scored = sorted(by_base.items(), key=lambda x: x[1], reverse=True) + ranks = {base: idx for idx, (base, _) in enumerate(scored, 1)} LIQUIDITY_RANK_CACHE["ranks"] = ranks LIQUIDITY_RANK_CACHE["total"] = len(scored) LIQUIDITY_RANK_CACHE["updated_at"] = now_ts @@ -4900,14 +4913,26 @@ def api_symbol_liquidity_rank(): if total <= 0: return jsonify({"ok": False, "msg": "日成交量排名读取失败"}), 502 if rank is None: - return jsonify({"ok": True, "symbol": symbol, "rank": None, "total": int(total), "in_top30": False}) + return jsonify( + { + "ok": True, + "symbol": symbol, + "rank": None, + "total": int(total), + "in_top30": False, + "rank_max": KEY_DAILY_VOLUME_RANK_MAX, + } + ) + in_top = bool(rank <= KEY_DAILY_VOLUME_RANK_MAX) return jsonify( { "ok": True, "symbol": symbol, "rank": int(rank), "total": int(total), - "in_top30": bool(rank <= 30), + "in_top30": in_top, + "in_top": in_top, + "rank_max": KEY_DAILY_VOLUME_RANK_MAX, } ) diff --git a/crypto_monitor_okx/templates/index.html b/crypto_monitor_okx/templates/index.html index 237fb59..e355c76 100644 --- a/crypto_monitor_okx/templates/index.html +++ b/crypto_monitor_okx/templates/index.html @@ -1459,8 +1459,9 @@ if(keyForm){ return; } const rankMax = data.rank_max || 30; - if(!data.in_top30){ - alert(`${data.symbol} 当前日成交量排名 ${data.rank}/${data.total},不在前${rankMax},已拦截。`); + const inTop = data.in_top != null ? data.in_top : data.in_top30; + if(data.rank == null || !inTop){ + alert(`${data.symbol} 当前日成交量排名 ${data.rank == null ? "—" : data.rank}/${data.total},不在前${rankMax},已拦截。`); return; } keyForm.submit();