#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 实时监测定时调度模块 支持交易日交易时间自动启动关闭监测服务 """ import schedule import time import threading from datetime import datetime, time as dtime from typing import Dict, Optional import json import os class TradingTimeScheduler: """交易时间调度器""" def __init__(self, monitor_service): self.monitor_service = monitor_service self.running = False self.thread = None self.config = self._load_config() def _load_config(self) -> Dict: """加载调度配置""" config_file = "monitor_schedule_config.json" default_config = { "enabled": False, # 默认不启用自动调度 "market": "CN", # CN=中国A股, US=美股, HK=港股 "trading_hours": { "CN": [ {"start": "09:30", "end": "11:30"}, # 上午 {"start": "13:00", "end": "15:00"} # 下午 ], "US": [ {"start": "21:30", "end": "04:00"} # 美股时间(北京时间) ], "HK": [ {"start": "09:30", "end": "12:00"}, # 上午 {"start": "13:00", "end": "16:00"} # 下午 ] }, "trading_days": [1, 2, 3, 4, 5], # 周一到周五 "auto_stop": True, # 收盘后自动停止 "pre_market_minutes": 5, # 提前5分钟启动 "post_market_minutes": 5 # 延后5分钟停止 } if os.path.exists(config_file): try: with open(config_file, 'r', encoding='utf-8') as f: loaded_config = json.load(f) # 合并配置,保留默认值 default_config.update(loaded_config) except Exception as e: print(f"加载调度配置失败,使用默认配置: {e}") return default_config def _save_config(self): """保存调度配置""" config_file = "monitor_schedule_config.json" try: with open(config_file, 'w', encoding='utf-8') as f: json.dump(self.config, f, indent=2, ensure_ascii=False) print(f"✅ 调度配置已保存") except Exception as e: print(f"❌ 保存调度配置失败: {e}") def update_config(self, **kwargs): """更新配置""" self.config.update(kwargs) self._save_config() def is_trading_day(self) -> bool: """判断是否为交易日""" now = datetime.now() weekday = now.weekday() + 1 # 转换为1-7(周一到周日) # 检查是否在交易日列表中 if weekday not in self.config['trading_days']: return False # TODO: 可以进一步检查是否为法定节假日 # 这里简单判断为工作日即交易日 return True def is_trading_time(self) -> bool: """判断当前是否在交易时间内""" if not self.is_trading_day(): return False now = datetime.now() current_time = now.time() market = self.config.get('market', 'CN') trading_hours = self.config['trading_hours'].get(market, []) for period in trading_hours: start_time = datetime.strptime(period['start'], '%H:%M').time() end_time = datetime.strptime(period['end'], '%H:%M').time() # 处理跨天的情况(如美股) if start_time > end_time: if current_time >= start_time or current_time <= end_time: return True else: if start_time <= current_time <= end_time: return True return False def get_next_trading_time(self) -> Optional[str]: """获取下一个交易时间""" if not self.is_trading_day(): return "非交易日" now = datetime.now() current_time = now.time() market = self.config.get('market', 'CN') trading_hours = self.config['trading_hours'].get(market, []) for period in trading_hours: start_time = datetime.strptime(period['start'], '%H:%M').time() if current_time < start_time: return period['start'] return "交易时间已结束" def start_scheduler(self): """启动调度器""" if self.running: print("⚠️ 调度器已在运行") return if not self.config.get('enabled', False): print("⚠️ 调度器未启用") return self.running = True self.thread = threading.Thread(target=self._schedule_loop, daemon=True) self.thread.start() print("✅ 调度器已启动") def stop_scheduler(self): """停止调度器""" self.running = False schedule.clear() if self.thread: self.thread.join(timeout=5) print("⏹️ 调度器已停止") def _schedule_loop(self): """调度循环""" # 清空之前的任务 schedule.clear() # 根据市场设置定时任务 market = self.config.get('market', 'CN') trading_hours = self.config['trading_hours'].get(market, []) for period in trading_hours: start_time = period['start'] end_time = period['end'] # 设置开盘启动任务 schedule.every().day.at(start_time).do(self._auto_start_monitoring) print(f"📅 已设置开盘启动任务: {start_time}") # 设置收盘停止任务 if self.config.get('auto_stop', True): schedule.every().day.at(end_time).do(self._auto_stop_monitoring) print(f"📅 已设置收盘停止任务: {end_time}") # 每分钟检查一次是否在交易时间 print("🔄 调度器循环已启动") while self.running: try: schedule.run_pending() # 智能检测:如果当前在交易时间但服务未运行,则启动 if self.is_trading_time() and not self.monitor_service.running: print("🔔 检测到交易时间,自动启动监测服务") self.monitor_service.start_monitoring() # 智能检测:如果当前不在交易时间但服务在运行,且auto_stop=True,则停止 if not self.is_trading_time() and self.monitor_service.running and self.config.get('auto_stop', True): print("🔔 检测到非交易时间,自动停止监测服务") self.monitor_service.stop_monitoring() time.sleep(60) # 每分钟检查一次 except Exception as e: print(f"❌ 调度器错误: {e}") time.sleep(60) def _auto_start_monitoring(self): """自动启动监测""" if self.is_trading_day(): print(f"🔔 定时启动监测服务 - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") if not self.monitor_service.running: self.monitor_service.start_monitoring() else: print("⏸️ 非交易日,跳过启动") def _auto_stop_monitoring(self): """自动停止监测""" print(f"🔔 定时停止监测服务 - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") if self.monitor_service.running: self.monitor_service.stop_monitoring() def get_status(self) -> Dict: """获取调度器状态""" return { 'scheduler_running': self.running, 'scheduler_enabled': self.config.get('enabled', False), 'is_trading_day': self.is_trading_day(), 'is_trading_time': self.is_trading_time(), 'market': self.config.get('market', 'CN'), 'next_trading_time': self.get_next_trading_time(), 'monitor_service_running': self.monitor_service.running, 'auto_stop': self.config.get('auto_stop', True) } # 全局调度器实例(延迟初始化) _scheduler_instance = None def get_scheduler(monitor_service=None): """获取调度器实例""" global _scheduler_instance if _scheduler_instance is None and monitor_service is not None: _scheduler_instance = TradingTimeScheduler(monitor_service) return _scheduler_instance