有同学问我怎么用AI进行新闻挖掘A股概念股, 这里写一写。在A股市场混,最怕的是什么?不是大盘跳水,而是 “消息跟不上” 和**“逻辑理不清”**。
你一定经历过这样的场景:早盘某条新闻刷屏——比如“高层推进新型工业化”,你看着这几个字发呆,心里想:这到底是利好机器人?还是利好工业软件?还是利好数控机床?等你还在纠结概念板块的时候,资金已经把龙头封死了。
信息差,就是交易的核心壁垒。
为了消灭这个信息差,今天我利用 Streamlit + Akshare + LangChain + 智谱 GLM-4,写了一个 “AI 财经新闻概念挖掘终端” 。它能自动读取实时新闻,并在 1 秒钟内提炼出核心概念,甚至直接给出相关的龙头股代码。
今天就来复盘这个项目的核心逻辑与代码实现。
一、 需求起源:从“人肉阅读”到“AI 推理”
传统的看新闻方式属于“人肉过滤”。我们需要打开财联社、同花顺,一条条看,还要在脑子里检索知识库:
- 这条新闻提到了“CPO”,那是干什么的,哪家公司强?
这个过程效率极低,且高度依赖个人的知识储备。
而大模型(LLM)最擅长的就是语义理解与逻辑推理。我的目标很简单:让 AI 帮我读新闻,然后把“新闻文本”直接转化为“交易逻辑”。
二、 架构设计:三步走策略
为了把这个想法落地,我设计了三层架构:
- 数据层:利用
akshare 获取A股的实时财经新闻数据。 - 交互层:利用
streamlit 快速构建一个左侧列表、右侧详情的 Web 界面,模拟专业交易终端。 - 大脑层:利用
langchain 调用智谱 AI 的 glm-4-flash 模型,进行概念提取与个股映射。
三、 核心代码拆解
1. 数据源:Akshare 稳定军心
做量化,数据是灵魂。Akshare 是目前开源界最好的财经数据接口之一。在代码中,我们只需要一行函数就能获取最新的财经新闻:
def get_news_data():return ak.stock_info_global_cls()
这个函数返回的 DataFrame 包含了标题、发布时间、内容等字段,构成了我们分析的原始素材。
2. 界面:Streamlit 打造“操作感”
虽然用命令行(CLI)也能跑,但为了沉浸式的体验,我使用了 Streamlit。关键点在于利用 st.session_state 来记录用户点击的是哪一条新闻,从而实现左侧点击、右侧刷新的联动效果。
3. 大脑:Prompt Engineering 决定上限
这是整个项目最核心的部分。如何让 AI 不仅仅是“总结新闻”,而是去“挖掘概念”?
我设计了一个结构化的 Prompt(提示词):
prompt = ChatPromptTemplate.from_messages([ ("system", "你是一位专业的财经证券分析师。请阅读用户提供的财经新闻,完成以下任务:\n" "1. **概念识别**:分析该新闻涉及的核心产业链概念(例如:Robotaxi, CPO, 创新药等)。\n" "2. **个股挖掘**:根据概念,列出3-5只A股或港股中最相关的龙头个股名称,并用一句话解释关联理由。\n\n" "输出格式请使用 Markdown,清晰分级。"), ("user", "新闻标题:{title}\n\n新闻内容:{content}\n\n请开始分析。")])
注意这里有两个技巧:
- 角色设定:先定调“你是专业分析师”,让 AI 主动往金融逻辑上靠。
- 任务拆解:明确要求“概念识别”和“个股挖掘”两个步骤,避免 AI 输出泛泛而谈的总结。
- 模型选择:我使用了
glm-4-flash。为什么选它?因为新闻分析对延迟很敏感,Flash 版本速度快且免费,完全能满足这种逻辑推理的需求,性价比极高。
通过 chain = prompt | llm | StrOutputParser() 这一行经典的 LangChain 链式调用,数据就流动了起来。
四、 最后总结:AI 是交易员的“外骨骼”
写这个工具的初衷,并非是为了让 AI 直接代替我做交易决策。股市变幻莫测,只有逻辑才是恒定的。
这个工具的价值在于,它充当了交易员的“外骨骼”:
在量化与主观交易的融合道路上,Python + AI 已经成为了不可或缺的武器。如果你也对用代码武装投资感兴趣,不妨动手试试这段代码。
最后这里贴一下完整代码,参考下思路, 具体根据自己的实际情况改造。 备注:如果发现格式有多余的特殊字符,用普通浏览器打开复制应该没问题。 希望我的分享对大家有所帮助。 使用前,记得换成自己的api-key
import streamlit as stfrom langchain_openai import ChatOpenAIfrom langchain.prompts import ChatPromptTemplatefrom langchain_core.output_parsers import StrOutputParserimport akshare as ak# ================= 配置部分 =================st.set_page_config( page_title="AI 财经新闻概念挖掘终端", page_icon="📰", layout="wide")# ================= 数据获取层 =================def get_news_data(): return ak.stock_info_global_cls()def app(): # ================= 界面布局 ================= st.title("🤖 AI 新闻概念与个股挖掘") api_key = 'XXXXXX' # ================= 主程序逻辑 ================= # 加载数据 news_df = get_news_data() # 初始化 Session State 用于存储选中的新闻 if 'selected_idx' not in st.session_state: st.session_state.selected_idx = 0 # 布局:左侧新闻列表,右侧详情与分析 col_list, col_detail = st.columns([3, 7]) with col_list: st.subheader("📰 实时新闻流") # 显示新闻列表 for idx, row in news_df.iterrows(): # 简单的卡片样式 with st.container(): # 高亮选中项 border_color = "#2563eb" if idx == st.session_state.selected_idx else "#e2e8f0" # 点击事件 if st.button( f"**{row['标题']}**\n\n`{row['发布日期']}{row['发布时间']}`", key=f"news_{idx}", use_container_width=True, help="点击查看分析" ): st.session_state.selected_idx = idx st.rerun() # 重新运行以更新右侧视图 st.markdown(f"<div style='border-bottom: 2px solid {border_color}; margin-bottom: 10px;'></div>", unsafe_allow_html=True) with col_detail: # 获取当前选中的新闻 current_news = news_df.iloc[st.session_state.selected_idx] st.markdown("---") # 1. 展示新闻原文 st.subheader(f"📌 {current_news['标题']}") st.caption(f"发布时间:{current_news['发布日期']}{current_news['发布时间']}") st.info(current_news['内容']) # 2. AI 分析按钮 st.markdown("### 🧠 AI 深度分析") if st.button("✨ 开始分析:提取概念 & 挖掘个股", type="primary", use_container_width=True): with st.spinner("GLM-4-Flash 正在阅读新闻并进行逻辑推理..."): try: # 初始化 LLM llm = ChatOpenAI( api_key=api_key, base_url="https://open.bigmodel.cn/api/paas/v4/", model="glm-4-flash", temperature=0.3 # 降低温度以获得更精确的分析 ) # 构建 Prompt prompt = ChatPromptTemplate.from_messages([ ("system", "你是一位专业的财经证券分析师。请阅读用户提供的财经新闻,完成以下任务:\n" "1. **概念识别**:分析该新闻涉及的核心产业链概念(例如:Robotaxi, CPO, 创新药等)。\n" "2. **个股挖掘**:根据概念,列出3-5只A股或港股中最相关的龙头个股名称,并用一句话解释关联理由。\n\n" "输出格式请使用 Markdown,清晰分级。"), ("user", "新闻标题:{title}\n\n新闻内容:{content}\n\n请开始分析。") ]) chain = prompt | llm | StrOutputParser() # 调用模型 analysis_result = chain.invoke({ "title": current_news['标题'], "content": current_news['内容'] }) # 展示结果 st.success("分析完成!") st.markdown(analysis_result) # 为了方便用户复制 with st.expander("查看原始输出 JSON"): st.text(analysis_result) except Exception as e: st.error(f"分析过程出错: {e}") st.error("请检查 API Key 或网络连接。")if __name__ == "__main__": #st.set_page_config(layout="wide") app()
如果我的分享对你有所帮助, 不吝啬给个点赞呗
以防失联,可关注我的备用公众号 或加我微信。