Files
NewStock/qmt/api_server.py

156 lines
5.5 KiB
Python
Raw Normal View History

2026-01-04 22:43:13 +08:00
# coding:utf-8
import os
import datetime
from typing import Optional, List, Dict, Any
from fastapi import FastAPI, Query
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse
from pydantic import BaseModel
# 导入新的管理器类
from qmt_engine import MultiEngineManager, TerminalStatus
2026-01-04 22:43:13 +08:00
# ================= Pydantic模型 =================
class TerminalStatusModel(BaseModel):
"""单个终端状态模型"""
qmt_id: str
alias: str
account_id: str
is_connected: bool
last_heartbeat: str
2026-01-04 22:43:13 +08:00
class StatusResponse(BaseModel):
"""全局状态响应模型"""
2026-01-04 22:43:13 +08:00
running: bool
start_time: str
terminals: List[TerminalStatusModel]
2026-01-04 22:43:13 +08:00
class PositionsResponse(BaseModel):
"""持仓响应模型"""
# 按 qmt_id 分组的实盘持仓
real_positions: Dict[str, List[Dict[str, Any]]]
# 按策略名分组的虚拟持仓
2026-01-04 22:43:13 +08:00
virtual_positions: Dict[str, Dict[str, str]]
class LogsResponse(BaseModel):
"""日志响应模型"""
logs: List[str]
# ================= FastAPI应用 =================
2026-01-04 22:43:13 +08:00
class QMTAPIServer:
"""多终端 QMT API服务器"""
2026-01-04 22:43:13 +08:00
def __init__(self, manager: MultiEngineManager):
self.app = FastAPI(title="QMT Multi-Terminal Monitor")
self.manager = manager
2026-01-04 22:43:13 +08:00
self._setup_middleware()
self._setup_routes()
def _setup_middleware(self):
"""设置中间件"""
self.app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
def _setup_routes(self):
"""设置路由"""
@self.app.get("/", summary="仪表盘页面")
async def read_root():
"""返回仪表盘HTML页面"""
if os.path.exists("dashboard.html"):
return FileResponse("dashboard.html")
return {"error": "Dashboard not found"}
@self.app.get("/api/status", response_model=StatusResponse, summary="获取所有终端状态")
2026-01-04 22:43:13 +08:00
def get_status():
"""获取所有 QMT 终端的连接状态"""
terminal_data = self.manager.get_all_status()
terminals = [
TerminalStatusModel(
qmt_id=t.qmt_id,
alias=t.alias,
account_id=t.account_id,
is_connected=t.is_connected,
last_heartbeat=t.last_heartbeat
) for t in terminal_data
]
2026-01-04 22:43:13 +08:00
return StatusResponse(
running=self.manager.is_running,
start_time=self.manager.start_time,
terminals=terminals
2026-01-04 22:43:13 +08:00
)
@self.app.get("/api/positions", response_model=PositionsResponse, summary="获取持仓信息")
def get_positions():
"""汇总所有终端的实盘持仓和所有策略的虚拟持仓"""
real_pos_data = {}
virtual_pos_data = {}
# 1. 遍历所有终端单元获取实盘持仓
for qmt_id, unit in self.manager.units.items():
positions = []
if unit.callback and unit.callback.is_connected:
try:
xt_pos = unit.xt_trader.query_stock_positions(unit.acc_obj)
if xt_pos:
positions = [
{
"code": p.stock_code,
"volume": p.volume,
"can_use": p.can_use_volume,
"market_value": round(p.market_value, 2)
} for p in xt_pos if p.volume > 0
]
except:
pass
real_pos_data[qmt_id] = positions
# 2. 遍历所有策略获取虚拟持仓
for s_name in self.manager.config.get('strategies', {}).keys():
v_data = self.manager.pos_manager.get_all_virtual_positions(s_name)
virtual_pos_data[s_name] = v_data
2026-01-04 22:43:13 +08:00
return PositionsResponse(
real_positions=real_pos_data,
virtual_positions=virtual_pos_data
2026-01-04 22:43:13 +08:00
)
@self.app.get("/api/logs", response_model=LogsResponse, summary="获取系统日志")
def get_logs(lines: int = Query(50, ge=1, le=1000)):
"""获取最近的系统运行日志"""
logs = self.manager.get_logs(lines)
2026-01-04 22:43:13 +08:00
return LogsResponse(logs=logs)
@self.app.get("/api/health", summary="健康检查")
def health_check():
"""健康检查:只要有一个终端在线即视为正常"""
terminal_data = self.manager.get_all_status()
any_connected = any(t.is_connected for t in terminal_data)
if self.manager.is_running and any_connected:
2026-01-04 22:43:13 +08:00
return {"status": "healthy", "timestamp": datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
else:
return {"status": "unhealthy", "reason": "No terminals connected", "timestamp": datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
2026-01-04 22:43:13 +08:00
def get_app(self) -> FastAPI:
"""获取FastAPI应用实例"""
return self.app
# ================= 辅助函数 =================
def create_api_server(manager: MultiEngineManager) -> FastAPI:
"""创建API服务器入口"""
server = QMTAPIServer(manager)
return server.get_app()