Files
NewQuant/plans/strategy_manager_optimization_plan.md
liaozhaorun c0d996f39b feat(strategy_manager): 添加策略自动启动的白名单管理
实现全面的白名单管理系统,支持策略自动启动:

- 添加 WhitelistManager 类用于持久化白名单配置存储
- 将白名单功能集成到 StrategyManager 核心模块
- 添加用于白名单 CRUD 操作的 REST API 端点
- 通过 start.py 创建用于白名单管理的 CLI 命令
- 更新前端 UI,添加白名单状态指示器和批量操作功能
- 实现每日 08:58 的自动启动调度
- 为白名单操作添加配置验证和日志记录

同时添加项目文档:
- 代码格式规则(缩进、行长度、导入、命名)
- 文件、变量、常量、函数、类的命名规范
- 受限制文件和目录的保护规则
2026-01-26 01:21:46 +08:00

15 KiB
Raw Blame History

策略管理优化方案

1. 需求概述

1.1 问题背景

  • 策略启动后如果出现异常会停止进程
  • 需要机制确保重要策略能够自动重启

1.2 优化目标

  1. 白名单机制: 本地文件保存希望自动启动的策略列表
  2. Web管理: 界面可以管理白名单策略
  3. 定时启动: 每个工作日 8:58 自动尝试启动白名单中未运行的策略
  4. 单日单次: 每天只尝试一次,避免重复尝试
  5. 手动控制: 手动停止后不自动重启,需要用户重新操作
  6. 双状态展示: 每个策略显示"是否在白名单"和"是否运行中"

2. 系统架构

2.1 新增/修改文件

文件 操作 说明
config/whitelist.json 新增 白名单配置文件
core/whitelist_manager.py 新增 白名单管理器
core/manager.py 修改 集成白名单功能
web_backend.py 修改 新增白名单管理 API
frontend/ 修改 前端界面添加白名单管理

2.2 核心数据结构

白名单配置 (config/whitelist.json)

{
  "version": "1.0",
  "last_auto_start_date": "2024-01-25",
  "strategies": {
    "DualModeTrendlineHawkesStrategy2_FG": {
      "enabled": true,
      "added_at": "2024-01-25T10:00:00",
      "added_by": "web"
    },
    "SpectralTrendStrategy_rb": {
      "enabled": true,
      "added_at": "2024-01-25T10:00:00",
      "added_by": "web"
    }
  }
}

策略状态结构扩展

# 在 StrategyManager.strategies 字典中新增字段
{
  "strategy_key": {
    # ... 现有字段 ...
    "in_whitelist": True,  # 是否在白名单中
    "whitelist_enabled": True,  # 白名单中是否启用
    "last_auto_start_attempt": "2024-01-25T08:58:00",  # 上次自动启动尝试
    "auto_start_success": False  # 上次自动启动是否成功
  }
}

3. 详细设计

3.1 白名单管理器 (core/whitelist_manager.py)

