ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

用DeepSeek与Python搭建股票趋势预测系统实战指南

用DeepSeek与Python搭建股票趋势预测系统实战指南 简介这是一份基于DeepSeek与Python的股票趋势预测系统教程面向具备Python基础并对量化分析感兴趣的投资者、金融从业者与数据科学初学者帮助读者借助自然语言指令驱动DeepSeek自动生成数据分析代码降低量化分析的技术门槛。文档以宁德时代300750.SZ为实战案例系统演示了通过AKShare与yfinance获取行情数据、利用pandas-ta计算MACD、RSI与布林带等指标并使用matplotlib绘制包含K线、成交量和指标子图的复合图表随后引入backtesting库构建双均线策略完成回测并解读夏普比率与回撤等关键指标形成一套从数据获取、指标计算、可视化到策略评估的完整流程。资料为单个docx文档大小仅19KB内容紧凑适合边读边实践已有266人学习下载对希望快速上手AI辅助量化分析、提升自动化分析能力的财经研究人员和交易爱好者具有较好的参考价值。1. 用 DeepSeek 与 Python 搭一套股票趋势预测系统到底值不值得做手工翻 K 线判断均线金叉、再拿 Excel 手算回测收益的日子做过的人都懂费时间不说手续费一算错策略结论就全偏了。标题里这套系统把 DeepSeek 放进去不是让它直接预测涨跌而是让它当“指标解读员”和“策略助手”——Python 负责算技术指标、跑双均线回测DeepSeek 负责把指标状态翻译成你能看懂的交易信号说明。它适合三类人刚学完 pandas 想练手量化的开发者、有编程基础但不想碰 MATLAB 这类重工具的投资者、以及需要快速给领导交付一份“带结论和回测曲线”分析的金融 IT。看完这篇你能跑通一条从行情数据到指标计算再到双均线回测和数据解读的完整链路也知道哪些做法的结果根本不能信。2. DeepSeek 与 Python 环境搭建语言模型在量化流水线里到底干什么2.1 为什么是 DeepSeek趋势预测系统里的“翻译官”和“辅助实现者”先说一个常见的预期误区很多人以为把 DeepSeek 接进来就能直接问它“明天涨不涨”然后把回答当成买卖信号。我自己的实践结论是这类问题的准确率跟抛硬币没本质区别而且大模型不会告诉你它的置信度从哪来。真正靠谱的用法是让它干三件事。第一把技术指标状态翻译成自然语言。比如 MACD 金叉、RSI 进入超买区、双均线多头排列这些在代码里就是一堆布尔值但写成“5日均线上穿20日均线且 MACD 红柱连续三天放大但 RSI 已到 72”这样的描述人能快速判断当前市场情绪。第二在回测前帮你审查策略逻辑比如把策略代码贴给它让它指出“信号是否用了当日收盘价成交”“有没有未来函数”这类问题。第三生成回测结果解读把年化收益率、最大回撤、夏普比率这些数字串成一段有逻辑的文字方便汇报。选 DeepSeek 而不是其他模型我主要看三点一是成本跑日常的指标解读和代码审查它的 token 价格比那些旗舰模型低一个数量级一天调几千次也没压力二是中文表达质量金融领域“死叉”“超买”“量价背离”这些术语它理解得很准三是接口兼容 OpenAI 格式这意味着你之前写过的调用代码改一个 base_url 就能切过来codex、vscode 这类工具要接入也很方便。如果数据敏感还能用 ollama 这类工具本地部署模型权重文件下载后内网离线跑不经过外部服务。2.2 最小环境安装conda 建环境与依赖清单这个项目不需要特别重的环境我一般用 Miniconda 建一个独立环境避免把系统 Python 搞乱。Python 版本建议选 3.10 或 3.113.12 在部分科学计算扩展上还有兼容性小坑新手没必要在这上面浪费时间。conda create -n quant python3.10 -y conda activate quant pip install pandas numpy akshare tushare backtrader matplotlib openai依赖里逐个说明用途pandas 和 numpy 是数据清洗和指标计算的地基akshare 用来拉免费 A 股日线行情tushare 作为备用数据源backtrader 是回测框架如果你打算自己写向量化回测可以只装前面的matplotlib 用来画净值和参数热力图openai 不是给 OpenAI 用的是复用它的客户端库把 base_url 指向 DeepSeek 的接口地址。装完之后可以用一条命令验证环境没问题python -c import pandas, akshare, backtrader; print(pandas.__version__)看到版本号输出就说明依赖都到位了。这里不建议在系统 Python 里直接装特别是公司机器上等到被系统自带的旧版 pandas 坑了再回头建环境白白浪费半天。2.3 封装 DeepSeek API 调用把自然语言回答变成 JSON 信号DeepSeek API 的调用方式核心就一句话构造一个 OpenAI 兼容的对话请求返回的既可以是普通文本也可以是结构化 JSON。下面是这个系统里最常用的一段封装代码传入指标快照和一段提示词返回解析好的字典。import json import re from openai import OpenAI client OpenAI( api_keysk-xxxxxxxx, base_urlhttps://api.deepseek.com ) def ask_deepseek(system_prompt: str, user_content: str) - dict: resp client.chat.completions.create( modeldeepseek-chat, temperature0.2, response_format{type: json_object}, messages[ {role: system, content: system_prompt}, {role: user, content: user_content} ] ) content resp.choices[0].message.content # 兜底偶尔模型会在 JSON 外夹带解释性文字 match re.search(r\{.*\}, content, re.S) return json.loads(match.group(0))参数说明temperature 设 0.2 是让输出尽量稳定金融场景宁可保守也不要发挥response_format 指定 json_object要求模型只输出合法 JSON但实际使用中我仍然保留了正则抽取的兜底逻辑——因为偶尔还是会遇见模型在 JSON 前后多写一行注释的情况。system_prompt 里要写死“你是一名量化分析师根据输入的技术指标快照输出包含 trend_signal、risk_level、reason 三个字段的 JSON”。补充一个调用层面的坑如果你用 function calling 功能DeepSeek 要求模型发出 tool_calls 后立即在同一轮对话中补上工具返回消息否则会报 “messages tool calls need immediate results” 之类的错误。这个系统里其实用不到 function calling我后来都改成纯提示词输出 JSON 了少一个环节就少一层出错概率。3. 技术指标集成把 K 线行情变成特征矩阵3.1 用 akshare 拉数据复权方式决定回测可信度技术指标计算的第一步是拿到干净的日线数据。A 股行情我用 akshare 比较多它的接口覆盖全不需要 token适合快速验证。下面是拉取单只股票日线并转向量化的代码。import akshare as ak import pandas as pd df ak.stock_zh_a_hist( symbol600519, perioddaily, start_date20200101, end_date20241231, adjusthfq ) df.columns [date, open, close, high, low, volume, amount, amplitude, pct_change, change, turnover] df df[[date, open, close, high, low, volume]].copy() df[date] pd.to_datetime(df[date]) df df.sort_values(date).reset_index(dropTrue)参数说明symbol 传股票代码adjust 有三档qfq 前复权、hfq 后复权、空字符串是不复权。这里必须强调一个多数教程不讲透的点——做回测建议用 hfq 后复权。原因我在第 5 章的避坑部分会展开简单说就是前复权的历史价格会随着该股票每次新的除权除息而整体改写等于你用“未来发生过的新事件”重写了历史行情回测结果自然不可信。拿到数据后先检查三件事有没有停牌导致的 NaN 行、日期是否严格递增、有没有成交量恒为 0 但价格正常跳动的异常数据。这些脏数据不清理后面算 MACD 时一个 NaN 就能让整列指标失效。3.2 用 pandas 计算双均线与 MACD、RSI指标代码与参数含义技术指标集成这一步说白了就是把 K 线转换成一张特征矩阵每行对应一个交易日每列是一个指标值。双均线是基础MACD 看趋势延续RSI 看超买超卖三者组合是趋势跟踪最常见的搭配。# 双均线 df[ma_fast] df[close].rolling(window5).mean() df[ma_slow] df[close].rolling(window20).mean() # MACD: EMA12 - EMA26, 再用 DEA9 作为信号线 df[ema_fast] df[close].ewm(span12, adjustFalse).mean() df[ema_slow] df[close].ewm(span26, adjustFalse).mean() df[macd_dif] df[ema_fast] - df[ema_slow] df[macd_dea] df[macd_dif].ewm(span9, adjustFalse).mean() df[macd_hist] df[macd_dif] - df[macd_dea] # RSI14: 用 Wilder 平滑而不是简单平均 delta df[close].diff() gain delta.clip(lower0) loss -delta.clip(upper0) avg_gain gain.ewm(alpha1/14, adjustFalse).mean() avg_loss loss.ewm(alpha1/14, adjustFalse).mean() df[rsi14] 100 - 100 / (1 avg_gain / avg_loss)参数说明rolling(5) 和 rolling(20) 是最常见的双均线组合但后面你会在第 6 章看到5 和 20 绝不是最优解不同股票差异很大MACD 的 12、26、9 是经典参数源自原始 EMA 设计一般不必改RSI 里我特意用了 Wilder 平滑alpha1/14这比简单移动平均更平滑在趋势行情里不会频繁触碰 30/70 阈值。所有指标都基于当日收盘价计算所以它们天然只能用来生成“次日信号”这一点是回测逻辑的地基。算完之后建议马上做一步验证打印 df.tail() 看最后几行的指标值再手动拿一只票的行情软件 K 线对照一下 MACD 和 RSI 数值是否一致。指标算错了后面策略再漂亮也是空中楼阁。3.3 信号合成多指标打分比规则叠加更抗噪有了单个指标接下来要决定怎么合成交易信号。最朴素的做法是硬规则叠加5 日均线上穿 20 日均线且 MACD 红柱为正且 RSI 大于 50三个条件全部满足才买入。这个方案在牛市里还行震荡市里会被反复打脸——三个指标稍微不同步信号就频繁开合手续费全给券商打工。我常用的替代方案是打分制。每个指标贡献一个分数加总后超过阈值才触发信号features pd.DataFrame(indexdf.index) # 双均线: 多头排列 1, 金叉 2 features[score_ma] (df[ma_fast] df[ma_slow]).astype(int) features[score_ma] ( (df[ma_fast] df[ma_slow]) (df[ma_fast].shift(1) df[ma_slow].shift(1)) ).astype(int) * 2 # MACD: 零轴上方 1, 红柱放大 1 features[score_macd] (df[macd_dif] 0).astype(int) features[score_macd] (df[macd_hist] df[macd_hist].shift(1)).astype(int) # RSI: 回踩中轴不破 1, 超买区减 1 (防止追高) features[score_rsi] (df[rsi14] 50).astype(int) features[score_rsi] - (df[rsi14] 75).astype(1) df[signal_score] features.sum(axis1)打分逻辑说明score_ma 里金叉事件单独加 2 分而不是普通多头排列的 1 分是为了让金叉这个“拐点”在总分里权重足够大score_macd 看红柱是否在放大对应的是动能增强score_rsi 做了个防追高惩罚RSI 超过 75 反而扣分。最终 signal_score 大于等于 3 才视为买入信号。这套打分矩阵有两个好处一是阈值可调你可以根据风险偏好把买入线从 3 改成 4或者加入新的指标维度而不影响已有逻辑二是它的输出结果直接就是一段结构化特征丢给 DeepSeek 时不用贴原始行情只传每个维度的分数和对应的文字状态token 消耗小很多模型也更容易输出准确解读。把 scores 转成 JSON 字符串拼进 user_content就能得到类似“当前综合评分 4 分趋势偏多但追高风险上升”的判断。4. 双均线策略回测实现从金叉死叉到净值曲线4.1 回测引擎选型backtrader 与向量化回测的取舍动手写回测前先选工具。双均线这种策略可以只用 pandas 做向量化回测也可以上 backtrader 这类事件驱动框架两条路我都走过给一个不吹不黑的对比。向量化回测的优点是代码透明、执行快一个 8 年日线数据跑一遍只要几十毫秒参数网格搜索时可以循环几千次缺点是逻辑复杂后容易失控带止损、加仓、多品种联动时条件判断会绕晕。backtrader 的优点是券商佣金、滑点、成交量限制这些实盘要素都有原生支持而且天然按“每日 bar 推进”的节奏撮合更接近真实交易缺点是学习曲线陡策略类要继承它的 Strategy 基类回调方法多新手容易在 next 和 notify_order 之间看懵。我的建议很直接双均线这种无状态策略先用向量化回测跑通逻辑、验证参数再用 backtrader 做一次带交易成本的复核。下面 4.2 和 4.3 分别给出两套实现你可以直接对照用。4.2 双均线策略骨架前一日收盘信号次日开盘成交先看向量化版本这是整个回测逻辑里最重要的一段信号偏移的处理也在这里import pandas as pd def run_backtest(df, fast5, slow20, fee0.0003, slippage0.001): data df[[date, open, close]].copy() data[ma_fast] data[close].rolling(fast).mean() data[ma_slow] data[close].rolling(slow).mean() # 用收盘价产生的信号只能次日执行 data[target] (data[ma_fast] data[ma_slow]).astype(int) data[target] data[target].fillna(0) data[target_exec] data[target].shift(1) data[trade] data[target_exec].diff().fillna(0) # 成交价: 次日开盘价 滑点损失 data[exec_price] data[open] * (1 slippage) data[position] data[target_exec] data[daily_ret] data[close].pct_change().fillna(0) # 手续费按双边费率从当日净值中扣除 data[cost] data[trade].abs() * fee data[strategy_ret] data[position] * data[daily_ret] - data[cost] data[nav] (1 data[strategy_ret]).cumprod() return data result run_backtest(df, fast5, slow20)逻辑说明与关键参数signal 用快慢均线比较生成1 表示持有、0 表示空仓target_exec 是 target 的 shift(1)这是回测里不能省的一步——5 日均线和 20 日均线都是收盘后才有确定值金叉信号最早只能让策略在下一个交易日开盘时下单如果直接用当天收盘价成交就等于偷看了收盘价再交易属于典型的未来函数。trade 是 target_exec 的差分1 表示买入、-1 表示卖出。手续费 fee 默认万三slippage 默认千一这两个值后面会专门展开讲。跑完这段代码才能算真正有了“双均线策略”。但从结果文件里我只能看到两组结果对比一组是未调参的默认版一组是网格搜索后的优化版。4.3 交易成本与滑点设置扣完手续费还赚不赚回测里最容易被美化的是交易成本。很多人拿免费的行情数据回测手续费设 0滑点设 0最后跑出年化 50% 的曲线实盘一周就原形毕露。A 股的实际交易成本分三块佣金双边万 2.5 到万 3最低收取 5 元卖出时缴纳印花税当前是成交额的 0.05%另外还有极小的过户费可以忽略不计。按满仓进出一次计算双边综合成本大约在千分之一点五到千分之二。如果策略年交易次数超过 50 次光成本就把一半的毛收益吃掉了。把成本放进回测就是下面这个 backtrader 复核版import backtrader as bt class DoubleMA(bt.Strategy): params ((fast, 5), (slow, 20)) def __init__(self): self.ma_fast bt.ind.SMA(periodself.p.fast) self.ma_slow bt.ind.SMA(periodself.p.slow) self.cross bt.ind.CrossOver(self.ma_fast, self.ma_slow) def next(self): if not self.position and self.cross 0: self.buy(size1000) elif self.position and self.cross 0: self.sell(size1000) cerebro bt.Cerebro() cerebro.addstrategy(DoubleMA) feed bt.feeds.PandasData(datanamedf) cerebro.adddata(feed) cerebro.broker.set_cash(100000) cerebro.broker.set_commission(commission0.0003) cerebro.broker.set_slippage_perc(perc0.001) results cerebro.run()参数说明bt.ind.CrossOver 在快线上穿慢线时返回 1下穿时返回 -1next 方法里据此发出买卖指令set_commission 是双边佣金率set_slippage_perc 按成交价百分比模拟滑点。backtrader 的 next 方法在每日 bar 开始后执行买入按当日开盘价加滑点成交这跟我们向量化版本 shift(1) 的语义是一致的——它天然杜绝了“收盘价信号同日成交”的未来函数。对比两个版本的输出重点看三类指标总交易次数、最终净值、最大回撤。如果 backtrader 版本因为手续费和滑点导致交易次数明显少于向量化版本说明向量化版本可能在高频翻转区域做了一堆无效交易策略本身就不过关如果两版本净值差距超过 5%优先查持仓状态的计算有没有偏差。5. 回测与 DeepSeek 集成的四个常见坑现象、原因、解决5.1 信号与成交价错位金叉当天收盘价成交是最大的净利润幻觉现象回测净值曲线非常漂亮年化收益 30% 以上最大回撤不到 10%但按同样参数做模拟盘一个月业绩直接腰斩。查了半天发现回测里所有买入都发生在金叉当天的收盘价而实盘里你最快也只能在金叉次日开盘买入。原因这是未来函数最典型的一种。双均线是收盘后的确定值你在收盘瞬间看到金叉的同时就已经用这个收盘价成交等于在同一根 K 线上既当裁判又当运动员。A 股没有收盘后交易机制这个成交根本不可能发生。解决向量化代码里用 target.shift(1) 把信号整体后移一天成交价用次日开盘价或者改用 backtrader它天然按次日开盘撮合。这一个改动做完回测年化收益通常会下降 5 到 10 个百分点但这才是你实盘能拿到的数字。5.2 前视偏差指标和 DeepSeek 回答都别偷看未来现象同一套双均线参数在 2020 到 2022 年数据上回测年化 40%换到 2017 到 2019 年数据上直接亏损参数完全失效。原因除了信号错位还有一种隐蔽的前视偏差来自数据预处理。比如用全样本的均值和标准差做标准化或者计算指标时用了未来窗口的数据做平滑。更隐蔽的是 DeepSeek 侧的问题——如果你在提示词里把整段含当日及以后的行情数据都传给它它的回答里透着“我知道后面涨了”的后见之明这种解读等于把你的决策带偏。解决数据侧任何标准化参数都只用截至 t 日的历史数据计算rolling 窗口默认向后看DeepSeek 侧提示词里明确写“以下数据截至 2024-12-31请基于此日期之前的信息分析”同时在构造上下文时只保留截止当天的指标快照不要在提问里带上未来任意一天的数据。5.3 前复权价格漂移换一次除权历史信号全变现象同样一只股票、同样的策略代码上个月回测是盈利的这个月公司除权除息后重新拉数据跑一遍结果变成了亏损而这段历史行情明明没有变过。原因数据源默认返回的前复权价格会以最新交易日为基准重写全部历史价格。每次新的分红送转发生过去的每根 K 线都会被等比调整你的均线金叉死叉位置跟着移动回测信号自然变。说直白点前复权让历史行情被未来事件污染了。解决回测统一用 hfq 后复权它的价格序列不会因为后续除权而改变实盘决策时再用前复权看真实成交价。这个教训是我自己踩过的当时一只持仓股分红后参数全变我还以为是代码 bug查了两天才明白是复权方式的问题。5.4 过拟合参数择优把噪音当成了规律现象用网格搜索跑 60 组双均线参数找到一组在历史数据上年化收益最高的比如快线 3、慢线 47但样本外跑一个月就失效亏损速度比默认参数还快。原因双均线参数只有快线周期和慢线周期两个自由度在 60 组组合里挑表现最好的本质上是在历史噪音里找到一组巧合这组参数的市场规律含义趋近于零。参数越极端过拟合风险越高3 日均线这种超短周期参数尤其可疑。解决不要只看最优参数要看参数平原。把网格结果画成热力图找到“周围一大片参数收益都还不错”的区域取这个区域的中心点作为最终参数单独一个尖峰再高也不能选。我在第 6 章会给出具体画法。6. 进阶双均线参数敏感性分析与参数平原选取最后一层落地实操用参数敏感性分析给双均线策略“验尸”。方法很简单固定回测逻辑和交易成本让快线周期和慢线周期各自遍历一组范围跑完所有组合后画一张热力图。看这张图你能直接回答两个问题最优参数到底稳不稳、策略在哪个区间内是鲁棒的。import numpy as np import matplotlib.pyplot as plt fast_list [3, 5, 8, 10, 15, 20] slow_list [15, 20, 30, 40, 50, 60] grid np.full((len(fast_list), len(slow_list)), np.nan) for i, f in enumerate(fast_list): for j, s in enumerate(slow_list): if f s: continue r run_backtest(df, fastf, slows) grid[i, j] r[nav].iloc[-1] - 1 fig, ax plt.subplots(figsize(10, 7)) im ax.imshow(grid, cmapRdYlBu, aspectauto) ax.set_xticks(range(len(slow_list)), slow_list) ax.set_yticks(range(len(fast_list)), fast_list) ax.set_xlabel(slow period) ax.set_ylabel(fast period) plt.colorbar(im) plt.show()说明一下我自己的判读顺序先找颜色最深的格子再看它周围至少两个方向上的邻域是不是也偏深色。如果最优参数周围一圈全是深蓝亏损区说明这是一根尖峰纯属运气如果周围是一大片黄色到红色渐变才算得上参数平原这时候取平原几何中心的参数比直接取峰值参数稳得多。我实际用下来还有个衍生习惯把时间轴切成年分年度画同样的热力图如果最优参数在不同年份里漂移严重说明这个策略对市场风格切换极度敏感不值得投入真金白银。这套系统整体走完我的个人习惯是在每季度重新拉一次数据、重跑一遍参数热力图不轻易改参数但会观察参数平原是否在移动。做量化这一行稳定压倒一切回测里能讲清楚的钱才是真的能赚到的钱。希望这篇文章的思路和代码帮你在趋势预测系统上少走几段弯路。本文还有配套的精品资源点击获取
返回列表