Files
evotraders/backend/utils/progress.py
cillin 12de93aa30 feat: initial commit - EvoTraders project
量化交易多智能体系统,包含:
- 分析师、投资组合经理、风险经理等智能体
- 股票分析、投资组合管理、风险控制工具
- React 前端界面
- FastAPI 后端服务

Co-Authored-By: Claude <noreply@anthropic.com>
2026-03-13 04:34:06 +08:00

141 lines
4.5 KiB
Python

# -*- coding: utf-8 -*-
from datetime import datetime, timezone
from typing import Callable, Optional
from rich.console import Console
from rich.live import Live
from rich.style import Style
from rich.table import Table
from rich.text import Text
console = Console()
class AgentProgress:
"""Manages progress tracking for multiple agents."""
def __init__(self):
self.agent_status = {}
self.table = Table(show_header=False, box=None, padding=(0, 1))
self.live = Live(self.table, console=console, refresh_per_second=4)
self.started = False
self.update_handlers = []
def register_handler(
self,
handler: Callable[[str, Optional[str], str], None],
):
"""Register a handler to be called when agent status updates."""
self.update_handlers.append(handler)
return handler # Return handler to support use as decorator
def unregister_handler(
self,
handler: Callable[[str, Optional[str], str], None],
):
"""Unregister a previously registered handler."""
if handler in self.update_handlers:
self.update_handlers.remove(handler)
def start(self):
"""Start the progress display."""
if not self.started:
self.live.start()
self.started = True
def stop(self):
"""Stop the progress display."""
if self.started:
self.live.stop()
self.started = False
def update_status(
self,
agent_name: str,
ticker: Optional[str] = None,
status: str = "",
analysis: Optional[str] = None,
):
"""Update the status of an agent."""
if agent_name not in self.agent_status:
self.agent_status[agent_name] = {"status": "", "ticker": None}
if ticker:
self.agent_status[agent_name]["ticker"] = ticker
if status:
self.agent_status[agent_name]["status"] = status
if analysis:
self.agent_status[agent_name]["analysis"] = analysis
# Set the timestamp as UTC datetime
timestamp = datetime.now(timezone.utc).isoformat()
self.agent_status[agent_name]["timestamp"] = timestamp
# Notify all registered handlers
for handler in self.update_handlers:
handler(agent_name, ticker, status, analysis, timestamp)
self._refresh_display()
def get_all_status(self):
"""Get the current status of all agents as a dictionary."""
return {
agent_name: {
"ticker": info["ticker"],
"status": info["status"],
"display_name": self._get_display_name(agent_name),
}
for agent_name, info in self.agent_status.items()
}
def _get_display_name(self, agent_name: str) -> str:
"""Convert agent_name to a display-friendly format."""
return agent_name.replace("_agent", "").replace("_", " ").title()
def _refresh_display(self):
"""Refresh the progress display."""
self.table.columns.clear()
self.table.add_column(width=100)
# Sort Risk Management and Portfolio Management at the bottom
def sort_key(item):
agent_name = item[0]
if "risk_manager" in agent_name:
return (2, agent_name)
elif "portfolio_manager" in agent_name:
return (3, agent_name)
else:
return (1, agent_name)
for agent_name, info in sorted(
self.agent_status.items(),
key=sort_key,
):
status = info["status"]
ticker = info["ticker"]
# Create the status text with appropriate styling
if status.lower() == "done":
style = Style(color="green", bold=True)
symbol = ""
elif status.lower() == "error":
style = Style(color="red", bold=True)
symbol = ""
else:
style = Style(color="yellow")
symbol = ""
agent_display = self._get_display_name(agent_name)
status_text = Text()
status_text.append(f"{symbol} ", style=style)
status_text.append(f"{agent_display:<20}", style=Style(bold=True))
if ticker:
status_text.append(f"[{ticker}] ", style=Style(color="cyan"))
status_text.append(status, style=style)
self.table.add_row(status_text)
# Create a global instance
progress = AgentProgress()