refactor: 将共用代码迁入 lib/ 模块化目录
统一 strategy、key_monitor、trade、hub 等共用库到 lib/ 子包,并补充 lib-structure 文档,便于四所与中控维护。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
"""实盘/关键位放大 K 线:订单元数据与交易所浮盈、价格展示精度。"""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Callable, Optional
|
||||
|
||||
from lib.hub.hub_ohlcv_lib import (
|
||||
normalize_price_tick,
|
||||
price_tick_from_market,
|
||||
round_ohlcv_bars_to_tick,
|
||||
)
|
||||
from lib.trade.order_monitor_display_lib import (
|
||||
apply_order_live_price_display,
|
||||
apply_order_price_display_fields,
|
||||
)
|
||||
|
||||
|
||||
def resolve_kline_price_tick(
|
||||
exchange: Any,
|
||||
exchange_symbol: str,
|
||||
*,
|
||||
ensure_markets_fn: Callable[[], None],
|
||||
) -> Optional[float]:
|
||||
"""交易所最小价格变动单位,供 lightweight-charts 右侧刻度与标记线对齐。"""
|
||||
if not exchange_symbol:
|
||||
return None
|
||||
try:
|
||||
ensure_markets_fn()
|
||||
return normalize_price_tick(price_tick_from_market(exchange, exchange_symbol))
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def align_candles_to_price_tick(
|
||||
candles: list[dict[str, Any]],
|
||||
price_tick: Optional[float],
|
||||
) -> None:
|
||||
if price_tick is not None and candles:
|
||||
round_ohlcv_bars_to_tick(candles, price_tick)
|
||||
|
||||
|
||||
def kline_api_price_fields(
|
||||
exchange: Any,
|
||||
exchange_symbol: str,
|
||||
candles: list[dict[str, Any]],
|
||||
*,
|
||||
ensure_markets_fn: Callable[[], None],
|
||||
) -> dict[str, Any]:
|
||||
tick = resolve_kline_price_tick(
|
||||
exchange, exchange_symbol, ensure_markets_fn=ensure_markets_fn
|
||||
)
|
||||
align_candles_to_price_tick(candles, tick)
|
||||
return {"price_tick": tick}
|
||||
|
||||
|
||||
def load_swap_positions_for_order_kline(
|
||||
exchange: Any,
|
||||
*,
|
||||
private_configured: bool,
|
||||
ensure_markets_fn: Callable[[], None],
|
||||
settle: str = "usdt",
|
||||
) -> list:
|
||||
if not private_configured:
|
||||
return []
|
||||
try:
|
||||
ensure_markets_fn()
|
||||
try:
|
||||
return exchange.fetch_positions(None, {"settle": settle}) or []
|
||||
except Exception:
|
||||
return exchange.fetch_positions() or []
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
|
||||
def metrics_for_order_item(
|
||||
order_item: dict[str, Any],
|
||||
positions: list,
|
||||
*,
|
||||
resolve_ex_sym_fn: Callable[[Any], str],
|
||||
select_live_fn: Callable[[list, str, str], Any],
|
||||
parse_metrics_fn: Callable[..., Optional[dict]],
|
||||
) -> Optional[dict]:
|
||||
if not positions:
|
||||
return None
|
||||
ex_sym = resolve_ex_sym_fn(order_item)
|
||||
direction = order_item.get("direction") or "long"
|
||||
prow = select_live_fn(positions, ex_sym, direction)
|
||||
if not prow:
|
||||
return None
|
||||
lev = order_item.get("leverage")
|
||||
return parse_metrics_fn(prow, order_leverage=lev)
|
||||
|
||||
|
||||
def build_order_kline_order_payload(
|
||||
order_item: dict[str, Any],
|
||||
*,
|
||||
ticker_price: Any,
|
||||
format_price_fn: Callable[[Any, Any], str],
|
||||
calc_pnl_fn: Callable[..., float],
|
||||
calc_rr_ratio_fn: Callable[..., Optional[float]],
|
||||
ex_metrics: Optional[dict] = None,
|
||||
) -> dict[str, Any]:
|
||||
sym = order_item.get("symbol") or ""
|
||||
direction = order_item.get("direction") or "long"
|
||||
margin = float(order_item.get("margin_capital") or 0)
|
||||
leverage = float(order_item.get("leverage") or 0)
|
||||
entry = float(order_item.get("trigger_price") or 0)
|
||||
|
||||
float_pnl = 0.0
|
||||
float_pct = 0.0
|
||||
if ticker_price and entry > 0:
|
||||
float_pnl = float(
|
||||
calc_pnl_fn(direction, entry, ticker_price, margin, leverage)
|
||||
)
|
||||
float_pct = round((float_pnl / margin * 100), 4) if margin > 0 else 0.0
|
||||
|
||||
px_for_fmt = ticker_price
|
||||
mark_raw = None
|
||||
if ex_metrics and ex_metrics.get("mark_price") is not None:
|
||||
mark_raw = ex_metrics["mark_price"]
|
||||
try:
|
||||
px_for_fmt = float(mark_raw)
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
|
||||
if ex_metrics and ex_metrics.get("unrealized_pnl") is not None:
|
||||
float_pnl = round(float(ex_metrics["unrealized_pnl"]), 2)
|
||||
denom = ex_metrics.get("initial_margin") or margin
|
||||
float_pct = (
|
||||
round((float_pnl / float(denom)) * 100, 4)
|
||||
if denom and float(denom) > 0
|
||||
else float_pct
|
||||
)
|
||||
|
||||
payload: dict[str, Any] = {
|
||||
"id": order_item["id"],
|
||||
"symbol": sym,
|
||||
"direction": direction,
|
||||
"trigger_price": order_item.get("trigger_price"),
|
||||
"stop_loss": order_item.get("stop_loss"),
|
||||
"take_profit": order_item.get("take_profit"),
|
||||
"trigger_price_display": format_price_fn(sym, order_item.get("trigger_price")),
|
||||
"stop_loss_display": format_price_fn(sym, order_item.get("stop_loss")),
|
||||
"take_profit_display": format_price_fn(sym, order_item.get("take_profit")),
|
||||
"margin_capital": order_item.get("margin_capital"),
|
||||
"leverage": order_item.get("leverage"),
|
||||
"position_ratio": order_item.get("position_ratio"),
|
||||
"breakeven_enabled": bool(int(order_item.get("breakeven_enabled") or 0)),
|
||||
"current_price": round(float(px_for_fmt), 8) if px_for_fmt is not None else None,
|
||||
"float_pnl": round(float(float_pnl), 2),
|
||||
"float_pct": float_pct,
|
||||
}
|
||||
apply_order_price_display_fields(
|
||||
payload,
|
||||
direction=direction,
|
||||
entry_price=order_item.get("trigger_price"),
|
||||
initial_stop_loss=order_item.get("initial_stop_loss"),
|
||||
stop_loss=order_item.get("stop_loss"),
|
||||
take_profit=order_item.get("take_profit"),
|
||||
calc_rr_ratio_fn=calc_rr_ratio_fn,
|
||||
)
|
||||
apply_order_live_price_display(
|
||||
payload,
|
||||
sym,
|
||||
ticker_price,
|
||||
mark_raw,
|
||||
format_price_fn,
|
||||
)
|
||||
payload["current_price_display"] = payload.get("price_display") or (
|
||||
format_price_fn(sym, px_for_fmt) if px_for_fmt is not None else None
|
||||
)
|
||||
return payload
|
||||
|
||||
|
||||
def enrich_key_kline_response(
|
||||
*,
|
||||
symbol: str,
|
||||
current_price: Any,
|
||||
key_info: Optional[dict[str, Any]],
|
||||
format_price_fn: Callable[[Any, Any], str],
|
||||
) -> tuple[Any, Optional[dict[str, Any]]]:
|
||||
price_display = format_price_fn(symbol, current_price) if current_price is not None else None
|
||||
if key_info is None:
|
||||
return price_display, None
|
||||
enriched = dict(key_info)
|
||||
enriched["upper_display"] = format_price_fn(symbol, key_info.get("upper"))
|
||||
enriched["lower_display"] = format_price_fn(symbol, key_info.get("lower"))
|
||||
return price_display, enriched
|
||||
Reference in New Issue
Block a user