Files
claude_dev 918bbed0fc fix: 修复登录500错误和移除明文密码提示
- 修复 deps.py 中 get_vn_service 的引用错误 (vn_service.vn_service -> vn_service)
- 移除登录页面上的明文密码提示
- 改进前端错误处理,避免数据加载失败导致登录显示错误
2026-07-02 12:23:55 +08:00

289 lines
7.3 KiB
Python
Raw Permalink 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.
"""
交易路由
处理订单发送、撤单、查询
"""
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
)