This commit is contained in:
薇薇安 2026-01-13 21:37:32 +08:00
parent a3129f57b6
commit 9160617b8e

View File

@ -19,43 +19,122 @@ router = APIRouter()
async def get_realtime_account_data(): async def get_realtime_account_data():
"""从币安API实时获取账户数据""" """从币安API实时获取账户数据"""
logger.info("=" * 60)
logger.info("开始获取实时账户数据")
logger.info("=" * 60)
try: try:
# 从数据库读取API密钥 # 从数据库读取API密钥
logger.info("步骤1: 从数据库读取API配置...")
api_key = TradingConfig.get_value('BINANCE_API_KEY') api_key = TradingConfig.get_value('BINANCE_API_KEY')
api_secret = TradingConfig.get_value('BINANCE_API_SECRET') api_secret = TradingConfig.get_value('BINANCE_API_SECRET')
use_testnet = TradingConfig.get_value('USE_TESTNET', False) use_testnet = TradingConfig.get_value('USE_TESTNET', False)
logger.info(f" - API密钥存在: {bool(api_key)}")
if api_key:
logger.info(f" - API密钥长度: {len(api_key)} 字符")
logger.info(f" - API密钥前缀: {api_key[:10]}...")
else:
logger.warning(" - API密钥为空!")
logger.info(f" - API密钥存在: {bool(api_secret)}")
if api_secret:
logger.info(f" - API密钥长度: {len(api_secret)} 字符")
logger.info(f" - API密钥前缀: {api_secret[:10]}...")
else:
logger.warning(" - API密钥为空!")
logger.info(f" - 使用测试网: {use_testnet}")
if not api_key or not api_secret: if not api_key or not api_secret:
error_msg = "API密钥未配置请在配置界面设置BINANCE_API_KEY和BINANCE_API_SECRET"
logger.error(f"{error_msg}")
raise HTTPException( raise HTTPException(
status_code=400, status_code=400,
detail="API密钥未配置请在配置界面设置BINANCE_API_KEY和BINANCE_API_SECRET" detail=error_msg
) )
# 导入交易系统的BinanceClient # 导入交易系统的BinanceClient
logger.info("步骤2: 导入BinanceClient...")
try: try:
from binance_client import BinanceClient from binance_client import BinanceClient
except ImportError: logger.info(" ✓ 从当前路径导入BinanceClient成功")
except ImportError as e:
logger.warning(f" - 从当前路径导入失败: {e}")
# 如果直接导入失败尝试从trading_system导入 # 如果直接导入失败尝试从trading_system导入
trading_system_path = project_root / 'trading_system' trading_system_path = project_root / 'trading_system'
sys.path.insert(0, str(trading_system_path)) sys.path.insert(0, str(trading_system_path))
from binance_client import BinanceClient logger.info(f" - 添加路径到sys.path: {trading_system_path}")
try:
from binance_client import BinanceClient
logger.info(" ✓ 从trading_system路径导入BinanceClient成功")
except ImportError as e2:
logger.error(f" ✗ 导入BinanceClient失败: {e2}")
raise
# 创建客户端 # 创建客户端
logger.info("步骤3: 创建BinanceClient实例...")
client = BinanceClient( client = BinanceClient(
api_key=api_key, api_key=api_key,
api_secret=api_secret, api_secret=api_secret,
testnet=use_testnet testnet=use_testnet
) )
logger.info(f" ✓ 客户端创建成功 (testnet={use_testnet})")
await client.connect() # 连接币安API
logger.info("步骤4: 连接币安API...")
try:
await client.connect()
logger.info(" ✓ 币安API连接成功")
except Exception as e:
logger.error(f" ✗ 币安API连接失败: {e}", exc_info=True)
raise
# 获取账户余额 # 获取账户余额
balance = await client.get_account_balance() logger.info("步骤5: 获取账户余额...")
try:
balance = await client.get_account_balance()
logger.info(" ✓ 账户余额获取成功")
logger.info(f" - 返回数据类型: {type(balance)}")
logger.info(f" - 返回数据内容: {balance}")
if balance:
logger.info(f" - 总余额: {balance.get('total', 'N/A')} USDT")
logger.info(f" - 可用余额: {balance.get('available', 'N/A')} USDT")
logger.info(f" - 保证金: {balance.get('margin', 'N/A')} USDT")
if balance.get('total', 0) == 0:
logger.warning(" ⚠ 账户余额为0可能是API权限问题或账户确实无余额")
else:
logger.warning(" ⚠ 返回的余额数据为空")
except Exception as e:
logger.error(f" ✗ 获取账户余额失败: {e}", exc_info=True)
raise
# 获取持仓 # 获取持仓
positions = await client.get_open_positions() logger.info("步骤6: 获取持仓信息...")
try:
positions = await client.get_open_positions()
logger.info(" ✓ 持仓信息获取成功")
logger.info(f" - 返回数据类型: {type(positions)}")
logger.info(f" - 持仓数量: {len(positions)}")
if positions:
logger.info(" - 持仓详情:")
for i, pos in enumerate(positions[:5], 1): # 只显示前5个
logger.info(f" {i}. {pos.get('symbol', 'N/A')}: "
f"数量={pos.get('positionAmt', 0)}, "
f"入场价={pos.get('entryPrice', 0)}, "
f"盈亏={pos.get('unRealizedProfit', 0)}")
if len(positions) > 5:
logger.info(f" ... 还有 {len(positions) - 5} 个持仓")
else:
logger.info(" - 当前无持仓")
except Exception as e:
logger.error(f" ✗ 获取持仓信息失败: {e}", exc_info=True)
raise
# 计算总仓位价值和总盈亏 # 计算总仓位价值和总盈亏
logger.info("步骤7: 计算仓位统计...")
total_position_value = 0 total_position_value = 0
total_pnl = 0 total_pnl = 0
open_positions_count = 0 open_positions_count = 0
@ -77,21 +156,50 @@ async def get_realtime_account_data():
total_position_value += position_value total_position_value += position_value
total_pnl += unrealized_pnl total_pnl += unrealized_pnl
open_positions_count += 1 open_positions_count += 1
logger.debug(f" - {pos.get('symbol')}: 价值={position_value:.2f}, 盈亏={unrealized_pnl:.2f}")
await client.disconnect() logger.info(" ✓ 仓位统计计算完成")
logger.info(f" - 总仓位价值: {total_position_value:.2f} USDT")
logger.info(f" - 总盈亏: {total_pnl:.2f} USDT")
logger.info(f" - 持仓数量: {open_positions_count}")
return { # 断开连接
"total_balance": balance.get('total', 0), logger.info("步骤8: 断开币安API连接...")
"available_balance": balance.get('available', 0), try:
await client.disconnect()
logger.info(" ✓ 连接已断开")
except Exception as e:
logger.warning(f" ⚠ 断开连接时出错: {e}")
# 构建返回结果
result = {
"total_balance": balance.get('total', 0) if balance else 0,
"available_balance": balance.get('available', 0) if balance else 0,
"total_position_value": total_position_value, "total_position_value": total_position_value,
"total_pnl": total_pnl, "total_pnl": total_pnl,
"open_positions": open_positions_count "open_positions": open_positions_count
} }
except HTTPException:
logger.info("=" * 60)
logger.info("账户数据获取成功!")
logger.info(f"最终结果: {result}")
logger.info("=" * 60)
return result
except HTTPException as e:
logger.error("=" * 60)
logger.error(f"HTTP异常: {e.status_code} - {e.detail}")
logger.error("=" * 60)
raise raise
except Exception as e: except Exception as e:
logger.error(f"获取账户数据失败: {e}", exc_info=True) error_msg = f"获取账户数据失败: {str(e)}"
raise HTTPException(status_code=500, detail=f"获取账户数据失败: {str(e)}") logger.error("=" * 60)
logger.error(f"异常类型: {type(e).__name__}")
logger.error(f"错误信息: {error_msg}")
logger.error("=" * 60, exc_info=True)
raise HTTPException(status_code=500, detail=error_msg)
@router.get("/realtime") @router.get("/realtime")