本文参与 #WorkBuddy 话题征文。是一篇纯实战踩坑记录:怎么把每天雷打不动的盘后选股报告,从"每篇都烧 AI 积分"改造成"AI 只花一分钟取数,剩下全靠本地 Python 脚本白嫖"。文中的坑我都真踩过,代码可以直接抄。
我是 A 股日内交易者,每天收盘后要看一份固定的盘后报告:13 只跟踪股 + 10 只关注股 + 5 大指数 + 6 只 ETF,外加融资融券数据。用 WorkBuddy 生成这份报告很爽——数据自己取、分析自己算、报告自己写。
但月底一看积分账单,人麻了。后来研究明白了,问题出在三个地方:
积分杀手 | 原理 | 我的实测感受 |
|---|---|---|
长对话滚雪球 | 每发一条消息,整个历史对话都打包发给模型,第 20 轮的消耗可能是第 1 轮的 10 倍 | 选股是天天聊的话题,一个窗口聊几十轮,越聊越贵 |
Craft 模式 | 又要搜数据又要算指标又要写报告,单轮消耗是纯聊天的 2~3 倍 | 每天两份报告,日积月累 |
重复劳动 | 同样的均线、量能、形态分析,AI 每天从头算一遍 | 每一分积分都花在"昨天算过的东西"上 |
第三条最冤——分析逻辑是固定的,凭什么每天付一遍钱?
想通这一点,方案就自然出来了:
┌─────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ WorkBuddy │ │ 本地 Python │ │ 成品报告 │
│ 只负责取数 │ --> │ kline_utils.py │ --> │ HTML/Markdown │
│ 存成 JSON │ │ 分析+评分+生成 │ │ 零积分消耗 │
└─────────────┘ └──────────────────┘ └─────────────────┘
消耗积分:约1次 消耗积分:0 消耗积分:0
对话轮数:1轮 想跑几遍跑几遍改造前后对比(按我的使用强度估算):
改造前 | 改造后 | |
|---|---|---|
每日报告积分消耗 | 数十~上百积分/天 | AI 取数一轮(个位数积分) |
复算/回测 | 每次复算都要重新对话 | 本地脚本随便跑 |
结果稳定性 | 模型偶尔发挥不稳定 | 代码算的,每天一个样 |
这套系统跑通前,我出过一次25 只股票集体判错的事故。
行情接口返回的 K 线数据是最新在前(倒序)的。我最初的脚本没处理这个,直接拿 klines[-1] 当"最新一根"算均线位置——实际取到的是几个月前的数据。结果 25 只股票的"站上均线/跌破均线"全部判反:有只股票明明暴跌跌破均线,报告里却写着"站上均线"。
发现的时候后背发凉:这种错不会报错,只会安安静静地给你一份看起来很专业的错报告。
修复方案后来固化成了一个小模块,核心就 8 行:
def load_kline_safe(filepath, expected_recent_days=7):
with open(filepath, 'r', encoding='utf-8') as f:
data = json.load(f)
klines = data if isinstance(data, list) else data.get('data', [])
# 核心:判断是否倒序,倒了才翻
first_date, last_date = klines[0]['date'], klines[-1]['date']
if first_date > last_date: # 第一根比最后一根"新" = 倒序
klines = list(reversed(klines))
# 新鲜度校验:最后一根K线必须足够新
last_dt = datetime.strptime(klines[-1]['date'], '%Y-%m-%d')
if (datetime.now() - last_dt).days > expected_recent_days:
print(f"⚠️ 数据过期:最后一根K线是 {klines[-1]['date']}")
return klines两个细节值得说:
reversed() 的隐患是:如果哪天接口改成正序返回,无脑翻转会把好数据翻成坏的——同款事故换个方向再来一遍。现在我的规矩是:所有分析脚本禁止自己写 K 线加载,必须走 load_kline_safe() 这个统一入口。入口统一了,防错逻辑只需要对一个地方负责。
报告生成脚本 600 多行,骨架长这样(可复用的就这个分层思路):
# gen_tracking_report.py 骨架
def load_batch_klines_safe(filepath): # ① 统一入口:批量加载+翻转+校验
...
def get_ma_position(klines): # ② 均线位置(MA5/10/20/60)
...
def detect_bottom_patterns(klines): # ③ 底分型检测
...
def detect_master_klines(klines): # ④ 主控K线(涨幅+实体+量比三条件)
...
def calc_trend_angle(klines): # ⑤ 趋势角度(线性回归斜率转角度)
...
def calc_score(...): # ⑥ 综合评分 v2.2
...
def generate_report(stocks_data): # ⑦ 汇总生成 Markdown 报告
...
def md_to_html(md_content): # ⑧ 转 HTML 便于阅读
...
if __name__ == '__main__':
main() # 一条命令出全部报告,零积分
AI 取数存的 JSON 长这样(每次带元信息,方便校验):
{
"fetch_time": "2026-08-28T15:14:38",
"date": "2026-08-28",
"source": "westock-mcp",
"data": {
"sh600227": { "klines": [ {"date": "...", "open": 0, "last": 0, "high": 0, "low": 0, "volume": 0} ] }
}
}
fetch_time 和 date 这两个元信息字段是我的血泪经验:出问题的时候,第一件事就是看这份 JSON 到底是什么时候取的——先怀疑数据,再怀疑代码,最后才怀疑自己。
时间 | 动作 | 积分消耗 |
|---|---|---|
15:10 收盘后 | 开一个全新对话窗口(不带历史上下文),一句话让 WorkBuddy 把当天 K 线和快照存 JSON | 个位数 |
15:12 | 本地跑 | 0 |
随时 | 想复算、改参数、回测?本地脚本随便跑 | 0 |
例外情况 | 需要解读新闻、研报、盘中突发——这类非结构化任务才交给 AI | 按需 |

上面就是"取数"这一步的真实样子:WorkBuddy 调用行情连接器拉 K 线,结果存成 JSON,全程一轮对话。
另外一个省积分的细节:取数对话每次都开新窗口。长对话滚雪球是积分第一杀手,固定任务用固定的新窗口,消耗直接降一个数量级。
这套思路不限于股票,判断标准就一条:逻辑是否固定。
适合搬去本地脚本 | 留给 AI |
|---|---|
每天算同样指标的报表 | 解读新闻、研报、公告 |
固定格式的周报/日报排版 | 写作、翻译、总结 |
规则明确的筛选、评分、排序 | 临时性、探索性分析 |
数据清洗、格式转换 | 需要调用外部服务的取数动作 |
一句话总结:让 AI 当"数据搬运工"和"临时参谋",别让它当"每天重复算同一道题的计算器"。
这套系统现在每天稳定出报告,积分消耗降到原来的零头。更重要的是结果稳定性:代码算出来的均线位置,昨天今天明天都一样,不会因为模型状态波动而飘。

对了,本文的写作过程本身也是个示范——初稿也是我先跑通系统、攒下真实数据和踩坑记录,再让 WorkBuddy 帮着整理成文的。工具用得对,攒积分和花积分可以两不误。
⚠️ 风险提示:文中所有内容仅为个人工具使用记录,不构成任何投资建议。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。