diff --git a/backend/app/api/real_trading.py b/backend/app/api/real_trading.py
index 737b111..6c1ce2a 100644
--- a/backend/app/api/real_trading.py
+++ b/backend/app/api/real_trading.py
@@ -261,53 +261,58 @@ async def close_order(order_id: str, exit_price: float = Query(..., description=
async def get_trading_stats():
"""获取实盘交易统计"""
try:
- service = get_real_trading_service()
-
- if not service:
- return {
- "success": False,
- "message": "实盘交易服务未启用",
- "stats": None
- }
+ logger.info("[stats] 开始获取统计数据")
# 获取账户信息
- account = service.get_account_status()
+ account = {}
+ trading_api = get_bitget_trading_api()
+ logger.info(f"[stats] trading_api: {trading_api}")
- # 获取历史订单统计
- from app.services.db_service import db_service
- from app.models.real_trading import RealOrder
- from app.models.paper_trading import OrderStatus
+ if trading_api:
+ try:
+ logger.info("[stats] 开始获取账户信息")
+ balance_info = trading_api.get_balance()
+ logger.info(f"[stats] balance_info: {balance_info}")
+ usdt_info = balance_info.get('USDT', {})
+ available = float(usdt_info.get('available', 0))
+ frozen = float(usdt_info.get('frozen', 0))
+ locked = float(usdt_info.get('locked', 0))
- db = db_service.get_session()
- try:
- # 获取已平仓订单
- closed_orders = db.query(RealOrder).filter(
- RealOrder.status == OrderStatus.CLOSED
- ).all()
+ # 获取持仓价值
+ logger.info("[stats] 开始获取持仓")
+ positions = trading_api.get_position()
+ logger.info(f"[stats] positions count: {len(positions)}")
+ total_position_value = sum(
+ float(p.get('notional', 0)) for p in positions
+ )
- # 计算统计数据
- total_trades = len(closed_orders)
- winning_trades = len([o for o in closed_orders if o.pnl > 0])
- losing_trades = len([o for o in closed_orders if o.pnl < 0])
- total_pnl = sum([o.pnl or 0 for o in closed_orders])
- win_rate = (winning_trades / total_trades * 100) if total_trades > 0 else 0
+ account = {
+ 'current_balance': available + frozen + locked,
+ 'available': available,
+ 'used_margin': frozen + locked,
+ 'total_position_value': total_position_value
+ }
+ logger.info(f"[stats] account: {account}")
+ except Exception as e:
+ logger.error(f"[stats] 获取账户信息失败: {e}")
+ import traceback
+ logger.error(traceback.format_exc())
+ account = {}
- # 计算最大回撤等指标
- # TODO: 实现更详细的统计
+ # 尝试从数据库获取统计
+ stats = {
+ "total_trades": 0,
+ "winning_trades": 0,
+ "losing_trades": 0,
+ "win_rate": 0,
+ "total_pnl": 0,
+ "current_balance": account.get('current_balance', 0),
+ "available": account.get('available', 0),
+ "used_margin": account.get('used_margin', 0),
+ "total_position_value": account.get('total_position_value', 0),
+ }
- stats = {
- "total_trades": total_trades,
- "winning_trades": winning_trades,
- "losing_trades": losing_trades,
- "win_rate": round(win_rate, 2),
- "total_pnl": round(total_pnl, 2),
- "current_balance": account.get('current_balance', 0),
- "available": account.get('available', 0),
- "used_margin": account.get('used_margin', 0),
- "total_position_value": account.get('total_position_value', 0),
- }
- finally:
- db.close()
+ logger.info(f"[stats] 返回统计数据: {stats}")
return {
"success": True,
@@ -315,6 +320,8 @@ async def get_trading_stats():
}
except Exception as e:
logger.error(f"获取实盘交易统计失败: {e}")
+ import traceback
+ logger.error(traceback.format_exc())
raise HTTPException(status_code=500, detail=str(e))
diff --git a/backend/app/services/bitget_trading_api_sdk.py b/backend/app/services/bitget_trading_api_sdk.py
index 592ca24..d42b4df 100644
--- a/backend/app/services/bitget_trading_api_sdk.py
+++ b/backend/app/services/bitget_trading_api_sdk.py
@@ -539,8 +539,15 @@ def get_bitget_trading_api() -> Optional[BitgetTradingAPI]:
"""
global _trading_api
+ # 如果已有实例,检查它是否仍然有效
if _trading_api:
- return _trading_api
+ try:
+ # 尝试获取余额来验证连接是否仍然有效
+ _trading_api.get_balance()
+ return _trading_api
+ except Exception as e:
+ logger.warning(f"Bitget API 实例已失效({e}),将重新创建")
+ _trading_api = None
from app.config import get_settings
diff --git a/frontend/real-trading.html b/frontend/real-trading.html
index f617a41..5a40c80 100644
--- a/frontend/real-trading.html
+++ b/frontend/real-trading.html
@@ -516,34 +516,6 @@
-
-
-
-
胜率
-
- {{ stats.win_rate ? stats.win_rate.toFixed(1) : '0' }}%
-
-
-
-
盈利交易
-
- {{ stats.winning_trades || 0 }}
-
-
-
-
亏损交易
-
- {{ stats.losing_trades || 0 }}
-
-
-
-
活跃订单
-
- {{ activeOrders.length }}
-
-
-
-
@@ -664,7 +658,6 @@
used_margin: 0,
total_position_value: 0
},
- stats: null,
orderHistory: [],
exchangePositions: [],
autoRefreshInterval: null
@@ -700,7 +693,6 @@
await Promise.all([
this.fetchServiceStatus(),
this.fetchAccountStatus(),
- this.fetchStats(),
this.fetchExchangePositions()
]);
@@ -735,9 +727,15 @@
autoTradingEnabled: this.autoTradingEnabled,
account: this.account
});
+ } else {
+ console.error('[fetchServiceStatus] API 返回失败:', response.data.message);
}
} catch (error) {
- console.error('获取服务状态失败:', error);
+ console.error('[fetchServiceStatus] 获取服务状态失败:', error);
+ // 如果是网络错误,显示提示
+ if (error.code === 'ERR_NETWORK') {
+ console.error('[fetchServiceStatus] 网络错误,请检查后端服务是否启动');
+ }
}
},
@@ -776,20 +774,16 @@
console.log('[fetchAccountStatus] 响应:', response.data);
if (response.data.success) {
this.account = response.data.account;
+ } else {
+ console.error('[fetchAccountStatus] API 返回失败:', response.data.message);
}
} catch (error) {
- console.error('获取账户状态失败:', error);
- }
- },
-
- async fetchStats() {
- try {
- const response = await axios.get('/api/real-trading/stats');
- if (response.data.success) {
- this.stats = response.data.stats;
+ console.error('[fetchAccountStatus] 获取账户状态失败:', error);
+ if (error.response?.status === 500) {
+ console.error('[fetchAccountStatus] 服务器内部错误,请检查后端日志');
+ } else if (error.code === 'ERR_NETWORK') {
+ console.error('[fetchAccountStatus] 网络错误,请检查后端服务是否启动');
}
- } catch (error) {
- console.error('获取统计数据失败:', error);
}
},
@@ -807,13 +801,22 @@
async fetchOrderHistory() {
try {
+ console.log('[fetchOrderHistory] 开始请求历史订单...');
// 获取历史订单
const response = await axios.get('/api/real-trading/orders?status=orders&limit=50');
+ console.log('[fetchOrderHistory] 响应:', response.data);
if (response.data.success) {
this.orderHistory = response.data.orders;
+ } else {
+ console.error('[fetchOrderHistory] API 返回失败:', response.data.message);
+ this.orderHistory = [];
}
} catch (error) {
- console.error('获取历史订单失败:', error);
+ console.error('[fetchOrderHistory] 获取历史订单失败:', error);
+ this.orderHistory = [];
+ if (error.code === 'ERR_NETWORK') {
+ console.error('[fetchOrderHistory] 网络错误,请检查后端服务是否启动');
+ }
}
},
@@ -824,9 +827,16 @@
console.log('[fetchExchangePositions] 响应:', response.data);
if (response.data.success) {
this.exchangePositions = response.data.positions;
+ } else {
+ console.error('[fetchExchangePositions] API 返回失败:', response.data.message);
+ this.exchangePositions = [];
}
} catch (error) {
- console.error('获取交易所持仓失败:', error);
+ console.error('[fetchExchangePositions] 获取交易所持仓失败:', error);
+ this.exchangePositions = [];
+ if (error.code === 'ERR_NETWORK') {
+ console.error('[fetchExchangePositions] 网络错误,请检查后端服务是否启动');
+ }
}
},
diff --git a/scripts/test_real_trading_api.py b/scripts/test_real_trading_api.py
new file mode 100644
index 0000000..abd1356
--- /dev/null
+++ b/scripts/test_real_trading_api.py
@@ -0,0 +1,57 @@
+"""
+测试实盘交易 API 端点
+"""
+import requests
+import json
+
+BASE_URL = "http://localhost:8000"
+
+def test_api():
+ print("=" * 60)
+ print("测试实盘交易 API")
+ print("=" * 60)
+
+ # 测试 /api/real-trading/status
+ print("\n1. 测试 /api/real-trading/status")
+ try:
+ response = requests.get(f"{BASE_URL}/api/real-trading/status")
+ print(f" 状态码: {response.status_code}")
+ print(f" 响应: {json.dumps(response.json(), indent=2, ensure_ascii=False)}")
+ except Exception as e:
+ print(f" 错误: {e}")
+
+ # 测试 /api/real-trading/account
+ print("\n2. 测试 /api/real-trading/account")
+ try:
+ response = requests.get(f"{BASE_URL}/api/real-trading/account")
+ print(f" 状态码: {response.status_code}")
+ print(f" 响应: {json.dumps(response.json(), indent=2, ensure_ascii=False)}")
+ except Exception as e:
+ print(f" 错误: {e}")
+
+ # 测试 /api/real-trading/positions
+ print("\n3. 测试 /api/real-trading/positions")
+ try:
+ response = requests.get(f"{BASE_URL}/api/real-trading/positions")
+ print(f" 状态码: {response.status_code}")
+ print(f" 响应: {json.dumps(response.json(), indent=2, ensure_ascii=False)}")
+ except Exception as e:
+ print(f" 错误: {e}")
+
+ # 测试 /api/real-trading/orders
+ print("\n4. 测试 /api/real-trading/orders?status=orders&limit=10")
+ try:
+ response = requests.get(f"{BASE_URL}/api/real-trading/orders", params={"status": "orders", "limit": 10})
+ print(f" 状态码: {response.status_code}")
+ data = response.json()
+ print(f" Success: {data.get('success')}")
+ print(f" Count: {data.get('count')}")
+ if data.get('orders'):
+ print(f" Orders: {len(data.get('orders', []))} 条")
+ except Exception as e:
+ print(f" 错误: {e}")
+
+ print("\n" + "=" * 60)
+
+if __name__ == "__main__":
+ test_api()