mirror of
https://github.com/ZhuLinsen/daily_stock_analysis
synced 2026-09-20 10:53:33 +08:00
* feat: 大盘复盘可选 A 股/美股区域 (Issue #299) - 新增 MARKET_REVIEW_REGION 配置:cn/us/both - 新增 market_profile 抽象,按 region 切换新闻搜索、Prompt、模板 - 数据层 get_main_indices(region):yfinance 支持 us 返回 SPX/IXIC/DJI/VIX - MarketAnalyzer 支持 region 参数,美股时跳过涨跌统计与板块 - region=both 时顺序执行 A 股+美股复盘并合并报告 - 更新 .env.example、full-guide、README、CHANGELOG * Issue #299: 审查建议修复与优化 - bot: 透传 market_review_region 到 MarketAnalyzer - yfinance: 提取 _fetch_yf_ticker_data 公共方法,消除 cn/us 重复逻辑 - market_analyzer: 修正 mood_index 匹配逻辑,美股搜索 stock_name 为 US market - market_analyzer: region=us 时 LLM 提示语改为英文模板 - market_review: both 模式增加 A股/美股生成进度日志 - tests: 新增 _get_us_main_indices 单元测试(mock yfinance) * Issue #299: 落实审查建议 - config: _parse_market_review_region 解析到非法值时打印 warning 日志 - market_review: both 模式报告分隔符增加描述性说明 - market_analyzer: 指数表格中 amount=0.0 时显示 N/A,避免用户误解 * docs: 优化 MARKET_REVIEW_REGION 描述措辞,避免歧义 - 移除「仅炒美股用户可设为 us」表述 - 明确 both 模式可同时复盘 A 股与美股 - 更新 full-guide、README、CHANGELOG、config 注释、env.example * style: 移除 bot market 命令中冗余的 or 'cn' 回退
123 lines
3.7 KiB
Python
123 lines
3.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
===================================
|
|
大盘复盘命令
|
|
===================================
|
|
|
|
执行大盘复盘分析,生成市场概览报告。
|
|
"""
|
|
|
|
import logging
|
|
import threading
|
|
from typing import List
|
|
|
|
from bot.commands.base import BotCommand
|
|
from bot.models import BotMessage, BotResponse
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class MarketCommand(BotCommand):
|
|
"""
|
|
大盘复盘命令
|
|
|
|
执行大盘复盘分析,包括:
|
|
- 主要指数表现
|
|
- 板块热点
|
|
- 市场情绪
|
|
- 后市展望
|
|
|
|
用法:
|
|
/market - 执行大盘复盘
|
|
"""
|
|
|
|
@property
|
|
def name(self) -> str:
|
|
return "market"
|
|
|
|
@property
|
|
def aliases(self) -> List[str]:
|
|
return ["m", "大盘", "复盘", "行情"]
|
|
|
|
@property
|
|
def description(self) -> str:
|
|
return "大盘复盘分析"
|
|
|
|
@property
|
|
def usage(self) -> str:
|
|
return "/market"
|
|
|
|
def execute(self, message: BotMessage, args: List[str]) -> BotResponse:
|
|
"""执行大盘复盘命令"""
|
|
logger.info(f"[MarketCommand] 开始大盘复盘分析")
|
|
|
|
# 在后台线程中执行复盘(避免阻塞)
|
|
thread = threading.Thread(
|
|
target=self._run_market_review,
|
|
args=(message,),
|
|
daemon=True
|
|
)
|
|
thread.start()
|
|
|
|
return BotResponse.markdown_response(
|
|
"✅ **大盘复盘任务已启动**\n\n"
|
|
"正在分析:\n"
|
|
"• 主要指数表现\n"
|
|
"• 板块热点分析\n"
|
|
"• 市场情绪判断\n"
|
|
"• 后市展望\n\n"
|
|
"分析完成后将自动推送结果。"
|
|
)
|
|
|
|
def _run_market_review(self, message: BotMessage) -> None:
|
|
"""后台执行大盘复盘"""
|
|
try:
|
|
from src.config import get_config
|
|
from src.notification import NotificationService
|
|
from src.market_analyzer import MarketAnalyzer
|
|
from src.search_service import SearchService
|
|
from src.analyzer import GeminiAnalyzer
|
|
|
|
config = get_config()
|
|
notifier = NotificationService(source_message=message)
|
|
|
|
# 初始化搜索服务
|
|
search_service = None
|
|
if config.bocha_api_keys or config.tavily_api_keys or config.brave_api_keys or config.serpapi_keys:
|
|
search_service = SearchService(
|
|
bocha_keys=config.bocha_api_keys,
|
|
tavily_keys=config.tavily_api_keys,
|
|
brave_keys=config.brave_api_keys,
|
|
serpapi_keys=config.serpapi_keys,
|
|
news_max_age_days=config.news_max_age_days,
|
|
)
|
|
|
|
# 初始化 AI 分析器
|
|
analyzer = None
|
|
if config.gemini_api_key or config.openai_api_key:
|
|
analyzer = GeminiAnalyzer()
|
|
|
|
# 读取配置中的市场区域,与定时任务/CLI 保持一致
|
|
region = getattr(config, 'market_review_region', 'cn')
|
|
|
|
# 执行复盘
|
|
market_analyzer = MarketAnalyzer(
|
|
search_service=search_service,
|
|
analyzer=analyzer,
|
|
region=region,
|
|
)
|
|
|
|
review_report = market_analyzer.run_daily_review()
|
|
|
|
if review_report:
|
|
# 推送结果
|
|
report_content = f"🎯 **大盘复盘**\n\n{review_report}"
|
|
notifier.send(report_content, email_send_to_all=True)
|
|
logger.info("[MarketCommand] 大盘复盘完成并已推送")
|
|
else:
|
|
logger.warning("[MarketCommand] 大盘复盘返回空结果")
|
|
|
|
except Exception as e:
|
|
logger.error(f"[MarketCommand] 大盘复盘失败: {e}")
|
|
logger.exception(e)
|