class WhitelistManager:
    """白名单管理器"""
    
    def __init__(self, config_path: str = "config/whitelist.json"):
        self.config_path = Path(config_path)
        self.data = self._load()
    
    def _load(self) -> Dict:
        """加载白名单配置"""
        if not self.config_path.exists():
            return {"version": "1.0", "strategies": {}}
        with open(self.config_path, 'r') as f:
            return json.load(f)
    
    def _save(self):
        """保存白名单配置"""
        self.config_path.parent.mkdir(exist_ok=True)
        with open(self.config_path, 'w') as f:
            json.dump(self.data, f, indent=2, ensure_ascii=False)
    
    def add(self, strategy_key: str, enabled: bool = True) -> bool:
        """添加策略到白名单"""
        if strategy_key in self.data["strategies"]:
            return False  # 已存在
        self.data["strategies"][strategy_key] = {
            "enabled": enabled,
            "added_at": datetime.now().isoformat(),
            "added_by": "web"
        }
        self._save()
        return True
    
    def remove(self, strategy_key: str) -> bool:
        """从白名单移除策略"""
        if strategy_key not in self.data["strategies"]:
            return False
        del self.data["strategies"][strategy_key]
        self._save()
        return True
    
    def set_enabled(self, strategy_key: str, enabled: bool) -> bool:
        """设置策略在白名单中的启用状态"""
        if strategy_key not in self.data["strategies"]:
            return False
        self.data["strategies"][strategy_key]["enabled"] = enabled
        self._save()
        return True
    
    def get_all(self) -> Dict[str, Dict]:
        """获取所有白名单策略"""
        return self.data.get("strategies", {})
    
    def is_in_whitelist(self, strategy_key: str) -> bool:
        """检查策略是否在白名单中"""
        return strategy_key in self.data.get("strategies", {})
    
    def is_enabled_in_whitelist(self, strategy_key: str) -> bool:
        """检查策略是否在白名单中且已启用"""
        if strategy_key not in self.data.get("strategies", {}):
            return False
        return self.data["strategies"][strategy_key].get("enabled", False)
    
    def update_last_auto_start_date(self, date_str: str):
        """更新最后自动启动日期"""
        self.data["last_auto_start_date"] = date_str
        self._save()
    
    def should_auto_start_today(self) -> bool:
        """检查今天是否应该自动启动"""
        today = datetime.now().date().isoformat()
        return self.data.get("last_auto_start_date") != today

3.2 修改 core/manager.py

新增功能

class StrategyManager:
    def __init__(self, config_path: str = "config/main.json"):
        # ... 现有代码 ...
        self.whitelist_manager = WhitelistManager()
    
    def get_status(self) -> Dict[str, Any]:
        """获取完整状态(扩展白名单信息)"""
        status = super().get_status()
        
        # 添加白名单信息
        for name, info in status["strategies"].items():
            info["in_whitelist"] = self.whitelist_manager.is_in_whitelist(name)
            info["whitelist_enabled"] = self.whitelist_manager.is_enabled_in_whitelist(name)
        
        status["whitelist_auto_start_today"] = self.whitelist_manager.should_auto_start_today()
        
        return status
    
    def add_to_whitelist(self, name: str) -> bool:
        """添加策略到白名单"""
        return self.whitelist_manager.add(name, enabled=True)
    
    def remove_from_whitelist(self, name: str) -> bool:
        """从白名单移除策略"""
        return self.whitelist_manager.remove(name)
    
    def set_whitelist_enabled(self, name: str, enabled: bool) -> bool:
        """设置白名单中策略的启用状态"""
        return self.whitelist_manager.set_enabled(name, enabled)
    
    def start_strategy(self, name: str, auto_start: bool = False) -> bool:
        """
        启动策略
        
        Args:
            name: 策略标识符
            auto_start: 是否为自动启动(自动启动不会更新最后尝试日期)
        """
        # ... 现有启动逻辑 ...
        
        # 如果是手动启动,清除自动启动相关的标记
        if not auto_start:
            if name in self.strategies:
                self.strategies[name]["last_auto_start_attempt"] = None
                self.strategies[name]["auto_start_success"] = None
        
        return success
    
    def auto_start_whitelist_strategies(self) -> Dict[str, bool]:
        """
        自动启动白名单中所有未运行的策略
        一天只执行一次
        
        Returns:
            Dict[str, bool]: 每个策略的启动结果
        """
        if not self.whitelist_manager.should_auto_start_today():
            return {}
        
        results = {}
        whitelist = self.whitelist_manager.get_all()
        
        for name, config in whitelist.items():
            if not config.get("enabled", True):
                continue
            
            if name not in self.strategies:
                continue
            
            # 检查是否已在运行
            if self._is_running(name):
                results[name] = True
                continue
            
            # 尝试启动
            success = self.start_strategy(name, auto_start=True)
            results[name] = success
            
            # 更新策略状态
            if name in self.strategies:
                self.strategies[name]["last_auto_start_attempt"] = datetime.now().isoformat()
                self.strategies[name]["auto_start_success"] = success
        
        # 更新日期
        self.whitelist_manager.update_last_auto_start_date(
            datetime.now().date().isoformat()
        )
        
        return results

