更新qmt代码,支持多端qmt登录

This commit is contained in:
2026-01-10 04:06:35 +08:00
parent dd60589280
commit 50ee1a5a0a
6 changed files with 487 additions and 495 deletions

View File

@@ -8,37 +8,46 @@ from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse
from pydantic import BaseModel
from qmt_engine import QMTEngine, QMTStatus
# 导入新的管理器类
from qmt_engine import MultiEngineManager, TerminalStatus
# ================= Pydantic模型 =================
class StatusResponse(BaseModel):
"""状态响应模型"""
running: bool
qmt_connected: bool
start_time: str
last_loop_update: str
account_id: str
class TerminalStatusModel(BaseModel):
"""单个终端状态模型"""
qmt_id: str
alias: str
account_id: str
is_connected: bool
last_heartbeat: str
class StatusResponse(BaseModel):
"""全局状态响应模型"""
running: bool
start_time: str
terminals: List[TerminalStatusModel]
class PositionsResponse(BaseModel):
"""持仓响应模型"""
real_positions: List[Dict[str, Any]]
# 按 qmt_id 分组的实盘持仓
real_positions: Dict[str, List[Dict[str, Any]]]
# 按策略名分组的虚拟持仓
virtual_positions: Dict[str, Dict[str, str]]
class LogsResponse(BaseModel):
"""日志响应模型"""
logs: List[str]
# ================= FastAPI应用 =================
class QMTAPIServer:
"""QMT API服务器"""
"""多终端 QMT API服务器"""
def __init__(self, qmt_engine: QMTEngine):
self.app = FastAPI(title="QMT Monitor")
self.qmt_engine = qmt_engine
def __init__(self, manager: MultiEngineManager):
self.app = FastAPI(title="QMT Multi-Terminal Monitor")
self.manager = manager
self._setup_middleware()
self._setup_routes()
@@ -61,41 +70,78 @@ class QMTAPIServer:
return FileResponse("dashboard.html")
return {"error": "Dashboard not found"}
@self.app.get("/api/status", response_model=StatusResponse, summary="获取系统状态")
@self.app.get("/api/status", response_model=StatusResponse, summary="获取所有终端状态")
def get_status():
"""获取QMT连接状态和系统信息"""
status = self.qmt_engine.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
]
return StatusResponse(
running=status.is_running,
qmt_connected=status.is_connected,
start_time=status.start_time,
last_loop_update=status.last_heartbeat,
account_id=status.account_id
running=self.manager.is_running,
start_time=self.manager.start_time,
terminals=terminals
)
@self.app.get("/api/positions", response_model=PositionsResponse, summary="获取持仓信息")
def get_positions():
"""获取实盘和虚拟持仓信息"""
positions = self.qmt_engine.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
return PositionsResponse(
real_positions=positions["real_positions"],
virtual_positions=positions["virtual_positions"]
real_positions=real_pos_data,
virtual_positions=virtual_pos_data
)
@self.app.get("/api/logs", response_model=LogsResponse, summary="获取日志")
def get_logs(lines: int = Query(50, ge=1, le=1000, description="返回日志行数")):
"""获取最近的交易日志"""
logs = self.qmt_engine.get_logs(lines)
@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)
return LogsResponse(logs=logs)
@self.app.get("/api/health", summary="健康检查")
def health_check():
"""健康检查接口"""
status = self.qmt_engine.get_status()
if status.is_running and status.is_connected:
"""健康检查:只要有一个终端在线即视为正常"""
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:
return {"status": "healthy", "timestamp": datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
else:
return {"status": "unhealthy", "timestamp": datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
return {"status": "unhealthy", "reason": "No terminals connected", "timestamp": datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
def get_app(self) -> FastAPI:
"""获取FastAPI应用实例"""
@@ -103,7 +149,8 @@ class QMTAPIServer:
# ================= 辅助函数 =================
def create_api_server(qmt_engine: QMTEngine) -> FastAPI:
"""创建API服务器"""
server = QMTAPIServer(qmt_engine)
return server.get_app()
def create_api_server(manager: MultiEngineManager) -> FastAPI:
"""创建API服务器入口"""
server = QMTAPIServer(manager)
return server.get_app()