ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Python + 大模型 API 实现 A 股自选股自动分析报告与多端推送

Python + 大模型 API 实现 A 股自选股自动分析报告与多端推送 简介这是一套面向个人投资者与量化初学者的AI驱动股票智能分析系统解决A/H/美股自选股日常决策效率低、信息整合难、操作纪律弱等痛点无需编程或金融工程背景即可快速上手。资源包共205个文件含76个核心Python脚本实现数据采集、模型调用、策略判断与推送逻辑、24张可视化图表如每日分析动图、仪表盘截图、21个TypeScript/React前端组件用于本地Web查看界面及20份Markdown文档含部署指南、API配置说明与交易纪律详解整体压缩包40.93MB。已有56人学习下载。用户可直接运行定时分析流程获得Gemini生成的一句话结论、精确买卖点位与带状态标记的操作检查清单并通过企业微信、飞书或邮件自动接收每日决策仪表盘项目支持零服务器部署内置GitHub Actions自动化方案与Dockerfile同时兼容多种开源大模型与行情数据源开箱即用。 每个工作日的早上8点30分我会在手机上收到一条来自企业微信的推送内容是我那10只A股自选股的AI分析日报。每只股票昨日收盘后的走势总结、量价信号、资金流方向、财务面的简要提醒以及一个用大模型算出来的综合评分都被整理成了一张排版清晰的“决策仪表盘”。点开推送里的链接我瞄一眼就能知道今天哪些股票该重点关注、哪些风险需要回避。这套系统用Python编写核心基于AI大模型每天自动分析一次然后把仪表盘推送到企业微信、飞书、邮箱这三个渠道。这套系统主要解决一个很实际的问题白天要上班没法盯盘晚上复盘又没时间逐只翻行情和公告。它适合三类人一是手里有自选股但工作忙、没时间系统复盘的上班族二是想学大模型在实际项目中落地应用的Python开发者三是喜欢折腾自动化工具、想把日常数据流程打通的技术玩家。先说一句必须说的话这套系统输出的所有内容都只是数据分析参考不是投资建议股市有风险任何决策请结合自己的判断。1. 先拆需求这个系统到底要解决什么问题1.1 自选股复盘痛点不在“看”而在“时间”很多人以为炒股盯盘的核心问题是“信息不够”我实际用下来发现恰恰相反问题是信息太多、太碎。自选股列表里一旦超过10只股票每个交易日收盘后都会产生一堆数据K线形态、成交量变化、主力资金净流入、板块异动、公告消息、外围市场影响。这些信息散落在不同软件、不同页面里就算每个只花3分钟10只股票就是半小时而且看完之后脑子里往往是乱的因为缺乏统一的比较框架。我就是被这个痛点折磨了一阵子才决定做一个自动化的分析系统。最初的想法很简单能不能每天早上自动把自选股的数据全部拉一遍然后让大模型按照同一套标准帮我小结一下最后推送到手机上看这套系统最初只是我自己用的小脚本后来逐步完善成了现在这个可以部署到服务器上、多端推送的完整项目。1.2 需求拆成四个模块系统边界就清晰了动手之前我先把这个系统拆成了四个独立的模块这样每个模块只干一件事后面调试和维护都省心模块核心职责对应实现数据采集拉取行情、财务、资金流等原始数据akshare pandasAI分析对数据进行解读输出结构化结论大模型API调用报告生成把结论渲染成可视化仪表盘Python模板 HTML/CSS多渠道推送把报告推给用户企业微信/飞书/邮件三种渠道这个拆分思路看起来简单但价值很大。如果没有做模块化把数据采集和推送逻辑全部写在一个脚本里后面只要akshare接口变更或者微信机器人规则调整都要动主逻辑很容易出问题。拆开之后数据层只负责把数据拿出来AI层只负责分析推送层只负责把结果送出去互不影响。1.3 技术选型为什么是Python 大模型API而不是本地部署大模型技术选型是很多人问得最多的问题尤其是最近“本地部署AI大模型”这个概念很火。我最终选择Python加大模型API的组合而不是在本地跑一个开源模型原因有三点。第一是硬件成本。本地部署一个效果勉强能用的7B模型推理速度慢不说效果和大厂商用API还是有不小差距。真要用上13B或者更大参数模型一张中高端显卡起步就是几千块钱普通用户没必要为每天分析几只股票去承担这个成本。第二是维护成本。本地部署大模型听起来很酷但后续要处理模型版本升级、Python环境冲突、显存管理、推理服务保活这些问题。我见过不少人在部署阶段热情高涨结果模型还没真正用起来光配环境就折腾了一周。第三是效果和稳定性。商用API经过大规模优化输出质量和稳定性明显优于个人本地部署的小模型而且调用方只需要关心业务逻辑。以DeepSeek、通义千问、智谱这类国内可直接访问的模型服务为例每天分析10只股票一个月的API费用完全可以控制在几块钱到十几块钱的水平比自己买显卡划算得多。当然如果你自选股数量特别多、对数据隐私有严格要求本地部署也确实有必要。我的建议是先用API把流程跑通跑通之后再考虑用Ollama等工具替换模型来源不要一上来就本地部署容易劝退。1.4 整体数据流四条线串起一个每日闭环整套系统的数据流是这样的系统读取配置文件里的自选股列表通过akshare把每只股票的日K线、近期成交量、资金流向、基本面指标抓下来整理成结构化的文本接着拼接好的数据会和Prompt一起发送给大模型API模型返回JSON格式的分析结论然后系统把这些结论渲染成HTML仪表盘最后推送到企业微信、飞书和邮箱。整个流程由定时任务触发每天自动执行一轮。这个闭环里最关键的一点是“数据流转格式的统一”。无论哪个环节数据都以JSON作为中间格式行情数据是JSON模型输出是JSON报告生成也依赖JSON字段。这样设计的好处是每个模块都可以单独测试模型输出格式变了只改AI分析模块推送渠道变了只改推送模块不会牵一发而动全身。2. 数据层和AI分析层系统的两条命脉2.1 用akshare拿A股行情数据零门槛还免费数据是整个系统的基础如果数据不准后面AI分析再强也是空中楼阁。我选用的数据源是akshare这是一个开源的Python财经数据接口库最大的优势是无需注册、无需申请token安装之后直接就能用对个人开发者非常友好。对比之下tushare虽然数据质量也不错但多数接口需要积分权限新用户要先攒积分才能调用高频接口这对一个想快速搭起来的项目来说有点门槛。akshare的接口完全免费覆盖股票、基金、期货、宏观数据等多个领域对个人自选股分析来说足够用了。下面是获取单只股票日K线数据的基础代码import akshare as ak import pandas as pd # 获取贵州茅台600519的日K线数据 df ak.stock_zh_a_hist( symbol600519, perioddaily, start_date20240101, end_date20241231, adjustqfq ) print(df.tail())参数说明symbol填股票代码period填daily表示日线adjust填qfq是前复权。前复权很重要因为股票分红送股会导致历史价格出现断层不复权的话技术指标会失真。实际项目中不能只取一只股票要遍历自选股列表。这里有一个很容易踩的坑akshare免费接口有频率限制如果循环里不控制请求间隔很可能抓到一半就被服务端限流。我的做法是在每次请求之间加一个time.sleep(0.5)到time.sleep(1)把请求频率控制在合理范围。毕竟这是每日定时任务对实时性要求不高慢一点完全没关系。2.2 Prompt设计让大模型输出稳定JSON的关键数据拿到之后下一步就是把数据交给大模型分析。这一步很多人容易出问题直接把行情数据往模型里一丢输出结果五花八门一会儿是散文一会儿是列表根本没有办法程序化处理。我的经验是必须让模型按照固定Schema输出JSON。Prompt设计是整个AI分析层的灵魂。我总结了一套比较稳定的模板结构核心包括四个部分一是角色设定告诉模型它是一个A股分析助手二是输入数据把行情、量价、财务等数据以结构化文本形式放进去三是输出格式约束明确要求返回JSON并且规定每个字段的含义和取值四是不确定性处理让模型在数据不足时明确说“无法判断”而不是硬编一个结论。温度参数也要调低。我一般设置temperature0.2这个值下模型输出比较稳定不容易出现发散性的表达。如果你用的是OpenAI兼容接口代码结构都差不多只需要改base_url和model就行了。以DeepSeek为例from openai import OpenAI client OpenAI( api_keysk-你的key, base_urlhttps://api.deepseek.com ) resp client.chat.completions.create( modeldeepseek-chat, temperature0.2, response_format{type: json_object}, messages[ {role: system, content: 你是一名严谨的A股分析助手输出内容只代表数据分析意见。}, {role: user, content: prompt} ] ) result_json resp.choices[0].message.content print(result_json)这个Prompt模板中还有个很容易被忽略的细节要让模型学会“自知之明”。所谓AI幻觉就是模型在不知道答案时也会一本正经地编一个结论。放在股票分析里这是很危险的因为模型可能会在缺乏数据的情况下编造一个支撑位或者压力位。我在Prompt里明确要求它如果某类数据缺失必须在对应字段标记为“数据不足”并给用户明确的风险提示。这个操作简单有效实测能大幅减少幻觉输出。2.3 生成决策仪表盘一份能直接打开的HTML报告AI分析完成后拿到的是JSON但JSON本身没法看所以要把结论渲染成可视化报告。我选择了HTML方案因为HTML可以做到跨平台无论手机浏览器、企业微信内置页面、邮件客户端都能直接打开不需要额外安装任何App。报告核心包含几个区域自选股总览列表、每只股票的综合评分、趋势判断、技术信号标签、以及风险提示。综合评分我用一个进度条展示技术信号用不同颜色的标签区分比如“放量上涨”“MACD金叉”“跌破支撑位”等。为了视觉效果我精简地引入ECharts的CDN绘制雷达图从多个维度展示股票的强弱格局。报告用Python的模板字符串生成HTML核心结构是这样的伪代码def build_report(results): card_html for item in results: card_html f div classstock-card h3{item[code]} {item[name]}/h3 p综合评分{item[score]}/p p趋势判断{item[trend]}/p p技术信号{item[signals]}/p p风险提示{item[risk]}/p /div return fhtmlbody{card_html}/body/html这里有一个很重要的经验不要在报告里堆砌所有数据。我一开始也踩过这个坑把K线指标、换手率、流通市值全塞进去结果手机上根本看不过来。现在的原则是“一屏抓重点”每只股票给3到4个核心结论、1个综合评分、1个风险提示就够了其他原始数据作为背景信息存日志不展示。3. 三端推送打通企业微信、飞书、邮箱一个不落3.1 企业微信机器人推送配置加签十分钟搞定企业微信推送是我最常用的渠道因为手机必装微信消息触达率最高。配置流程非常简单进入企业微信群点击右上角群设置添加群机器人复制Webhook地址即可通过HTTP请求发送消息。如果你对安全性有要求可以在机器人设置里开启加签这样请求地址除了webhook本身还要附带timestamp和sign参数。企业微信机器人的消息格式支持text和markdown两种我用的是markdown因为可以在消息里加粗标题、分隔线、链接信息层次更清晰。核心发送代码如下import requests import time import hmac import hashlib import base64 def send_wechat_markdown(content, webhook_url, secretNone): if secret: timestamp str(int(time.time())) string_to_sign f{timestamp}\n{secret} hmac_code hmac.new( secret.encode(utf-8), string_to_sign.encode(utf-8), digestmodhashlib.sha256 ).digest() sign base64.b64encode(hmac_code).decode(utf-8) webhook_url f{webhook_url}timestamp{timestamp}sign{sign} data { msgtype: markdown, markdown: { content: content } } resp requests.post(webhook_url, jsondata) return resp.json()实测下来有两点要注意第一企业微信机器人的markdown只支持部分语法表格、图片这类富元素是不行的所以推送正文里我只放文字小结和报告链接第二消息内容不要太长太长了会被截断我的做法是正文精简成两三行摘要完整内容放链接里点开看。3.2 飞书自定义机器人卡片消息比Markdown更精致飞书的消息能力比企业微信更丰富它的自定义机器人支持发送交互式卡片可以做更清晰的视觉布局。如果你的团队主要用飞书这一路推送值得配置。飞书机器人的创建流程和企业微信类似创建之后获取Webhook地址然后发送POST请求即可。飞书卡片消息的格式稍微复杂一些需要按Card的JSON结构组织。我的简化版实现如下def send_feishu_card(content, webhook_url, secretNone): card { msg_type: interactive, card: { config: {wide_screen_mode: True}, header: { title: {tag: plain_text, content: 自选股决策仪表盘}, template: blue }, elements: [ {tag: markdown, content: content} ] } } resp requests.post(webhook_url, jsoncard) return resp.json()飞书卡片适合展示评分列表、结论摘要整体观感比纯文本舒服不少。但要注意飞书的签名校验方式和企业微信不完全一样它用的是timestamp secret的拼接校验配置的时候一定要把secret放在环境变量或者配置文件里不要写死在代码中。3.3 SMTP邮件推送老牌方案HTML正文直接看邮件推送是这个系统里最“传统”却最稳定的一路。它有一个其他渠道不具备的优势邮件可以直接发送完整的HTML正文也就是说决策仪表盘可以直接作为邮件正文出现不需要用户再点链接跳转。使用SMTP发送邮件时有个关键点绝大多数邮箱服务商不支持直接使用账号密码登录SMTP需要开启SMTP服务后生成授权码。以QQ邮箱为例登录网页版邮箱在设置里开启SMTP服务之后会自动生成一个授权码用这个授权码作为login的密码参数。import smtplib from email.mime.text import MIMEText from email.header import Header def send_email_html(subject, html_content, smtp_config, to_addr): msg MIMEText(html_content, html, utf-8) msg[Subject] Header(subject, utf-8) msg[From] smtp_config[user] msg[To] to_addr with smtplib.SMTP_SSL(smtp_config[host], smtp_config[port]) as server: server.login(smtp_config[user], smtp_config[auth_code]) server.send_message(msg)实测下来QQ邮箱SMTP在Linux服务器上几乎没有兼容性问题反而是有些邮箱服务商对第三方登录限制比较多稍微配置不好就被当成垃圾邮件。如果遇到发不出去或者进垃圾箱的情况优先检查授权码格式、发件人地址是否和SMTP账号一致。3.4 推送层统一封装一套代码三端并行三种渠道都实现之后我建议把它们封装成一个统一的推送函数。主流程里只需要调用一个方法然后传入渠道列表系统自动把报告发送到指定渠道。这样主逻辑干净利落后续想加新的推送渠道比如钉钉、Telegram只需要扩展这个模块。def push_report(report, channels, config): if wechat in channels: send_wechat_markdown(report[summary], config[wechat_webhook], config[wechat_secret]) if feishu in channels: send_feishu_card(report[summary], config[feishu_webhook], config[feishu_secret]) if email in channels: send_email_html(report[title], report[html], config[smtp], config[mail_to])我现在的配置是三端同时推送企业微信用来快速扫一眼飞书卡片用来做团队协作展示邮件则留作全量报告的归档。三份内容形式不同、侧重点不同但数据来源完全一致不会出现“微信说涨、邮件说跌”的矛盾。4. 安装部署与定时任务让系统自己跑起来4.1 环境准备虚拟环境装依赖别污染系统部署的第一步是准备Python环境。我建议在服务器上使用Python 3.9或更高版本并且一定要用虚拟环境。很多人在自己的电脑上跑脚本没问题一放到服务器上就各种报错原因多半是系统自带的Python环境和项目依赖发生了冲突。创建虚拟环境并使用mkdir stock_report cd stock_report python3 -m venv venv source venv/bin/activate pip install --upgrade pip项目依赖集中在requirements.txt里主要是以下几个库akshare1.14.0 pandas2.0.0 requests2.31.0 openai1.30.0 PyYAML6.0安装依赖pip install -r requirements.txt这里补充一句akshare的版本更新频率比较高个别接口会有变动。如果你运行的时候发现某个数据接口报错了先看看是不是akshare版本太旧升级到最新版往往能解决问题。4.2 项目结构与配置把敏感的Key全部隔离出来项目结构我习惯这样组织每个文件职责单一stock_report/ ├── main.py # 主入口 ├── config.yaml # 配置文件 ├── requirements.txt # 依赖清单 ├── core/ │ ├── data_fetcher.py # 数据获取 │ ├── ai_analyzer.py # AI分析 │ └── report_builder.py # 报告生成 ├── pusher/ │ ├── wechat.py # 企业微信推送 │ ├── feishu.py # 飞书推送 │ └── email.py # 邮件推送 └── logs/ └── run.log # 运行日志配置文件使用YAML格式把所有需要改动的参数集中在一起。自选股列表、大模型API的base_url和Key、各推送渠道的Webhook地址、SMTP配置全部放在config.yaml里stocks: - 600519 - 000001 - 300750 llm: base_url: https://api.deepseek.com api_key: sk-你的key model: deepseek-chat push: wechat_webhook: https://qyapi.weixin.qq.com/cgi-bin/webhook/send?keyxxx wechat_secret: feishu_webhook: https://open.feishu.cn/open-apis/bot/v2/hook/xxx feishu_secret: smtp: host: smtp.qq.com port: 465 user: 你的邮箱qq.com auth_code: 你的授权码 mail_to: 收件人example.com敏感信息放在配置文件里之后还要注意一件事如果你把项目传到GitHub等公开平台一定要在.gitignore里排除config.yaml和venv目录。我有一次差点把真实的Webhook地址提交到公开仓库还好及时发现撤回了不然后果就是任何人拿到你的Webhook地址都能往你的群里发消息。4.3 定时调度crontab和任务计划程序二选一主程序开发完成之后最后一步是配置定时任务让系统每天自动运行。我的服务器运行的是Linux系统直接使用crontab。核心配置项如下30 8 * * 1-5 cd /opt/stock_report /opt/stock_report/venv/bin/python main.py logs/run.log 21这行cron表达式的含义是每周一到周五的8点30分执行一次main.py并把标准输出和错误日志都写进logs/run.log。时间是按照服务器本地时间来的如果你的服务器是UTC时间记得换算成北京时间否则定时任务就在凌晨跑了。如果你的部署环境是Windows可以在任务计划程序里创建基本任务触发器选择“每周”然后指定周一到周五、触发时间操作选择运行Python脚本效果是一样的。这里有一个crontab经典坑cron运行时环境变量和普通终端不一致。直接写python main.py很可能找不到Python因为cron的PATH里没有虚拟环境的路径。所以cron命令里一定要写Python的绝对路径也就是/opt/stock_report/venv/bin/python不要偷懒。此外建议在main.py里加一个非交易日判断。A股周末和法定节假日不开盘如果定时任务在节假日也跑拿到的数据就是前一天的旧数据不仅没意义还会产生无用的推送。我使用akshare的交易日历接口来判断当天是不是交易日如果是节假日就直接退出脚本。5. 常见问题与排查技巧我踩过的坑你就不用再踩5.1 高频问题速查表这个系统跑起来之后我陆续遇到过不少问题把高频问题整理成了一个速查表方便大家对照排查现象可能原因解决办法akshare获取行情报错接口版本升级或临时维护升级akshare到最新版或稍后重试模型返回的不是合法JSON模型输出飘了或者带Markdown代码块在Prompt中加严格JSON约束解析时strip掉json围栏企业微信推送提示签名错误加签的timestamp和sign拼接顺序不对严格按“timestamp\n密钥”格式计算签名飞书卡片发送成功但不显示卡片JSON结构不符合飞书要求使用飞书官方卡片调试工具校验结构邮件进入垃圾箱发件账号、授权码或SPF配置有问题使用QQ邮箱SMTP检查发件人和授权码是否一致定时任务没执行cron的PATH环境变量和虚拟环境不一致使用Python绝对路径重启cron服务报告里中文乱码服务器缺少中文字体或HTML没有声明UTF-8安装中文字体HTML的head里加charsetutf-8表格只是索引具体调试方法我在下面补充几条经验。5.2 几个容易忽略但很关键的细节第一个是模型返回内容的清洗。我调试的时候发现大模型输出JSON时偶尔会在开头加一段解释文字或者用json围栏把JSON包起来。解析之前必须做清理把多余的前缀后缀去掉再用json.loads解析。更稳妥的做法是加上response_format{type: json_object}这样模型会尽量只输出JSON解析成功率会高很多。第二个是推送渠道的联动问题。如果某个渠道推送失败不要影响其他渠道。比如企业微信Webhook偶尔会限流但邮件照样能发。我的主流程对每个推送渠道做了独立的try-except某个渠道异常只记日志不影响整体执行。这个设计在实际运行中非常管用。第三个是日志的重要性。整个系统挂在定时任务里如果出了问题不及时看日志排查会非常痛苦。我在关键节点都加了日志输出比如“开始拉取数据”“AI分析完成”“企业微信推送结果success”。使用logging模块把日志同时输出到控制台和文件一旦系统没有推送打开logs/run.log就能看到卡在哪一步。第四个是报告链接的时效性。如果你把HTML报告放在本机服务器上然后推送一个本地链接企业微信和飞书里点开是没有意义的因为手机没法访问你的服务器内网地址。我目前的方案是用推送内容代替链接把最重要的结论直接展示在消息里完整报告则通过邮件发送HTML正文。这样最省事而且不受服务器访问限制。5.3 对“顶底信号98%指标源码”这类东西我的看法在做这个系统的过程中我经常在搜索技术方案时看到“顶底信号98%指标源码”“稳赚指标源码”之类的词条。这类内容通常宣传某个技术指标的胜率高达98%只要拿到源码就能精准抄底逃顶售价往往还不便宜。我的看法比较直接这类宣传绝大多数是事后拟合的产物用历史数据回测出来的高胜率指标在实盘环境里大概率会失效。这套系统本身也会用到技术指标比如MACD、RSI、均线但我始终把指标当作辅助参考而不是决策核心。真正的价值在于自动化流程、数据完整性、分析逻辑的一致性而不是某个“神奇指标”。提醒一下读者遇到任何声称高胜率、稳赚不赔的指标源码或课程先冷静下来多问一句它有没有经过足够长的实盘验证有没有考虑滑点和手续费。股市里没有免费的午餐这句话什么时候都不过时。使用这套系统还有几个真正的风险点模型分析结论的准确性受数据质量影响很大我每次升级数据源或者调整Prompt都会用历史数据先回测一遍确认结论没有明显偏差再上线。另外任何自动化系统都应该设定安全边界比如如果某只股票跌幅超过阈值系统会强制在报告里置顶风险提示不能因为“AI说没事”就忽略市场的异常信号。我个人在实际操作中最大的体会是可以用这套系统节省时间、提高信息整理效率但绝对不能把决策权完全交给AI。模型给的是“第二意见”你自己才是最终决策者。每天推送的报告里我第一眼看的不是评分最高的股票而是评分相比昨天变化最大的那几只因为异常往往意味着风险或者机会。这个习惯帮我避开了好几次回调也让这套系统真正成了我每天开盘前离不开的辅助工具。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进