918bbed0fc
- 修复 deps.py 中 get_vn_service 的引用错误 (vn_service.vn_service -> vn_service) - 移除登录页面上的明文密码提示 - 改进前端错误处理,避免数据加载失败导致登录显示错误
289 lines
7.3 KiB
Python
289 lines
7.3 KiB
Python
"""
|
||
交易路由
|
||
处理订单发送、撤单、查询
|
||
"""
|
||
from fastapi import APIRouter, Depends, HTTPException, status
|
||
from typing import List
|
||
import logging
|
||
|
||
from ..models import (
|
||
SendOrderRequest, CancelOrderRequest, OrderResponse,
|
||
AccountResponse, PositionData, AccountData, ApiResponse, TradeData
|
||
)
|
||
from ..deps import get_current_user, get_vn_service
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
router = APIRouter()
|
||
|
||
|
||
# ============================================
|
||
# 账户和持仓
|
||
# ============================================
|
||
|
||
@router.get("/accounts", response_model=List[AccountData])
|
||
async def get_accounts(
|
||
current_user: dict = Depends(get_current_user),
|
||
vn_service=Depends(get_vn_service)
|
||
):
|
||
"""
|
||
获取账户信息
|
||
|
||
返回所有账户的资金信息
|
||
"""
|
||
accounts = await vn_service.get_accounts()
|
||
return [
|
||
AccountData(
|
||
account_id=acc["account_id"],
|
||
balance=acc["balance"],
|
||
available=acc["available"],
|
||
frozen=acc.get("frozen", 0.0),
|
||
)
|
||
for acc in accounts
|
||
]
|
||
|
||
|
||
@router.get("/positions", response_model=List[PositionData])
|
||
async def get_positions(
|
||
current_user: dict = Depends(get_current_user),
|
||
vn_service=Depends(get_vn_service)
|
||
):
|
||
"""
|
||
获取持仓信息
|
||
|
||
返回所有持仓数据
|
||
"""
|
||
positions = await vn_service.get_positions()
|
||
return [
|
||
PositionData(
|
||
symbol=p["symbol"],
|
||
exchange=p["exchange"],
|
||
direction=p["direction"],
|
||
volume=p["volume"],
|
||
price=p["price"],
|
||
pnl=p["pnl"],
|
||
pnl_ratio=p.get("pnl_ratio", 0.0),
|
||
frozen=p.get("frozen", 0.0),
|
||
)
|
||
for p in positions
|
||
]
|
||
|
||
|
||
# ============================================
|
||
# 订单管理
|
||
# ============================================
|
||
|
||
@router.get("/orders", response_model=List[OrderResponse])
|
||
async def get_orders(
|
||
current_user: dict = Depends(get_current_user),
|
||
vn_service=Depends(get_vn_service)
|
||
):
|
||
"""
|
||
获取所有委托
|
||
|
||
返回所有订单,包括历史订单和活动订单
|
||
"""
|
||
orders_data = await vn_service.get_orders()
|
||
|
||
return [
|
||
OrderResponse(
|
||
order_id=o["order_id"],
|
||
symbol=o["symbol"],
|
||
exchange=o["exchange"],
|
||
direction=o["direction"],
|
||
order_type=o["order_type"],
|
||
volume=o["volume"],
|
||
price=o.get("price"),
|
||
traded=o["traded"],
|
||
status=o["status"],
|
||
time=o["time"]
|
||
)
|
||
for o in orders_data
|
||
]
|
||
|
||
|
||
@router.get("/orders/active", response_model=List[OrderResponse])
|
||
async def get_active_orders(
|
||
current_user: dict = Depends(get_current_user),
|
||
vn_service=Depends(get_vn_service)
|
||
):
|
||
"""
|
||
获取活动委托
|
||
|
||
返回所有未完成的活动订单
|
||
"""
|
||
orders_data = await vn_service.get_active_orders()
|
||
|
||
return [
|
||
OrderResponse(
|
||
order_id=o["order_id"],
|
||
symbol=o["symbol"],
|
||
exchange=o["exchange"],
|
||
direction=o["direction"],
|
||
order_type=o["order_type"],
|
||
volume=o["volume"],
|
||
price=o.get("price"),
|
||
traded=o["traded"],
|
||
status=o["status"],
|
||
time=o["time"]
|
||
)
|
||
for o in orders_data
|
||
]
|
||
|
||
|
||
@router.post("/orders", response_model=dict)
|
||
async def send_order(
|
||
request: SendOrderRequest,
|
||
current_user: dict = Depends(get_current_user),
|
||
vn_service=Depends(get_vn_service)
|
||
):
|
||
"""
|
||
发送订单
|
||
|
||
- **symbol**: 品种代码
|
||
- **exchange**: 交易所
|
||
- **direction**: 方向 (buy/sell)
|
||
- **order_type**: 类型 (limit/market/stop)
|
||
- **volume**: 数量
|
||
- **price**: 价格(限价单必填)
|
||
- **reference**: 客户引用(可选)
|
||
"""
|
||
order_id = await vn_service.send_order(
|
||
symbol=request.symbol,
|
||
exchange=request.exchange,
|
||
direction=request.direction.value,
|
||
order_type=request.order_type.value,
|
||
volume=request.volume,
|
||
price=request.price,
|
||
reference=request.reference
|
||
)
|
||
|
||
if order_id:
|
||
return {
|
||
"success": True,
|
||
"order_id": order_id,
|
||
"message": "Order sent successfully"
|
||
}
|
||
else:
|
||
raise HTTPException(
|
||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||
detail="Failed to send order"
|
||
)
|
||
|
||
|
||
@router.delete("/orders/{vt_orderid}")
|
||
async def cancel_order(
|
||
vt_orderid: str,
|
||
current_user: dict = Depends(get_current_user),
|
||
vn_service=Depends(get_vn_service)
|
||
):
|
||
"""
|
||
撤销订单
|
||
|
||
- **vt_orderid**: 订单号(格式:gateway_name.orderid)
|
||
"""
|
||
success = await vn_service.cancel_order(vt_orderid)
|
||
|
||
if success:
|
||
return ApiResponse(
|
||
success=True,
|
||
message=f"Order {vt_orderid} cancelled successfully"
|
||
)
|
||
else:
|
||
raise HTTPException(
|
||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||
detail=f"Failed to cancel order {vt_orderid}"
|
||
)
|
||
|
||
|
||
# ============================================
|
||
# 成交记录
|
||
# ============================================
|
||
|
||
@router.get("/trades")
|
||
async def get_trades(
|
||
current_user: dict = Depends(get_current_user),
|
||
vn_service=Depends(get_vn_service)
|
||
):
|
||
"""
|
||
获取成交列表
|
||
|
||
返回所有成交记录
|
||
"""
|
||
trades = await vn_service.get_trades()
|
||
return {
|
||
"trades": trades,
|
||
"total": len(trades)
|
||
}
|
||
|
||
|
||
# ============================================
|
||
# 综合查询
|
||
# ============================================
|
||
|
||
@router.get("/account", response_model=AccountResponse)
|
||
async def get_account(
|
||
current_user: dict = Depends(get_current_user),
|
||
vn_service=Depends(get_vn_service)
|
||
):
|
||
"""
|
||
获取账户信息(包括持仓和委托)
|
||
|
||
返回账户资金、持仓和委托的综合信息
|
||
"""
|
||
accounts = await vn_service.get_accounts()
|
||
positions_data = await vn_service.get_positions()
|
||
orders_data = await vn_service.get_orders()
|
||
|
||
# 取第一个账户
|
||
account_data = accounts[0] if accounts else None
|
||
|
||
if not account_data:
|
||
raise HTTPException(
|
||
status_code=status.HTTP_404_NOT_FOUND,
|
||
detail="No account found"
|
||
)
|
||
|
||
account = AccountData(
|
||
account_id=account_data["account_id"],
|
||
balance=account_data["balance"],
|
||
available=account_data["available"],
|
||
frozen=account_data.get("frozen", 0.0),
|
||
)
|
||
|
||
positions = [
|
||
PositionData(
|
||
symbol=p["symbol"],
|
||
exchange=p["exchange"],
|
||
direction=p["direction"],
|
||
volume=p["volume"],
|
||
price=p["price"],
|
||
pnl=p["pnl"],
|
||
pnl_ratio=p.get("pnl_ratio", 0.0),
|
||
frozen=p.get("frozen", 0.0),
|
||
)
|
||
for p in positions_data
|
||
]
|
||
|
||
orders = [
|
||
OrderResponse(
|
||
order_id=o["order_id"],
|
||
symbol=o["symbol"],
|
||
exchange=o["exchange"],
|
||
direction=o["direction"],
|
||
order_type=o["order_type"],
|
||
volume=o["volume"],
|
||
price=o.get("price"),
|
||
traded=o["traded"],
|
||
status=o["status"],
|
||
time=o["time"]
|
||
)
|
||
for o in orders_data
|
||
]
|
||
|
||
return AccountResponse(
|
||
account=account,
|
||
positions=positions,
|
||
orders=orders
|
||
)
|