Fix dashboard PnL using spot contract size of 1.
Prefer perpetual symbols and normalize before market.contractSize lookup so Gate BTC float matches ~0.4U not thousands. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -358,18 +358,52 @@ def collect_options_items(
|
||||
return out
|
||||
|
||||
|
||||
def _swap_symbol_candidates(row: dict[str, Any]) -> list[str]:
|
||||
"""优先永续 symbol(含 settle),避免用现货 BTC/USDT 查到 contractSize=1."""
|
||||
raw: list[str] = []
|
||||
for key in ("symbol", "exchange_symbol", "price_symbol"):
|
||||
s = str(row.get(key) or "").strip()
|
||||
if s and s not in raw:
|
||||
raw.append(s)
|
||||
swapish: list[str] = []
|
||||
others: list[str] = []
|
||||
for s in raw:
|
||||
if ":" in s:
|
||||
swapish.append(s)
|
||||
continue
|
||||
others.append(s)
|
||||
if "/" in s:
|
||||
base, quote = s.split("/", 1)
|
||||
q = quote.split(":")[0].strip()
|
||||
if base and q:
|
||||
swapish.append(f"{base}/{q}:{q}")
|
||||
out: list[str] = []
|
||||
for s in swapish + others:
|
||||
if s and s not in out:
|
||||
out.append(s)
|
||||
return out
|
||||
|
||||
|
||||
def _resolve_contract_size(
|
||||
sym: str,
|
||||
row_or_sym: Any,
|
||||
*,
|
||||
get_contract_size: Optional[Callable[[str], Any]] = None,
|
||||
) -> float:
|
||||
if not callable(get_contract_size) or not sym:
|
||||
return 1.0
|
||||
try:
|
||||
cs = float(get_contract_size(sym) or 1.0)
|
||||
return cs if cs > 0 else 1.0
|
||||
except Exception:
|
||||
if not callable(get_contract_size):
|
||||
return 1.0
|
||||
if isinstance(row_or_sym, dict):
|
||||
candidates = _swap_symbol_candidates(row_or_sym)
|
||||
else:
|
||||
sym = str(row_or_sym or "").strip()
|
||||
candidates = _swap_symbol_candidates({"symbol": sym}) if sym else []
|
||||
for sym in candidates:
|
||||
try:
|
||||
cs = float(get_contract_size(sym) or 0)
|
||||
if cs > 0:
|
||||
return cs
|
||||
except Exception:
|
||||
continue
|
||||
return 1.0
|
||||
|
||||
|
||||
def _fill_order_pnl_fields(row: dict[str, Any], *, mark: Optional[float], contract_size: float) -> None:
|
||||
@@ -415,23 +449,23 @@ def enrich_order_items_with_marks(
|
||||
out: list[dict[str, Any]] = []
|
||||
for it in items:
|
||||
row = dict(it)
|
||||
sym = str(row.get("price_symbol") or row.get("symbol") or "").strip()
|
||||
# 标记价:先试 price_symbol,再试永续候选
|
||||
mark = _safe_float(row.get("mark_price"))
|
||||
if callable(get_price) and sym:
|
||||
try:
|
||||
px = get_price(sym)
|
||||
except Exception:
|
||||
px = None
|
||||
mark = _safe_float(px)
|
||||
if mark is None and ":" in sym:
|
||||
if callable(get_price):
|
||||
ordered: list[str] = []
|
||||
for s in [str(row.get("price_symbol") or "").strip()] + _swap_symbol_candidates(row):
|
||||
if s and s not in ordered:
|
||||
ordered.append(s)
|
||||
for sym in ordered:
|
||||
try:
|
||||
px = get_price(sym.split(":", 1)[0])
|
||||
px = get_price(sym)
|
||||
except Exception:
|
||||
px = None
|
||||
mark = _safe_float(px)
|
||||
if mark is not None:
|
||||
row["mark_price"] = mark
|
||||
cs = _resolve_contract_size(sym, get_contract_size=get_contract_size)
|
||||
if mark is not None:
|
||||
row["mark_price"] = mark
|
||||
break
|
||||
cs = _resolve_contract_size(row, get_contract_size=get_contract_size)
|
||||
_fill_order_pnl_fields(row, mark=mark, contract_size=cs)
|
||||
out.append(row)
|
||||
return out
|
||||
|
||||
Reference in New Issue
Block a user