From eeac457323342d202d9544fcdb16bde922f72a71 Mon Sep 17 00:00:00 2001 From: aaron <> Date: Fri, 20 Feb 2026 20:25:50 +0800 Subject: [PATCH] update --- backend/app/stock_agent/stock_agent.py | 115 ++++++++++++++++++++----- 1 file changed, 94 insertions(+), 21 deletions(-) diff --git a/backend/app/stock_agent/stock_agent.py b/backend/app/stock_agent/stock_agent.py index 3aa220f..4a84fa2 100644 --- a/backend/app/stock_agent/stock_agent.py +++ b/backend/app/stock_agent/stock_agent.py @@ -157,38 +157,52 @@ class StockAgent: us_market_open = self._is_market_hours('US') hk_market_open = self._is_market_hours('0700.HK') - if not us_market_open and not hk_market_open: - logger.debug("非交易时间(美股和港股均闭市),跳过本次分析") - continue + # 检查是否是盘后分析时间 + us_after_hours = self._is_after_hours('US') + hk_after_hours = self._is_after_hours('0700.HK') # 确定要分析的股票列表 stocks_to_analyze = [] - if us_market_open: - stocks_to_analyze.extend(us_stocks) - logger.info(f"美股交易时间,分析 {len(us_stocks)} 只美股") - if hk_market_open: - stocks_to_analyze.extend(hk_stocks) - logger.info(f"港股交易时间,分析 {len(hk_stocks)} 只港股") + analysis_type = "盘中" # 默认为盘中分析 + # 盘后分析:优先级更高,用于日线级别分析 + if us_after_hours or hk_after_hours: + analysis_type = "盘后" + if us_after_hours: + stocks_to_analyze.extend(us_stocks) + logger.info(f"美股盘后分析,分析 {len(us_stocks)} 只美股(日线级别)") + if hk_after_hours: + stocks_to_analyze.extend(hk_stocks) + logger.info(f"港股盘后分析,分析 {len(hk_stocks)} 只港股(日线级别)") + else: + # 盘中分析 + if us_market_open: + stocks_to_analyze.extend(us_stocks) + logger.info(f"美股交易时间,分析 {len(us_stocks)} 只美股") + if hk_market_open: + stocks_to_analyze.extend(hk_stocks) + logger.info(f"港股交易时间,分析 {len(hk_stocks)} 只港股") + + # 如果没有需要分析的股票 if not stocks_to_analyze: logger.debug("没有需要分析的股票") continue # 分析股票并收集结果 - logger.info(f"开始分析 {len(stocks_to_analyze)} 只股票") + logger.info(f"开始{analysis_type}分析 {len(stocks_to_analyze)} 只股票") analysis_results = [] for symbol in stocks_to_analyze: if not self.running: break - result = await self.analyze_symbol(symbol) + result = await self.analyze_symbol(symbol, is_after_hours=(analysis_type == "盘后")) if result: analysis_results.append(result) # 生成并发送汇总报告 - await self._send_summary_report(analysis_results) + await self._send_summary_report(analysis_results, analysis_type) - logger.info("本次分析完成") + logger.info(f"本次{analysis_type}分析完成") except Exception as e: logger.error(f"分析循环出错: {e}") @@ -256,12 +270,65 @@ class StockAgent: """判断当前是否在任一市场的交易时间(美股或港股)""" return self._is_market_hours('US') or self._is_market_hours('0700.HK') - async def analyze_symbol(self, symbol: str) -> Optional[Dict[str, Any]]: + def _is_after_hours(self, symbol: str) -> bool: + """ + 判断当前是否是盘后分析时间(收盘后2小时内) + + 美股收盘时间: + - 夏令时: 北京时间 04:00 收盘 + - 冬令时: 北京时间 05:00 收盘 + + 港股收盘时间: 北京时间 16:00 收盘 + + 盘后分析时间: 收盘后 2 小时内 + + Args: + symbol: 股票代码(用于判断是美股还是港股) + + Returns: + 是否是盘后分析时间 + """ + from datetime import datetime + + # 获取当前时间 + now = datetime.now() + + # 检查是否为周末 + if now.weekday() >= 5: # 5=周六, 6=周日 + return False + + # 判断是港股还是美股 + is_hk_stock = symbol and symbol.endswith('.HK') if symbol else False + + # 获取当前小时和分钟 + hour = now.hour + minute = now.minute + current_time = hour * 100 + minute # 转换为数字,如 1630 表示 16:30 + + if is_hk_stock: + # 港股盘后: 16:00-18:00 (收盘后2小时) + return 1600 <= current_time < 1800 + else: + # 美股盘后 + # 判断夏令时/冬令时(简单判断:3-11月为夏令时) + is_summer = 3 <= now.month <= 11 + + if is_summer: + # 夏令时: 04:00-06:00 (收盘后2小时) + return 400 <= current_time < 600 + else: + # 冬令时: 05:00-07:00 (收盘后2小时) + return 500 <= current_time < 700 + + return False + + async def analyze_symbol(self, symbol: str, is_after_hours: bool = False) -> Optional[Dict[str, Any]]: """ 分析单个股票 Args: symbol: 股票代码 + is_after_hours: 是否是盘后分析(盘后会更关注日线级别机会) Returns: 分析结果字典,包含股票信息和信号 @@ -499,12 +566,13 @@ class StockAgent: } } - async def _send_summary_report(self, results: List[Dict[str, Any]]): + async def _send_summary_report(self, results: List[Dict[str, Any]], analysis_type: str = "盘中"): """ 生成并发送分析汇总报告 Args: results: 所有股票的分析结果列表 + analysis_type: 分析类型 ("盘中" 或 "盘后") """ try: now = datetime.now() @@ -542,8 +610,9 @@ class StockAgent: high_quality_signals.sort(key=lambda x: x.get('confidence', 0), reverse=True) # 构建汇总报告 + analysis_tag = f"【{analysis_type}分析】" logger.info(f"\n{'='*80}") - logger.info(f"📊 股票分析汇总报告") + logger.info(f"📊 股票分析汇总报告 {analysis_tag}") logger.info(f"{'='*80}") logger.info(f"时间: {now.strftime('%Y-%m-%d %H:%M:%S')}") logger.info(f"分析总数: {total} 只 (美股: {len(us_results)}, 港股: {len(hk_results)})") @@ -581,7 +650,8 @@ class StockAgent: await self._send_feishu_summary( now, total, with_signals, notified, buy_signals, sell_signals, high_quality_signals, - len(us_results), len(hk_results) + len(us_results), len(hk_results), + analysis_type ) except Exception as e: @@ -599,13 +669,15 @@ class StockAgent: sell_signals: List, high_quality_signals: List, us_count: int = 0, - hk_count: int = 0 + hk_count: int = 0, + analysis_type: str = "盘中" ): """发送飞书汇总报告""" try: # 构建内容 + analysis_tag = f"【{analysis_type}分析】" content_parts = [ - f"**📊 股票分析汇总报告**", + f"**📊 股票分析汇总报告 {analysis_tag}**", f"", f"⏰ 时间: {now.strftime('%Y-%m-%d %H:%M')}", f"", @@ -643,8 +715,9 @@ class StockAgent: content = "\n".join(content_parts) - # 发送飞书 - title = f"📊 股票分析汇总 ({now.strftime('%H:%M')})" + # 发送飞书 - 标题包含分析类型 + type_tag = "盘后" if analysis_type == "盘后" else "分析" + title = f"📊 股票{type_tag}汇总 ({now.strftime('%H:%M')})" color = "blue" await self.feishu.send_card(title, content, color)