From 06f900b89b7005c27cbdf584675ee98aac913470 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 11 Mar 2026 16:02:04 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20=5Fget=5Fstrategy=5Ftrade=5Fstats=20?= =?UTF-8?q?=E5=85=BC=E5=AE=B9=E6=97=A7=E6=95=B0=E6=8D=AE(strategy=E6=96=87?= =?UTF-8?q?=E6=9C=AC)=E5=92=8C=E6=96=B0=E6=95=B0=E6=8D=AE(strategy=5Fid)?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E5=A4=8Dopen=5Fpositions=E8=AE=A1=E7=AE=97(?= =?UTF-8?q?=E5=90=ABtp1=5Fhit)=EF=BC=8Ccurrent=5Fbalance=E5=AE=9E=E6=97=B6?= =?UTF-8?q?=E8=AE=A1=E7=AE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/main.py | 73 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 21 deletions(-) diff --git a/backend/main.py b/backend/main.py index 3c5ea96..4673289 100644 --- a/backend/main.py +++ b/backend/main.py @@ -2456,22 +2456,39 @@ def _strategy_row_to_detail(row: dict) -> dict: async def _get_strategy_trade_stats(strategy_id: str) -> dict: - """Fetch trade statistics for a strategy by strategy_id""" - rows = await async_fetch( - """SELECT status, pnl_r, tp1_hit, entry_ts, exit_ts - FROM paper_trades - WHERE strategy_id=$1 AND status != 'active' - ORDER BY entry_ts DESC""", - strategy_id - ) + """Fetch trade statistics for a strategy by strategy_id. + 兼容新数据(strategy_id列)和旧数据(strategy文本列)。 + """ + # 固定 UUID → legacy strategy文本名映射(迁移时写死的三条策略) + LEGACY_NAME_MAP = { + "00000000-0000-0000-0000-000000000053": "v53", + "00000000-0000-0000-0000-000000000054": "v53_middle", + "00000000-0000-0000-0000-000000000055": "v53_fast", + } + legacy_name = LEGACY_NAME_MAP.get(strategy_id) + + # 查已关闭的交易记录(同时兼容新旧两种匹配方式) + if legacy_name: + rows = await async_fetch( + """SELECT status, pnl_r, tp1_hit, entry_ts, exit_ts + FROM paper_trades + WHERE status NOT IN ('active', 'tp1_hit') + AND (strategy_id=$1 OR (strategy_id IS NULL AND strategy=$2)) + ORDER BY entry_ts DESC""", + strategy_id, legacy_name + ) + else: + rows = await async_fetch( + """SELECT status, pnl_r, tp1_hit, entry_ts, exit_ts + FROM paper_trades + WHERE strategy_id=$1 AND status NOT IN ('active', 'tp1_hit') + ORDER BY entry_ts DESC""", + strategy_id + ) + if not rows: - return { - "trade_count": 0, "win_rate": 0.0, - "avg_win_r": 0.0, "avg_loss_r": 0.0, - "open_positions": 0, - "pnl_usdt_24h": 0.0, "pnl_r_24h": 0.0, - "last_trade_at": None, - } + # 即使没有历史记录也要查持仓 + pass total = len(rows) wins = [r for r in rows if (r["pnl_r"] or 0) > 0] @@ -2487,12 +2504,21 @@ async def _get_strategy_trade_stats(strategy_id: str) -> dict: pnl_r_24h = round(sum(r["pnl_r"] or 0 for r in rows_24h), 3) pnl_usdt_24h = round(pnl_r_24h * 200, 2) - # Open positions - open_rows = await async_fetch( - "SELECT COUNT(*) as cnt FROM paper_trades WHERE strategy_id=$1 AND status='active'", - strategy_id - ) - open_positions = open_rows[0]["cnt"] if open_rows else 0 + # Open positions — status IN ('active','tp1_hit'),同时兼容新旧记录 + if legacy_name: + open_rows = await async_fetch( + """SELECT COUNT(*) as cnt FROM paper_trades + WHERE status IN ('active','tp1_hit') + AND (strategy_id=$1 OR (strategy_id IS NULL AND strategy=$2))""", + strategy_id, legacy_name + ) + else: + open_rows = await async_fetch( + """SELECT COUNT(*) as cnt FROM paper_trades + WHERE strategy_id=$1 AND status IN ('active','tp1_hit')""", + strategy_id + ) + open_positions = int(open_rows[0]["cnt"]) if open_rows else 0 return { "trade_count": total, @@ -2503,6 +2529,8 @@ async def _get_strategy_trade_stats(strategy_id: str) -> dict: "pnl_usdt_24h": pnl_usdt_24h, "pnl_r_24h": pnl_r_24h, "last_trade_at": last_trade_at, + "net_r": round(sum(r["pnl_r"] or 0 for r in rows), 3), + "net_usdt": round(sum(r["pnl_r"] or 0 for r in rows) * 200, 2), } @@ -2569,6 +2597,8 @@ async def list_strategies( d = _strategy_row_to_card(dict(row)) stats = await _get_strategy_trade_stats(str(row["strategy_id"])) d.update(stats) + # 用实时计算的 net_usdt 覆盖 DB 静态的 current_balance + d["current_balance"] = round(row["initial_balance"] + d["net_usdt"], 2) result.append(d) return {"strategies": result} @@ -2580,6 +2610,7 @@ async def get_strategy(sid: str, user: dict = Depends(get_current_user)): detail = _strategy_row_to_detail(row) stats = await _get_strategy_trade_stats(sid) detail.update(stats) + detail["current_balance"] = round(row["initial_balance"] + detail["net_usdt"], 2) return {"strategy": detail}