"""实例 USDT 永续合约信息(与实盘 ccxt 精度一致)。""" from __future__ import annotations from typing import Any, Callable, Optional, Tuple from hub_calculator_market_lib import ( amount_decimals_from_exchange, normalize_base_symbol, price_decimals_from_exchange, resolve_usdt_perp_symbol, ) from hub_ohlcv_lib import normalize_price_tick, price_tick_from_market def fetch_usdt_swap_market_info( *, base_or_symbol: str, normalize_symbol_input: Callable[[str], str], normalize_exchange_symbol: Callable[[str], str], ensure_markets_loaded: Callable[[], None], exchange: Any, exchange_id: str = "", ) -> dict[str, Any]: """供各实例 /api/hub/market 调用。""" raw = str(base_or_symbol or "").strip() if not raw: return {"ok": False, "msg": "请输入币种,如 ETH"} try: ensure_markets_loaded() except Exception as exc: return {"ok": False, "msg": f"加载市场失败: {exc}"} base_u = normalize_base_symbol(raw) hub_sym = normalize_symbol_input(raw if base_u else raw) try: ex_sym = normalize_exchange_symbol(hub_sym) except Exception: ex_sym = hub_sym sym, err = resolve_usdt_perp_symbol(exchange, base_u or hub_sym) if err and ex_sym: markets = getattr(exchange, "markets", None) or {} if ex_sym in markets: sym = ex_sym err = None if err or not sym: return {"ok": False, "msg": err or f"未找到 {base_u or raw}/USDT 永续合约"} market = exchange.market(sym) try: contract_size = float(market.get("contractSize") or 1.0) except (TypeError, ValueError): contract_size = 1.0 if contract_size <= 0: contract_size = 1.0 price_tick = normalize_price_tick(price_tick_from_market(exchange, sym)) amt_dec = amount_decimals_from_exchange(exchange, sym) px_dec = price_decimals_from_exchange(exchange, sym, price_tick) min_amount = None try: min_amount = float((market.get("limits") or {}).get("amount", {}).get("min")) except (TypeError, ValueError): min_amount = None base_out = (market.get("base") or base_u or "").upper() or base_u return { "ok": True, "exchange": (exchange_id or "").strip().lower(), "base": base_out, "exchange_symbol": sym, "display_symbol": f"{base_out}/USDT" if base_out else sym, "contract_size": contract_size, "price_tick": price_tick, "price_decimals": px_dec, "amount_decimals": amt_dec, "min_amount": min_amount, }