From a3129f57b638fa71247d774918febd2b64803538 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=87=E8=96=87=E5=AE=89?= Date: Tue, 13 Jan 2026 20:58:29 +0800 Subject: [PATCH] a --- backend/api/routes/account.py | 17 +++++-- backend/api/routes/stats.py | 92 ++++++++++++++++++++++++++++++----- 2 files changed, 93 insertions(+), 16 deletions(-) diff --git a/backend/api/routes/account.py b/backend/api/routes/account.py index e451d25..64595b9 100644 --- a/backend/api/routes/account.py +++ b/backend/api/routes/account.py @@ -4,7 +4,6 @@ from fastapi import APIRouter, HTTPException import sys from pathlib import Path -import asyncio import logging project_root = Path(__file__).parent.parent.parent.parent @@ -13,7 +12,6 @@ sys.path.insert(0, str(project_root / 'backend')) sys.path.insert(0, str(project_root / 'trading_system')) from database.models import TradingConfig -from fastapi import HTTPException logger = logging.getLogger(__name__) router = APIRouter() @@ -111,10 +109,14 @@ async def get_realtime_positions(): api_secret = TradingConfig.get_value('BINANCE_API_SECRET') use_testnet = TradingConfig.get_value('USE_TESTNET', False) + logger.info(f"尝试获取实时持仓数据 (testnet={use_testnet})") + if not api_key or not api_secret: + error_msg = "API密钥未配置" + logger.warning(error_msg) raise HTTPException( status_code=400, - detail="API密钥未配置" + detail=error_msg ) # 导入BinanceClient @@ -131,10 +133,13 @@ async def get_realtime_positions(): testnet=use_testnet ) + logger.info("连接币安API获取持仓...") await client.connect() positions = await client.get_open_positions() await client.disconnect() + logger.info(f"获取到 {len(positions)} 个持仓") + # 格式化持仓数据 formatted_positions = [] for pos in positions: @@ -165,9 +170,11 @@ async def get_realtime_positions(): "leverage": int(pos.get('leverage', 1)) }) + logger.info(f"格式化后 {len(formatted_positions)} 个有效持仓") return formatted_positions except HTTPException: raise except Exception as e: - logger.error(f"获取持仓数据失败: {e}", exc_info=True) - raise HTTPException(status_code=500, detail=f"获取持仓数据失败: {str(e)}") + error_msg = f"获取持仓数据失败: {str(e)}" + logger.error(error_msg, exc_info=True) + raise HTTPException(status_code=500, detail=error_msg) diff --git a/backend/api/routes/stats.py b/backend/api/routes/stats.py index 0c57079..8919f05 100644 --- a/backend/api/routes/stats.py +++ b/backend/api/routes/stats.py @@ -5,6 +5,7 @@ from fastapi import APIRouter, Query import sys from pathlib import Path from datetime import datetime, timedelta +import logging project_root = Path(__file__).parent.parent.parent.parent sys.path.insert(0, str(project_root)) @@ -13,6 +14,7 @@ sys.path.insert(0, str(project_root / 'backend')) from database.models import AccountSnapshot, Trade, MarketScan, TradingSignal from fastapi import HTTPException +logger = logging.getLogger(__name__) router = APIRouter() @@ -41,41 +43,109 @@ async def get_dashboard_data(): """获取仪表板数据""" try: account_data = None + account_error = None # 优先尝试获取实时账户数据 try: from api.routes.account import get_realtime_account_data account_data = await get_realtime_account_data() - except Exception as e: - logger.warning(f"获取实时账户数据失败,使用数据库快照: {e}") + logger.info("成功获取实时账户数据") + except HTTPException as e: + # HTTPException 需要特殊处理,提取错误信息 + account_error = e.detail + logger.warning(f"获取实时账户数据失败 (HTTP {e.status_code}): {account_error}") # 回退到数据库快照 - snapshots = AccountSnapshot.get_recent(1) - account_data = snapshots[0] if snapshots else None + try: + snapshots = AccountSnapshot.get_recent(1) + if snapshots: + account_data = { + "total_balance": snapshots[0].get('total_balance', 0), + "available_balance": snapshots[0].get('available_balance', 0), + "total_position_value": snapshots[0].get('total_position_value', 0), + "total_pnl": snapshots[0].get('total_pnl', 0), + "open_positions": snapshots[0].get('open_positions', 0) + } + logger.info("使用数据库快照作为账户数据") + else: + logger.warning("数据库中没有账户快照数据") + except Exception as db_error: + logger.error(f"从数据库获取账户快照失败: {db_error}") + except Exception as e: + account_error = str(e) + logger.warning(f"获取实时账户数据失败: {account_error}", exc_info=True) + # 回退到数据库快照 + try: + snapshots = AccountSnapshot.get_recent(1) + if snapshots: + account_data = { + "total_balance": snapshots[0].get('total_balance', 0), + "available_balance": snapshots[0].get('available_balance', 0), + "total_position_value": snapshots[0].get('total_position_value', 0), + "total_pnl": snapshots[0].get('total_pnl', 0), + "open_positions": snapshots[0].get('open_positions', 0) + } + logger.info("使用数据库快照作为账户数据") + except Exception as db_error: + logger.error(f"从数据库获取账户快照失败: {db_error}") # 获取持仓数据(优先实时,回退到数据库) open_trades = [] + positions_error = None try: from api.routes.account import get_realtime_positions positions = await get_realtime_positions() # 转换为前端需要的格式 open_trades = positions - except Exception as e: - logger.warning(f"获取实时持仓失败,使用数据库记录: {e}") + logger.info(f"成功获取实时持仓数据: {len(open_trades)} 个持仓") + except HTTPException as e: + positions_error = e.detail + logger.warning(f"获取实时持仓失败 (HTTP {e.status_code}): {positions_error}") # 回退到数据库记录 - open_trades = Trade.get_all(status='open')[:10] + try: + open_trades = Trade.get_all(status='open')[:10] + logger.info(f"使用数据库记录作为持仓数据: {len(open_trades)} 个持仓") + except Exception as db_error: + logger.error(f"从数据库获取持仓记录失败: {db_error}") + except Exception as e: + positions_error = str(e) + logger.warning(f"获取实时持仓失败: {positions_error}", exc_info=True) + # 回退到数据库记录 + try: + open_trades = Trade.get_all(status='open')[:10] + logger.info(f"使用数据库记录作为持仓数据: {len(open_trades)} 个持仓") + except Exception as db_error: + logger.error(f"从数据库获取持仓记录失败: {db_error}") # 最近的扫描记录 - recent_scans = MarketScan.get_recent(10) + recent_scans = [] + try: + recent_scans = MarketScan.get_recent(10) + except Exception as e: + logger.error(f"获取扫描记录失败: {e}") # 最近的信号 - recent_signals = TradingSignal.get_recent(20) + recent_signals = [] + try: + recent_signals = TradingSignal.get_recent(20) + except Exception as e: + logger.error(f"获取交易信号失败: {e}") - return { + result = { "account": account_data, "open_trades": open_trades, "recent_scans": recent_scans, "recent_signals": recent_signals } + + # 如果有错误,在响应中包含错误信息(但不影响返回) + if account_error or positions_error: + result["warnings"] = {} + if account_error: + result["warnings"]["account"] = account_error + if positions_error: + result["warnings"]["positions"] = positions_error + + return result except Exception as e: logger.error(f"获取仪表板数据失败: {e}", exc_info=True) - raise HTTPException(status_code=500, detail=str(e)) + raise HTTPException(status_code=500, detail=f"获取仪表板数据失败: {str(e)}")