Files
aiagents-stock/sector_strategy_engine.py
oficcejo f3af15ddc8 update
2026-02-27 12:08:00 +08:00

609 lines
22 KiB
Python
Raw Permalink 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.
"""
智策综合研判引擎
整合各智能体分析,生成板块多空/轮动/热度预测
"""
from sector_strategy_agents import SectorStrategyAgents
from sector_strategy_db import SectorStrategyDatabase
from deepseek_client import DeepSeekClient
from typing import Dict, Any
import time
import json
import pandas as pd
import logging
import config
class SectorStrategyEngine:
"""板块策略综合研判引擎"""
def __init__(self, model=None):
self.model = model or config.DEFAULT_MODEL_NAME
self.agents = SectorStrategyAgents(model=self.model)
self.deepseek_client = DeepSeekClient(model=self.model)
self.database = SectorStrategyDatabase()
self.logger = logging.getLogger(__name__)
if not self.logger.handlers:
logging.basicConfig(level=logging.INFO, format='[%(asctime)s] %(levelname)s %(name)s: %(message)s')
print(f"[智策引擎] 初始化完成 (模型: {self.model})")
def save_raw_data_with_fallback(self, data_type, data_df, data_date=None):
"""
保存原始数据,支持失败回退机制
Args:
data_type: 数据类型
data_df: 数据DataFrame
data_date: 数据日期,默认为今天
Returns:
tuple: (success, version, message)
"""
if data_date is None:
data_date = time.strftime("%Y-%m-%d")
try:
is_empty = False
if data_df is None:
is_empty = True
elif hasattr(data_df, 'empty'):
is_empty = data_df.empty
elif isinstance(data_df, (list, tuple, set, dict)):
is_empty = len(data_df) == 0
if is_empty:
self.logger.warning(f"[智策引擎] {data_type}数据为空,跳过保存")
return False, None, "数据为空"
version = self.database.save_raw_data(data_date, data_type, data_df)
return True, version, f"保存成功,版本: {version}"
except Exception as e:
self.logger.error(f"[智策引擎] 保存{data_type}数据失败: {e}")
return False, None, str(e)
def get_data_with_fallback(self, data_type, data_date=None):
"""
获取数据,支持失败时回退到历史数据
Args:
data_type: 数据类型
data_date: 数据日期,默认为今天
Returns:
tuple: (data_df, is_fallback, message)
"""
if data_date is None:
data_date = time.strftime("%Y-%m-%d")
try:
# 尝试获取指定日期的数据
data_df = self.database.get_latest_data(data_type, data_date)
if not data_df.empty:
return data_df, False, f"获取{data_date}数据成功"
# 如果指定日期没有数据,获取最新的历史数据
self.logger.warning(f"[智策引擎] {data_date}{data_type}数据不存在,尝试获取历史数据")
data_df = self.database.get_latest_data(data_type)
if not data_df.empty:
fallback_date = data_df.iloc[0].get('data_date', '未知日期')
return data_df, True, f"回退到{fallback_date}的历史数据"
else:
return pd.DataFrame(), True, "无可用的历史数据"
except Exception as e:
self.logger.error(f"[智策引擎] 获取{data_type}数据失败: {e}")
return pd.DataFrame(), True, str(e)
def run_comprehensive_analysis(self, data: Dict) -> Dict[str, Any]:
"""
运行综合分析流程
Args:
data: 包含市场数据的字典
Returns:
完整的分析结果
"""
print("\n" + "=" * 60)
print("🚀 智策综合分析系统启动")
print("=" * 60)
results = {
"success": False,
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
"agents_analysis": {},
"comprehensive_report": "",
"final_predictions": {}
}
try:
# 1. 运行四个AI智能体分析
print("\n[阶段1] AI智能体分析集群工作中...")
print("-" * 60)
agents_results = {}
# 宏观策略师
print("1/4 宏观策略师...")
macro_result = self.agents.macro_strategist_agent(
market_data=data.get("market_overview", {}),
news_data=data.get("news", [])
)
agents_results["macro"] = macro_result
# 板块诊断师
print("2/4 板块诊断师...")
sector_result = self.agents.sector_diagnostician_agent(
sectors_data=data.get("sectors", {}),
concepts_data=data.get("concepts", {}),
market_data=data.get("market_overview", {})
)
agents_results["sector"] = sector_result
# 资金流向分析师
print("3/4 资金流向分析师...")
fund_result = self.agents.fund_flow_analyst_agent(
fund_flow_data=data.get("sector_fund_flow", {}),
north_flow_data=data.get("north_flow", {}),
sectors_data=data.get("sectors", {})
)
agents_results["fund"] = fund_result
# 市场情绪解码员
print("4/4 市场情绪解码员...")
sentiment_result = self.agents.market_sentiment_decoder_agent(
market_data=data.get("market_overview", {}),
sectors_data=data.get("sectors", {}),
concepts_data=data.get("concepts", {})
)
agents_results["sentiment"] = sentiment_result
results["agents_analysis"] = agents_results
print("\n✓ 所有智能体分析完成")
# 2. 综合研判
print("\n[阶段2] 综合研判引擎工作中...")
print("-" * 60)
comprehensive_report = self._conduct_comprehensive_discussion(agents_results)
results["comprehensive_report"] = comprehensive_report
print("✓ 综合研判完成")
# 3. 生成最终预测
print("\n[阶段3] 生成最终预测...")
print("-" * 60)
predictions = self._generate_final_predictions(comprehensive_report, agents_results, data)
results["final_predictions"] = predictions
print("✓ 预测生成完成")
results["success"] = True
# 4. 保存分析报告
print("\n[阶段4] 保存分析报告...")
print("-" * 60)
try:
report_id = self.save_analysis_report(results, data)
results["report_id"] = report_id
print(f"✓ 分析报告已保存 (ID: {report_id})")
# 保存后读取报告详情并回传到结果,用于主页面动态渲染
try:
saved_report = self.database.get_analysis_report(report_id)
if saved_report:
results["saved_report"] = saved_report
except Exception as fetch_e:
self.logger.warning(f"[智策引擎] 获取保存报告详情失败: {fetch_e}")
except Exception as e:
print(f"⚠ 保存分析报告失败: {e}")
self.logger.error(f"[智策引擎] 保存分析报告失败: {e}")
print("\n" + "=" * 60)
print("✓ 智策综合分析完成!")
print("=" * 60)
except Exception as e:
print(f"\n✗ 分析过程出错: {e}")
import traceback
traceback.print_exc()
results["error"] = str(e)
return results
def _conduct_comprehensive_discussion(self, agents_results: Dict) -> str:
"""
综合研判 - 整合各智能体的分析
"""
print(" 🤝 智能体团队正在综合讨论...")
time.sleep(2)
# 收集各分析师的报告
macro_analysis = agents_results.get("macro", {}).get("analysis", "")
sector_analysis = agents_results.get("sector", {}).get("analysis", "")
fund_analysis = agents_results.get("fund", {}).get("analysis", "")
sentiment_analysis = agents_results.get("sentiment", {}).get("analysis", "")
prompt = f"""
你是智策系统的首席策略官,现在需要综合四位专业分析师的报告,形成全面的市场和板块研判。
【宏观策略师报告】
{macro_analysis}
【板块诊断师报告】
{sector_analysis}
【资金流向分析师报告】
{fund_analysis}
【市场情绪解码员报告】
{sentiment_analysis}
请基于以上四位分析师的专业报告,进行深度综合研判:
1. **观点一致性分析**
- 四位分析师的核心观点有哪些一致之处?
- 在哪些方面存在分歧或不同看法?
- 如何理解这些分歧的合理性?
2. **多维度交叉验证**
- 宏观环境、板块基本面、资金流向、市场情绪是否形成共振?
- 哪些板块得到了多维度的支持?
- 哪些板块存在多维度的风险信号?
3. **关键矛盾识别**
- 当前市场和板块的主要矛盾是什么?
- 哪些因素可能成为决定性因素?
- 如何平衡不同维度的分析结论?
4. **综合判断**
- 基于四个维度的综合分析,对市场整体趋势的判断
- 对板块轮动方向的判断
- 对市场风险收益比的评估
- 当前最值得把握的机会在哪里?
5. **策略权重建议**
- 在当前环境下,四个分析维度的重要性权重(宏观/板块/资金/情绪)
- 应该重点参考哪个维度的建议?
- 需要警惕哪个维度的风险?
请给出专业、全面的综合研判报告,体现多维度分析的价值。
"""
messages = [
{"role": "system", "content": "你是智策系统的首席策略官,需要整合多维度分析,形成全面的投资策略。"},
{"role": "user", "content": prompt}
]
report = self.deepseek_client.call_api(messages, max_tokens=5000)
print(" ✓ 综合研判完成")
return report
def _generate_final_predictions(self, comprehensive_report: str, agents_results: Dict, raw_data: Dict) -> Dict:
"""
生成最终预测 - 板块多空/轮动/热度
"""
print(" 📊 生成板块多空/轮动/热度预测...")
time.sleep(2)
# 提取板块列表用于预测
sectors_list = []
if raw_data.get("sectors"):
sorted_sectors = sorted(raw_data["sectors"].items(), key=lambda x: abs(x[1]["change_pct"]), reverse=True)
sectors_list = [name for name, _ in sorted_sectors[:30]] # 取前30个活跃板块
sectors_str = ", ".join(sectors_list) if sectors_list else "未知板块"
prompt = f"""
基于前期的深度分析和综合研判,现在需要生成最终的板块预测报告。
【综合研判结论】
{comprehensive_report}
【参考板块列表】
{sectors_str}
请生成以下三类预测,并以JSON格式输出:
1. **板块多空情况**
- 看多板块(5-8个):综合判断未来1-2周看涨的板块
- 看空板块(3-5个):综合判断未来1-2周看跌的板块
- 中性板块(2-3个):走势不明朗的板块
对每个板块给出:
- 板块名称
- 多空判断(看多/看空/中性)
- 推荐理由(100字以内)
- 信心度(1-10分)
- 风险提示
2. **板块轮动预测**
- 当前强势板块(正在走强的2-3个板块)
- 潜力接力板块(可能轮动到的3-5个板块)
- 衰退板块(正在走弱的2-3个板块)
对每个板块给出:
- 板块名称
- 轮动阶段(强势/潜力/衰退)
- 轮动逻辑(150字以内)
- 预计时间窗口
- 操作建议
3. **板块热度排行**
- 最热板块TOP5(综合资金、情绪、涨幅)
- 升温板块TOP5(热度快速上升的板块)
- 降温板块TOP3(热度快速下降的板块)
对每个板块给出:
- 板块名称
- 热度评分(0-100分)
- 热度变化趋势(升温/降温/稳定)
- 持续性评估(强/中/弱)
请严格按照以下JSON格式输出:
{{
"long_short": {{
"bullish": [
{{
"sector": "板块名称",
"direction": "看多",
"reason": "推荐理由",
"confidence": 8,
"risk": "风险提示"
}}
],
"bearish": [...],
"neutral": [...]
}},
"rotation": {{
"current_strong": [
{{
"sector": "板块名称",
"stage": "强势",
"logic": "轮动逻辑",
"time_window": "1-2周",
"advice": "操作建议"
}}
],
"potential": [...],
"declining": [...]
}},
"heat": {{
"hottest": [
{{
"sector": "板块名称",
"score": 95,
"trend": "升温",
"sustainability": "强"
}}
],
"heating": [...],
"cooling": [...]
}},
"summary": {{
"market_view": "市场整体看法",
"key_opportunity": "核心机会",
"major_risk": "主要风险",
"strategy": "整体策略建议"
}}
}}
注意:
1. 所有板块名称必须从参考板块列表中选择
2. 分析要基于前期的多维度研判
3. 给出的建议要具体、可操作
4. 预测要客观、理性,避免过度乐观或悲观
"""
messages = [
{"role": "system", "content": "你是智策系统的预测引擎,需要生成专业、精准的板块预测报告。"},
{"role": "user", "content": prompt}
]
response = self.deepseek_client.call_api(messages, temperature=0.3, max_tokens=6000)
# 尝试解析JSON
try:
import re
json_match = re.search(r'\{.*\}', response, re.DOTALL)
if json_match:
predictions = json.loads(json_match.group())
print(" ✓ 预测报告生成成功(JSON格式)")
return predictions
else:
print(" ⚠ 未能解析JSON,返回文本格式")
return {"prediction_text": response}
except Exception as e:
print(f" ⚠ JSON解析失败: {e},返回文本格式")
return {"prediction_text": response}
def save_analysis_report(self, results: Dict, original_data: Dict) -> int:
"""
保存分析报告到数据库
Args:
results: 分析结果
original_data: 原始数据
Returns:
int: 报告ID
"""
try:
# 提取数据日期范围
data_date_range = f"{time.strftime('%Y-%m-%d')} 数据分析"
# 提取推荐板块
recommended_sectors = []
predictions = results.get("final_predictions", {})
if isinstance(predictions, dict):
# 从预测结果中提取推荐板块
hot_sectors = predictions.get("hot_sectors", [])
rotation_sectors = predictions.get("rotation_opportunities", [])
for sector in hot_sectors[:5]: # 取前5个热门板块
if isinstance(sector, dict):
recommended_sectors.append({
"sector_name": sector.get("name", ""),
"reason": sector.get("reason", ""),
"confidence": sector.get("confidence", ""),
"type": "热门板块"
})
for sector in rotation_sectors[:3]: # 取前3个轮动机会
if isinstance(sector, dict):
recommended_sectors.append({
"sector_name": sector.get("name", ""),
"reason": sector.get("reason", ""),
"confidence": sector.get("confidence", ""),
"type": "轮动机会"
})
# 生成摘要
summary = self._generate_report_summary(results)
# 提取其他信息
confidence_score = self._extract_confidence_score(results)
risk_level = self._extract_risk_level(results)
investment_horizon = self._extract_investment_horizon(results)
market_outlook = self._extract_market_outlook(results)
# 保存到数据库
report_id = self.database.save_analysis_report(
data_date_range=data_date_range,
analysis_content=results,
recommended_sectors=recommended_sectors,
summary=summary,
confidence_score=confidence_score,
risk_level=risk_level,
investment_horizon=investment_horizon,
market_outlook=market_outlook
)
return report_id
except Exception as e:
self.logger.error(f"[智策引擎] 保存分析报告失败: {e}")
raise
def _generate_report_summary(self, results: Dict) -> str:
"""生成报告摘要"""
try:
predictions = results.get("final_predictions", {})
if isinstance(predictions, dict):
# 从summary中提取市场趋势信息
summary_info = predictions.get("summary", {})
market_trend = summary_info.get("market_view", "") if isinstance(summary_info, dict) else ""
# 从long_short.bullish中计算热门板块数量
long_short_info = predictions.get("long_short", {})
bullish_sectors = long_short_info.get("bullish", []) if isinstance(long_short_info, dict) else []
hot_sectors_count = len(bullish_sectors)
# 如果有看多板块信息,则添加到摘要中
if bullish_sectors and isinstance(bullish_sectors, list):
# 提取前3个看多板块名称
bullish_names = [sector.get("sector", "") for sector in bullish_sectors[:3] if isinstance(sector, dict)]
if bullish_names:
bullish_text = "".join(bullish_names)
return f"市场趋势: {market_trend},识别{hot_sectors_count}个热门板块机会,看多板块: {bullish_text}"
return f"市场趋势: {market_trend},识别{hot_sectors_count}个热门板块机会"
else:
return "智策板块分析报告"
except:
return "智策板块分析报告"
def _extract_confidence_score(self, results: Dict) -> float:
"""提取置信度分数"""
try:
predictions = results.get("final_predictions", {})
if isinstance(predictions, dict):
return predictions.get("confidence_score", 0.75)
return 0.75
except:
return 0.75
def _extract_risk_level(self, results: Dict) -> str:
"""提取风险等级"""
try:
predictions = results.get("final_predictions", {})
if isinstance(predictions, dict):
return predictions.get("risk_level", "中等")
return "中等"
except:
return "中等"
def _extract_investment_horizon(self, results: Dict) -> str:
"""提取投资周期"""
try:
predictions = results.get("final_predictions", {})
if isinstance(predictions, dict):
return predictions.get("investment_horizon", "短期")
return "短期"
except:
return "短期"
def _extract_market_outlook(self, results: Dict) -> str:
"""提取市场展望"""
try:
predictions = results.get("final_predictions", {})
if isinstance(predictions, dict):
return predictions.get("market_outlook", "谨慎乐观")
return "谨慎乐观"
except:
return "谨慎乐观"
def get_historical_reports(self, limit=10):
"""获取历史报告"""
return self.database.get_analysis_reports(limit)
def get_report_detail(self, report_id):
"""获取报告详情"""
return self.database.get_analysis_report(report_id)
def delete_report(self, report_id):
"""删除报告"""
return self.database.delete_analysis_report(report_id)
# 测试函数
if __name__ == "__main__":
print("=" * 60)
print("测试智策综合研判引擎")
print("=" * 60)
# 创建模拟数据
test_data = {
"success": True,
"sectors": {
"电子": {"change_pct": 2.5, "turnover": 3.5, "top_stock": "某某科技", "top_stock_change": 5.0, "up_count": 80, "down_count": 20},
"计算机": {"change_pct": 1.8, "turnover": 4.0, "top_stock": "某某软件", "top_stock_change": 4.5, "up_count": 70, "down_count": 30}
},
"market_overview": {
"sh_index": {"close": 3200, "change_pct": 0.5},
"total_stocks": 5000,
"up_count": 3000,
"up_ratio": 60.0
},
"news": [
{"title": "测试新闻", "content": "测试内容", "publish_time": "2024-01-15"}
],
"sector_fund_flow": {
"today": [
{"sector": "电子", "main_net_inflow": 100000, "main_net_inflow_pct": 2.0, "change_pct": 2.5, "super_large_net_inflow": 50000}
]
},
"north_flow": {
"date": "2024-01-15",
"north_net_inflow": 50000
}
}
engine = SectorStrategyEngine()
print("\n开始综合分析...")
# 注意:这只是测试框架,实际运行需要真实数据和API key
# results = engine.run_comprehensive_analysis(test_data)
# print(f"\n分析结果: {results.get('success')}")