实现全面的白名单管理系统,支持策略自动启动: - 添加 WhitelistManager 类用于持久化白名单配置存储 - 将白名单功能集成到 StrategyManager 核心模块 - 添加用于白名单 CRUD 操作的 REST API 端点 - 通过 start.py 创建用于白名单管理的 CLI 命令 - 更新前端 UI,添加白名单状态指示器和批量操作功能 - 实现每日 08:58 的自动启动调度 - 为白名单操作添加配置验证和日志记录 同时添加项目文档: - 代码格式规则(缩进、行长度、导入、命名) - 文件、变量、常量、函数、类的命名规范 - 受限制文件和目录的保护规则
494 lines
15 KiB
Markdown
494 lines
15 KiB
Markdown
# 策略管理优化方案
|
||
|
||
## 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`)
|
||
```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"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 策略状态结构扩展
|
||
```python
|
||
# 在 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`)
|
||
|
||
```python
|
||
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`
|
||
|
||
#### 新增功能
|
||
```python
|
||
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 端点
|
||
```python
|
||
# ============ 白名单管理 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
|
||
```
|
||
|
||
#### 修改定时任务
|
||
```python
|
||
@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 命令
|
||
```python
|
||
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 自动启动流程
|
||
|
||
```mermaid
|
||
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 手动管理流程
|
||
|
||
```mermaid
|
||
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/` | 修改 | 前端界面添加白名单管理功能 |
|