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

174 lines
5.9 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 asyncio
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
from fastapi import HTTPException
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)
if not api_key or not api_secret:
raise HTTPException(
status_code=400,
detail="API密钥未配置"
)
# 导入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
)
await client.connect()
positions = await client.get_open_positions()
await client.disconnect()
# 格式化持仓数据
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))
})
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)}")