3.3 修改 web_backend.py

新增 API 端点

# ============ 白名单管理 API ============

@app.get("/api/whitelist")
def get_whitelist():
    """获取白名单列表"""
    whitelist = manager.whitelist_manager.get_all()
    return {
        "whitelist": whitelist,
        "auto_start_today": manager.whitelist_manager.should_auto_start_today()
    }

@app.post("/api/whitelist/{name}/add")
def add_to_whitelist(name: str):
    """添加策略到白名单"""
    if manager.add_to_whitelist(name):
        return {"success": True}
    raise HTTPException(400, "添加失败,策略可能已存在")

@app.post("/api/whitelist/{name}/remove")
def remove_from_whitelist(name: str):
    """从白名单移除策略"""
    if manager.remove_from_whitelist(name):
        return {"success": True}
    raise HTTPException(400, "移除失败,策略可能不在白名单中")

@app.post("/api/whitelist/{name}/enable")
def enable_in_whitelist(name: str):
    """启用白名单中的策略"""
    if manager.set_whitelist_enabled(name, True):
        return {"success": True}
    raise HTTPException(400, "操作失败")

@app.post("/api/whitelist/{name}/disable")
def disable_in_whitelist(name: str):
    """禁用白名单中的策略"""
    if manager.set_whitelist_enabled(name, False):
        return {"success": True}
    raise HTTPException(400, "操作失败")

@app.post("/api/whitelist/auto-start")
def trigger_auto_start():
    """手动触发白名单自动启动(用于测试)"""
    results = manager.auto_start_whitelist_strategies()
    return {
        "success": True,
        "results": results,
        "count": len(results)
    }

# ============ 修改现有的状态 API ============

@app.get("/api/status")
def get_status():
    """获取策略状态(包含白名单信息)"""
    status_data = manager.get_status()
    status_data['git_info'] = get_git_commit_info()
    return status_data

修改定时任务

@app.on_event("startup")
async def start_scheduler():
    # ... 现有的 08:58, 20:58 重启任务 ...
    
    # 新增:白名单自动启动任务(仅 08:58
    scheduler.add_job(
        auto_start_whitelist_task,
        CronTrigger(hour=8, minute=58),
        id="whitelist_auto_start",
        replace_existing=True
    )
    logger.info("📅 白名单自动启动任务已添加 (计划时间: 08:58)")


def auto_start_whitelist_task():
    """
    白名单自动启动任务
    """
    logger.info("⏰ [白名单任务] 触发自动启动...")
    
    results = manager.auto_start_whitelist_strategies()
    
    if not results:
        logger.info("⏰ [白名单任务] 今天已执行过或无需启动")
        return
    
    success_count = sum(1 for v in results.values() if v)
    fail_count = len(results) - success_count
    
    logger.info(f"⏰ [白名单任务] 完成: 成功 {success_count}, 失败 {fail_count}")
    
    for name, success in results.items():
        if success:
            logger.info(f"✅ [白名单任务] {name} 启动成功")
        else:
            logger.warning(f"❌ [白名单任务] {name} 启动失败")

3.4 修改 start.py

新增 CLI 命令

def main():
    # ... 现有的参数解析 ...
    
    parser.add_argument("--whitelist", action="store_true", help="白名单操作模式")
    
    # 白名单子命令
    whitelist_parser = subparsers.add_parser("whitelist", help="白名单管理")
    whitelist_parser.add_argument("action", choices=["add", "remove", "list", "enable", "disable"])
    whitelist_parser.add_argument("-n", "--name", help="策略标识符")

