增加主力资金选股
This commit is contained in:
@@ -16,6 +16,7 @@ from monitor_manager import display_monitor_manager, get_monitor_summary
|
||||
from monitor_service import monitor_service
|
||||
from notification_service import notification_service
|
||||
from config_manager import config_manager
|
||||
from main_force_ui import display_main_force_selector
|
||||
|
||||
# 页面配置
|
||||
st.set_page_config(
|
||||
@@ -296,6 +297,17 @@ def main():
|
||||
st.session_state.show_monitor = True
|
||||
if 'show_history' in st.session_state:
|
||||
del st.session_state.show_history
|
||||
if 'show_main_force' in st.session_state:
|
||||
del st.session_state.show_main_force
|
||||
|
||||
if st.button("🎯 主力选股", use_container_width=True, key="nav_main_force"):
|
||||
st.session_state.show_main_force = True
|
||||
if 'show_history' in st.session_state:
|
||||
del st.session_state.show_history
|
||||
if 'show_monitor' in st.session_state:
|
||||
del st.session_state.show_monitor
|
||||
if 'show_config' in st.session_state:
|
||||
del st.session_state.show_config
|
||||
|
||||
if st.button("🏠 返回首页", use_container_width=True, key="nav_home"):
|
||||
if 'show_history' in st.session_state:
|
||||
@@ -304,6 +316,8 @@ def main():
|
||||
del st.session_state.show_monitor
|
||||
if 'show_config' in st.session_state:
|
||||
del st.session_state.show_config
|
||||
if 'show_main_force' in st.session_state:
|
||||
del st.session_state.show_main_force
|
||||
|
||||
if st.button("⚙️ 环境配置", use_container_width=True, key="nav_config"):
|
||||
st.session_state.show_config = True
|
||||
@@ -373,6 +387,7 @@ def main():
|
||||
|
||||
**功能说明**
|
||||
- **智能分析**:AI团队深度分析
|
||||
- **主力选股**:主力资金精选标的
|
||||
- **实时监测**:价格监控与提醒
|
||||
- **历史记录**:查看分析历史
|
||||
|
||||
@@ -393,6 +408,11 @@ def main():
|
||||
display_monitor_manager()
|
||||
return
|
||||
|
||||
# 检查是否显示主力选股
|
||||
if 'show_main_force' in st.session_state and st.session_state.show_main_force:
|
||||
display_main_force_selector()
|
||||
return
|
||||
|
||||
# 检查是否显示环境配置
|
||||
if 'show_config' in st.session_state and st.session_state.show_config:
|
||||
display_config_manager()
|
||||
@@ -539,6 +559,8 @@ def main():
|
||||
del st.session_state.discussion_result
|
||||
if 'final_decision' in st.session_state:
|
||||
del st.session_state.final_decision
|
||||
if 'just_completed' in st.session_state:
|
||||
del st.session_state.just_completed
|
||||
|
||||
run_stock_analysis(stock_input, period)
|
||||
|
||||
@@ -566,32 +588,36 @@ def main():
|
||||
# 运行批量分析
|
||||
run_batch_analysis(stock_list, period, batch_mode)
|
||||
|
||||
# 检查是否有已完成的单个分析结果
|
||||
# 检查是否有已完成的单个分析结果(但不是刚刚完成的,避免重复显示)
|
||||
if 'analysis_completed' in st.session_state and st.session_state.analysis_completed:
|
||||
# 重新显示分析结果
|
||||
stock_info = st.session_state.stock_info
|
||||
agents_results = st.session_state.agents_results
|
||||
discussion_result = st.session_state.discussion_result
|
||||
final_decision = st.session_state.final_decision
|
||||
|
||||
# 重新获取股票数据用于显示图表
|
||||
stock_info_current, stock_data, indicators = get_stock_data(stock_info['symbol'], period)
|
||||
|
||||
# 显示股票基本信息
|
||||
display_stock_info(stock_info, indicators)
|
||||
|
||||
# 显示股票图表
|
||||
if stock_data is not None:
|
||||
display_stock_chart(stock_data, stock_info)
|
||||
|
||||
# 显示各分析师报告
|
||||
display_agents_analysis(agents_results)
|
||||
|
||||
# 显示团队讨论
|
||||
display_team_discussion(discussion_result)
|
||||
|
||||
# 显示最终决策
|
||||
display_final_decision(final_decision, stock_info, agents_results, discussion_result)
|
||||
# 如果是刚刚完成的分析,清除标志,避免重复显示
|
||||
if st.session_state.get('just_completed', False):
|
||||
st.session_state.just_completed = False
|
||||
else:
|
||||
# 重新显示之前的分析结果(页面刷新后)
|
||||
stock_info = st.session_state.stock_info
|
||||
agents_results = st.session_state.agents_results
|
||||
discussion_result = st.session_state.discussion_result
|
||||
final_decision = st.session_state.final_decision
|
||||
|
||||
# 重新获取股票数据用于显示图表
|
||||
stock_info_current, stock_data, indicators = get_stock_data(stock_info['symbol'], period)
|
||||
|
||||
# 显示股票基本信息
|
||||
display_stock_info(stock_info, indicators)
|
||||
|
||||
# 显示股票图表
|
||||
if stock_data is not None:
|
||||
display_stock_chart(stock_data, stock_info)
|
||||
|
||||
# 显示各分析师报告
|
||||
display_agents_analysis(agents_results)
|
||||
|
||||
# 显示团队讨论
|
||||
display_team_discussion(discussion_result)
|
||||
|
||||
# 显示最终决策
|
||||
display_final_decision(final_decision, stock_info, agents_results, discussion_result)
|
||||
|
||||
# 检查是否有已完成的批量分析结果
|
||||
elif 'batch_analysis_results' in st.session_state and st.session_state.batch_analysis_results:
|
||||
@@ -1064,12 +1090,16 @@ def run_stock_analysis(symbol, period):
|
||||
final_decision = agents.make_final_decision(discussion_result, stock_info, indicators)
|
||||
progress_bar.progress(100)
|
||||
|
||||
# 保存分析结果到session_state
|
||||
# 显示最终决策
|
||||
display_final_decision(final_decision, stock_info, agents_results, discussion_result)
|
||||
|
||||
# 保存分析结果到session_state(用于页面刷新后显示)
|
||||
st.session_state.analysis_completed = True
|
||||
st.session_state.stock_info = stock_info
|
||||
st.session_state.agents_results = agents_results
|
||||
st.session_state.discussion_result = discussion_result
|
||||
st.session_state.final_decision = final_decision
|
||||
st.session_state.just_completed = True # 标记刚刚完成分析
|
||||
|
||||
# 保存到数据库
|
||||
try:
|
||||
@@ -1086,9 +1116,6 @@ def run_stock_analysis(symbol, period):
|
||||
except Exception as e:
|
||||
st.warning(f"⚠️ 保存到数据库时出现错误: {str(e)}")
|
||||
|
||||
# 显示最终决策
|
||||
display_final_decision(final_decision, stock_info, agents_results, discussion_result)
|
||||
|
||||
status_text.text("✅ 分析完成!")
|
||||
time.sleep(1)
|
||||
status_text.empty()
|
||||
|
||||
@@ -0,0 +1,549 @@
|
||||
#!/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 = 90,
|
||||
final_n: int = 5) -> Dict:
|
||||
"""
|
||||
运行完整的主力选股分析流程 - 整体批量分析
|
||||
|
||||
Args:
|
||||
start_date: 开始日期,格式如"2025年10月1日"
|
||||
days_ago: 距今多少天,默认90天
|
||||
final_n: 最终精选N只,默认5只
|
||||
|
||||
Returns:
|
||||
分析结果字典
|
||||
"""
|
||||
result = {
|
||||
'success': False,
|
||||
'total_stocks': 0,
|
||||
'filtered_stocks': 0,
|
||||
'final_recommendations': [],
|
||||
'error': None
|
||||
}
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
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=30.0,
|
||||
min_market_cap=50.0,
|
||||
max_market_cap=1300.0
|
||||
)
|
||||
|
||||
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()
|
||||
@@ -0,0 +1,456 @@
|
||||
import os
|
||||
import base64
|
||||
import re
|
||||
from datetime import datetime
|
||||
import streamlit as st
|
||||
import pandas as pd
|
||||
|
||||
def generate_main_force_markdown_report(analyzer, result):
|
||||
"""生成主力选股Markdown格式的分析报告"""
|
||||
|
||||
# 获取当前时间
|
||||
current_time = datetime.now().strftime("%Y年%m月%d日 %H:%M:%S")
|
||||
|
||||
# 获取分析参数
|
||||
params = result.get('params', {})
|
||||
start_date = params.get('start_date', 'N/A')
|
||||
min_cap = params.get('min_market_cap', 50)
|
||||
max_cap = params.get('max_market_cap', 5000)
|
||||
max_change = params.get('max_range_change', 50)
|
||||
|
||||
markdown_content = f"""
|
||||
# 主力选股AI分析报告
|
||||
|
||||
**生成时间**: {current_time}
|
||||
|
||||
---
|
||||
|
||||
## 📊 选股参数
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|-----|
|
||||
| **起始日期** | {start_date} |
|
||||
| **市值范围** | {min_cap}亿 - {max_cap}亿 |
|
||||
| **最大涨跌幅** | {max_change}% |
|
||||
| **初始数据量** | {result.get('total_fetched', 0)}只 |
|
||||
| **筛选后数量** | {result.get('filtered_count', 0)}只 |
|
||||
| **最终推荐** | {len(result.get('final_recommendations', []))}只 |
|
||||
|
||||
---
|
||||
|
||||
## 🤖 AI分析师团队报告
|
||||
|
||||
"""
|
||||
|
||||
# 添加资金流向分析
|
||||
if hasattr(analyzer, 'fund_flow_analysis') and analyzer.fund_flow_analysis:
|
||||
markdown_content += f"""
|
||||
### 💰 资金流向分析师
|
||||
|
||||
{analyzer.fund_flow_analysis}
|
||||
|
||||
---
|
||||
|
||||
"""
|
||||
|
||||
# 添加行业板块分析
|
||||
if hasattr(analyzer, 'industry_analysis') and analyzer.industry_analysis:
|
||||
markdown_content += f"""
|
||||
### 📊 行业板块及市场热点分析师
|
||||
|
||||
{analyzer.industry_analysis}
|
||||
|
||||
---
|
||||
|
||||
"""
|
||||
|
||||
# 添加财务基本面分析
|
||||
if hasattr(analyzer, 'fundamental_analysis') and analyzer.fundamental_analysis:
|
||||
markdown_content += f"""
|
||||
### 📈 财务基本面分析师
|
||||
|
||||
{analyzer.fundamental_analysis}
|
||||
|
||||
---
|
||||
|
||||
"""
|
||||
|
||||
# 添加精选推荐
|
||||
markdown_content += """
|
||||
## ⭐ 精选推荐股票
|
||||
|
||||
"""
|
||||
|
||||
final_recommendations = result.get('final_recommendations', [])
|
||||
if final_recommendations:
|
||||
for rec in final_recommendations:
|
||||
markdown_content += f"""
|
||||
### 【第{rec['rank']}名】{rec['symbol']} - {rec['name']}
|
||||
|
||||
**推荐理由**:
|
||||
{rec.get('reason', '暂无')}
|
||||
|
||||
**关键指标**:
|
||||
"""
|
||||
if 'stock_data' in rec:
|
||||
stock_data = rec['stock_data']
|
||||
markdown_content += f"""
|
||||
- **所属行业**: {stock_data.get('industry', 'N/A')}
|
||||
- **市值**: {stock_data.get('market_cap', 'N/A')}
|
||||
- **主力资金流向**: {stock_data.get('main_fund_inflow', 'N/A')}
|
||||
- **区间涨跌幅**: {stock_data.get('range_change', 'N/A')}%
|
||||
- **市盈率**: {stock_data.get('pe_ratio', 'N/A')}
|
||||
- **市净率**: {stock_data.get('pb_ratio', 'N/A')}
|
||||
|
||||
"""
|
||||
|
||||
if 'scores' in rec.get('stock_data', {}):
|
||||
scores = rec['stock_data']['scores']
|
||||
if scores:
|
||||
markdown_content += "**能力评分**:\n"
|
||||
for score_name, score_value in scores.items():
|
||||
markdown_content += f"- {score_name}: {score_value}\n"
|
||||
markdown_content += "\n"
|
||||
|
||||
markdown_content += "---\n\n"
|
||||
else:
|
||||
markdown_content += "暂无推荐股票\n\n---\n\n"
|
||||
|
||||
# 添加候选股票列表(前100名,按主力资金排序)
|
||||
if analyzer and analyzer.raw_stocks is not None and not analyzer.raw_stocks.empty:
|
||||
markdown_content += """
|
||||
## 📋 候选股票完整列表(按主力资金净流入排序)
|
||||
|
||||
"""
|
||||
|
||||
# 获取主力资金列名
|
||||
df = analyzer.raw_stocks
|
||||
main_fund_col = None
|
||||
main_fund_patterns = [
|
||||
'区间主力资金流向', '区间主力资金净流入',
|
||||
'主力资金流向', '主力资金净流入', '主力净流入'
|
||||
]
|
||||
for pattern in main_fund_patterns:
|
||||
matching = [col for col in df.columns if pattern in col]
|
||||
if matching:
|
||||
main_fund_col = matching[0]
|
||||
break
|
||||
|
||||
# 按主力资金排序
|
||||
if main_fund_col:
|
||||
df_sorted = df.copy()
|
||||
df_sorted[main_fund_col] = pd.to_numeric(df_sorted[main_fund_col], errors='coerce')
|
||||
df_sorted = df_sorted.sort_values(by=main_fund_col, ascending=False).head(100)
|
||||
else:
|
||||
df_sorted = df.head(100)
|
||||
|
||||
# 选择要显示的列
|
||||
display_cols = []
|
||||
if '股票代码' in df_sorted.columns:
|
||||
display_cols.append('股票代码')
|
||||
if '股票简称' in df_sorted.columns:
|
||||
display_cols.append('股票简称')
|
||||
|
||||
# 行业
|
||||
industry_cols = [col for col in df_sorted.columns if '行业' in col]
|
||||
if industry_cols:
|
||||
display_cols.append(industry_cols[0])
|
||||
|
||||
# 主力资金
|
||||
if main_fund_col:
|
||||
display_cols.append(main_fund_col)
|
||||
|
||||
# 涨跌幅
|
||||
change_cols = [col for col in df_sorted.columns if '涨跌幅' in col]
|
||||
if change_cols:
|
||||
display_cols.append(change_cols[0])
|
||||
|
||||
# 市值、市盈率、市净率
|
||||
for col_name in ['总市值', '市盈率', '市净率']:
|
||||
matching_cols = [col for col in df_sorted.columns if col_name in col]
|
||||
if matching_cols:
|
||||
display_cols.append(matching_cols[0])
|
||||
|
||||
# 生成表格
|
||||
if display_cols:
|
||||
final_display_cols = [col for col in display_cols if col in df_sorted.columns]
|
||||
markdown_content += "| 序号 | " + " | ".join(final_display_cols) + " |\n"
|
||||
markdown_content += "|------|" + "|".join(['-----' for _ in final_display_cols]) + "|\n"
|
||||
|
||||
for idx, (_, row) in enumerate(df_sorted[final_display_cols].iterrows(), 1):
|
||||
row_data = [str(idx)]
|
||||
for col in final_display_cols:
|
||||
value = row[col]
|
||||
if pd.isna(value):
|
||||
row_data.append('N/A')
|
||||
else:
|
||||
row_data.append(str(value))
|
||||
markdown_content += "| " + " | ".join(row_data) + " |\n"
|
||||
|
||||
markdown_content += "\n"
|
||||
|
||||
# 添加免责声明
|
||||
markdown_content += f"""
|
||||
---
|
||||
|
||||
## 📝 免责声明
|
||||
|
||||
本报告由AI系统生成,仅供参考,不构成投资建议。投资有风险,入市需谨慎。请在做出投资决策前咨询专业的投资顾问。
|
||||
|
||||
---
|
||||
|
||||
*报告生成时间: {current_time}*
|
||||
*主力选股AI分析系统 v1.0*
|
||||
"""
|
||||
|
||||
return markdown_content
|
||||
|
||||
|
||||
def generate_html_content(markdown_content):
|
||||
"""将Markdown转换为HTML"""
|
||||
html_content = f"""
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>主力选股AI分析报告</title>
|
||||
<style>
|
||||
body {{
|
||||
font-family: 'Microsoft YaHei', Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background-color: #f5f5f5;
|
||||
}}
|
||||
.container {{
|
||||
background-color: white;
|
||||
padding: 30px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
}}
|
||||
h1 {{
|
||||
color: #2c3e50;
|
||||
border-bottom: 3px solid #3498db;
|
||||
padding-bottom: 10px;
|
||||
}}
|
||||
h2 {{
|
||||
color: #34495e;
|
||||
border-left: 4px solid #3498db;
|
||||
padding-left: 15px;
|
||||
margin-top: 30px;
|
||||
}}
|
||||
h3 {{
|
||||
color: #2980b9;
|
||||
margin-top: 25px;
|
||||
}}
|
||||
table {{
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 20px 0;
|
||||
font-size: 14px;
|
||||
}}
|
||||
th, td {{
|
||||
border: 1px solid #ddd;
|
||||
padding: 8px;
|
||||
text-align: left;
|
||||
}}
|
||||
th {{
|
||||
background-color: #3498db;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}}
|
||||
tr:nth-child(even) {{
|
||||
background-color: #f9f9f9;
|
||||
}}
|
||||
tr:hover {{
|
||||
background-color: #f0f0f0;
|
||||
}}
|
||||
.disclaimer {{
|
||||
background-color: #fff3cd;
|
||||
border: 1px solid #ffeaa7;
|
||||
border-radius: 5px;
|
||||
padding: 15px;
|
||||
margin-top: 30px;
|
||||
}}
|
||||
.footer {{
|
||||
text-align: center;
|
||||
margin-top: 30px;
|
||||
color: #7f8c8d;
|
||||
font-style: italic;
|
||||
}}
|
||||
hr {{
|
||||
border: none;
|
||||
height: 2px;
|
||||
background-color: #ecf0f1;
|
||||
margin: 20px 0;
|
||||
}}
|
||||
strong {{
|
||||
color: #2c3e50;
|
||||
}}
|
||||
ul, ol {{
|
||||
margin: 10px 0;
|
||||
padding-left: 30px;
|
||||
}}
|
||||
li {{
|
||||
margin: 5px 0;
|
||||
}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
"""
|
||||
|
||||
# 简单的Markdown到HTML转换
|
||||
html_body = markdown_content
|
||||
html_body = html_body.replace('\n# ', '\n<h1>').replace('\n## ', '\n<h2>').replace('\n### ', '\n<h3>')
|
||||
html_body = html_body.replace('# ', '<h1>').replace('## ', '<h2>').replace('### ', '<h3>')
|
||||
html_body = html_body.replace('\n---\n', '\n<hr>\n')
|
||||
|
||||
# 处理粗体文本
|
||||
html_body = re.sub(r'\*\*(.*?)\*\*', r'<strong>\1</strong>', html_body)
|
||||
|
||||
# 处理表格
|
||||
lines = html_body.split('\n')
|
||||
in_table = False
|
||||
processed_lines = []
|
||||
|
||||
for line in lines:
|
||||
if '|' in line and not in_table and line.strip().startswith('|'):
|
||||
processed_lines.append('<table>')
|
||||
in_table = True
|
||||
cells = [cell.strip() for cell in line.split('|')[1:-1]]
|
||||
processed_lines.append('<tr>')
|
||||
for cell in cells:
|
||||
processed_lines.append(f'<th>{cell}</th>')
|
||||
processed_lines.append('</tr>')
|
||||
elif '|' in line and in_table:
|
||||
if '---' not in line:
|
||||
cells = [cell.strip() for cell in line.split('|')[1:-1]]
|
||||
processed_lines.append('<tr>')
|
||||
for cell in cells:
|
||||
processed_lines.append(f'<td>{cell}</td>')
|
||||
processed_lines.append('</tr>')
|
||||
elif in_table and '|' not in line:
|
||||
processed_lines.append('</table>')
|
||||
in_table = False
|
||||
processed_lines.append(line)
|
||||
else:
|
||||
processed_lines.append(line)
|
||||
|
||||
if in_table:
|
||||
processed_lines.append('</table>')
|
||||
|
||||
html_body = '\n'.join(processed_lines)
|
||||
|
||||
# 处理列表
|
||||
html_body = re.sub(r'\n- (.*)', r'\n<li>\1</li>', html_body)
|
||||
html_body = re.sub(r'(<li>.*</li>)\n(?!<li>)', r'<ul>\1</ul>\n', html_body)
|
||||
html_body = re.sub(r'(<li>.*</li>\n)+', lambda m: '<ul>\n' + m.group(0) + '</ul>\n', html_body)
|
||||
|
||||
# 处理换行
|
||||
html_body = html_body.replace('\n\n', '</p><p>')
|
||||
html_body = '<p>' + html_body + '</p>'
|
||||
|
||||
html_content += html_body
|
||||
html_content += """
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
return html_content
|
||||
|
||||
|
||||
def create_download_link(content, filename, link_text):
|
||||
"""创建下载链接"""
|
||||
b64 = base64.b64encode(content.encode()).decode()
|
||||
href = f'<a href="data:text/markdown;base64,{b64}" download="{filename}" style="display: inline-block; padding: 10px 20px; background-color: #4CAF50; color: white; text-decoration: none; border-radius: 5px; margin: 5px;">{link_text}</a>'
|
||||
return href
|
||||
|
||||
|
||||
def create_html_download_link(content, filename, link_text):
|
||||
"""创建HTML下载链接"""
|
||||
b64 = base64.b64encode(content.encode('utf-8')).decode()
|
||||
href = f'<a href="data:text/html;base64,{b64}" download="{filename}" style="display: inline-block; padding: 10px 20px; background-color: #2196F3; color: white; text-decoration: none; border-radius: 5px; margin: 5px;">{link_text}</a>'
|
||||
return href
|
||||
|
||||
|
||||
def display_report_download_section(analyzer, result):
|
||||
"""显示报告下载区域"""
|
||||
|
||||
st.markdown("---")
|
||||
st.markdown("### 📥 下载分析报告")
|
||||
|
||||
col1, col2 = st.columns(2)
|
||||
|
||||
with col1:
|
||||
st.markdown("#### 📄 Markdown格式")
|
||||
st.caption("适合编辑和进一步处理")
|
||||
|
||||
# 生成Markdown报告
|
||||
markdown_content = generate_main_force_markdown_report(analyzer, result)
|
||||
|
||||
# 生成文件名
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
md_filename = f"主力选股分析报告_{timestamp}.md"
|
||||
|
||||
# 创建下载链接
|
||||
md_link = create_download_link(markdown_content, md_filename, "📥 下载Markdown报告")
|
||||
st.markdown(md_link, unsafe_allow_html=True)
|
||||
|
||||
# 显示预览
|
||||
with st.expander("👀 预览Markdown内容"):
|
||||
st.code(markdown_content[:2000] + "..." if len(markdown_content) > 2000 else markdown_content)
|
||||
|
||||
with col2:
|
||||
st.markdown("#### 🌐 HTML格式")
|
||||
st.caption("可在浏览器中打开查看")
|
||||
|
||||
# 生成HTML报告
|
||||
html_content = generate_html_content(markdown_content)
|
||||
|
||||
# 生成文件名
|
||||
html_filename = f"主力选股分析报告_{timestamp}.html"
|
||||
|
||||
# 创建下载链接
|
||||
html_link = create_html_download_link(html_content, html_filename, "📥 下载HTML报告")
|
||||
st.markdown(html_link, unsafe_allow_html=True)
|
||||
|
||||
# 显示说明
|
||||
st.info("💡 HTML报告可以直接在浏览器中打开,格式美观易读")
|
||||
|
||||
# 添加CSV下载(候选股票列表)
|
||||
if analyzer and analyzer.raw_stocks is not None and not analyzer.raw_stocks.empty:
|
||||
st.markdown("---")
|
||||
st.markdown("#### 📊 候选股票数据")
|
||||
|
||||
# 按主力资金排序
|
||||
df = analyzer.raw_stocks.copy()
|
||||
main_fund_col = None
|
||||
main_fund_patterns = [
|
||||
'区间主力资金流向', '区间主力资金净流入',
|
||||
'主力资金流向', '主力资金净流入', '主力净流入'
|
||||
]
|
||||
for pattern in main_fund_patterns:
|
||||
matching = [col for col in df.columns if pattern in col]
|
||||
if matching:
|
||||
main_fund_col = matching[0]
|
||||
break
|
||||
|
||||
if main_fund_col:
|
||||
df[main_fund_col] = pd.to_numeric(df[main_fund_col], errors='coerce')
|
||||
df = df.sort_values(by=main_fund_col, ascending=False)
|
||||
|
||||
# 导出为CSV
|
||||
csv = df.to_csv(index=False, encoding='utf-8-sig')
|
||||
csv_filename = f"主力选股候选列表_{timestamp}.csv"
|
||||
|
||||
st.download_button(
|
||||
label="📥 下载候选股票CSV",
|
||||
data=csv,
|
||||
file_name=csv_filename,
|
||||
mime="text/csv",
|
||||
use_container_width=True
|
||||
)
|
||||
|
||||
@@ -0,0 +1,386 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
主力选股模块
|
||||
使用pywencai获取主力资金净流入前100名股票,并进行智能筛选
|
||||
"""
|
||||
|
||||
import pandas as pd
|
||||
import pywencai
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Dict, List, Tuple
|
||||
import time
|
||||
|
||||
class MainForceStockSelector:
|
||||
"""主力选股类"""
|
||||
|
||||
def __init__(self):
|
||||
self.raw_data = None
|
||||
self.filtered_stocks = None
|
||||
|
||||
def get_main_force_stocks(self, start_date: str = None, days_ago: int = 90) -> Tuple[bool, pd.DataFrame, str]:
|
||||
"""
|
||||
获取主力资金净流入前100名股票
|
||||
|
||||
Args:
|
||||
start_date: 开始日期,格式如"2025年10月1日",如果不提供则使用days_ago
|
||||
days_ago: 距今多少天,默认90天(约3个月)
|
||||
|
||||
Returns:
|
||||
(success, dataframe, message)
|
||||
"""
|
||||
try:
|
||||
# 如果没有提供开始日期,根据days_ago计算
|
||||
if not start_date:
|
||||
date_obj = datetime.now() - timedelta(days=days_ago)
|
||||
start_date = f"{date_obj.year}年{date_obj.month}月{date_obj.day}日"
|
||||
|
||||
print(f"\n{'='*60}")
|
||||
print(f"🔍 主力选股 - 数据获取中")
|
||||
print(f"{'='*60}")
|
||||
print(f"开始日期: {start_date}")
|
||||
print(f"目标: 获取主力资金净流入排名前100名股票")
|
||||
|
||||
# 构建查询语句 - 使用多个备选方案,所有方案都要求计算区间涨跌幅
|
||||
queries = [
|
||||
# 方案1: 完整查询(最优)
|
||||
f"{start_date}以来主力资金净流入排名,并计算区间涨跌幅,市值50-5000亿之间,非科创非st,"
|
||||
f"所属同花顺行业,总市值,净利润,营收,市盈率,市净率,"
|
||||
f"盈利能力评分,成长能力评分,营运能力评分,偿债能力评分,"
|
||||
f"现金流评分,资产质量评分,流动性评分,资本充足性评分",
|
||||
|
||||
# 方案2: 简化查询
|
||||
f"{start_date}以来主力资金净流入,并计算区间涨跌幅,市值50-5000亿,非科创非st,"
|
||||
f"所属同花顺行业,总市值,净利润,营收,市盈率,市净率",
|
||||
|
||||
# 方案3: 基础查询
|
||||
f"{start_date}以来主力资金净流入排名,并计算区间涨跌幅,市值50-5000亿,非科创非st,"
|
||||
f"所属行业,总市值",
|
||||
|
||||
# 方案4: 最简查询
|
||||
f"{start_date}以来主力资金净流入前100名,并计算区间涨跌幅,市值50-5000亿,非st非科创板,所属行业,总市值",
|
||||
]
|
||||
|
||||
# 尝试不同的查询方案
|
||||
for i, query in enumerate(queries, 1):
|
||||
print(f"\n尝试方案 {i}/{len(queries)}...")
|
||||
print(f"查询语句: {query[:100]}...")
|
||||
|
||||
try:
|
||||
result = pywencai.get(query=query, loop=True)
|
||||
|
||||
if result is None:
|
||||
print(f" ⚠️ 方案{i}返回None,尝试下一个方案")
|
||||
continue
|
||||
|
||||
# 转换为DataFrame
|
||||
df_result = self._convert_to_dataframe(result)
|
||||
|
||||
if df_result is None or df_result.empty:
|
||||
print(f" ⚠️ 方案{i}数据为空,尝试下一个方案")
|
||||
continue
|
||||
|
||||
# 成功获取数据
|
||||
print(f" ✅ 方案{i}成功!获取到 {len(df_result)} 只股票")
|
||||
self.raw_data = df_result
|
||||
|
||||
# 显示获取到的列名
|
||||
print(f"\n获取到的数据字段:")
|
||||
for col in df_result.columns[:15]: # 只显示前15个字段
|
||||
print(f" - {col}")
|
||||
if len(df_result.columns) > 15:
|
||||
print(f" ... 还有 {len(df_result.columns) - 15} 个字段")
|
||||
|
||||
return True, df_result, f"成功获取{len(df_result)}只股票数据"
|
||||
|
||||
except Exception as e:
|
||||
print(f" ❌ 方案{i}失败: {str(e)}")
|
||||
time.sleep(2) # 失败后等待2秒再试
|
||||
continue
|
||||
|
||||
# 所有方案都失败
|
||||
error_msg = "所有查询方案都失败了,请检查网络或稍后重试"
|
||||
print(f"\n❌ {error_msg}")
|
||||
return False, None, error_msg
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"获取主力选股数据失败: {str(e)}"
|
||||
print(f"\n❌ {error_msg}")
|
||||
return False, None, error_msg
|
||||
|
||||
def _convert_to_dataframe(self, result) -> pd.DataFrame:
|
||||
"""转换问财返回结果为DataFrame"""
|
||||
try:
|
||||
if isinstance(result, pd.DataFrame):
|
||||
return result
|
||||
elif isinstance(result, dict):
|
||||
# 检查是否有嵌套的tableV1结构
|
||||
if 'tableV1' in result:
|
||||
table_data = result['tableV1']
|
||||
if isinstance(table_data, pd.DataFrame):
|
||||
return table_data
|
||||
elif isinstance(table_data, list):
|
||||
return pd.DataFrame(table_data)
|
||||
# 直接转换字典
|
||||
return pd.DataFrame([result])
|
||||
elif isinstance(result, list):
|
||||
return pd.DataFrame(result)
|
||||
else:
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f" 转换DataFrame失败: {e}")
|
||||
return None
|
||||
|
||||
def filter_stocks(self, df: pd.DataFrame,
|
||||
max_range_change: float = 30.0,
|
||||
min_market_cap: float = 50.0,
|
||||
max_market_cap: float = 1300.0) -> pd.DataFrame:
|
||||
"""
|
||||
智能筛选股票
|
||||
|
||||
Args:
|
||||
df: 原始数据
|
||||
max_range_change: 区间涨跌幅上限(%),默认30%
|
||||
min_market_cap: 最小市值(亿),默认50亿
|
||||
max_market_cap: 最大市值(亿),默认1300亿
|
||||
|
||||
Returns:
|
||||
筛选后的DataFrame
|
||||
"""
|
||||
if df is None or df.empty:
|
||||
return df
|
||||
|
||||
print(f"\n{'='*60}")
|
||||
print(f"🔍 智能筛选中...")
|
||||
print(f"{'='*60}")
|
||||
print(f"筛选条件:")
|
||||
print(f" - 区间涨跌幅 < {max_range_change}%")
|
||||
print(f" - 市值范围: {min_market_cap}-{max_market_cap}亿")
|
||||
|
||||
original_count = len(df)
|
||||
filtered_df = df.copy()
|
||||
|
||||
# 1. 筛选区间涨跌幅(智能匹配列名)
|
||||
# 优先精确匹配,按优先级查找
|
||||
interval_pct_col = None
|
||||
possible_interval_pct_names = [
|
||||
'区间涨跌幅:前复权',
|
||||
'区间涨跌幅:前复权(%)',
|
||||
'区间涨跌幅(%)',
|
||||
'区间涨跌幅',
|
||||
'涨跌幅:前复权',
|
||||
'涨跌幅:前复权(%)',
|
||||
'涨跌幅(%)',
|
||||
'涨跌幅'
|
||||
]
|
||||
|
||||
# 优先精确匹配
|
||||
for name in possible_interval_pct_names:
|
||||
for col in df.columns:
|
||||
if name in col:
|
||||
interval_pct_col = col
|
||||
break
|
||||
if interval_pct_col:
|
||||
break
|
||||
|
||||
if interval_pct_col:
|
||||
print(f"\n使用字段: {interval_pct_col}")
|
||||
|
||||
# 转换为数值并筛选
|
||||
filtered_df[interval_pct_col] = pd.to_numeric(filtered_df[interval_pct_col], errors='coerce')
|
||||
before = len(filtered_df)
|
||||
filtered_df = filtered_df[
|
||||
(filtered_df[interval_pct_col].notna()) &
|
||||
(filtered_df[interval_pct_col] < max_range_change)
|
||||
]
|
||||
print(f" 区间涨跌幅筛选: {before} -> {len(filtered_df)} 只")
|
||||
else:
|
||||
print(f" ⚠️ 未找到区间涨跌幅字段,跳过涨跌幅筛选")
|
||||
print(f" 可用字段: {list(df.columns[:10])}")
|
||||
|
||||
# 2. 筛选市值
|
||||
market_cap_cols = [col for col in df.columns if '总市值' in col or '市值' in col]
|
||||
if market_cap_cols:
|
||||
col_name = market_cap_cols[0]
|
||||
print(f"\n使用字段: {col_name}")
|
||||
|
||||
# 转换为数值(单位可能是亿或元)
|
||||
filtered_df[col_name] = pd.to_numeric(filtered_df[col_name], errors='coerce')
|
||||
|
||||
# 判断单位(如果值很大,可能是元)
|
||||
max_val = filtered_df[col_name].max()
|
||||
if max_val > 100000: # 大于10万,认为是元
|
||||
print(f" 检测到单位为元,转换为亿")
|
||||
filtered_df[col_name] = filtered_df[col_name] / 100000000
|
||||
|
||||
before = len(filtered_df)
|
||||
filtered_df = filtered_df[
|
||||
(filtered_df[col_name].notna()) &
|
||||
(filtered_df[col_name] >= min_market_cap) &
|
||||
(filtered_df[col_name] <= max_market_cap)
|
||||
]
|
||||
print(f" 市值筛选: {before} -> {len(filtered_df)} 只")
|
||||
|
||||
# 3. 去除ST股票(额外保险)
|
||||
if '股票简称' in filtered_df.columns:
|
||||
before = len(filtered_df)
|
||||
filtered_df = filtered_df[~filtered_df['股票简称'].str.contains('ST', na=False)]
|
||||
if before != len(filtered_df):
|
||||
print(f" ST股票过滤: {before} -> {len(filtered_df)} 只")
|
||||
|
||||
print(f"\n筛选完成: {original_count} -> {len(filtered_df)} 只股票")
|
||||
|
||||
self.filtered_stocks = filtered_df
|
||||
return filtered_df
|
||||
|
||||
def get_top_stocks(self, df: pd.DataFrame, top_n: int = 20) -> pd.DataFrame:
|
||||
"""
|
||||
获取主力资金净流入最多的前N只股票
|
||||
|
||||
Args:
|
||||
df: 筛选后的数据
|
||||
top_n: 取前N名,默认20
|
||||
|
||||
Returns:
|
||||
前N名股票DataFrame
|
||||
"""
|
||||
if df is None or df.empty:
|
||||
return df
|
||||
|
||||
# 查找主力资金相关列(智能匹配)
|
||||
main_fund_col = None
|
||||
main_fund_patterns = [
|
||||
'区间主力资金流向', # 实际列名
|
||||
'区间主力资金净流入',
|
||||
'主力资金流向',
|
||||
'主力资金净流入',
|
||||
'主力净流入'
|
||||
]
|
||||
for pattern in main_fund_patterns:
|
||||
matching = [col for col in df.columns if pattern in col]
|
||||
if matching:
|
||||
main_fund_col = matching[0]
|
||||
break
|
||||
|
||||
if main_fund_col:
|
||||
print(f"\n使用字段排序: {main_fund_col}")
|
||||
|
||||
# 转换为数值并排序
|
||||
df[main_fund_col] = pd.to_numeric(df[main_fund_col], errors='coerce')
|
||||
top_df = df.nlargest(top_n, main_fund_col)
|
||||
|
||||
print(f"获取主力资金净流入前 {len(top_df)} 名")
|
||||
return top_df
|
||||
else:
|
||||
# 如果没有主力资金列,直接返回前N条
|
||||
print(f"未找到主力资金列,返回前{top_n}条数据")
|
||||
return df.head(top_n)
|
||||
|
||||
def format_stock_list_for_analysis(self, df: pd.DataFrame) -> List[Dict]:
|
||||
"""
|
||||
格式化股票列表,准备提交给AI分析师
|
||||
|
||||
Args:
|
||||
df: 股票数据DataFrame
|
||||
|
||||
Returns:
|
||||
格式化后的股票列表
|
||||
"""
|
||||
if df is None or df.empty:
|
||||
return []
|
||||
|
||||
stock_list = []
|
||||
|
||||
for idx, row in df.iterrows():
|
||||
stock_data = {
|
||||
'symbol': row.get('股票代码', 'N/A'),
|
||||
'name': row.get('股票简称', 'N/A'),
|
||||
'industry': row.get('所属同花顺行业', row.get('所属行业', 'N/A')),
|
||||
'market_cap': row.get('总市值[20241209]', row.get('总市值', 'N/A')),
|
||||
'range_change': None,
|
||||
'main_fund_inflow': None,
|
||||
'pe_ratio': row.get('市盈率', 'N/A'),
|
||||
'pb_ratio': row.get('市净率', 'N/A'),
|
||||
'revenue': row.get('营业收入', row.get('营收', 'N/A')),
|
||||
'net_profit': row.get('净利润', 'N/A'),
|
||||
'scores': {},
|
||||
'raw_data': row.to_dict()
|
||||
}
|
||||
|
||||
# 提取区间涨跌幅(使用智能匹配)
|
||||
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:
|
||||
stock_data['range_change'] = row.get(interval_pct_col, 'N/A')
|
||||
|
||||
# 提取主力资金(智能匹配)
|
||||
main_fund_col = None
|
||||
main_fund_patterns = [
|
||||
'区间主力资金流向', '区间主力资金净流入',
|
||||
'主力资金流向', '主力资金净流入', '主力净流入'
|
||||
]
|
||||
for pattern in main_fund_patterns:
|
||||
matching = [col for col in df.columns if pattern in col]
|
||||
if matching:
|
||||
main_fund_col = matching[0]
|
||||
break
|
||||
if main_fund_col:
|
||||
stock_data['main_fund_inflow'] = row.get(main_fund_col, 'N/A')
|
||||
|
||||
# 提取评分
|
||||
score_keywords = ['评分', '能力']
|
||||
for col in df.columns:
|
||||
if any(keyword in col for keyword in score_keywords):
|
||||
stock_data['scores'][col] = row.get(col, 'N/A')
|
||||
|
||||
stock_list.append(stock_data)
|
||||
|
||||
return stock_list
|
||||
|
||||
def print_stock_summary(self, stock_list: List[Dict]):
|
||||
"""打印股票摘要信息"""
|
||||
print(f"\n{'='*80}")
|
||||
print(f"📊 候选股票列表 ({len(stock_list)}只)")
|
||||
print(f"{'='*80}")
|
||||
print(f"{'序号':<4} {'代码':<8} {'名称':<12} {'行业':<15} {'主力资金':<12} {'涨跌幅':<8}")
|
||||
print(f"{'-'*80}")
|
||||
|
||||
for i, stock in enumerate(stock_list, 1):
|
||||
symbol = stock['symbol']
|
||||
name = stock['name'][:10] if isinstance(stock['name'], str) else 'N/A'
|
||||
industry = stock['industry'][:13] if isinstance(stock['industry'], str) else 'N/A'
|
||||
|
||||
# 格式化主力资金
|
||||
main_fund = stock['main_fund_inflow']
|
||||
if isinstance(main_fund, (int, float)):
|
||||
if abs(main_fund) >= 100000000: # 大于1亿
|
||||
main_fund_str = f"{main_fund/100000000:.2f}亿"
|
||||
else:
|
||||
main_fund_str = f"{main_fund/10000:.2f}万"
|
||||
else:
|
||||
main_fund_str = 'N/A'
|
||||
|
||||
# 格式化涨跌幅
|
||||
change = stock['range_change']
|
||||
if isinstance(change, (int, float)):
|
||||
change_str = f"{change:.2f}%"
|
||||
else:
|
||||
change_str = 'N/A'
|
||||
|
||||
print(f"{i:<4} {symbol:<8} {name:<12} {industry:<15} {main_fund_str:<12} {change_str:<8}")
|
||||
|
||||
print(f"{'='*80}\n")
|
||||
|
||||
# 全局实例
|
||||
main_force_selector = MainForceStockSelector()
|
||||
|
||||
@@ -0,0 +1,419 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
主力选股UI模块
|
||||
"""
|
||||
|
||||
import streamlit as st
|
||||
from datetime import datetime, timedelta
|
||||
from main_force_analysis import MainForceAnalyzer
|
||||
from main_force_pdf_generator import display_report_download_section
|
||||
import pandas as pd
|
||||
|
||||
def display_main_force_selector():
|
||||
"""显示主力选股界面"""
|
||||
|
||||
st.markdown("## 🎯 主力选股 - 智能筛选优质标的")
|
||||
st.markdown("---")
|
||||
|
||||
st.markdown("""
|
||||
### 功能说明
|
||||
|
||||
本功能通过以下步骤筛选优质股票:
|
||||
|
||||
1. **数据获取**: 使用问财获取指定日期以来主力资金净流入前100名股票
|
||||
2. **智能筛选**: 过滤掉涨幅过高、市值不符的股票
|
||||
3. **AI分析**: 调用资金流向、行业板块、财务基本面三大分析师团队
|
||||
4. **综合决策**: 资深研究员综合评估,精选3-5只优质标的
|
||||
|
||||
**筛选标准**:
|
||||
- ✅ 主力资金净流入较多
|
||||
- ✅ 区间涨跌幅适中(避免追高)
|
||||
- ✅ 财务基本面良好
|
||||
- ✅ 行业前景明朗
|
||||
- ✅ 综合素质优秀
|
||||
""")
|
||||
|
||||
st.markdown("---")
|
||||
|
||||
# 参数设置
|
||||
col1, col2, col3 = st.columns(3)
|
||||
|
||||
with col1:
|
||||
date_option = st.selectbox(
|
||||
"选择时间区间",
|
||||
["最近3个月", "最近6个月", "最近1年", "自定义日期"]
|
||||
)
|
||||
|
||||
if date_option == "最近3个月":
|
||||
days_ago = 90
|
||||
start_date = None
|
||||
elif date_option == "最近6个月":
|
||||
days_ago = 180
|
||||
start_date = None
|
||||
elif date_option == "最近1年":
|
||||
days_ago = 365
|
||||
start_date = None
|
||||
else:
|
||||
custom_date = st.date_input(
|
||||
"选择开始日期",
|
||||
value=datetime.now() - timedelta(days=90)
|
||||
)
|
||||
start_date = f"{custom_date.year}年{custom_date.month}月{custom_date.day}日"
|
||||
days_ago = None
|
||||
|
||||
with col2:
|
||||
final_n = st.slider(
|
||||
"最终精选数量",
|
||||
min_value=3,
|
||||
max_value=10,
|
||||
value=5,
|
||||
step=1,
|
||||
help="最终推荐的股票数量"
|
||||
)
|
||||
|
||||
with col3:
|
||||
st.info("💡 系统将获取前100名股票,进行整体分析后精选优质标的")
|
||||
|
||||
# 高级选项
|
||||
with st.expander("⚙️ 高级筛选参数"):
|
||||
col1, col2, col3 = st.columns(3)
|
||||
|
||||
with col1:
|
||||
max_change = st.number_input(
|
||||
"最大涨跌幅(%)",
|
||||
min_value=10.0,
|
||||
max_value=100.0,
|
||||
value=30.0,
|
||||
step=5.0,
|
||||
help="过滤掉涨幅过高的股票,避免追高"
|
||||
)
|
||||
|
||||
with col2:
|
||||
min_cap = st.number_input(
|
||||
"最小市值(亿)",
|
||||
min_value=10.0,
|
||||
max_value=500.0,
|
||||
value=50.0,
|
||||
step=10.0
|
||||
)
|
||||
|
||||
with col3:
|
||||
max_cap = st.number_input(
|
||||
"最大市值(亿)",
|
||||
min_value=100.0,
|
||||
max_value=50000.0,
|
||||
value=5000.0,
|
||||
step=100.0
|
||||
)
|
||||
|
||||
# 模型选择
|
||||
model = st.selectbox(
|
||||
"选择AI模型",
|
||||
["deepseek-chat", "deepseek-reasoner"],
|
||||
help="deepseek-chat速度快,deepseek-reasoner推理能力强"
|
||||
)
|
||||
|
||||
st.markdown("---")
|
||||
|
||||
# 开始分析按钮
|
||||
if st.button("🚀 开始主力选股", type="primary", use_container_width=True):
|
||||
|
||||
with st.spinner("正在获取数据并分析,这可能需要几分钟..."):
|
||||
|
||||
# 创建分析器
|
||||
analyzer = MainForceAnalyzer(model=model)
|
||||
|
||||
# 运行分析
|
||||
result = analyzer.run_full_analysis(
|
||||
start_date=start_date,
|
||||
days_ago=days_ago,
|
||||
final_n=final_n
|
||||
)
|
||||
|
||||
# 保存结果到session_state
|
||||
st.session_state.main_force_result = result
|
||||
st.session_state.main_force_analyzer = analyzer
|
||||
|
||||
# 显示结果
|
||||
if result['success']:
|
||||
st.success(f"✅ 分析完成!共筛选出 {len(result['final_recommendations'])} 只优质标的")
|
||||
st.rerun()
|
||||
else:
|
||||
st.error(f"❌ 分析失败: {result.get('error', '未知错误')}")
|
||||
|
||||
# 显示分析结果
|
||||
if 'main_force_result' in st.session_state:
|
||||
result = st.session_state.main_force_result
|
||||
|
||||
if result['success']:
|
||||
display_analysis_results(result, st.session_state.get('main_force_analyzer'))
|
||||
|
||||
def display_analysis_results(result: dict, analyzer):
|
||||
"""显示分析结果"""
|
||||
|
||||
st.markdown("---")
|
||||
st.markdown("## 📊 分析结果")
|
||||
|
||||
# 统计信息
|
||||
col1, col2, col3 = st.columns(3)
|
||||
|
||||
with col1:
|
||||
st.metric("获取股票数", result['total_stocks'])
|
||||
|
||||
with col2:
|
||||
st.metric("筛选后", result['filtered_stocks'])
|
||||
|
||||
with col3:
|
||||
st.metric("最终推荐", len(result['final_recommendations']))
|
||||
|
||||
st.markdown("---")
|
||||
|
||||
# 显示AI分析师完整报告
|
||||
if analyzer and hasattr(analyzer, 'fund_flow_analysis'):
|
||||
display_analyst_reports(analyzer)
|
||||
|
||||
st.markdown("---")
|
||||
|
||||
# 显示推荐股票
|
||||
if result['final_recommendations']:
|
||||
st.markdown("### ⭐ 精选推荐")
|
||||
|
||||
for rec in result['final_recommendations']:
|
||||
with st.expander(
|
||||
f"【第{rec['rank']}名】{rec['symbol']} - {rec['name']}",
|
||||
expanded=(rec['rank'] <= 3)
|
||||
):
|
||||
display_recommendation_detail(rec)
|
||||
|
||||
# 显示候选股票列表
|
||||
if analyzer and analyzer.raw_stocks is not None and not analyzer.raw_stocks.empty:
|
||||
st.markdown("---")
|
||||
st.markdown("### 📋 候选股票列表(筛选后)")
|
||||
|
||||
# 选择关键列显示
|
||||
display_cols = ['股票代码', '股票简称']
|
||||
|
||||
# 添加行业列
|
||||
industry_cols = [col for col in analyzer.raw_stocks.columns if '行业' in col]
|
||||
if industry_cols:
|
||||
display_cols.append(industry_cols[0])
|
||||
|
||||
# 添加区间主力资金净流入(智能匹配)
|
||||
main_fund_col = None
|
||||
main_fund_patterns = [
|
||||
'区间主力资金流向', # 实际列名
|
||||
'区间主力资金净流入',
|
||||
'主力资金流向',
|
||||
'主力资金净流入',
|
||||
'主力净流入',
|
||||
'主力资金'
|
||||
]
|
||||
for pattern in main_fund_patterns:
|
||||
matching = [col for col in analyzer.raw_stocks.columns if pattern in col]
|
||||
if matching:
|
||||
main_fund_col = matching[0]
|
||||
break
|
||||
if main_fund_col:
|
||||
display_cols.append(main_fund_col)
|
||||
|
||||
# 添加区间涨跌幅(前复权)(智能匹配)
|
||||
interval_pct_col = None
|
||||
interval_pct_patterns = [
|
||||
'区间涨跌幅:前复权', '区间涨跌幅:前复权(%)', '区间涨跌幅(%)',
|
||||
'区间涨跌幅', '涨跌幅:前复权', '涨跌幅:前复权(%)', '涨跌幅(%)', '涨跌幅'
|
||||
]
|
||||
for pattern in interval_pct_patterns:
|
||||
matching = [col for col in analyzer.raw_stocks.columns if pattern in col]
|
||||
if matching:
|
||||
interval_pct_col = matching[0]
|
||||
break
|
||||
if interval_pct_col:
|
||||
display_cols.append(interval_pct_col)
|
||||
|
||||
# 添加市值、市盈率、市净率
|
||||
for col_name in ['总市值', '市盈率', '市净率']:
|
||||
matching_cols = [col for col in analyzer.raw_stocks.columns if col_name in col]
|
||||
if matching_cols:
|
||||
display_cols.append(matching_cols[0])
|
||||
|
||||
# 选择存在的列
|
||||
final_cols = [col for col in display_cols if col in analyzer.raw_stocks.columns]
|
||||
|
||||
# 调试信息:显示找到的列名
|
||||
with st.expander("🔍 调试信息 - 查看数据列", expanded=False):
|
||||
st.caption("所有可用列:")
|
||||
cols_list = list(analyzer.raw_stocks.columns)
|
||||
st.write(cols_list)
|
||||
st.caption(f"\n已选择显示的列: {final_cols}")
|
||||
if main_fund_col:
|
||||
st.success(f"✅ 找到主力资金列: {main_fund_col}")
|
||||
else:
|
||||
st.warning("⚠️ 未找到主力资金列")
|
||||
if interval_pct_col:
|
||||
st.success(f"✅ 找到涨跌幅列: {interval_pct_col}")
|
||||
else:
|
||||
st.warning("⚠️ 未找到涨跌幅列")
|
||||
|
||||
# 显示DataFrame
|
||||
display_df = analyzer.raw_stocks[final_cols].copy()
|
||||
st.dataframe(display_df, use_container_width=True, height=400)
|
||||
|
||||
# 显示统计
|
||||
st.caption(f"共 {len(display_df)} 只候选股票,显示 {len(final_cols)} 个字段")
|
||||
|
||||
# 下载按钮
|
||||
csv = display_df.to_csv(index=False, encoding='utf-8-sig')
|
||||
st.download_button(
|
||||
label="📥 下载候选列表CSV",
|
||||
data=csv,
|
||||
file_name=f"main_force_stocks_{datetime.now().strftime('%Y%m%d')}.csv",
|
||||
mime="text/csv"
|
||||
)
|
||||
|
||||
# 显示PDF报告下载区域
|
||||
if analyzer and result:
|
||||
display_report_download_section(analyzer, result)
|
||||
|
||||
def display_recommendation_detail(rec: dict):
|
||||
"""显示单个推荐股票的详细信息"""
|
||||
|
||||
col1, col2 = st.columns([1, 1])
|
||||
|
||||
with col1:
|
||||
st.markdown("#### 📌 推荐理由")
|
||||
for reason in rec.get('reasons', []):
|
||||
st.markdown(f"- {reason}")
|
||||
|
||||
st.markdown("#### 💡 投资亮点")
|
||||
st.info(rec.get('highlights', 'N/A'))
|
||||
|
||||
with col2:
|
||||
st.markdown("#### 📊 投资建议")
|
||||
st.markdown(f"**建议仓位**: {rec.get('position', 'N/A')}")
|
||||
st.markdown(f"**投资周期**: {rec.get('investment_period', 'N/A')}")
|
||||
|
||||
st.markdown("#### ⚠️ 风险提示")
|
||||
st.warning(rec.get('risks', 'N/A'))
|
||||
|
||||
# 显示股票详细数据
|
||||
if 'stock_data' in rec:
|
||||
st.markdown("---")
|
||||
st.markdown("#### 📊 股票详细数据")
|
||||
|
||||
stock_data = rec['stock_data']
|
||||
|
||||
# 创建数据展示
|
||||
col1, col2, col3 = st.columns(3)
|
||||
|
||||
with col1:
|
||||
st.metric("股票代码", stock_data.get('股票代码', 'N/A'))
|
||||
|
||||
# 显示行业
|
||||
industry_keys = [k for k in stock_data.keys() if '行业' in k]
|
||||
if industry_keys:
|
||||
st.metric("所属行业", stock_data.get(industry_keys[0], 'N/A'))
|
||||
|
||||
with col2:
|
||||
# 显示主力资金
|
||||
fund_keys = [k for k in stock_data.keys() if '主力' in k and '净流入' in k]
|
||||
if fund_keys:
|
||||
fund_value = stock_data.get(fund_keys[0], 'N/A')
|
||||
if isinstance(fund_value, (int, float)):
|
||||
st.metric("主力资金净流入", f"{fund_value/100000000:.2f}亿")
|
||||
else:
|
||||
st.metric("主力资金净流入", str(fund_value))
|
||||
|
||||
with col3:
|
||||
# 显示涨跌幅
|
||||
change_keys = [k for k in stock_data.keys() if '涨跌幅' in k]
|
||||
if change_keys:
|
||||
change_value = stock_data.get(change_keys[0], 'N/A')
|
||||
if isinstance(change_value, (int, float)):
|
||||
st.metric("区间涨跌幅", f"{change_value:.2f}%")
|
||||
else:
|
||||
st.metric("区间涨跌幅", str(change_value))
|
||||
|
||||
# 显示其他关键指标
|
||||
st.markdown("**其他关键指标:**")
|
||||
metrics_col1, metrics_col2, metrics_col3 = st.columns(3)
|
||||
|
||||
with metrics_col1:
|
||||
if '市盈率' in stock_data or any('市盈率' in k for k in stock_data.keys()):
|
||||
pe_keys = [k for k in stock_data.keys() if '市盈率' in k]
|
||||
if pe_keys:
|
||||
st.caption(f"市盈率: {stock_data.get(pe_keys[0], 'N/A')}")
|
||||
|
||||
with metrics_col2:
|
||||
if '市净率' in stock_data or any('市净率' in k for k in stock_data.keys()):
|
||||
pb_keys = [k for k in stock_data.keys() if '市净率' in k]
|
||||
if pb_keys:
|
||||
st.caption(f"市净率: {stock_data.get(pb_keys[0], 'N/A')}")
|
||||
|
||||
with metrics_col3:
|
||||
if '总市值' in stock_data or any('总市值' in k for k in stock_data.keys()):
|
||||
cap_keys = [k for k in stock_data.keys() if '总市值' in k]
|
||||
if cap_keys:
|
||||
st.caption(f"总市值: {stock_data.get(cap_keys[0], 'N/A')}")
|
||||
|
||||
def display_analyst_reports(analyzer):
|
||||
"""显示AI分析师完整报告"""
|
||||
|
||||
st.markdown("### 🤖 AI分析师团队完整报告")
|
||||
|
||||
# 创建三个标签页
|
||||
tab1, tab2, tab3 = st.tabs(["💰 资金流向分析", "📊 行业板块分析", "📈 财务基本面分析"])
|
||||
|
||||
with tab1:
|
||||
st.markdown("#### 💰 资金流向分析师报告")
|
||||
st.markdown("---")
|
||||
if hasattr(analyzer, 'fund_flow_analysis') and analyzer.fund_flow_analysis:
|
||||
st.markdown(analyzer.fund_flow_analysis)
|
||||
else:
|
||||
st.info("暂无资金流向分析报告")
|
||||
|
||||
with tab2:
|
||||
st.markdown("#### 📊 行业板块及市场热点分析师报告")
|
||||
st.markdown("---")
|
||||
if hasattr(analyzer, 'industry_analysis') and analyzer.industry_analysis:
|
||||
st.markdown(analyzer.industry_analysis)
|
||||
else:
|
||||
st.info("暂无行业板块分析报告")
|
||||
|
||||
with tab3:
|
||||
st.markdown("#### 📈 财务基本面分析师报告")
|
||||
st.markdown("---")
|
||||
if hasattr(analyzer, 'fundamental_analysis') and analyzer.fundamental_analysis:
|
||||
st.markdown(analyzer.fundamental_analysis)
|
||||
else:
|
||||
st.info("暂无财务基本面分析报告")
|
||||
|
||||
def format_number(value, unit='', suffix=''):
|
||||
"""格式化数字显示"""
|
||||
if value is None or value == 'N/A':
|
||||
return 'N/A'
|
||||
|
||||
try:
|
||||
num = float(value)
|
||||
|
||||
# 如果单位是亿,需要转换
|
||||
if unit == '亿':
|
||||
if abs(num) >= 100000000: # 大于1亿(以元为单位)
|
||||
num = num / 100000000
|
||||
elif abs(num) < 100: # 小于100,可能已经是亿
|
||||
pass
|
||||
else: # 100-100000000之间,可能是万
|
||||
num = num / 10000
|
||||
|
||||
# 格式化显示
|
||||
if abs(num) >= 1000:
|
||||
formatted = f"{num:,.2f}"
|
||||
elif abs(num) >= 1:
|
||||
formatted = f"{num:.2f}"
|
||||
else:
|
||||
formatted = f"{num:.4f}"
|
||||
|
||||
return f"{formatted}{suffix}"
|
||||
except (ValueError, TypeError):
|
||||
return str(value)
|
||||
|
||||
+3
-2
@@ -249,8 +249,9 @@ def display_pdf_export_section(stock_info, agents_results, discussion_result, fi
|
||||
col1, col2, col3 = st.columns([1, 2, 1])
|
||||
|
||||
with col2:
|
||||
# 生成PDF报告按钮
|
||||
if st.button("📄 生成并下载PDF报告", type="primary", use_container_width=True):
|
||||
# 生成PDF报告按钮(使用股票代码作为key的一部分,确保唯一性)
|
||||
button_key = f"pdf_btn_{stock_info.get('symbol', 'unknown')}"
|
||||
if st.button("📄 生成并下载PDF报告", type="primary", use_container_width=True, key=button_key):
|
||||
with st.spinner("正在生成PDF报告..."):
|
||||
try:
|
||||
# 生成PDF内容
|
||||
|
||||
+76
-13
@@ -463,20 +463,14 @@ class StockDataFetcher:
|
||||
except Exception as e:
|
||||
print(f"获取财务指标失败: {e}")
|
||||
|
||||
# 5. 获取季度业绩(尝试不同API)
|
||||
# 5. 获取季度业绩(使用问财)
|
||||
try:
|
||||
# 尝试获取业绩预告
|
||||
quarter_data = ak.stock_profit_forecast_em(symbol=symbol)
|
||||
if quarter_data is not None and not quarter_data.empty:
|
||||
financial_data["quarter_data"] = quarter_data.head(4).to_dict('records')
|
||||
except:
|
||||
try:
|
||||
# 备用方案:获取季度财报
|
||||
quarter_data = ak.stock_financial_report_sina(stock=symbol, symbol="季报")
|
||||
if quarter_data is not None and not quarter_data.empty:
|
||||
financial_data["quarter_data"] = quarter_data.head(4).to_dict('records')
|
||||
except Exception as e:
|
||||
print(f"获取季度数据失败: {e}")
|
||||
# 使用pywencai获取季报数据
|
||||
quarter_data = self._get_quarter_data_from_wencai(symbol)
|
||||
if quarter_data:
|
||||
financial_data["quarter_data"] = quarter_data
|
||||
except Exception as e:
|
||||
print(f"获取季度数据失败: {e}")
|
||||
|
||||
return financial_data
|
||||
|
||||
@@ -484,6 +478,75 @@ class StockDataFetcher:
|
||||
print(f"获取中国股票财务数据失败: {e}")
|
||||
return financial_data
|
||||
|
||||
def _get_quarter_data_from_wencai(self, symbol):
|
||||
"""使用问财获取季报数据 - 直接返回原始数据给AI分析"""
|
||||
try:
|
||||
# 构建查询语句 - 获取最近4个季度的数据
|
||||
query = f"{symbol}最近4个季度的营业收入、净利润、每股收益、净资产收益率、营业收入同比增长率、净利润同比增长率"
|
||||
|
||||
# 使用pywencai查询
|
||||
print(f"正在使用问财获取 {symbol} 的季报数据...")
|
||||
result = pywencai.get(question=query, perpage=10)
|
||||
|
||||
# 检查返回类型
|
||||
if result is None:
|
||||
print(f"问财未返回 {symbol} 的季报数据")
|
||||
return None
|
||||
|
||||
# 处理不同返回类型
|
||||
quarter_data = None
|
||||
|
||||
# 如果返回的是DataFrame
|
||||
if isinstance(result, pd.DataFrame):
|
||||
if result.empty:
|
||||
print(f"问财返回的DataFrame为空")
|
||||
return None
|
||||
|
||||
print(f" 问财返回DataFrame,共 {len(result)} 行数据")
|
||||
print(f" 列名: {list(result.columns)}")
|
||||
|
||||
# 将DataFrame转为字典列表,保留所有原始数据
|
||||
quarter_data = {
|
||||
'data_type': 'dataframe',
|
||||
'columns': list(result.columns),
|
||||
'records': result.head(10).to_dict('records'), # 最多取10条
|
||||
'row_count': len(result),
|
||||
'summary': f"获取到{len(result)}条季报相关数据"
|
||||
}
|
||||
|
||||
# 如果返回的是字典
|
||||
elif isinstance(result, dict):
|
||||
print(f" 问财返回字典数据")
|
||||
print(f" 字典键: {list(result.keys())}")
|
||||
|
||||
quarter_data = {
|
||||
'data_type': 'dict',
|
||||
'raw_data': result,
|
||||
'summary': f"获取到季报字典数据,包含 {len(result)} 个字段"
|
||||
}
|
||||
|
||||
# 其他类型
|
||||
else:
|
||||
print(f" 问财返回未知类型: {type(result)}")
|
||||
quarter_data = {
|
||||
'data_type': 'unknown',
|
||||
'raw_data': str(result),
|
||||
'summary': f"获取到季报数据,类型: {type(result).__name__}"
|
||||
}
|
||||
|
||||
if quarter_data:
|
||||
print(f"✅ 成功获取季报数据,将原始数据交由AI分析师处理")
|
||||
return quarter_data
|
||||
else:
|
||||
print(f"⚠️ 未能获取有效的季报数据")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
print(f"使用问财获取季报数据失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return None
|
||||
|
||||
def _get_us_financial_data(self, symbol):
|
||||
"""获取美股财务数据"""
|
||||
financial_data = {
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
主力选股功能测试脚本
|
||||
快速验证功能是否正常工作
|
||||
"""
|
||||
|
||||
import sys
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
def test_imports():
|
||||
"""测试模块导入"""
|
||||
print("="*60)
|
||||
print("测试1: 检查模块导入")
|
||||
print("="*60)
|
||||
|
||||
try:
|
||||
print("导入 pywencai...", end=" ")
|
||||
import pywencai
|
||||
print("✅")
|
||||
except Exception as e:
|
||||
print(f"❌ {e}")
|
||||
return False
|
||||
|
||||
try:
|
||||
print("导入 main_force_selector...", end=" ")
|
||||
from main_force_selector import main_force_selector
|
||||
print("✅")
|
||||
except Exception as e:
|
||||
print(f"❌ {e}")
|
||||
return False
|
||||
|
||||
try:
|
||||
print("导入 main_force_analysis...", end=" ")
|
||||
from main_force_analysis import MainForceAnalyzer
|
||||
print("✅")
|
||||
except Exception as e:
|
||||
print(f"❌ {e}")
|
||||
return False
|
||||
|
||||
try:
|
||||
print("导入 main_force_ui...", end=" ")
|
||||
from main_force_ui import display_main_force_selector
|
||||
print("✅")
|
||||
except Exception as e:
|
||||
print(f"❌ {e}")
|
||||
return False
|
||||
|
||||
print("\n✅ 所有模块导入成功!\n")
|
||||
return True
|
||||
|
||||
def test_data_fetch():
|
||||
"""测试数据获取"""
|
||||
print("="*60)
|
||||
print("测试2: 测试数据获取功能")
|
||||
print("="*60)
|
||||
|
||||
try:
|
||||
from main_force_selector import main_force_selector
|
||||
|
||||
# 使用较短的时间范围进行测试
|
||||
print("\n尝试获取最近30天的主力资金数据...")
|
||||
success, data, message = main_force_selector.get_main_force_stocks(days_ago=30)
|
||||
|
||||
if success:
|
||||
print(f"\n✅ 数据获取成功!")
|
||||
print(f" 获取到 {len(data)} 只股票")
|
||||
print(f"\n前5只股票:")
|
||||
print(data.head(5) if len(data) > 0 else "无数据")
|
||||
return True
|
||||
else:
|
||||
print(f"\n❌ 数据获取失败: {message}")
|
||||
print("\n可能原因:")
|
||||
print(" 1. 网络连接问题")
|
||||
print(" 2. pywencai服务暂时不可用")
|
||||
print(" 3. 需要安装Node.js >= 16.0")
|
||||
print("\n请检查:")
|
||||
print(" - 网络连接是否正常")
|
||||
print(" - Node.js版本: node --version")
|
||||
print(" - pywencai是否正确安装: pip list | findstr pywencai")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"\n❌ 测试过程出错: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def test_filter():
|
||||
"""测试筛选功能"""
|
||||
print("\n" + "="*60)
|
||||
print("测试3: 测试筛选功能")
|
||||
print("="*60)
|
||||
|
||||
try:
|
||||
from main_force_selector import main_force_selector
|
||||
import pandas as pd
|
||||
|
||||
# 创建测试数据
|
||||
test_data = pd.DataFrame({
|
||||
'股票代码': ['000001', '000002', '600519', '300750'],
|
||||
'股票简称': ['平安银行', '万科A', '贵州茅台', '宁德时代'],
|
||||
'区间涨跌幅': [15.5, 35.8, 12.3, 28.9],
|
||||
'总市值': [3000, 2500, 25000, 9000],
|
||||
'主力资金净流入': [50000000, 80000000, 120000000, 95000000]
|
||||
})
|
||||
|
||||
print("\n原始测试数据:")
|
||||
print(test_data)
|
||||
|
||||
print("\n应用筛选条件:")
|
||||
print(" - 区间涨跌幅 < 30%")
|
||||
print(" - 市值 50-1300亿")
|
||||
|
||||
filtered_data = main_force_selector.filter_stocks(
|
||||
test_data,
|
||||
max_range_change=30.0,
|
||||
min_market_cap=50.0,
|
||||
max_market_cap=1300.0
|
||||
)
|
||||
|
||||
print("\n筛选后数据:")
|
||||
print(filtered_data)
|
||||
|
||||
print("\n✅ 筛选功能正常!")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"\n❌ 筛选测试失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def test_ai_analysis():
|
||||
"""测试AI分析(需要API配置)"""
|
||||
print("\n" + "="*60)
|
||||
print("测试4: 测试AI分析功能")
|
||||
print("="*60)
|
||||
|
||||
try:
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
api_key = os.getenv('DEEPSEEK_API_KEY')
|
||||
if not api_key:
|
||||
print("\n⚠️ 未配置DEEPSEEK_API_KEY,跳过AI分析测试")
|
||||
print(" 请在.env文件中配置API密钥后再测试AI功能")
|
||||
return None
|
||||
|
||||
print("\n✅ API密钥已配置")
|
||||
print(" 如需测试完整AI分析,请运行主程序")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"\n⚠️ {e}")
|
||||
return None
|
||||
|
||||
def main():
|
||||
"""主测试函数"""
|
||||
print("\n" + "="*80)
|
||||
print(" "*20 + "主力选股功能测试")
|
||||
print("="*80 + "\n")
|
||||
|
||||
results = []
|
||||
|
||||
# 测试1: 模块导入
|
||||
result1 = test_imports()
|
||||
results.append(("模块导入", result1))
|
||||
|
||||
if not result1:
|
||||
print("\n❌ 模块导入失败,请先安装依赖:")
|
||||
print(" pip install pywencai pandas streamlit")
|
||||
return
|
||||
|
||||
# 测试2: 数据获取
|
||||
result2 = test_data_fetch()
|
||||
results.append(("数据获取", result2))
|
||||
|
||||
# 测试3: 筛选功能
|
||||
result3 = test_filter()
|
||||
results.append(("数据筛选", result3))
|
||||
|
||||
# 测试4: AI分析
|
||||
result4 = test_ai_analysis()
|
||||
if result4 is not None:
|
||||
results.append(("AI分析", result4))
|
||||
|
||||
# 总结
|
||||
print("\n" + "="*80)
|
||||
print(" "*30 + "测试总结")
|
||||
print("="*80 + "\n")
|
||||
|
||||
for test_name, result in results:
|
||||
status = "✅ 通过" if result else "❌ 失败"
|
||||
print(f"{test_name:<15} {status}")
|
||||
|
||||
passed = sum(1 for _, r in results if r)
|
||||
total = len(results)
|
||||
|
||||
print(f"\n总计: {passed}/{total} 项测试通过")
|
||||
|
||||
if passed == total:
|
||||
print("\n🎉 恭喜!所有测试通过,主力选股功能可以正常使用!")
|
||||
print("\n下一步:")
|
||||
print(" 1. 运行主程序: streamlit run app.py")
|
||||
print(" 2. 点击侧边栏的 '🎯 主力选股' 按钮")
|
||||
print(" 3. 设置参数并开始分析")
|
||||
else:
|
||||
print("\n⚠️ 部分测试未通过,请根据上述错误信息进行排查")
|
||||
print("\n常见问题:")
|
||||
print(" 1. 数据获取失败 → 检查网络和Node.js版本")
|
||||
print(" 2. 模块导入失败 → 检查依赖安装")
|
||||
print(" 3. API测试失败 → 检查.env配置")
|
||||
|
||||
print("\n" + "="*80 + "\n")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
+313
@@ -0,0 +1,313 @@
|
||||
# 主力选股功能 - 快速使用指南
|
||||
|
||||
## ✨ 核心特点
|
||||
|
||||
**整体批量分析,不是逐个分析!**
|
||||
|
||||
传统方式:获取100只股票 → 逐个分析(慢,费时)
|
||||
本系统:获取100只股票 → **整体分析** → 精选优质标的(快速高效)
|
||||
|
||||
## 🔄 工作流程
|
||||
|
||||
```
|
||||
1️⃣ 数据获取
|
||||
└─ 使用pywencai获取主力资金净流入前100名
|
||||
└─ 包含:资金、涨跌幅、行业、市值、财务等完整数据
|
||||
|
||||
2️⃣ 智能筛选
|
||||
└─ 涨幅过滤(<30%,避免追高)
|
||||
└─ 市值筛选(50-1300亿)
|
||||
└─ ST股过滤
|
||||
|
||||
3️⃣ 整体分析(核心创新!)
|
||||
├─ 💰 资金流向分析师
|
||||
│ └─ 分析整体资金流向特征
|
||||
│ └─ 识别板块资金集中度
|
||||
│ └─ 发现资金流入但涨幅不高的机会
|
||||
│
|
||||
├─ 📊 行业板块分析师
|
||||
│ └─ 识别当前热点板块
|
||||
│ └─ 分析板块轮动态势
|
||||
│ └─ 评估各行业发展前景
|
||||
│
|
||||
└─ 📈 财务基本面分析师
|
||||
└─ 评估整体财务质量
|
||||
└─ 筛选估值合理的标的
|
||||
└─ 关注成长性突出的股票
|
||||
|
||||
4️⃣ 综合决策
|
||||
└─ 资深研究员AI综合三位分析师意见
|
||||
└─ 从候选股票中精选3-5只最优标的
|
||||
└─ 给出详细推荐理由和风险提示
|
||||
```
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
### 步骤1:进入功能
|
||||
侧边栏点击 **🎯 主力选股**
|
||||
|
||||
### 步骤2:设置参数
|
||||
- **时间区间**:最近3个月(默认)
|
||||
- **精选数量**:5只(默认)
|
||||
- **AI模型**:deepseek-chat(快速)
|
||||
|
||||
### 步骤3:开始分析
|
||||
点击 **🚀 开始主力选股**
|
||||
|
||||
### 预期时间
|
||||
- 数据获取:30-60秒
|
||||
- 整体分析:1-2分钟
|
||||
- 总耗时:约2-3分钟(比逐个分析快10倍!)
|
||||
|
||||
## 📊 分析逻辑
|
||||
|
||||
### 为什么是"整体分析"?
|
||||
|
||||
**传统逐个分析的问题**:
|
||||
- ❌ 耗时长(100只股票 × 15秒 = 25分钟)
|
||||
- ❌ 成本高(大量API调用)
|
||||
- ❌ 缺乏全局视角
|
||||
|
||||
**整体分析的优势**:
|
||||
- ✅ 快速高效(2-3分钟完成)
|
||||
- ✅ 成本低(3次AI调用)
|
||||
- ✅ 宏观视角(板块热点、资金流向)
|
||||
- ✅ 更符合实际选股逻辑
|
||||
|
||||
### AI分析师如何工作?
|
||||
|
||||
#### 💰 资金流向分析师
|
||||
```
|
||||
看什么:
|
||||
- 哪些板块资金流入最多?
|
||||
- 主力资金的整体行为特征
|
||||
- 资金流入但涨幅不高的潜力股
|
||||
|
||||
输出:
|
||||
- 资金集中的热点板块
|
||||
- 值得关注的3-5只股票
|
||||
```
|
||||
|
||||
#### 📊 行业板块分析师
|
||||
```
|
||||
看什么:
|
||||
- 当前市场热点板块
|
||||
- 板块轮动和趋势
|
||||
- 行业发展前景
|
||||
|
||||
输出:
|
||||
- 热点行业识别
|
||||
- 板块机会评估
|
||||
- 推荐的优质板块标的
|
||||
```
|
||||
|
||||
#### 📈 财务基本面分析师
|
||||
```
|
||||
看什么:
|
||||
- 整体财务质量分布
|
||||
- 估值水平合理性
|
||||
- 成长性突出的股票
|
||||
|
||||
输出:
|
||||
- 基本面优秀的股票
|
||||
- 估值合理的标的
|
||||
- 财务风险提示
|
||||
```
|
||||
|
||||
## 🎯 筛选标准
|
||||
|
||||
### 数据层面
|
||||
- ✅ 主力资金净流入前100名
|
||||
- ✅ 区间涨跌幅 < 30%(避免追高)
|
||||
- ✅ 市值 50-1300亿(优质中盘)
|
||||
- ✅ 排除ST股
|
||||
|
||||
### 分析层面
|
||||
- ✅ 资金面:主力看好,持续流入
|
||||
- ✅ 行业面:热点板块,前景明朗
|
||||
- ✅ 基本面:财务健康,成长性好
|
||||
- ✅ 综合性:三方面都不错的均衡标的
|
||||
|
||||
## 📋 结果展示
|
||||
|
||||
### 精选推荐(3-5只)
|
||||
每只股票包含:
|
||||
- **推荐理由**(3-5条,综合三位分析师观点)
|
||||
- **投资亮点**(突出优势)
|
||||
- **风险提示**(需要注意的风险)
|
||||
- **建议仓位**(如20-30%)
|
||||
- **投资周期**(短期/中期/长期)
|
||||
- **详细数据**(主力资金、涨跌幅、行业等)
|
||||
|
||||
### 候选列表(筛选后所有股票)
|
||||
- 完整的数据表格
|
||||
- 可下载CSV格式
|
||||
- 方便进一步研究
|
||||
|
||||
## 💡 使用建议
|
||||
|
||||
### 最佳使用时机
|
||||
```
|
||||
周末(推荐)
|
||||
└─ 为下周交易做准备
|
||||
└─ 时间充裕,深入研究
|
||||
|
||||
月初
|
||||
└─ 调整持仓结构
|
||||
└─ 发现新的机会
|
||||
|
||||
热点出现时
|
||||
└─ 快速捕捉市场机会
|
||||
└─ 参数设置:最近1个月
|
||||
```
|
||||
|
||||
### 参数配置建议
|
||||
```
|
||||
保守型:
|
||||
时间:6个月
|
||||
涨幅:<20%
|
||||
精选:3只
|
||||
|
||||
平衡型(推荐):
|
||||
时间:3个月
|
||||
涨幅:<30%
|
||||
精选:5只
|
||||
|
||||
激进型:
|
||||
时间:1个月
|
||||
涨幅:<40%
|
||||
精选:8只
|
||||
```
|
||||
|
||||
### 后续操作
|
||||
```
|
||||
1. 查看精选推荐
|
||||
↓
|
||||
2. 阅读AI分析报告
|
||||
↓
|
||||
3. 查看候选列表完整数据
|
||||
↓
|
||||
4. 选择2-3只深入研究
|
||||
↓
|
||||
5. 查看K线和技术指标
|
||||
↓
|
||||
6. 周一择机建仓
|
||||
↓
|
||||
7. 加入实时监测
|
||||
```
|
||||
|
||||
## ⚠️ 注意事项
|
||||
|
||||
### 环境要求
|
||||
```bash
|
||||
Node.js >= 16.0 # 重要!pywencai依赖
|
||||
pywencai >= 0.7.0
|
||||
DEEPSEEK_API_KEY # 在.env中配置
|
||||
```
|
||||
|
||||
### 数据时效
|
||||
- 数据有1-2天延迟
|
||||
- 适合中短期投资
|
||||
- 不适合日内交易
|
||||
|
||||
### 市场环境
|
||||
- **牛市**:效果最佳,资金推动明显
|
||||
- **震荡**:关注短期机会
|
||||
- **熊市**:谨慎使用,关注防御性板块
|
||||
|
||||
## 🆚 对比说明
|
||||
|
||||
### 主力选股 vs 单个分析
|
||||
|
||||
| 特性 | 主力选股 | 单个分析 |
|
||||
|-----|---------|---------|
|
||||
| 分析对象 | 100只股票整体 | 1只股票 |
|
||||
| 分析视角 | 宏观(板块、热点) | 微观(个股) |
|
||||
| 耗时 | 2-3分钟 | 10-15秒/只 |
|
||||
| 适用场景 | 选股、发现机会 | 研究特定股票 |
|
||||
| 输出 | 3-5只精选标的 | 1只详细分析 |
|
||||
|
||||
### 何时使用?
|
||||
|
||||
**使用主力选股**:
|
||||
- ✅ 不知道买什么股票
|
||||
- ✅ 想发现市场热点
|
||||
- ✅ 需要批量筛选
|
||||
- ✅ 寻找新的投资机会
|
||||
|
||||
**使用单个分析**:
|
||||
- ✅ 已有明确目标股票
|
||||
- ✅ 需要深入研究
|
||||
- ✅ 验证投资想法
|
||||
- ✅ 查看详细技术面
|
||||
|
||||
## ❓ 常见问题
|
||||
|
||||
### Q: 为什么只精选3-5只?
|
||||
A: 精选的目的是找出最优标的,太多会降低质量。3-5只足够分散风险,又便于深入研究。
|
||||
|
||||
### Q: 推荐结果每次一样吗?
|
||||
A: 不一样。数据每天更新,AI分析也会考虑最新市场环境。
|
||||
|
||||
### Q: 如何判断推荐质量?
|
||||
A: 看推荐理由是否具体、有数据支撑、逻辑连贯。建议结合自己判断,不要盲目跟从。
|
||||
|
||||
### Q: 可以每天用吗?
|
||||
A: 可以,但建议每周1-2次。数据有延迟,频繁使用意义不大。
|
||||
|
||||
## 📈 实战示例
|
||||
|
||||
### 场景:周末选股
|
||||
```
|
||||
1. 周日晚上运行主力选股
|
||||
参数:最近3个月,精选5只
|
||||
|
||||
2. 查看结果
|
||||
- 精选推荐:5只
|
||||
- AI分析:资金、行业、基本面
|
||||
|
||||
3. 深入研究
|
||||
- 选择前3只
|
||||
- 查看K线图
|
||||
- 了解公司业务
|
||||
|
||||
4. 制定策略
|
||||
- 周一开盘价
|
||||
- 买入价位
|
||||
- 止损止盈
|
||||
|
||||
5. 周一执行
|
||||
- 分批建仓
|
||||
- 加入监测
|
||||
```
|
||||
|
||||
## 🎓 学习建议
|
||||
|
||||
1. **先了解逻辑**
|
||||
- 理解整体分析的优势
|
||||
- 明白三位分析师的作用
|
||||
|
||||
2. **实践使用**
|
||||
- 先用默认参数试试
|
||||
- 查看完整结果
|
||||
|
||||
3. **调整优化**
|
||||
- 根据市场环境调整参数
|
||||
- 找到适合自己的配置
|
||||
|
||||
4. **结合其他功能**
|
||||
- 单个分析:深入研究精选标的
|
||||
- 实时监测:跟踪股价变化
|
||||
- 批量分析:对比分析
|
||||
|
||||
---
|
||||
|
||||
**开始使用**:
|
||||
```bash
|
||||
streamlit run app.py
|
||||
→ 点击 🎯 主力选股
|
||||
→ 开始分析
|
||||
```
|
||||
|
||||
**祝您投资顺利!** 🚀📈💰
|
||||
|
||||
+435
@@ -0,0 +1,435 @@
|
||||
# 主力选股功能说明
|
||||
|
||||
## 功能概述
|
||||
|
||||
**主力选股**是一个智能选股系统,通过分析主力资金流向,结合AI多智能体分析,自动筛选出近期拉升概率高、主力资金净流入较多、综合素质优秀的优质投资标的。
|
||||
|
||||
## 核心特点
|
||||
|
||||
### 1. 数据来源权威
|
||||
- 使用 `pywencai` 获取同花顺数据
|
||||
- 主力资金流向真实可靠
|
||||
- 包含完整的财务评分和行业信息
|
||||
|
||||
### 2. 智能筛选机制
|
||||
- **主力资金排名**:优先选择主力资金净流入前100名
|
||||
- **涨幅过滤**:排除涨幅过高的股票,避免追高
|
||||
- **市值筛选**:聚焦50-1300亿市值区间的优质标的
|
||||
- **基本面保护**:自动过滤ST股、科创板(可配置)
|
||||
|
||||
### 3. AI多维度分析
|
||||
整合三大分析师团队:
|
||||
- **💰 资金流向分析师**:分析主力资金行为和市场情绪
|
||||
- **📊 行业板块分析师**:评估行业前景和市场热点
|
||||
- **📈 财务基本面分析师**:考察盈利能力和财务健康度
|
||||
|
||||
### 4. 资深研究员决策
|
||||
- AI研究员综合所有分析结果
|
||||
- 从候选股票中精选最优标的
|
||||
- 提供详细的推荐理由和风险提示
|
||||
|
||||
## 工作流程
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ 1. 数据获取 │
|
||||
│ 使用pywencai获取主力资金净流入前100名股票 │
|
||||
│ 包含:资金流向、涨跌幅、市值、财务指标、行业等 │
|
||||
└──────────────────┬──────────────────────────────────────┘
|
||||
│
|
||||
┌──────────────────▼──────────────────────────────────────┐
|
||||
│ 2. 智能筛选 │
|
||||
│ ✓ 区间涨跌幅 < 30%(避免追高) │
|
||||
│ ✓ 市值 50-1300亿(优质中盘股) │
|
||||
│ ✓ 排除ST股和科创板 │
|
||||
│ ✓ 按主力资金排序,取前20名 │
|
||||
└──────────────────┬──────────────────────────────────────┘
|
||||
│
|
||||
┌──────────────────▼──────────────────────────────────────┐
|
||||
│ 3. AI深度分析 │
|
||||
│ 对每只候选股票进行三维度分析: │
|
||||
│ • 资金流向(主力行为、资金结构) │
|
||||
│ • 行业板块(行业地位、市场热度) │
|
||||
│ • 财务基本面(盈利能力、成长性) │
|
||||
└──────────────────┬──────────────────────────────────────┘
|
||||
│
|
||||
┌──────────────────▼──────────────────────────────────────┐
|
||||
│ 4. 综合决策 │
|
||||
│ 资深研究员AI综合评估: │
|
||||
│ • 对比所有候选股票 │
|
||||
│ • 精选3-5只最优标的 │
|
||||
│ • 提供推荐理由、投资亮点、风险提示 │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 步骤1:进入主力选股界面
|
||||
|
||||
在系统侧边栏点击 **🎯 主力选股** 按钮
|
||||
|
||||
### 步骤2:设置参数
|
||||
|
||||
#### 基础参数
|
||||
1. **时间区间**:选择数据统计的时间范围
|
||||
- 最近3个月(默认)
|
||||
- 最近6个月
|
||||
- 最近1年
|
||||
- 自定义日期
|
||||
|
||||
2. **初步筛选数量**:从符合条件的股票中选取前N名(默认20只)
|
||||
- 范围:10-50只
|
||||
- 建议:20-30只
|
||||
|
||||
3. **最终精选数量**:最终推荐的股票数量(默认5只)
|
||||
- 范围:3-10只
|
||||
- 建议:3-5只
|
||||
|
||||
#### 高级参数(可选)
|
||||
4. **最大涨跌幅**:过滤涨幅过高的股票(默认30%)
|
||||
- 作用:避免追高
|
||||
- 建议:20%-40%
|
||||
|
||||
5. **市值范围**:
|
||||
- 最小市值:默认50亿
|
||||
- 最大市值:默认1300亿
|
||||
- 作用:聚焦优质中盘股
|
||||
|
||||
6. **AI模型**:选择分析使用的AI模型
|
||||
- `deepseek-chat`:速度快,适合快速筛选
|
||||
- `deepseek-reasoner`:推理能力强,分析更深入
|
||||
|
||||
### 步骤3:开始分析
|
||||
|
||||
点击 **🚀 开始主力选股** 按钮,系统将自动:
|
||||
1. 获取数据(约30-60秒)
|
||||
2. 智能筛选(约10秒)
|
||||
3. AI深度分析(约2-5分钟,取决于股票数量)
|
||||
4. 综合决策(约30秒)
|
||||
|
||||
### 步骤4:查看结果
|
||||
|
||||
#### 统计概览
|
||||
显示四个关键指标:
|
||||
- **获取股票数**:原始数据数量(通常100只)
|
||||
- **筛选后**:符合筛选条件的数量
|
||||
- **深度分析**:成功完成AI分析的数量
|
||||
- **最终推荐**:精选的优质标的数量
|
||||
|
||||
#### 精选推荐
|
||||
对每只推荐股票,系统提供:
|
||||
|
||||
1. **📌 推荐理由**(3-5条核心理由)
|
||||
- 为什么推荐这只股票
|
||||
- 关键优势是什么
|
||||
|
||||
2. **💡 投资亮点**
|
||||
- 突出的投资价值
|
||||
- 主要看点
|
||||
|
||||
3. **⚠️ 风险提示**
|
||||
- 需要关注的风险
|
||||
- 注意事项
|
||||
|
||||
4. **📊 投资建议**
|
||||
- 建议仓位:如20-30%
|
||||
- 目标价位:预期目标价
|
||||
- 投资周期:短期/中期/长期
|
||||
|
||||
5. **🤖 AI分析师详细报告**
|
||||
- 资金流向分析
|
||||
- 行业板块分析
|
||||
- 财务基本面分析
|
||||
|
||||
#### 候选股票列表
|
||||
显示所有候选股票的详细数据:
|
||||
- 股票代码、名称
|
||||
- 所属行业
|
||||
- 市值
|
||||
- 主力资金净流入
|
||||
- 区间涨跌幅
|
||||
- 市盈率、市净率
|
||||
|
||||
支持下载CSV格式数据
|
||||
|
||||
## 筛选逻辑详解
|
||||
|
||||
### 主力资金标准
|
||||
- **主力资金净流入排名**:选择资金流入最多的股票
|
||||
- **资金持续性**:优先考虑持续流入的股票
|
||||
- **资金占比**:主力资金占比高的更受关注
|
||||
|
||||
### 涨幅控制
|
||||
```
|
||||
✅ 涨幅适中(<30%):
|
||||
- 还有上涨空间
|
||||
- 风险相对可控
|
||||
|
||||
❌ 涨幅过高(>30%):
|
||||
- 可能面临回调压力
|
||||
- 追高风险较大
|
||||
- 自动过滤
|
||||
```
|
||||
|
||||
### 市值要求
|
||||
```
|
||||
市值范围:50-1300亿
|
||||
|
||||
原因:
|
||||
✓ <50亿:流动性差,风险高
|
||||
✓ 50-1300亿:优质中盘股,兼顾成长性和稳定性
|
||||
✓ >1300亿:大盘股,成长空间有限
|
||||
```
|
||||
|
||||
### 基本面保护
|
||||
- 自动排除ST股票(特别处理)
|
||||
- 可配置排除科创板(波动较大)
|
||||
- 要求财务数据完整
|
||||
|
||||
## AI分析维度
|
||||
|
||||
### 1. 资金流向分析
|
||||
**分析内容**:
|
||||
- 主力资金流向趋势
|
||||
- 大单、中单、小单分布
|
||||
- 机构与散户资金博弈
|
||||
- 资金推动与股价配合度
|
||||
- 换手率与成交活跃度
|
||||
|
||||
**评判标准**:
|
||||
- ✅ 主力持续流入 + 股价上涨 = 强势信号
|
||||
- ⚠️ 主力流出 + 股价上涨 = 警惕接盘
|
||||
- 💡 主力流入 + 股价下跌 = 可能低吸
|
||||
- ❌ 主力流出 + 股价下跌 = 弱势信号
|
||||
|
||||
### 2. 行业板块分析
|
||||
**分析内容**:
|
||||
- 所属行业发展前景
|
||||
- 行业在市场中的地位
|
||||
- 板块轮动和市场热度
|
||||
- 政策支持和行业催化
|
||||
- 行业竞争格局
|
||||
|
||||
**关注重点**:
|
||||
- 行业是否处于上升周期
|
||||
- 是否有政策利好支持
|
||||
- 市场关注度和热度
|
||||
- 行业龙头还是跟随者
|
||||
|
||||
### 3. 财务基本面分析
|
||||
**分析内容**:
|
||||
- 盈利能力(净利润、ROE等)
|
||||
- 成长能力(营收增长、利润增长)
|
||||
- 营运能力(周转率等)
|
||||
- 偿债能力(资产负债率)
|
||||
- 现金流状况
|
||||
- 资产质量
|
||||
|
||||
**评分体系**:
|
||||
系统获取8大评分:
|
||||
1. 盈利能力评分
|
||||
2. 成长能力评分
|
||||
3. 营运能力评分
|
||||
4. 偿债能力评分
|
||||
5. 现金流评分
|
||||
6. 资产质量评分
|
||||
7. 流动性评分
|
||||
8. 资本充足性评分
|
||||
|
||||
## 使用建议
|
||||
|
||||
### 适用场景
|
||||
1. **中短期波段交易**
|
||||
- 捕捉主力资金推动的行情
|
||||
- 关注3个月内的主力行为
|
||||
|
||||
2. **行业轮动投资**
|
||||
- 发现市场热点板块
|
||||
- 把握资金流向切换
|
||||
|
||||
3. **价值成长投资**
|
||||
- 寻找被主力关注的潜力股
|
||||
- 结合基本面和资金面
|
||||
|
||||
### 使用频率
|
||||
- **建议**:每周执行1-2次
|
||||
- **最佳时机**:周末或交易日收盘后
|
||||
- **避免**:开盘前或盘中(数据可能不完整)
|
||||
|
||||
### 注意事项
|
||||
|
||||
#### 1. 数据时效性
|
||||
- 数据有一定延迟(通常1-2天)
|
||||
- 适合中短期布局,不适合日内交易
|
||||
- 建议结合实时行情确认
|
||||
|
||||
#### 2. 市场环境
|
||||
- **牛市**:主力选股效果更佳,资金推动明显
|
||||
- **震荡市**:关注短期波段机会
|
||||
- **熊市**:谨慎使用,关注防御性板块
|
||||
|
||||
#### 3. 仓位管理
|
||||
- 不要孤注一掷,建议分散投资
|
||||
- 单只股票仓位不超过30%
|
||||
- 保留一定现金仓位
|
||||
|
||||
#### 4. 风险控制
|
||||
- 设置止损位(建议-8%到-10%)
|
||||
- 设置止盈位(建议+15%到+20%)
|
||||
- 不追高,不贪婪
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q1: 为什么获取数据失败?
|
||||
**可能原因**:
|
||||
1. 网络连接问题
|
||||
2. pywencai服务暂时不可用
|
||||
3. 查询语句触发限制
|
||||
|
||||
**解决方法**:
|
||||
- 检查网络连接
|
||||
- 等待片刻后重试
|
||||
- 调整时间区间参数
|
||||
|
||||
### Q2: 为什么筛选后股票很少?
|
||||
**可能原因**:
|
||||
1. 筛选条件过于严格
|
||||
2. 当前市场符合条件的股票较少
|
||||
|
||||
**解决方法**:
|
||||
- 适当放宽涨跌幅限制(如改为40%)
|
||||
- 扩大市值范围
|
||||
- 调整时间区间
|
||||
|
||||
### Q3: AI分析需要多长时间?
|
||||
**时间估算**:
|
||||
- 单只股票:约10-15秒
|
||||
- 20只股票:约3-5分钟
|
||||
- 50只股票:约8-10分钟
|
||||
|
||||
**影响因素**:
|
||||
- 股票数量
|
||||
- AI模型选择
|
||||
- 网络速度
|
||||
|
||||
### Q4: 推荐结果每次都一样吗?
|
||||
**答案**:不完全一样
|
||||
|
||||
**原因**:
|
||||
1. 数据每天更新(主力资金、价格等)
|
||||
2. AI分析会考虑最新市场环境
|
||||
3. 不同时间段的数据可能不同
|
||||
|
||||
### Q5: 如何判断推荐质量?
|
||||
**评判标准**:
|
||||
1. **理由充分性**:推荐理由是否具体、有说服力
|
||||
2. **数据支撑**:是否有真实数据支撑
|
||||
3. **风险提示**:是否明确指出风险
|
||||
4. **逻辑连贯性**:资金、行业、基本面是否相互印证
|
||||
|
||||
**建议**:
|
||||
- 认真阅读AI分析报告
|
||||
- 对比多个候选股票
|
||||
- 结合自己的投资逻辑
|
||||
- 不盲目跟从,独立思考
|
||||
|
||||
## 技术要求
|
||||
|
||||
### 环境依赖
|
||||
```bash
|
||||
# 必须安装
|
||||
pywencai>=0.7.0
|
||||
pandas
|
||||
streamlit
|
||||
|
||||
# Node.js要求
|
||||
Node.js >= 16.0(pywencai依赖)
|
||||
```
|
||||
|
||||
### 安装方法
|
||||
```bash
|
||||
# 安装Python依赖
|
||||
pip install pywencai pandas streamlit
|
||||
|
||||
# 检查Node.js版本
|
||||
node --version
|
||||
|
||||
# 如果版本低于16.0,需要升级Node.js
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 每周选股流程
|
||||
```
|
||||
周日晚上 → 运行主力选股
|
||||
↓
|
||||
查看推荐结果
|
||||
↓
|
||||
深入研究前3名
|
||||
↓
|
||||
周一开盘前制定策略
|
||||
↓
|
||||
择机建仓
|
||||
```
|
||||
|
||||
### 2. 结合技术分析
|
||||
推荐股票后,建议再进行:
|
||||
- K线形态分析
|
||||
- 支撑压力位判断
|
||||
- 均线系统确认
|
||||
- 成交量变化观察
|
||||
|
||||
### 3. 分批建仓
|
||||
```
|
||||
发现优质标的后:
|
||||
第1批:20% → 试探性建仓
|
||||
第2批:30% → 确认后加仓
|
||||
第3批:30% → 突破后追加
|
||||
保留:20% → 备用资金
|
||||
```
|
||||
|
||||
### 4. 持仓管理
|
||||
```
|
||||
持有期间关注:
|
||||
✓ 主力资金是否继续流入
|
||||
✓ 股价是否沿着上升趋势
|
||||
✓ 行业是否仍有催化
|
||||
✓ 基本面是否发生变化
|
||||
|
||||
出现以下情况考虑减仓:
|
||||
✗ 主力资金持续流出
|
||||
✗ 技术面破位
|
||||
✗ 基本面恶化
|
||||
✗ 达到目标价位
|
||||
```
|
||||
|
||||
## 更新日志
|
||||
|
||||
### v1.0.0 (2025-10-09)
|
||||
- ✅ 初始版本发布
|
||||
- ✅ 支持主力资金数据获取
|
||||
- ✅ 实现智能筛选算法
|
||||
- ✅ 集成AI三大分析师
|
||||
- ✅ 资深研究员综合决策
|
||||
- ✅ Web界面集成
|
||||
|
||||
## 技术支持
|
||||
|
||||
如遇问题,请提供:
|
||||
1. 错误截图或错误信息
|
||||
2. 使用的参数配置
|
||||
3. 操作步骤描述
|
||||
|
||||
## 免责声明
|
||||
|
||||
**重要提示**:
|
||||
1. 本功能仅供学习和研究使用
|
||||
2. 不构成任何投资建议
|
||||
3. 股市有风险,投资需谨慎
|
||||
4. 请根据自身情况做出投资决策
|
||||
5. 盈亏自负,谨慎操作
|
||||
|
||||
---
|
||||
|
||||
**祝您投资顺利!** 🚀📈
|
||||
|
||||
+316
@@ -0,0 +1,316 @@
|
||||
# 主力选股功能 - 快速开始指南
|
||||
|
||||
## ✅ 已完成的功能模块
|
||||
|
||||
### 核心模块
|
||||
1. **main_force_selector.py** - 数据获取和筛选
|
||||
- 使用pywencai获取主力资金数据
|
||||
- 智能筛选算法
|
||||
- 数据格式化
|
||||
|
||||
2. **main_force_analysis.py** - AI分析整合
|
||||
- 整合三大分析师团队
|
||||
- 资深研究员综合决策
|
||||
- 完整的分析流程
|
||||
|
||||
3. **main_force_ui.py** - Web界面
|
||||
- 参数配置界面
|
||||
- 结果展示
|
||||
- 数据导出
|
||||
|
||||
4. **app.py** - 主应用集成
|
||||
- 添加导航按钮
|
||||
- 路由配置
|
||||
|
||||
### 文档
|
||||
5. **主力选股功能说明.md** - 详细使用手册
|
||||
6. **test_main_force.py** - 功能测试脚本
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
### 步骤1: 测试功能
|
||||
```bash
|
||||
# 运行测试脚本
|
||||
python test_main_force.py
|
||||
```
|
||||
|
||||
测试内容:
|
||||
- ✅ 模块导入检查
|
||||
- ✅ 数据获取功能
|
||||
- ✅ 筛选功能
|
||||
- ✅ API配置检查
|
||||
|
||||
### 步骤2: 启动系统
|
||||
```bash
|
||||
streamlit run app.py
|
||||
```
|
||||
|
||||
### 步骤3: 使用主力选股
|
||||
1. 在侧边栏点击 **🎯 主力选股**
|
||||
2. 设置参数(时间区间、筛选数量等)
|
||||
3. 点击 **🚀 开始主力选股**
|
||||
4. 等待3-5分钟完成分析
|
||||
5. 查看精选推荐结果
|
||||
|
||||
## 📊 功能特点
|
||||
|
||||
### 智能筛选
|
||||
```
|
||||
原始数据(100只)
|
||||
↓ 涨幅过滤(<30%)
|
||||
↓ 市值筛选(50-1300亿)
|
||||
↓ ST股过滤
|
||||
筛选结果(20-50只)
|
||||
↓ 主力资金排序
|
||||
候选股票(前20名)
|
||||
```
|
||||
|
||||
### AI三维分析
|
||||
```
|
||||
💰 资金流向分析师
|
||||
├─ 主力资金行为
|
||||
├─ 资金流向趋势
|
||||
└─ 市场情绪判断
|
||||
|
||||
📊 行业板块分析师
|
||||
├─ 行业发展前景
|
||||
├─ 市场热点判断
|
||||
└─ 板块轮动分析
|
||||
|
||||
📈 财务基本面分析师
|
||||
├─ 盈利能力评估
|
||||
├─ 成长性分析
|
||||
└─ 财务健康度
|
||||
```
|
||||
|
||||
### 综合决策
|
||||
```
|
||||
资深研究员AI
|
||||
├─ 综合评估所有候选
|
||||
├─ 精选3-5只最优标的
|
||||
├─ 提供推荐理由
|
||||
├─ 投资建议和风险提示
|
||||
└─ 目标价位和持仓建议
|
||||
```
|
||||
|
||||
## 📋 参数说明
|
||||
|
||||
### 基础参数
|
||||
| 参数 | 默认值 | 范围 | 说明 |
|
||||
|-----|--------|------|------|
|
||||
| 时间区间 | 最近3个月 | 自定义 | 主力资金统计周期 |
|
||||
| 初步筛选 | 20只 | 10-50 | 候选股票数量 |
|
||||
| 最终精选 | 5只 | 3-10 | 推荐标的数量 |
|
||||
|
||||
### 高级参数
|
||||
| 参数 | 默认值 | 范围 | 说明 |
|
||||
|-----|--------|------|------|
|
||||
| 最大涨幅 | 30% | 10-100% | 过滤涨幅过高的股票 |
|
||||
| 最小市值 | 50亿 | 10-500亿 | 市值下限 |
|
||||
| 最大市值 | 1300亿 | 100-5000亿 | 市值上限 |
|
||||
| AI模型 | deepseek-chat | - | 分析使用的模型 |
|
||||
|
||||
## 🎯 使用场景
|
||||
|
||||
### 1. 周末选股
|
||||
**时机**: 每周日晚上
|
||||
**参数**: 最近3个月,精选5只
|
||||
**用途**: 为下周交易做准备
|
||||
|
||||
### 2. 月度调仓
|
||||
**时机**: 每月初
|
||||
**参数**: 最近6个月,精选8-10只
|
||||
**用途**: 调整持仓结构
|
||||
|
||||
### 3. 热点捕捉
|
||||
**时机**: 市场出现明显热点时
|
||||
**参数**: 最近1个月,精选3只
|
||||
**用途**: 抓住短期机会
|
||||
|
||||
## ⚠️ 注意事项
|
||||
|
||||
### 环境要求
|
||||
```bash
|
||||
# 必须安装
|
||||
Python >= 3.8
|
||||
Node.js >= 16.0(重要!pywencai依赖)
|
||||
|
||||
# Python包
|
||||
pywencai >= 0.7.0
|
||||
pandas
|
||||
streamlit
|
||||
deepseek
|
||||
```
|
||||
|
||||
### 检查Node.js版本
|
||||
```bash
|
||||
node --version
|
||||
|
||||
# 如果低于16.0,需要升级
|
||||
# Windows: 从nodejs.org下载最新版本
|
||||
# Mac: brew install node
|
||||
# Linux: nvm install 18
|
||||
```
|
||||
|
||||
### API配置
|
||||
确保.env文件中配置了:
|
||||
```env
|
||||
DEEPSEEK_API_KEY=your_api_key_here
|
||||
EMAIL_ENABLED=true # 如需邮件通知
|
||||
```
|
||||
|
||||
## 🔍 常见问题
|
||||
|
||||
### Q: 数据获取失败?
|
||||
**检查**:
|
||||
- [ ] 网络连接正常
|
||||
- [ ] Node.js版本 >= 16.0
|
||||
- [ ] pywencai已正确安装
|
||||
|
||||
**解决**:
|
||||
```bash
|
||||
# 重新安装pywencai
|
||||
pip uninstall pywencai
|
||||
pip install pywencai --upgrade
|
||||
|
||||
# 检查Node.js
|
||||
node --version
|
||||
```
|
||||
|
||||
### Q: 分析时间太长?
|
||||
**原因**: 候选股票太多
|
||||
|
||||
**优化**:
|
||||
- 减少初步筛选数量(改为15只)
|
||||
- 使用deepseek-chat模型(更快)
|
||||
- 调整筛选条件减少候选数量
|
||||
|
||||
### Q: 推荐结果不理想?
|
||||
**建议**:
|
||||
- 调整时间区间(试试最近6个月)
|
||||
- 放宽涨幅限制(改为40%)
|
||||
- 多次运行对比结果
|
||||
- 结合自己的投资逻辑
|
||||
|
||||
## 📈 最佳实践
|
||||
|
||||
### 1. 参数配置建议
|
||||
```yaml
|
||||
保守型:
|
||||
时间区间: 6个月
|
||||
最大涨幅: 20%
|
||||
市值范围: 100-1300亿
|
||||
精选数量: 3只
|
||||
|
||||
平衡型:
|
||||
时间区间: 3个月
|
||||
最大涨幅: 30%
|
||||
市值范围: 50-1300亿
|
||||
精选数量: 5只
|
||||
|
||||
激进型:
|
||||
时间区间: 1个月
|
||||
最大涨幅: 40%
|
||||
市值范围: 50-800亿
|
||||
精选数量: 8只
|
||||
```
|
||||
|
||||
### 2. 使用流程
|
||||
```
|
||||
1. 周末运行主力选股
|
||||
↓
|
||||
2. 查看推荐结果和AI分析
|
||||
↓
|
||||
3. 深入研究前3名标的
|
||||
↓
|
||||
4. 查看实时K线和技术指标
|
||||
↓
|
||||
5. 周一开盘后择机建仓
|
||||
↓
|
||||
6. 加入实时监测,设置止盈止损
|
||||
```
|
||||
|
||||
### 3. 风险控制
|
||||
```
|
||||
✅ 分散投资: 不超过3-5只股票
|
||||
✅ 仓位控制: 单只不超过30%
|
||||
✅ 止损设置: -8%到-10%
|
||||
✅ 止盈目标: +15%到+20%
|
||||
✅ 动态调整: 根据走势调整策略
|
||||
```
|
||||
|
||||
## 📊 输出结果
|
||||
|
||||
### 统计数据
|
||||
- 获取股票总数
|
||||
- 筛选后数量
|
||||
- 深度分析数量
|
||||
- 最终推荐数量
|
||||
|
||||
### 推荐详情
|
||||
每只股票包含:
|
||||
- ✅ 推荐理由(3-5条)
|
||||
- ✅ 投资亮点
|
||||
- ✅ 风险提示
|
||||
- ✅ 建议仓位
|
||||
- ✅ 目标价位
|
||||
- ✅ 投资周期
|
||||
- ✅ AI详细分析报告
|
||||
|
||||
### 数据导出
|
||||
- CSV格式候选列表
|
||||
- 包含所有关键指标
|
||||
- 可用于进一步分析
|
||||
|
||||
## 🎓 学习资源
|
||||
|
||||
### 相关文档
|
||||
- 主力选股功能说明.md - 完整使用手册
|
||||
- 资金流向功能说明.md - 资金分析原理
|
||||
- 实时监测优化说明.md - 监测功能
|
||||
- README.md - 系统总体说明
|
||||
|
||||
### 代码学习
|
||||
- main_force_selector.py - 数据处理逻辑
|
||||
- main_force_analysis.py - AI分析流程
|
||||
- main_force_ui.py - 界面实现
|
||||
|
||||
## 🆘 获取帮助
|
||||
|
||||
### 运行测试
|
||||
```bash
|
||||
python test_main_force.py
|
||||
```
|
||||
|
||||
### 查看日志
|
||||
运行时终端会显示详细日志:
|
||||
- 数据获取过程
|
||||
- 筛选统计
|
||||
- AI分析进度
|
||||
- 错误信息
|
||||
|
||||
### 问题反馈
|
||||
提供以下信息:
|
||||
1. 错误截图
|
||||
2. 终端日志
|
||||
3. 使用的参数
|
||||
4. 系统环境(Python版本、Node.js版本)
|
||||
|
||||
## ✨ 开始使用
|
||||
|
||||
```bash
|
||||
# 1. 测试功能
|
||||
python test_main_force.py
|
||||
|
||||
# 2. 启动系统
|
||||
streamlit run app.py
|
||||
|
||||
# 3. 点击 🎯 主力选股
|
||||
|
||||
# 4. 开始分析
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**祝您选股顺利,投资成功!** 🚀📈💰
|
||||
|
||||
Reference in New Issue
Block a user