auto_trade_sys/backend/api/routes/trades.py
薇薇安 d9830f395b a
2026-01-13 22:12:24 +08:00

138 lines
5.0 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
"""
from fastapi import APIRouter, Query, HTTPException
from typing import Optional
from datetime import datetime, timedelta
import sys
from pathlib import Path
project_root = Path(__file__).parent.parent.parent.parent
sys.path.insert(0, str(project_root))
sys.path.insert(0, str(project_root / 'backend'))
from database.models import Trade
router = APIRouter()
def get_date_range(period: Optional[str] = None):
"""
根据时间段参数返回开始和结束日期
Args:
period: 时间段 ('1d', '7d', '30d', 'custom')
Returns:
(start_date, end_date) 元组,格式为 'YYYY-MM-DD HH:MM:SS'
"""
end_date = datetime.now()
if period == '1d':
start_date = end_date - timedelta(days=1)
elif period == '7d':
start_date = end_date - timedelta(days=7)
elif period == '30d':
start_date = end_date - timedelta(days=30)
else:
return None, None
return start_date.strftime('%Y-%m-%d 00:00:00'), end_date.strftime('%Y-%m-%d %H:%M:%S')
@router.get("/")
async def get_trades(
start_date: Optional[str] = Query(None, description="开始日期 (YYYY-MM-DD 或 YYYY-MM-DD HH:MM:SS)"),
end_date: Optional[str] = Query(None, description="结束日期 (YYYY-MM-DD 或 YYYY-MM-DD HH:MM:SS)"),
period: Optional[str] = Query(None, description="快速时间段筛选: '1d'(最近1天), '7d'(最近7天), '30d'(最近30天)"),
symbol: Optional[str] = Query(None, description="交易对筛选"),
status: Optional[str] = Query(None, description="状态筛选: 'open', 'closed', 'cancelled'"),
limit: int = Query(100, ge=1, le=1000, description="返回记录数限制")
):
"""
获取交易记录
支持两种筛选方式:
1. 快速时间段筛选:使用 period 参数 ('1d', '7d', '30d')
2. 自定义时间段筛选:使用 start_date 和 end_date 参数
如果同时提供了 period 和 start_date/end_dateperiod 优先级更高
"""
try:
# 如果提供了 period使用快速时间段筛选
if period:
period_start, period_end = get_date_range(period)
if period_start and period_end:
start_date = period_start
end_date = period_end
# 格式化日期(如果只提供了日期,添加时间部分)
if start_date and len(start_date) == 10: # YYYY-MM-DD
start_date = f"{start_date} 00:00:00"
if end_date and len(end_date) == 10: # YYYY-MM-DD
end_date = f"{end_date} 23:59:59"
trades = Trade.get_all(start_date, end_date, symbol, status)
return {
"total": len(trades),
"trades": trades[:limit],
"filters": {
"start_date": start_date,
"end_date": end_date,
"period": period,
"symbol": symbol,
"status": status
}
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/stats")
async def get_trade_stats(
start_date: Optional[str] = Query(None, description="开始日期 (YYYY-MM-DD 或 YYYY-MM-DD HH:MM:SS)"),
end_date: Optional[str] = Query(None, description="结束日期 (YYYY-MM-DD 或 YYYY-MM-DD HH:MM:SS)"),
period: Optional[str] = Query(None, description="快速时间段筛选: '1d', '7d', '30d'"),
symbol: Optional[str] = Query(None, description="交易对筛选")
):
"""获取交易统计"""
try:
# 如果提供了 period使用快速时间段筛选
if period:
period_start, period_end = get_date_range(period)
if period_start and period_end:
start_date = period_start
end_date = period_end
# 格式化日期
if start_date and len(start_date) == 10:
start_date = f"{start_date} 00:00:00"
if end_date and len(end_date) == 10:
end_date = f"{end_date} 23:59:59"
trades = Trade.get_all(start_date, end_date, symbol, None)
closed_trades = [t for t in trades if t['status'] == 'closed']
win_trades = [t for t in closed_trades if float(t['pnl']) > 0]
stats = {
"total_trades": len(trades),
"closed_trades": len(closed_trades),
"open_trades": len(trades) - len(closed_trades),
"win_trades": len(win_trades),
"loss_trades": len(closed_trades) - len(win_trades),
"win_rate": len(win_trades) / len(closed_trades) * 100 if closed_trades else 0,
"total_pnl": sum(float(t['pnl']) for t in closed_trades),
"avg_pnl": sum(float(t['pnl']) for t in closed_trades) / len(closed_trades) if closed_trades else 0,
"filters": {
"start_date": start_date,
"end_date": end_date,
"period": period,
"symbol": symbol
}
}
return stats
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))