Files
dekun 53863559f4 Initialize crypto_monitor_user (user edition) from monitor codebase.
Retarget git remote, install path, and deploy docs from crypto_monitor to crypto_monitor_user.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-17 16:18:13 +08:00

125 lines
3.9 KiB
Python

"""price_snapshot 共用:订单行情价兜底,避免 get_price 失败时整单不入 order_prices."""
from __future__ import annotations
from typing import Any, Callable, Mapping, Optional, Sequence
from lib.hub.hub_position_metrics import parse_position_mark_price
def resolve_order_snapshot_price(
symbol: str,
prices: Mapping[str, float],
*,
position_row: Optional[dict[str, Any]] = None,
order_leverage=None,
parse_position_metrics_fn: Callable[..., dict[str, Any] | None] | None = None,
get_mark_price_fn: Callable[[str], float | None] | None = None,
fallback_entry: float | None = None,
) -> float | None:
"""
解析下单监控轮询用的现价/标记价,优先级:
1. 已批量拉取的 ticker last
2. get_symbol_mark_price(含 mark)
3. 交易所持仓 mark(parse_ccxt_position_metrics / parse_position_mark_price)
4. 计划成交价 trigger_price
"""
sym = (symbol or "").strip()
if not sym:
return None
cached = prices.get(sym)
if cached is not None:
try:
v = float(cached)
if v > 0:
return v
except (TypeError, ValueError):
pass
if get_mark_price_fn is not None:
try:
mp = get_mark_price_fn(sym)
if mp is not None and float(mp) > 0:
return float(mp)
except Exception:
pass
if position_row:
mark = None
if parse_position_metrics_fn is not None:
try:
metrics = parse_position_metrics_fn(
position_row, order_leverage=order_leverage
)
if isinstance(metrics, dict) and metrics.get("mark_price") is not None:
mark = float(metrics["mark_price"])
except Exception:
mark = None
if mark is None or mark <= 0:
try:
mp = parse_position_mark_price(position_row)
if mp is not None and mp > 0:
mark = float(mp)
except Exception:
mark = None
if mark is not None and mark > 0:
return mark
if fallback_entry is not None:
try:
entry = float(fallback_entry)
if entry > 0:
return entry
except (TypeError, ValueError):
pass
return None
def seed_prices_from_positions(
prices: dict[str, float],
order_rows: Sequence[Any],
all_positions: Sequence[dict[str, Any]],
*,
resolve_ex_sym_fn: Callable[[Any], str],
) -> None:
"""用持仓标记价补全 prices 字典(symbol 与 order_monitors 行对齐)."""
if not all_positions or not order_rows:
return
try:
from lib.hub.hub_symbol_lib import symbols_match
except Exception:
symbols_match = None
for r in order_rows:
try:
sym = str(r["symbol"] or "").strip()
except (KeyError, TypeError, IndexError):
sym = ""
if not sym or sym in prices:
continue
try:
ex_sym = resolve_ex_sym_fn(r)
except Exception:
ex_sym = sym
try:
direction = str(r["direction"] or "long").lower()
except (KeyError, TypeError, IndexError):
direction = "long"
for p in all_positions:
if not isinstance(p, dict):
continue
ps = p.get("symbol") or ""
if not ps:
continue
matched = ps == sym or ps == ex_sym
if not matched and symbols_match is not None:
matched = symbols_match(sym, ps) or symbols_match(ex_sym, ps)
if not matched:
continue
side = (p.get("side") or "").lower()
if side and side != direction:
continue
mp = parse_position_mark_price(p)
if mp is not None and mp > 0:
prices[sym] = float(mp)
break