#!/usr/bin/env python3 """ 市场扫描定时任务脚本 专门用于Docker容器中定时执行市场扫描 """ import sys import os from pathlib import Path # 将src目录添加到Python路径 current_dir = Path(__file__).parent src_dir = current_dir / "src" sys.path.insert(0, str(src_dir)) from loguru import logger from src.utils.config_loader import config_loader from src.data.tushare_fetcher import TushareFetcher from src.data.stock_pool_manager import StockPoolManager from src.strategy.kline_pattern_strategy import KLinePatternStrategy from src.execution.strategy_executor import StrategyExecutor from src.utils.notification import NotificationManager from datetime import datetime def setup_logging(): """设置日志配置""" log_level = os.environ.get('LOG_LEVEL', 'INFO') logger.remove() logger.add( sys.stdout, level=log_level, format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}" ) # 确定日志目录 - Docker环境使用/app/logs,本地环境使用./logs if os.path.exists('/app'): log_dir = "/app/logs" else: log_dir = "./logs" # 创建日志目录 os.makedirs(log_dir, exist_ok=True) # 添加文件日志 log_file = os.path.join(log_dir, "market_scanner.log") logger.add( log_file, level=log_level, format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}", rotation="1 day", retention="30 days" ) def create_strategy_system(): """创建策略系统的所有组件""" # 数据层 fetcher = TushareFetcher() pool_manager = StockPoolManager(fetcher) # 通知层 notification_config = config_loader.get('notification', {}) notification_manager = NotificationManager(notification_config) # 策略层 strategy_config = config_loader.get('strategy', {}).get('kline_pattern', { 'min_entity_ratio': 0.55, 'final_yang_min_ratio': 0.40, 'max_turnover_ratio': 40.0, 'timeframes': ['daily'], 'pullback_tolerance': 0.02, 'monitor_days': 30, 'pullback_confirmation_days': 7 }) # 数据库层 from src.database.mysql_database_manager import MySQLDatabaseManager db_manager = MySQLDatabaseManager() kline_strategy = KLinePatternStrategy( data_fetcher=fetcher, notification_manager=notification_manager, config=strategy_config, db_manager=db_manager ) # 执行层 executor = StrategyExecutor(pool_manager, notification_manager) # 注册策略 executor.register_strategy("kline_pattern", kline_strategy) return executor def scan_market(max_stocks=200): """执行市场扫描""" logger.info(f"🚀 开始市场扫描任务 - 扫描前{max_stocks}只热门股票") try: # 初始化系统 executor = create_strategy_system() # 执行扫描任务 task_id = f"market_scan_{datetime.now().strftime('%Y%m%d_%H%M%S')}" result = executor.execute_task( task_id=task_id, strategy_id="kline_pattern", stock_pool_rule="tushare_hot", stock_pool_params={"limit": max_stocks}, max_stocks=max_stocks, send_notification=True # 启用通知 ) summary = result.get_summary() logger.info(f"✅ 市场扫描完成:") logger.info(f" 任务ID: {summary['task_id']}") logger.info(f" 股票池: {summary['stock_pool_rule_display']}") logger.info(f" 总扫描: {summary['total_stocks_analyzed']} 只") logger.info(f" 有信号: {summary['stocks_with_signals']} 只") logger.info(f" 信号数: {summary['total_signals_found']} 个") logger.info(f" 耗时: {summary['execution_time']:.2f} 秒") if summary['error']: logger.error(f" 错误: {summary['error']}") return 1 return 0 except Exception as e: logger.error(f"❌ 市场扫描失败: {e}") return 1 def main(): """主函数""" setup_logging() # 从环境变量或命令行参数获取扫描数量 max_stocks = 200 if len(sys.argv) > 1: try: max_stocks = int(sys.argv[1]) except ValueError: logger.warning(f"无效的股票数量参数: {sys.argv[1]},使用默认值: 200") # 从环境变量获取 max_stocks = int(os.environ.get('MARKET_SCAN_STOCKS', max_stocks)) logger.info(f"📊 市场扫描参数: 最大股票数={max_stocks}") return scan_market(max_stocks) if __name__ == "__main__": sys.exit(main())