增加定时分析功能
This commit is contained in:
@@ -0,0 +1,715 @@
|
||||
"""
|
||||
持仓定时分析调度器模块
|
||||
|
||||
提供定时任务调度功能,在设定时间自动执行持仓批量分析
|
||||
"""
|
||||
|
||||
import schedule
|
||||
import threading
|
||||
import time
|
||||
from datetime import datetime
|
||||
from typing import Optional, Callable
|
||||
import traceback
|
||||
|
||||
from portfolio_manager import portfolio_manager
|
||||
from notification_service import NotificationService
|
||||
|
||||
|
||||
class PortfolioScheduler:
|
||||
"""持仓分析定时调度器"""
|
||||
|
||||
def __init__(self):
|
||||
"""初始化调度器"""
|
||||
self.schedule_times = ["09:30"] # 支持多个定时时间点
|
||||
self.analysis_mode = "sequential" # 默认顺序分析
|
||||
self._is_running = False # 使用私有属性
|
||||
self.thread = None
|
||||
self.last_run_time = None
|
||||
self.next_run_time = None
|
||||
self.auto_monitor_sync = True # 默认启用自动监测同步
|
||||
self.notification_enabled = True # 默认启用通知
|
||||
self.selected_agents = None # None表示全部分析师
|
||||
self.notification_service = NotificationService()
|
||||
self.max_workers = 3 # 并行模式的线程数
|
||||
|
||||
# 兼容旧代码的属性
|
||||
@property
|
||||
def schedule_time(self) -> str:
|
||||
"""获取第一个定时时间(向后兼容)"""
|
||||
return self.schedule_times[0] if self.schedule_times else "09:30"
|
||||
|
||||
def is_running(self) -> bool:
|
||||
"""
|
||||
检查调度器是否正在运行
|
||||
|
||||
Returns:
|
||||
bool: True表示运行中,False表示已停止
|
||||
"""
|
||||
return self._is_running
|
||||
|
||||
def set_schedule_time(self, time_str: str):
|
||||
"""
|
||||
设置定时分析时间(向后兼容,设置为单个时间)
|
||||
|
||||
Args:
|
||||
time_str: 时间字符串,格式"HH:MM"(如"08:00")
|
||||
"""
|
||||
try:
|
||||
# 验证时间格式
|
||||
datetime.strptime(time_str, "%H:%M")
|
||||
self.schedule_times = [time_str]
|
||||
print(f"[OK] 设置定时分析时间: {time_str}")
|
||||
|
||||
# 如果调度器正在运行,重新调度
|
||||
if self._is_running:
|
||||
self._reschedule()
|
||||
|
||||
except ValueError:
|
||||
print(f"[ERROR] 无效的时间格式: {time_str},应为 HH:MM")
|
||||
|
||||
def add_schedule_time(self, time_str: str) -> bool:
|
||||
"""
|
||||
添加一个定时分析时间点
|
||||
|
||||
Args:
|
||||
time_str: 时间字符串,格式"HH:MM"
|
||||
|
||||
Returns:
|
||||
是否添加成功
|
||||
"""
|
||||
try:
|
||||
# 验证时间格式
|
||||
datetime.strptime(time_str, "%H:%M")
|
||||
|
||||
# 检查是否已存在
|
||||
if time_str in self.schedule_times:
|
||||
print(f"[WARN] 定时时间 {time_str} 已存在")
|
||||
return False
|
||||
|
||||
self.schedule_times.append(time_str)
|
||||
self.schedule_times.sort() # 保持时间顺序
|
||||
print(f"[OK] 添加定时时间: {time_str}")
|
||||
|
||||
# 如果调度器正在运行,重新调度
|
||||
if self._is_running:
|
||||
self._reschedule()
|
||||
|
||||
return True
|
||||
|
||||
except ValueError:
|
||||
print(f"[ERROR] 无效的时间格式: {time_str},应为 HH:MM")
|
||||
return False
|
||||
|
||||
def remove_schedule_time(self, time_str: str) -> bool:
|
||||
"""
|
||||
删除一个定时分析时间点
|
||||
|
||||
Args:
|
||||
time_str: 时间字符串
|
||||
|
||||
Returns:
|
||||
是否删除成功
|
||||
"""
|
||||
if time_str in self.schedule_times:
|
||||
self.schedule_times.remove(time_str)
|
||||
print(f"[OK] 删除定时时间: {time_str}")
|
||||
|
||||
# 如果调度器正在运行,重新调度
|
||||
if self._is_running:
|
||||
self._reschedule()
|
||||
|
||||
return True
|
||||
else:
|
||||
print(f"[WARN] 定时时间 {time_str} 不存在")
|
||||
return False
|
||||
|
||||
def get_schedule_times(self) -> list:
|
||||
"""
|
||||
获取所有定时分析时间点
|
||||
|
||||
Returns:
|
||||
时间列表
|
||||
"""
|
||||
return self.schedule_times.copy()
|
||||
|
||||
def set_schedule_times(self, times: list):
|
||||
"""
|
||||
批量设置定时分析时间点
|
||||
|
||||
Args:
|
||||
times: 时间字符串列表
|
||||
"""
|
||||
valid_times = []
|
||||
for time_str in times:
|
||||
try:
|
||||
datetime.strptime(time_str, "%H:%M")
|
||||
valid_times.append(time_str)
|
||||
except ValueError:
|
||||
print(f"[WARN] 跳过无效时间: {time_str}")
|
||||
|
||||
if valid_times:
|
||||
self.schedule_times = sorted(valid_times)
|
||||
print(f"[OK] 设置定时时间: {', '.join(self.schedule_times)}")
|
||||
|
||||
# 如果调度器正在运行,重新调度
|
||||
if self._is_running:
|
||||
self._reschedule()
|
||||
else:
|
||||
print(f"[ERROR] 没有有效的时间配置")
|
||||
|
||||
def set_analysis_mode(self, mode: str):
|
||||
"""
|
||||
设置分析模式
|
||||
|
||||
Args:
|
||||
mode: "sequential" 或 "parallel"
|
||||
"""
|
||||
if mode in ["sequential", "parallel"]:
|
||||
self.analysis_mode = mode
|
||||
print(f"[OK] 设置分析模式: {mode}")
|
||||
else:
|
||||
print(f"[ERROR] 无效的分析模式: {mode}")
|
||||
|
||||
def set_auto_monitor_sync(self, enabled: bool):
|
||||
"""设置是否启用自动监测同步"""
|
||||
self.auto_monitor_sync = enabled
|
||||
print(f"[OK] 自动监测同步: {'启用' if enabled else '禁用'}")
|
||||
|
||||
def set_notification_enabled(self, enabled: bool):
|
||||
"""设置是否启用通知"""
|
||||
self.notification_enabled = enabled
|
||||
print(f"[OK] 通知推送: {'启用' if enabled else '禁用'}")
|
||||
|
||||
def set_selected_agents(self, agents: Optional[list]):
|
||||
"""设置参与分析的AI分析师"""
|
||||
self.selected_agents = agents
|
||||
if agents:
|
||||
print(f"[OK] 选择分析师: {', '.join(agents)}")
|
||||
else:
|
||||
print("[OK] 选择分析师: 全部")
|
||||
|
||||
def _scheduled_job(self):
|
||||
"""定时任务执行的作业"""
|
||||
print("\n" + "="*60)
|
||||
print(f"定时分析开始: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
print("="*60 + "\n")
|
||||
|
||||
try:
|
||||
# 1. 执行批量分析
|
||||
print("[1/4] 执行持仓批量分析...")
|
||||
analysis_results = portfolio_manager.batch_analyze_portfolio(
|
||||
mode=self.analysis_mode,
|
||||
max_workers=self.max_workers,
|
||||
selected_agents=self.selected_agents
|
||||
)
|
||||
|
||||
if not analysis_results.get("success"):
|
||||
error_msg = analysis_results.get("error", "未知错误")
|
||||
print(f"[ERROR] 批量分析失败: {error_msg}")
|
||||
|
||||
# 发送错误通知
|
||||
if self.notification_enabled:
|
||||
self._send_error_notification(error_msg)
|
||||
|
||||
self.last_run_time = datetime.now()
|
||||
return
|
||||
|
||||
# 2. 保存分析结果
|
||||
print("\n[2/4] 保存分析结果...")
|
||||
saved_ids = portfolio_manager.save_analysis_results(analysis_results)
|
||||
print(f"[OK] 保存 {len(saved_ids)} 条分析记录")
|
||||
|
||||
# 3. 自动监测同步
|
||||
sync_result = None
|
||||
if self.auto_monitor_sync:
|
||||
print("\n[3/4] 自动同步到监测列表...")
|
||||
sync_result = self._sync_to_monitor(analysis_results)
|
||||
else:
|
||||
print("\n[3/4] 跳过监测同步(已禁用)")
|
||||
|
||||
# 4. 发送通知
|
||||
if self.notification_enabled:
|
||||
print("\n[4/4] 发送通知...")
|
||||
self._send_notification(analysis_results, sync_result)
|
||||
else:
|
||||
print("\n[4/4] 跳过通知发送(已禁用)")
|
||||
|
||||
# 更新运行时间
|
||||
self.last_run_time = datetime.now()
|
||||
|
||||
print("\n" + "="*60)
|
||||
print(f"定时分析完成: {self.last_run_time.strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
print("="*60 + "\n")
|
||||
|
||||
except Exception as e:
|
||||
print(f"\n[ERROR] 定时任务执行异常: {str(e)}")
|
||||
traceback.print_exc()
|
||||
|
||||
# 发送错误通知
|
||||
if self.notification_enabled:
|
||||
self._send_error_notification(str(e))
|
||||
|
||||
self.last_run_time = datetime.now()
|
||||
|
||||
def _sync_to_monitor(self, analysis_results: dict) -> dict:
|
||||
"""
|
||||
同步分析结果到监测列表
|
||||
|
||||
Args:
|
||||
analysis_results: 批量分析结果
|
||||
|
||||
Returns:
|
||||
同步结果统计
|
||||
"""
|
||||
try:
|
||||
from monitor_db import monitor_db
|
||||
|
||||
# 准备批量监测数据
|
||||
monitors_data = []
|
||||
failed_count = 0
|
||||
|
||||
for item in analysis_results.get("results", []):
|
||||
code = item.get("code")
|
||||
result = item.get("result", {})
|
||||
|
||||
# 检查分析是否成功
|
||||
if not result.get("success"):
|
||||
continue
|
||||
|
||||
final_decision = result.get("final_decision", {})
|
||||
stock_info = result.get("stock_info", {})
|
||||
|
||||
# 检查是否启用自动监测
|
||||
stock = portfolio_manager.db.get_stock_by_code(code)
|
||||
if not stock or not stock.get("auto_monitor"):
|
||||
continue
|
||||
|
||||
# 从final_decision中提取数据(使用正确的字段名)
|
||||
rating = final_decision.get("rating", "持有")
|
||||
entry_range = final_decision.get("entry_range", "")
|
||||
take_profit_str = final_decision.get("take_profit", "")
|
||||
stop_loss_str = final_decision.get("stop_loss", "")
|
||||
|
||||
# 解析进场区间(格式如"10.5-12.3")
|
||||
entry_min, entry_max = None, None
|
||||
if entry_range and isinstance(entry_range, str) and "-" in entry_range:
|
||||
try:
|
||||
parts = entry_range.split("-")
|
||||
entry_min = float(parts[0].strip())
|
||||
entry_max = float(parts[1].strip())
|
||||
except:
|
||||
pass
|
||||
|
||||
# 解析止盈止损(提取数字)
|
||||
import re
|
||||
take_profit, stop_loss = None, None
|
||||
if take_profit_str:
|
||||
try:
|
||||
numbers = re.findall(r'\d+\.?\d*', str(take_profit_str))
|
||||
if numbers:
|
||||
take_profit = float(numbers[0])
|
||||
except:
|
||||
pass
|
||||
|
||||
if stop_loss_str:
|
||||
try:
|
||||
numbers = re.findall(r'\d+\.?\d*', str(stop_loss_str))
|
||||
if numbers:
|
||||
stop_loss = float(numbers[0])
|
||||
except:
|
||||
pass
|
||||
|
||||
# 检查参数有效性
|
||||
if not all([entry_min, entry_max, take_profit, stop_loss]):
|
||||
print(f"[WARN] {code} 参数不完整,跳过同步")
|
||||
failed_count += 1
|
||||
continue
|
||||
|
||||
# 构建监测数据
|
||||
monitor_data = {
|
||||
"code": code,
|
||||
"name": stock_info.get("name", stock.get("name", code)),
|
||||
"rating": rating,
|
||||
"entry_min": entry_min,
|
||||
"entry_max": entry_max,
|
||||
"take_profit": take_profit,
|
||||
"stop_loss": stop_loss,
|
||||
"check_interval": 60,
|
||||
"notification_enabled": True
|
||||
}
|
||||
|
||||
monitors_data.append(monitor_data)
|
||||
|
||||
# 使用批量API同步
|
||||
if monitors_data:
|
||||
result = monitor_db.batch_add_or_update_monitors(monitors_data)
|
||||
return result
|
||||
else:
|
||||
print("[WARN] 没有需要同步的监测数据")
|
||||
return {"added": 0, "updated": 0, "failed": 0, "total": 0}
|
||||
|
||||
except Exception as e:
|
||||
print(f"[ERROR] 监测同步异常: {str(e)}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return {"added": 0, "updated": 0, "failed": 0, "total": 0}
|
||||
|
||||
def _send_notification(self, analysis_results: dict, sync_result: Optional[dict]):
|
||||
"""
|
||||
发送分析完成通知(使用新的notification_service方法)
|
||||
|
||||
Args:
|
||||
analysis_results: 批量分析结果
|
||||
sync_result: 监测同步结果
|
||||
"""
|
||||
try:
|
||||
from notification_service import notification_service
|
||||
|
||||
# 使用新的专用通知方法
|
||||
success = notification_service.send_portfolio_analysis_notification(
|
||||
analysis_results, sync_result
|
||||
)
|
||||
|
||||
if success:
|
||||
print("[OK] 持仓分析通知发送成功")
|
||||
else:
|
||||
print("[WARN] 持仓分析通知发送失败(可能未配置通知服务)")
|
||||
|
||||
except Exception as e:
|
||||
print(f"[ERROR] 发送通知失败: {str(e)}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def _send_error_notification(self, error_msg: str):
|
||||
"""发送错误通知"""
|
||||
try:
|
||||
content = f"""
|
||||
持仓定时分析执行失败
|
||||
|
||||
错误信息:
|
||||
{error_msg}
|
||||
|
||||
时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
|
||||
|
||||
请检查系统日志或手动运行分析。
|
||||
"""
|
||||
|
||||
if self.notification_service.email_enabled:
|
||||
self.notification_service.send_email("【持仓定时分析】执行失败", content)
|
||||
|
||||
if self.notification_service.webhook_enabled:
|
||||
self.notification_service.send_webhook("【持仓定时分析】执行失败", content)
|
||||
|
||||
except Exception as e:
|
||||
print(f"[ERROR] 发送错误通知失败: {str(e)}")
|
||||
|
||||
def _generate_notification_content(self, analysis_results: dict,
|
||||
sync_result: Optional[dict]) -> str:
|
||||
"""
|
||||
生成通知内容
|
||||
|
||||
Args:
|
||||
analysis_results: 批量分析结果
|
||||
sync_result: 监测同步结果
|
||||
|
||||
Returns:
|
||||
通知内容文本
|
||||
"""
|
||||
total = analysis_results.get("total", 0)
|
||||
succeeded = analysis_results.get("succeeded", 0)
|
||||
failed = analysis_results.get("failed", 0)
|
||||
mode = analysis_results.get("mode", "sequential")
|
||||
elapsed_time = analysis_results.get("elapsed_time", 0)
|
||||
|
||||
# 统计评级分布
|
||||
rating_stats = {"买入": 0, "持有": 0, "卖出": 0}
|
||||
rating_changes = []
|
||||
|
||||
for item in analysis_results.get("results", []):
|
||||
code = item.get("code")
|
||||
result = item.get("result", {})
|
||||
final_decision = result.get("final_decision", {})
|
||||
rating = final_decision.get("investment_rating", "持有")
|
||||
|
||||
rating_stats[rating] = rating_stats.get(rating, 0) + 1
|
||||
|
||||
# 检查评级变化
|
||||
stock = portfolio_manager.db.get_stock_by_code(code)
|
||||
if stock:
|
||||
history = portfolio_manager.db.get_analysis_history(stock['id'], limit=2)
|
||||
if len(history) >= 2:
|
||||
old_rating = history[1]['rating']
|
||||
new_rating = history[0]['rating']
|
||||
if old_rating != new_rating:
|
||||
stock_info = result.get("stock_info", {})
|
||||
name = stock_info.get("name", stock.get("name", code))
|
||||
rating_changes.append(f"{code} {name}: {old_rating} → {new_rating}")
|
||||
|
||||
# 构建通知内容
|
||||
content = f"""
|
||||
持仓定时分析报告 - {datetime.now().strftime('%Y-%m-%d %H:%M')}
|
||||
|
||||
📊 分析完成:{total}只持仓股票
|
||||
✅ 成功:{succeeded}只
|
||||
❌ 失败:{failed}只
|
||||
⏱ 耗时:{elapsed_time:.1f}秒
|
||||
🔄 模式:{'顺序分析' if mode == 'sequential' else '并行分析'}
|
||||
|
||||
📈 投资评级分布:
|
||||
• 买入:{rating_stats.get('买入', 0)}只
|
||||
• 持有:{rating_stats.get('持有', 0)}只
|
||||
• 卖出:{rating_stats.get('卖出', 0)}只
|
||||
"""
|
||||
|
||||
# 添加评级变化
|
||||
if rating_changes:
|
||||
content += "\n🔔 评级变化:\n"
|
||||
for change in rating_changes[:5]: # 最多显示5个
|
||||
content += f"• {change}\n"
|
||||
|
||||
# 添加监测同步结果
|
||||
if sync_result:
|
||||
content += f"""
|
||||
🎯 监测同步:
|
||||
• 新增:{sync_result.get('added', 0)}只
|
||||
• 更新:{sync_result.get('updated', 0)}只
|
||||
• 失败:{sync_result.get('failed', 0)}只
|
||||
"""
|
||||
|
||||
# 添加失败股票
|
||||
if failed > 0:
|
||||
failed_stocks = analysis_results.get("failed_stocks", [])
|
||||
content += "\n⚠️ 失败股票:\n"
|
||||
for stock in failed_stocks[:3]: # 最多显示3个
|
||||
content += f"• {stock.get('code')}: {stock.get('error')}\n"
|
||||
|
||||
content += "\n详细报告请登录系统查看。"
|
||||
|
||||
return content
|
||||
|
||||
def _reschedule(self):
|
||||
"""重新调度任务(支持多个时间点)"""
|
||||
schedule.clear()
|
||||
for time_str in self.schedule_times:
|
||||
schedule.every().day.at(time_str).do(self._scheduled_job)
|
||||
self._update_next_run_time()
|
||||
print(f"[OK] 重新调度任务: 每天 {', '.join(self.schedule_times)}")
|
||||
|
||||
def _update_next_run_time(self):
|
||||
"""更新下次运行时间"""
|
||||
jobs = schedule.jobs
|
||||
if jobs:
|
||||
self.next_run_time = jobs[0].next_run
|
||||
else:
|
||||
self.next_run_time = None
|
||||
|
||||
def _run_schedule_loop(self):
|
||||
"""调度循环(在后台线程中运行)"""
|
||||
print("[OK] 定时调度器线程启动")
|
||||
|
||||
while self._is_running:
|
||||
schedule.run_pending()
|
||||
self._update_next_run_time()
|
||||
time.sleep(1)
|
||||
|
||||
print("[OK] 定时调度器线程停止")
|
||||
|
||||
def start(self) -> bool:
|
||||
"""
|
||||
启动定时任务
|
||||
|
||||
Returns:
|
||||
是否启动成功
|
||||
"""
|
||||
if self._is_running:
|
||||
print("[WARN] 定时任务已在运行中")
|
||||
return False
|
||||
|
||||
# 检查持仓数量
|
||||
stock_count = portfolio_manager.get_stock_count()
|
||||
if stock_count == 0:
|
||||
print("[ERROR] 没有持仓股票,无法启动定时任务")
|
||||
return False
|
||||
|
||||
# 检查时间配置
|
||||
if not self.schedule_times:
|
||||
print("[ERROR] 没有配置定时时间")
|
||||
return False
|
||||
|
||||
# 调度任务(为每个时间点创建任务)
|
||||
schedule.clear()
|
||||
for time_str in self.schedule_times:
|
||||
schedule.every().day.at(time_str).do(self._scheduled_job)
|
||||
print(f"[OK] 添加调度任务: 每天 {time_str}")
|
||||
|
||||
self._update_next_run_time()
|
||||
|
||||
# 启动后台线程
|
||||
self._is_running = True
|
||||
self.thread = threading.Thread(target=self._run_schedule_loop, daemon=True)
|
||||
self.thread.start()
|
||||
|
||||
print(f"\n[OK] 定时任务已启动")
|
||||
print(f" 调度时间: {', '.join(self.schedule_times)}")
|
||||
print(f" 分析模式: {self.analysis_mode}")
|
||||
print(f" 持仓数量: {stock_count}只")
|
||||
if self.next_run_time:
|
||||
print(f" 下次运行: {self.next_run_time.strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
|
||||
return True
|
||||
|
||||
def stop(self) -> bool:
|
||||
"""
|
||||
停止定时任务
|
||||
|
||||
Returns:
|
||||
是否停止成功
|
||||
"""
|
||||
if not self._is_running:
|
||||
print("[WARN] 定时任务未运行")
|
||||
return False
|
||||
|
||||
self._is_running = False
|
||||
schedule.clear()
|
||||
|
||||
# 等待线程结束(最多等待2秒)
|
||||
if self.thread and self.thread.is_alive():
|
||||
self.thread.join(timeout=2)
|
||||
|
||||
self.thread = None
|
||||
self.next_run_time = None
|
||||
|
||||
print("[OK] 定时任务已停止")
|
||||
return True
|
||||
|
||||
def run_once(self) -> bool:
|
||||
"""
|
||||
立即执行一次分析(不影响定时计划)
|
||||
|
||||
Returns:
|
||||
是否执行成功
|
||||
"""
|
||||
# 检查持仓数量
|
||||
stock_count = portfolio_manager.get_stock_count()
|
||||
if stock_count == 0:
|
||||
print("[ERROR] 没有持仓股票")
|
||||
return False
|
||||
|
||||
print("[OK] 立即执行持仓分析...")
|
||||
self._scheduled_job()
|
||||
return True
|
||||
|
||||
def get_status(self) -> dict:
|
||||
"""
|
||||
获取定时任务状态
|
||||
|
||||
Returns:
|
||||
状态字典
|
||||
"""
|
||||
return {
|
||||
"is_running": self._is_running,
|
||||
"schedule_time": self.schedule_time,
|
||||
"analysis_mode": self.analysis_mode,
|
||||
"auto_monitor_sync": self.auto_monitor_sync,
|
||||
"notification_enabled": self.notification_enabled,
|
||||
"last_run_time": self.last_run_time.strftime("%Y-%m-%d %H:%M:%S") if self.last_run_time else None,
|
||||
"next_run_time": self.next_run_time.strftime("%Y-%m-%d %H:%M:%S") if self.next_run_time else None,
|
||||
"portfolio_count": portfolio_manager.get_stock_count()
|
||||
}
|
||||
|
||||
def get_next_run_time(self) -> Optional[str]:
|
||||
"""
|
||||
获取下次运行时间
|
||||
|
||||
Returns:
|
||||
下次运行时间字符串,格式"HH:MM",如果未设置则返回None
|
||||
"""
|
||||
if self.next_run_time:
|
||||
return self.next_run_time.strftime("%H:%M")
|
||||
return None
|
||||
|
||||
def update_config(self, schedule_time: str = None, analysis_mode: str = None,
|
||||
max_workers: int = None, auto_sync_monitor: bool = None,
|
||||
send_notification: bool = None):
|
||||
"""
|
||||
更新调度器配置
|
||||
|
||||
Args:
|
||||
schedule_time: 定时分析时间(格式"HH:MM",可选,用于向后兼容)
|
||||
analysis_mode: 分析模式("sequential"或"parallel")
|
||||
max_workers: 并行线程数(仅在parallel模式下有效)
|
||||
auto_sync_monitor: 是否自动同步到监测
|
||||
send_notification: 是否发送通知
|
||||
"""
|
||||
if schedule_time is not None:
|
||||
self.set_schedule_time(schedule_time)
|
||||
|
||||
if analysis_mode is not None:
|
||||
self.set_analysis_mode(analysis_mode)
|
||||
|
||||
if max_workers is not None:
|
||||
self.max_workers = max_workers
|
||||
print(f"[OK] 设置并行线程数: {max_workers}")
|
||||
|
||||
if auto_sync_monitor is not None:
|
||||
self.set_auto_monitor_sync(auto_sync_monitor)
|
||||
|
||||
if send_notification is not None:
|
||||
self.set_notification_enabled(send_notification)
|
||||
|
||||
print("[OK] 配置已更新")
|
||||
|
||||
def start_scheduler(self) -> bool:
|
||||
"""
|
||||
启动调度器(UI友好方法名)
|
||||
|
||||
Returns:
|
||||
是否启动成功
|
||||
"""
|
||||
return self.start()
|
||||
|
||||
def stop_scheduler(self) -> bool:
|
||||
"""
|
||||
停止调度器(UI友好方法名)
|
||||
|
||||
Returns:
|
||||
是否停止成功
|
||||
"""
|
||||
return self.stop()
|
||||
|
||||
def run_analysis_now(self) -> bool:
|
||||
"""
|
||||
立即执行一次分析(UI友好方法名)
|
||||
|
||||
Returns:
|
||||
是否执行成功
|
||||
"""
|
||||
return self.run_once()
|
||||
|
||||
|
||||
# 创建全局实例
|
||||
portfolio_scheduler = PortfolioScheduler()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 测试代码
|
||||
print("="*60)
|
||||
print("持仓定时调度器测试")
|
||||
print("="*60)
|
||||
|
||||
scheduler = PortfolioScheduler()
|
||||
|
||||
# 设置配置
|
||||
scheduler.set_schedule_time("09:00")
|
||||
scheduler.set_analysis_mode("sequential")
|
||||
scheduler.set_auto_monitor_sync(True)
|
||||
scheduler.set_notification_enabled(False) # 测试时禁用通知
|
||||
|
||||
# 获取状态
|
||||
status = scheduler.get_status()
|
||||
print("\n调度器状态:")
|
||||
for key, value in status.items():
|
||||
print(f" {key}: {value}")
|
||||
|
||||
print("\n[OK] 调度器测试完成")
|
||||
|
||||
Reference in New Issue
Block a user