Files
sanguo_vnpy_v2/_retired/sanguo_web/api/routes/trading.py
T
claude_dev bf57aed17a retire(web): sanguo_web legacy 平行后端归档——用户拍板「代码保留归档,服务删」 [nas]
- git mv sanguo_web → _retired/sanguo_web/(git 历史保全+墓碑 README:
  归档原因/拍板记录/现役=sanguo_api)
- 退出启动面三处: promote.sh ALL_MODS 白名单(15→14 模块)+docker/Dockerfile:63
  COPY+docker/Dockerfile.nas:16 COPY——不可再被部署或启动为服务
- 背景(架构审计 P0-3): 硬编码 SECRET_KEY/admin123 默认口令/CORS 全开/可下
  真实订单/零测试/与 sanguo_api 路由冲突; 生产从未部署为服务, 纯误启动风险
  (README 旧「生产模式 uvicorn sanguo_web」指引已于 f6ca85e 勘误)
- three-env §3.1 模块清单+§12 矩阵行同步; session-guide §5 角色表前端行
  勘误(旧表把 sanguo_web 当前端模块推——实为 legacy 后端, 前端=frontend/)
- 零外部 import(runuweb/tests/packages 全 grep 实证), pytest testpaths=tests
  不受影响

Co-Authored-By: Claude Code <notify@anthropic.com>
2026-10-01 09:46:21 +08:00

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