refactor: 将共用代码迁入 lib/ 模块化目录
统一 strategy、key_monitor、trade、hub 等共用库到 lib/ 子包,并补充 lib-structure 文档,便于四所与中控维护。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+107
-107
@@ -1,107 +1,107 @@
|
||||
"""中控数据看板:四户当日总览(无 AI,纯数据聚合)。"""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any, Optional
|
||||
|
||||
from hub_ai.context import (
|
||||
build_daily_context,
|
||||
collect_closed_trades_snapshot,
|
||||
format_account_remark,
|
||||
format_dashboard_account_detail,
|
||||
)
|
||||
from hub_ai.config import trading_day_reset_hour
|
||||
from hub_trades_lib import current_trading_day
|
||||
|
||||
LOSS_ALERT_PCT = 5.0
|
||||
DASHBOARD_POLL_INTERVAL_SEC = 60
|
||||
|
||||
|
||||
def _safe_float(v: Any) -> Optional[float]:
|
||||
try:
|
||||
if v is None or v == "":
|
||||
return None
|
||||
return float(v)
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
|
||||
|
||||
def _account_capital_base(ac: dict) -> Optional[float]:
|
||||
funding = _safe_float(ac.get("funding_usdt"))
|
||||
trading = _safe_float(ac.get("trading_usdt"))
|
||||
if funding is not None and trading is not None:
|
||||
return funding + trading
|
||||
if funding is not None:
|
||||
return funding
|
||||
if trading is not None:
|
||||
return trading
|
||||
return None
|
||||
|
||||
|
||||
def _enrich_account_row(ac: dict) -> dict:
|
||||
st = ac.get("trade_stats") or {}
|
||||
capital = _account_capital_base(ac)
|
||||
day_pnl = float(st.get("total_pnl_u") or 0)
|
||||
loss_pct: Optional[float] = None
|
||||
loss_alert = False
|
||||
if capital is not None and capital > 0 and day_pnl < -1e-9:
|
||||
loss_pct = round(abs(day_pnl) / capital * 100.0, 2)
|
||||
loss_alert = loss_pct >= LOSS_ALERT_PCT
|
||||
return {
|
||||
"id": ac.get("id"),
|
||||
"key": ac.get("key"),
|
||||
"name": ac.get("name"),
|
||||
"status": ac.get("status"),
|
||||
"monitored": ac.get("status") != "未监控",
|
||||
"funding_usdt": ac.get("funding_usdt"),
|
||||
"trading_usdt": ac.get("trading_usdt"),
|
||||
"capital_total_usdt": round(capital, 4) if capital is not None else None,
|
||||
"available_trading_usdt": ac.get("available_trading_usdt"),
|
||||
"pnl_u": st.get("total_pnl_u"),
|
||||
"closed_count": st.get("closed_count"),
|
||||
"win_count": st.get("win_count"),
|
||||
"loss_count": st.get("loss_count"),
|
||||
"float_pnl_u": ac.get("float_pnl_u"),
|
||||
"open_position_count": ac.get("open_position_count"),
|
||||
"remark": format_account_remark(ac),
|
||||
**format_dashboard_account_detail(ac),
|
||||
"issues": ac.get("issues") or [],
|
||||
"daily_loss_pct": loss_pct,
|
||||
"loss_alert": loss_alert,
|
||||
}
|
||||
|
||||
|
||||
def build_dashboard_payload(
|
||||
exchanges: list[dict],
|
||||
*,
|
||||
trading_day: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
ctx = build_daily_context(exchanges, trading_day=trading_day)
|
||||
day = ctx["trading_day"]
|
||||
accounts_raw = ctx.get("accounts") or []
|
||||
accounts = [
|
||||
_enrich_account_row(ac)
|
||||
for ac in accounts_raw
|
||||
if ac.get("status") != "未监控"
|
||||
]
|
||||
closed_trades = collect_closed_trades_snapshot(
|
||||
[ac for ac in accounts_raw if ac.get("status") != "未监控"],
|
||||
today=day,
|
||||
)
|
||||
loss_alert_count = sum(1 for ac in accounts if ac.get("loss_alert"))
|
||||
now = datetime.now(timezone.utc).astimezone().strftime("%Y-%m-%d %H:%M:%S")
|
||||
return {
|
||||
"ok": True,
|
||||
"updated_at": now,
|
||||
"trading_day": day,
|
||||
"totals": ctx.get("totals"),
|
||||
"accounts": accounts,
|
||||
"closed_trades": closed_trades,
|
||||
"loss_alert_pct_threshold": LOSS_ALERT_PCT,
|
||||
"loss_alert_count": loss_alert_count,
|
||||
"poll_interval_sec": DASHBOARD_POLL_INTERVAL_SEC,
|
||||
}
|
||||
|
||||
|
||||
def default_trading_day() -> str:
|
||||
return current_trading_day(reset_hour=trading_day_reset_hour())
|
||||
"""中控数据看板:四户当日总览(无 AI,纯数据聚合)。"""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any, Optional
|
||||
|
||||
from hub_ai.context import (
|
||||
build_daily_context,
|
||||
collect_closed_trades_snapshot,
|
||||
format_account_remark,
|
||||
format_dashboard_account_detail,
|
||||
)
|
||||
from hub_ai.config import trading_day_reset_hour
|
||||
from lib.hub.hub_trades_lib import current_trading_day
|
||||
|
||||
LOSS_ALERT_PCT = 5.0
|
||||
DASHBOARD_POLL_INTERVAL_SEC = 60
|
||||
|
||||
|
||||
def _safe_float(v: Any) -> Optional[float]:
|
||||
try:
|
||||
if v is None or v == "":
|
||||
return None
|
||||
return float(v)
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
|
||||
|
||||
def _account_capital_base(ac: dict) -> Optional[float]:
|
||||
funding = _safe_float(ac.get("funding_usdt"))
|
||||
trading = _safe_float(ac.get("trading_usdt"))
|
||||
if funding is not None and trading is not None:
|
||||
return funding + trading
|
||||
if funding is not None:
|
||||
return funding
|
||||
if trading is not None:
|
||||
return trading
|
||||
return None
|
||||
|
||||
|
||||
def _enrich_account_row(ac: dict) -> dict:
|
||||
st = ac.get("trade_stats") or {}
|
||||
capital = _account_capital_base(ac)
|
||||
day_pnl = float(st.get("total_pnl_u") or 0)
|
||||
loss_pct: Optional[float] = None
|
||||
loss_alert = False
|
||||
if capital is not None and capital > 0 and day_pnl < -1e-9:
|
||||
loss_pct = round(abs(day_pnl) / capital * 100.0, 2)
|
||||
loss_alert = loss_pct >= LOSS_ALERT_PCT
|
||||
return {
|
||||
"id": ac.get("id"),
|
||||
"key": ac.get("key"),
|
||||
"name": ac.get("name"),
|
||||
"status": ac.get("status"),
|
||||
"monitored": ac.get("status") != "未监控",
|
||||
"funding_usdt": ac.get("funding_usdt"),
|
||||
"trading_usdt": ac.get("trading_usdt"),
|
||||
"capital_total_usdt": round(capital, 4) if capital is not None else None,
|
||||
"available_trading_usdt": ac.get("available_trading_usdt"),
|
||||
"pnl_u": st.get("total_pnl_u"),
|
||||
"closed_count": st.get("closed_count"),
|
||||
"win_count": st.get("win_count"),
|
||||
"loss_count": st.get("loss_count"),
|
||||
"float_pnl_u": ac.get("float_pnl_u"),
|
||||
"open_position_count": ac.get("open_position_count"),
|
||||
"remark": format_account_remark(ac),
|
||||
**format_dashboard_account_detail(ac),
|
||||
"issues": ac.get("issues") or [],
|
||||
"daily_loss_pct": loss_pct,
|
||||
"loss_alert": loss_alert,
|
||||
}
|
||||
|
||||
|
||||
def build_dashboard_payload(
|
||||
exchanges: list[dict],
|
||||
*,
|
||||
trading_day: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
ctx = build_daily_context(exchanges, trading_day=trading_day)
|
||||
day = ctx["trading_day"]
|
||||
accounts_raw = ctx.get("accounts") or []
|
||||
accounts = [
|
||||
_enrich_account_row(ac)
|
||||
for ac in accounts_raw
|
||||
if ac.get("status") != "未监控"
|
||||
]
|
||||
closed_trades = collect_closed_trades_snapshot(
|
||||
[ac for ac in accounts_raw if ac.get("status") != "未监控"],
|
||||
today=day,
|
||||
)
|
||||
loss_alert_count = sum(1 for ac in accounts if ac.get("loss_alert"))
|
||||
now = datetime.now(timezone.utc).astimezone().strftime("%Y-%m-%d %H:%M:%S")
|
||||
return {
|
||||
"ok": True,
|
||||
"updated_at": now,
|
||||
"trading_day": day,
|
||||
"totals": ctx.get("totals"),
|
||||
"accounts": accounts,
|
||||
"closed_trades": closed_trades,
|
||||
"loss_alert_pct_threshold": LOSS_ALERT_PCT,
|
||||
"loss_alert_count": loss_alert_count,
|
||||
"poll_interval_sec": DASHBOARD_POLL_INTERVAL_SEC,
|
||||
}
|
||||
|
||||
|
||||
def default_trading_day() -> str:
|
||||
return current_trading_day(reset_hour=trading_day_reset_hour())
|
||||
|
||||
Reference in New Issue
Block a user