auto_trade_sys/backend/api/routes/account.py
薇薇安 a3129f57b6 a
2026-01-13 20:58:29 +08:00

181 lines
6.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
账户实时数据API - 从币安API获取实时账户和订单数据
"""
from fastapi import APIRouter, HTTPException
import sys
from pathlib import Path
import logging
project_root = Path(__file__).parent.parent.parent.parent
sys.path.insert(0, str(project_root))
sys.path.insert(0, str(project_root / 'backend'))
sys.path.insert(0, str(project_root / 'trading_system'))
from database.models import TradingConfig
logger = logging.getLogger(__name__)
router = APIRouter()
async def get_realtime_account_data():
"""从币安API实时获取账户数据"""
try:
# 从数据库读取API密钥
api_key = TradingConfig.get_value('BINANCE_API_KEY')
api_secret = TradingConfig.get_value('BINANCE_API_SECRET')
use_testnet = TradingConfig.get_value('USE_TESTNET', False)
if not api_key or not api_secret:
raise HTTPException(
status_code=400,
detail="API密钥未配置请在配置界面设置BINANCE_API_KEY和BINANCE_API_SECRET"
)
# 导入交易系统的BinanceClient
try:
from binance_client import BinanceClient
except ImportError:
# 如果直接导入失败尝试从trading_system导入
trading_system_path = project_root / 'trading_system'
sys.path.insert(0, str(trading_system_path))
from binance_client import BinanceClient
# 创建客户端
client = BinanceClient(
api_key=api_key,
api_secret=api_secret,
testnet=use_testnet
)
await client.connect()
# 获取账户余额
balance = await client.get_account_balance()
# 获取持仓
positions = await client.get_open_positions()
# 计算总仓位价值和总盈亏
total_position_value = 0
total_pnl = 0
open_positions_count = 0
for pos in positions:
position_amt = float(pos.get('positionAmt', 0))
if position_amt == 0:
continue
entry_price = float(pos.get('entryPrice', 0))
mark_price = float(pos.get('markPrice', 0))
unrealized_pnl = float(pos.get('unRealizedProfit', 0))
if mark_price == 0:
# 如果没有标记价格,使用入场价
mark_price = entry_price
position_value = abs(position_amt * mark_price)
total_position_value += position_value
total_pnl += unrealized_pnl
open_positions_count += 1
await client.disconnect()
return {
"total_balance": balance.get('total', 0),
"available_balance": balance.get('available', 0),
"total_position_value": total_position_value,
"total_pnl": total_pnl,
"open_positions": open_positions_count
}
except HTTPException:
raise
except Exception as e:
logger.error(f"获取账户数据失败: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=f"获取账户数据失败: {str(e)}")
@router.get("/realtime")
async def get_realtime_account():
"""获取实时账户数据"""
return await get_realtime_account_data()
@router.get("/positions")
async def get_realtime_positions():
"""获取实时持仓数据"""
try:
# 从数据库读取API密钥
api_key = TradingConfig.get_value('BINANCE_API_KEY')
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=error_msg
)
# 导入BinanceClient
try:
from binance_client import BinanceClient
except ImportError:
trading_system_path = project_root / 'trading_system'
sys.path.insert(0, str(trading_system_path))
from binance_client import BinanceClient
client = BinanceClient(
api_key=api_key,
api_secret=api_secret,
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:
position_amt = float(pos.get('positionAmt', 0))
if position_amt == 0:
continue
entry_price = float(pos.get('entryPrice', 0))
mark_price = float(pos.get('markPrice', 0))
unrealized_pnl = float(pos.get('unRealizedProfit', 0))
if mark_price == 0:
mark_price = entry_price
position_value = abs(position_amt * mark_price)
pnl_percent = 0
if entry_price > 0 and position_value > 0:
pnl_percent = (unrealized_pnl / position_value) * 100
formatted_positions.append({
"symbol": pos.get('symbol'),
"side": "BUY" if position_amt > 0 else "SELL",
"quantity": abs(position_amt),
"entry_price": entry_price,
"mark_price": mark_price,
"pnl": unrealized_pnl,
"pnl_percent": pnl_percent,
"leverage": int(pos.get('leverage', 1))
})
logger.info(f"格式化后 {len(formatted_positions)} 个有效持仓")
return formatted_positions
except HTTPException:
raise
except Exception as e:
error_msg = f"获取持仓数据失败: {str(e)}"
logger.error(error_msg, exc_info=True)
raise HTTPException(status_code=500, detail=error_msg)