实时监测支持定时调度开启关闭
This commit is contained in:
@@ -0,0 +1,235 @@
|
||||
#!/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
|
||||
|
||||
Reference in New Issue
Block a user