trading.ai/market_scanner.py
2025-10-01 09:58:52 +08:00

157 lines
4.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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())