3.5 前端界面修改

状态表格新增列

列名 说明 示例值
白名单 是否在白名单中 /
白名单状态 白名单中是否启用 启用 / 禁用
自动启动 今天是否已尝试自动启动 是 / 否
自动启动结果 上次自动启动是否成功 成功 / 失败 / -

新增管理操作

  1. 添加到白名单: 勾选策略后点击"添加到白名单"
  2. 从白名单移除: 勾选策略后点击"从白名单移除"
  3. 启用/禁用: 在白名单中启用或禁用某个策略
  4. 手动触发: 按钮"立即执行白名单启动"

4. 工作流程

4.1 自动启动流程

sequenceDiagram
    participant T as 定时任务 (08:58)
    participant W as Web Backend
    participant M as StrategyManager
    participant WM as WhitelistManager
    participant S as Strategy Process

    T->>W: 触发定时任务
    W->>M: auto_start_whitelist_strategies()
    M->>WM: should_auto_start_today()?
    
    alt 今天未执行过
        WM-->>M: True
        M->>WM: get_all() 获取白名单
        loop 遍历白名单策略
            M->>M: 检查策略是否运行
            alt 未运行
                M->>S: 启动策略进程 (auto_start=True)
                M->>M: 记录启动结果
            else 已在运行
                M->>M: 标记为成功
            end
        end
        M->>WM: update_last_auto_start_date(今天)
        M-->>W: 返回启动结果
        W->>T: 记录日志
    else 今天已执行过
        WM-->>M: False
        M-->>W: 返回空结果
        W->>T: 跳过(今天已执行)
    end

4.2 手动管理流程

sequenceDiagram
    participant U as 用户
    participant W as Web界面
    participant API as Web Backend API
    participant M as StrategyManager
    participant WM as WhitelistManager
    participant F as 白名单配置文件

    U->>W: 点击"添加到白名单"
    W->>API: POST /api/whitelist/{name}/add
    API->>M: add_to_whitelist(name)
    M->>WM: add(name)
    WM->>F: 写入配置
    F-->>WM: 保存成功
    WM-->>M: True
    M-->>API: True
    API-->>W: {"success": True}
    W->>U: 显示成功提示
    W->>API: GET /api/status
    API->>M: get_status()
    M->>WM: 获取白名单状态
    M-->>API: 状态数据
    API-->>W: 状态数据
    W->>U: 更新表格(显示白名单状态)

5. 兼容性设计

5.1 向后兼容

  • 现有 start.py status 命令保持不变
  • 现有 API /api/status 保持兼容(新增字段不影响现有功能)
  • 现有日志查看功能保持不变

5.2 数据迁移

  • 首次启动时自动创建 config/whitelist.json
  • 无需手动迁移现有配置

6. 实施计划

阶段一:后端实现

  1. 创建 config/whitelist.json 模板
  2. 实现 core/whitelist_manager.py
  3. 修改 core/manager.py 集成白名单功能
  4. 修改 web_backend.py 添加 API
  5. 修改 start.py 添加 CLI 命令

阶段二:前端实现

  1. 修改状态表格,添加白名单列
  2. 添加白名单管理操作按钮
  3. 添加手动触发按钮
  4. 美化界面交互

阶段三:测试

  1. 测试白名单添加/移除
  2. 测试自动启动功能
  3. 测试手动停止不自动重启
  4. 测试一天只启动一次
  5. 测试重启后状态恢复

7. 文件修改清单

文件路径 操作 说明
config/whitelist.json 新增 白名单配置文件
core/whitelist_manager.py 新增 白名单管理器类
core/manager.py 修改 集成白名单功能,扩展状态结构
web_backend.py 修改 添加白名单管理 API修改定时任务
start.py 修改 添加白名单 CLI 命令
frontend/ 修改 前端界面添加白名单管理功能