#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 主力选股AI分析整合模块 整体批量分析,从板块热点和资金流向角度筛选优质标的 """ from typing import Dict, List, Tuple import pandas as pd from main_force_selector import main_force_selector from stock_data import StockDataFetcher from ai_agents import StockAnalysisAgents from deepseek_client import DeepSeekClient import time import json class MainForceAnalyzer: """主力选股分析器 - 批量整体分析""" def __init__(self, model='deepseek-chat'): self.selector = main_force_selector self.fetcher = StockDataFetcher() self.model = model self.agents = StockAnalysisAgents(model=model) self.deepseek_client = self.agents.deepseek_client self.raw_stocks = None self.final_recommendations = [] def run_full_analysis(self, start_date: str = None, days_ago: int = None, final_n: int = None, max_range_change: float = None, min_market_cap: float = None, max_market_cap: float = None) -> Dict: """ 运行完整的主力选股分析流程 - 整体批量分析 Args: start_date: 开始日期,格式如"2025年10月1日" days_ago: 距今多少天 final_n: 最终精选N只 max_range_change: 最大涨跌幅限制 min_market_cap: 最小市值限制 max_market_cap: 最大市值限制 Returns: 分析结果字典 """ result = { 'success': False, 'total_stocks': 0, 'filtered_stocks': 0, 'final_recommendations': [], 'error': None, 'params': { 'start_date': start_date, 'days_ago': days_ago, 'final_n': final_n, 'max_range_change': max_range_change, 'min_market_cap': min_market_cap, 'max_market_cap': max_market_cap } } try: print(f"\n{'='*80}") print(f"🚀 主力选股智能分析系统 - 批量整体分析") print(f"{'='*80}\n") # 步骤1: 获取主力资金净流入前100名股票 success, raw_data, message = self.selector.get_main_force_stocks( start_date=start_date, days_ago=days_ago, min_market_cap=min_market_cap, max_market_cap=max_market_cap ) if not success: result['error'] = message return result result['total_stocks'] = len(raw_data) # 步骤2: 智能筛选(涨幅、市值等) filtered_data = self.selector.filter_stocks( raw_data, max_range_change=max_range_change, min_market_cap=min_market_cap, max_market_cap=max_market_cap ) result['filtered_stocks'] = len(filtered_data) if filtered_data.empty: result['error'] = "筛选后没有符合条件的股票" return result # 保存原始数据 self.raw_stocks = filtered_data # 步骤3: 整体数据分析(不是逐个分析) print(f"\n{'='*80}") print(f"🤖 AI分析师团队开始整体分析...") print(f"{'='*80}\n") # 准备整体数据摘要 overall_summary = self._prepare_overall_summary(filtered_data) # 三大分析师整体分析 fund_flow_analysis = self._fund_flow_overall_analysis(filtered_data, overall_summary) industry_analysis = self._industry_overall_analysis(filtered_data, overall_summary) fundamental_analysis = self._fundamental_overall_analysis(filtered_data, overall_summary) # 保存分析报告到对象属性,供UI展示 self.fund_flow_analysis = fund_flow_analysis self.industry_analysis = industry_analysis self.fundamental_analysis = fundamental_analysis # 步骤4: 综合决策,精选优质标的 print(f"\n{'='*80}") print(f"👔 资深研究员综合评估并精选标的...") print(f"{'='*80}\n") final_recommendations = self._select_best_stocks( filtered_data, fund_flow_analysis, industry_analysis, fundamental_analysis, final_n=final_n ) result['final_recommendations'] = final_recommendations result['success'] = True # 显示最终结果 self._print_final_recommendations(final_recommendations) return result except Exception as e: result['error'] = f"分析过程出错: {str(e)}" import traceback traceback.print_exc() return result def _prepare_overall_summary(self, df: pd.DataFrame) -> str: """准备整体数据摘要""" summary_lines = [] summary_lines.append(f"候选股票总数: {len(df)}只") # 主力资金统计 main_fund_cols = [col for col in df.columns if '主力' in col and '净流入' in col] if main_fund_cols: col_name = main_fund_cols[0] df[col_name] = pd.to_numeric(df[col_name], errors='coerce') total_inflow = df[col_name].sum() avg_inflow = df[col_name].mean() summary_lines.append(f"主力资金总净流入: {total_inflow/100000000:.2f}亿") summary_lines.append(f"平均主力资金净流入: {avg_inflow/100000000:.2f}亿") # 涨跌幅统计 range_cols = [col for col in df.columns if '涨跌幅' in col] if range_cols: col_name = range_cols[0] df[col_name] = pd.to_numeric(df[col_name], errors='coerce') avg_change = df[col_name].mean() max_change = df[col_name].max() min_change = df[col_name].min() summary_lines.append(f"平均涨跌幅: {avg_change:.2f}%") summary_lines.append(f"涨跌幅范围: {min_change:.2f}% ~ {max_change:.2f}%") # 行业分布 industry_cols = [col for col in df.columns if '行业' in col] if industry_cols: col_name = industry_cols[0] top_industries = df[col_name].value_counts().head(10) summary_lines.append("\n主要行业分布:") for industry, count in top_industries.items(): summary_lines.append(f" - {industry}: {count}只") return "\n".join(summary_lines) def _fund_flow_overall_analysis(self, df: pd.DataFrame, summary: str) -> str: """资金流向整体分析""" print("💰 资金流向分析师整体分析中...") # 准备数据表格 data_table = self._prepare_data_table(df, focus='fund_flow') prompt = f""" 你是一名资深的资金面分析师,现在需要你从整体角度分析这批主力资金净流入的股票。 【整体数据摘要】 {summary} 【候选股票详细数据】(共{len(df)}只) {data_table} 【分析任务】 请从资金流向的整体角度进行分析,重点关注: 1. **资金流向特征** - 哪些板块/行业资金流入最集中? - 主力资金的整体行为特征(大规模建仓/试探性进场/板块轮动) - 资金流向与涨跌幅的配合情况 2. **优质标的识别** - 从资金面角度,哪些股票最值得关注? - 主力资金流入大但涨幅不高的潜力股 - 资金持续流入且趋势明确的股票 3. **板块热点判断** - 当前资金最看好哪些板块? - 是否有板块轮动迹象? - 新兴热点 vs 传统强势板块 4. **投资建议** - 从资金面角度,建议重点关注哪3-5只股票? - 理由和风险提示 请给出专业、系统的资金面整体分析报告。 """ messages = [ {"role": "system", "content": "你是资金面分析专家,擅长从整体资金流向中发现投资机会。"}, {"role": "user", "content": prompt} ] analysis = self.deepseek_client.call_api(messages, max_tokens=4000) print(" ✅ 资金流向整体分析完成") time.sleep(1) return analysis def _industry_overall_analysis(self, df: pd.DataFrame, summary: str) -> str: """行业板块整体分析""" print("📊 行业板块分析师整体分析中...") # 准备数据表格 data_table = self._prepare_data_table(df, focus='industry') prompt = f""" 你是一名资深的行业板块分析师,现在需要你从行业热点和板块轮动角度分析这批股票。 【整体数据摘要】 {summary} 【候选股票详细数据】(共{len(df)}只) {data_table} 【分析任务】 请从行业板块的整体角度进行分析,重点关注: 1. **热点板块识别** - 哪些行业/板块最受资金青睐? - 热点板块的持续性如何? - 是否有新兴热点正在形成? 2. **板块特征分析** - 各板块的涨幅与资金流入匹配度 - 哪些板块处于启动阶段(资金流入但涨幅不大) - 哪些板块可能过热(涨幅高但资金流入减弱) 3. **行业前景评估** - 主力资金集中的行业,基本面支撑如何? - 政策面、产业面是否有催化因素? - 行业竞争格局和龙头地位 4. **优质标的推荐** - 从行业板块角度,推荐3-5只最具潜力的股票 - 推荐理由(行业地位、成长空间、催化因素) 请给出专业、深入的行业板块分析报告。 """ messages = [ {"role": "system", "content": "你是行业板块分析专家,擅长发现市场热点和板块机会。"}, {"role": "user", "content": prompt} ] analysis = self.deepseek_client.call_api(messages, max_tokens=4000) print(" ✅ 行业板块整体分析完成") time.sleep(1) return analysis def _fundamental_overall_analysis(self, df: pd.DataFrame, summary: str) -> str: """财务基本面整体分析""" print("📈 财务基本面分析师整体分析中...") # 准备数据表格 data_table = self._prepare_data_table(df, focus='fundamental') prompt = f""" 你是一名资深的基本面分析师,现在需要你从财务质量和基本面角度分析这批股票。 【整体数据摘要】 {summary} 【候选股票详细数据】(共{len(df)}只) {data_table} 【分析任务】 请从财务基本面的整体角度进行分析,重点关注: 1. **财务质量评估** - 整体财务指标健康度如何? - 哪些股票盈利能力、成长性突出? - 是否存在财务风险较大的股票? 2. **估值水平分析** - 市盈率、市净率的整体分布 - 哪些股票估值合理且有成长空间? - 高估值是否有业绩支撑? 3. **成长性评估** - 营收、净利润增长情况 - 哪些股票成长性最好? - 成长能力评分较高的股票 4. **优质标的筛选** - 从基本面角度,推荐3-5只最优质的股票 - 推荐理由(财务健康、估值合理、成长性好) 请给出专业、详实的基本面分析报告。 """ messages = [ {"role": "system", "content": "你是基本面分析专家,擅长从财务角度评估投资价值。"}, {"role": "user", "content": prompt} ] analysis = self.deepseek_client.call_api(messages, max_tokens=4000) print(" ✅ 财务基本面整体分析完成") time.sleep(1) return analysis def _prepare_data_table(self, df: pd.DataFrame, focus: str = 'all') -> str: """准备数据表格用于AI分析""" # 选择关键列 key_columns = ['股票代码', '股票简称'] # 根据分析重点添加相关列 if focus == 'fund_flow' or focus == 'all': fund_cols = [col for col in df.columns if '主力' in col or '资金' in col] key_columns.extend(fund_cols[:3]) # 最多3列资金数据 if focus == 'industry' or focus == 'all': industry_cols = [col for col in df.columns if '行业' in col] key_columns.extend(industry_cols[:1]) # 智能匹配区间涨跌幅列 interval_pct_col = None possible_names = [ '区间涨跌幅:前复权', '区间涨跌幅:前复权(%)', '区间涨跌幅(%)', '区间涨跌幅', '涨跌幅:前复权', '涨跌幅:前复权(%)', '涨跌幅(%)', '涨跌幅' ] for name in possible_names: for col in df.columns: if name in col: interval_pct_col = col break if interval_pct_col: break if interval_pct_col: key_columns.append(interval_pct_col) if focus == 'fundamental' or focus == 'all': fundamental_cols = [col for col in df.columns if any( keyword in col for keyword in ['市盈率', '市净率', '营收', '净利润', '评分'] )] key_columns.extend(fundamental_cols[:5]) # 去重并保持顺序 seen = set() unique_columns = [] for col in key_columns: if col in df.columns and col not in seen: seen.add(col) unique_columns.append(col) # 限制显示前50只股票的详细数据,避免超出token限制 display_df = df[unique_columns].head(50) # 转换为表格字符串 table_str = display_df.to_string(index=False, max_rows=50) if len(df) > 50: table_str += f"\n... 还有 {len(df) - 50} 只股票未显示" return table_str def _select_best_stocks(self, df: pd.DataFrame, fund_analysis: str, industry_analysis: str, fundamental_analysis: str, final_n: int = 5) -> List[Dict]: """综合三位分析师的意见,精选最优标的""" # 准备完整数据表格 data_table = self._prepare_data_table(df, focus='all') prompt = f""" 你是一名资深股票研究员,具有20年以上的投资研究经验。现在需要你综合三位分析师的意见, 从{len(df)}只候选股票中精选出{final_n}只最具投资价值的优质标的。 【候选股票数据】 {data_table} 【资金流向分析师观点】 {fund_analysis} 【行业板块分析师观点】 {industry_analysis} 【财务基本面分析师观点】 {fundamental_analysis} 【筛选标准】 1. **主力资金**: 主力资金净流入较多,显示机构看好 2. **涨幅适中**: 区间涨跌幅不是很高(避免追高),还有上涨空间 3. **行业热点**: 所属行业有发展前景,是市场热点 4. **基本面良好**: 财务指标健康,盈利能力强 5. **综合平衡**: 资金、行业、基本面三方面都不错 【任务要求】 综合三位分析师的观点,精选出{final_n}只最优标的。 对于每只精选股票,请提供: 1. **股票代码和名称** 2. **核心推荐理由**(3-5条,综合资金、行业、基本面) 3. **投资亮点**(最突出的优势) 4. **风险提示**(需要注意的风险) 5. **建议仓位**(如20-30%) 6. **投资周期**(短期/中期/长期) 请按以下JSON格式输出(只输出JSON,不要其他内容): ```json {{ "recommendations": [ {{ "rank": 1, "symbol": "股票代码", "name": "股票名称", "reasons": [ "理由1:资金面角度", "理由2:行业板块角度", "理由3:基本面角度" ], "highlights": "投资亮点描述", "risks": "风险提示", "position": "建议仓位", "investment_period": "投资周期" }} ] }} ``` 注意: - 必须严格按照JSON格式输出 - 推荐数量为{final_n}只 - 按投资价值从高到低排序 - 理由要具体、有说服力,体现三位分析师的综合观点 """ try: print(" 🔍 正在综合评估并精选标的...") messages = [ {"role": "system", "content": "你是资深股票研究员,擅长综合多维度分析做出投资决策。"}, {"role": "user", "content": prompt} ] response = self.deepseek_client.call_api(messages, max_tokens=4000) # 解析JSON响应 import re # 提取JSON部分 json_match = re.search(r'```json\s*(\{.*?\})\s*```', response, re.DOTALL) if json_match: json_str = json_match.group(1) else: # 尝试直接解析 json_str = response result = json.loads(json_str) recommendations = result.get('recommendations', []) # 补充详细数据 for rec in recommendations: symbol = rec['symbol'] # 从原始数据中找到对应股票 stock_data = df[df['股票代码'] == symbol] if not stock_data.empty: rec['stock_data'] = stock_data.iloc[0].to_dict() return recommendations except Exception as e: print(f" ❌ JSON解析失败,使用备选方案: {e}") # 降级方案:按主力资金排序返回前N个 main_fund_cols = [col for col in df.columns if '主力' in col and '净流入' in col] if main_fund_cols: col_name = main_fund_cols[0] df[col_name] = pd.to_numeric(df[col_name], errors='coerce') sorted_df = df.nlargest(final_n, col_name) else: sorted_df = df.head(final_n) recommendations = [] for i, (idx, row) in enumerate(sorted_df.iterrows(), 1): recommendations.append({ 'rank': i, 'symbol': row.get('股票代码', 'N/A'), 'name': row.get('股票简称', 'N/A'), 'reasons': [ f"主力资金净流入较多", f"所属行业: {row.get('所属同花顺行业', 'N/A')}", f"涨跌幅适中" ], 'highlights': '主力资金持续关注', 'risks': '需关注后续走势', 'position': '15-25%', 'investment_period': '中短期', 'stock_data': row.to_dict() }) return recommendations def _print_final_recommendations(self, recommendations: List[Dict]): """打印最终推荐结果""" if not recommendations: print("❌ 未能生成推荐结果") return print(f"\n{'='*80}") print(f"⭐ 最终精选推荐 ({len(recommendations)}只)") print(f"{'='*80}\n") for rec in recommendations: print(f"【第{rec['rank']}名】{rec['symbol']} - {rec['name']}") print(f"{'-'*60}") print(f"📌 推荐理由:") for reason in rec.get('reasons', []): print(f" • {reason}") print(f"\n💡 投资亮点: {rec.get('highlights', 'N/A')}") print(f"⚠️ 风险提示: {rec.get('risks', 'N/A')}") print(f"📊 建议仓位: {rec.get('position', 'N/A')}") print(f"⏰ 投资周期: {rec.get('investment_period', 'N/A')}") print(f"{'='*80}\n") # 全局实例 main_force_analyzer = MainForceAnalyzer()