☰
用Python构建股市分析工具:数据清洗、技术指标与选股策略实践
2026/10/17 13:44:56 网站建设 项目流程

简介:这是一份以股市分析为主题的 Jupyter Notebook 数据科学项目包,适合对量化投资、金融数据分析感兴趣的开发者与数据科学学习者。项目整体采用标准的数据科学工程组织方式,将数据、特征工程、模型与可视化分层,并重点提供三套分析流程:超级投资者买入标的解析、标普500持有模拟以及EDA探索性分析,覆盖从数据清洗、变量探索到持仓模拟的常见环节,能够帮助读者快速建立一套可复用的分析框架。压缩包共包含34个文件,大小约1.75MB,以Python脚本、Notebook、RST文档和Makefile配置文件为主,其中14个py文件承担数据处理、模型构建与工具函数等职责,3个ipynb文件承载核心分析演示,Makefile与tox.ini便于自动化运行、环境配置与测试。目前已有469人学习下载,使用者可直接参照目录约定和Notebook流程复现分析,或替换为自己的数据源扩展个股与指数研究,是接触股市数据项目的轻量级参考。 如果只是想看股票涨跌,打开行情软件就够了。但如果你和我一样,想要搞清楚一只股票为什么涨、凭什么跌、背后那些技术指标到底在说什么,就会意识到手动翻页面太浪费时间。于是我动手写了一套名为stock_analysis的股市分析工具,把行情数据拉下来,用代码批量计算指标,再根据结果过滤候选标的。这套东西不算复杂,但确实解决了不少实际问题,今天就把完整思路和踩坑过程分享一下。

很多人觉得"股市分析"就是装个软件看K线,或者听专家讲宏观。但真正落到自己操作上,你会发现核心痛点不是"看不看得到行情",而是"信息太多看不过来"。当时我手上有一批自选股,每天收盘后想快速知道哪些票放量、哪些票突破均线、哪些票的MACD出现金叉,如果一个个打开软件去点,至少要花一个多小时。而用 stock_analysis 之后,全市场扫描一遍只需要几分钟,结果还能按自定义规则排序。这篇文章就是写给那些想用代码辅助判断、又不想被各种神通广大的神棍理论带偏的朋友。

1. 从"看盘"到"写码":我决定自己做分析工具的三个理由

1.1 现成软件满足不了"批量对比"需求

市面上的行情软件功能确实强大,但它们都是给人眼设计的。你可以在一个屏幕上看四五只股票的走势图,但很难同时对比几百只股票的关键指标。而股票分析的工作流里,很多决策恰恰需要横向对比:今天哪些票的成交量放大到昨天的两倍?哪些票的短期均线刚刚上穿长期均线?哪些票的布林带收窄到了极点?这些筛选需求用软件自带的选股器也能做,但规则一旦复杂起来,比如"20日均线大于60日均线,同时当日成交量大于5日均量1.5倍,并且RSI介于50到70之间",很多免费软件的表达式就写得让人头疼。

写代码的好处是能把所有规则定义得清清楚楚,逻辑一目了然。之前我试图用某软件的自带公式编辑器实现类似功能,折腾了整整一个晚上,最后被"函数嵌套层数限制"搞得心态崩溃。换到 Python 之后,同样的逻辑二十行代码搞定,而且每次跑批还能自动保存结果。

1.2 数据口径不统一,亲手摸过才放心

第二个原因是数据源之间的差异。那时候我常用两个行情软件对比同一只股票的均线位置,发现有时候金叉、有时候没金叉,一度以为是自己眼花了。后来仔细核对才发现,有些平台把除权日的数据做复权处理,有些则直接切断了历史价格,导致均线算法结果完全不一样。

自己做 stock_analysis 之后,我从一开始就明确所有计算都基于前复权价格。理由很简单:前复权能保证当下价格与近期历史价格连续可比,对于技术指标计算更贴近实际交易视角。这些细节用现成软件时根本不会注意,但真正自己实现一遍,才发现数据源的一致性比策略本身还重要。

1.3 想验证"某套逻辑到底行不行",需要可复现的代码

市场上流传着无数种选股逻辑,比如"MACD金叉买入""放量突破平台买入""缩量回调到20日线买入"等等。很多人凭感觉觉得某条逻辑有效,但从来不去验证。我当时的想法很直接:能不能写一套程序,把过去三年的历史数据跑一遍,模拟每条逻辑的收益曲线?这个需求只有自己写代码才能实现,因为逻辑本身必须精确到"哪一天、哪个价格、什么条件触发操作",没法用嘴说。

2. 数据清洗与指标计算:拿到的数据不能直接用

2.1 数据源怎么选:免费接口的取舍

我在 stock_analysis 里用的是公开的免费行情数据接口,这当然存在一些限制,比如单日请求次数有限、部分字段缺失,但胜在零成本、够用。对个人研究来说,免费接口已经能满足绝大多数需求。如果你有更稳定的数据源,那更好,但注意要保持数据格式统一,否则后面所有指标计算都要跟着改。

实际获取的数据里,最常见的脏数据是停牌日:某天成交量、成交额全是0,但价格保持前一天收盘价。许多现成软件会直接跳过停牌日,但如果你机械地拿去算均线,结果就会把停牌日当成正常交易日重复计入,均线产生偏差。所以清洗的第一步就是把停牌日识别出来并做标记,计算指标时单独处理。

2.2 复权计算:跌坑最深的环节

复权是一个绕不开的大坑。股票分红送股后,价格会出现跳空,如果不复权,技术指标会瞬间失效。我一开始偷懒,直接用原始价格算均线,结果遇到除权日,5日均线直接从8元跳到7元,看起来像暴跌,其实是分红导致的。后来我彻底改用前复权价格。

实现前复权的方式有很多,有些接口自带,有些需要自己计算。我的经验是直接利用数据接口提供的复权因子,把历史价格乘以复权因子得到前复权价格。需要注意:前复权价格是动态变化的,每出现一次新的除权除息,历史价格都会被重新调整。所以不要把所有数据永久缓存,最好每周重新拉取一次历史数据,保证复权因子是最新的。

2.3 自定义指标类:把每个指标写成独立函数

为了后续扩展方便,我并没有把指标计算糊在一个大函数里,而是每个指标单独写一个方法,输入是干净的历史行情数据,输出是一个和原始数据对齐的序列。这样做的好处是,新增一个指标只需要增加一个方法,完全不影响原有代码。

代码结构大致长这样:

class Indicators: def __init__(self, df): self.df = df # 包含 date, open, high, low, close, volume def sma(self, n): return self.df['close'].rolling(window=n).mean() def ema(self, n): return self.df['close'].ewm(span=n, adjust=False).mean() def macd(self, fast=12, slow=26, signal=9): dif = self.ema(fast) - self.ema(slow) dea = dif.ewm(span=signal, adjust=False).mean() return dif, dea, (dif - dea) * 2 def rsi(self, n=14): diff = self.df['close'].diff() up = diff.clip(lower=0).rolling(window=n).mean() down = -diff.clip(upper=0).rolling(window=n).mean() rs = up / down.replace(0, float('nan')) return 100 - 100 / (1 + rs)

这个架构看起来平平无奇,但妙在每个函数都只依赖 DataFrame 的结构,不依赖任何全局状态。这样单测也容易写,比如我测试过 MACD 在连续上涨行情下 dif 始终大于 dea,结果确实如此。

3. 核心选股逻辑:从行情密度到趋势强度

3.1 技术指标不是越多越好,关键是组合逻辑

刚开始接触股票分析时,我也曾陷入"指标收集癖",把 BOLL、KDJ、CCI、OBV 全都塞进代码里,每个指标都看,结果哪个都不敢信。后来逐步淘汰,最终在 stock_analysis 里保留的主力选股逻辑只有三个维度:趋势、动量和成交量。

趋势维度看均线排列和价格相对均线的位置;动量维度看 MACD 的金叉死叉状态和加速度;成交量维度看量比和量价关系。为什么选这三个维度?因为趋势决定了方向,动量决定了力度,成交量决定了资金关注度,三者组合起来至少能过滤掉大部分跟风交易。

举个例子,我经常用的一个简单筛选逻辑是:20日均线大于60日均线、MACD 的 DIF 值大于 DEA 值、今日成交量大于5日均量。就这三条规则,就能把全市场大部分阴跌或者横盘的股票过滤掉。当然,它也会漏掉一些大涨前的无量标的,这无法避免,任何规则都有取舍。

3.2 用"连续N天满足条件"替代单点信号

早期版本中,我只要看到当天某个信号触发就输出一个候选结果。后来回测发现,很多单点信号是噪音。比如 MACD 金叉,在震荡行情里会反复金叉死叉,如果当天触发就记录,很容易陷入反复打脸。

后来我把逻辑改成"条件连续满足N天"才算有效。比如 not just MACD 金叉当天,而是 DIF 和 DEA 的差值连续3天放大,才认为动量在持续。这样一来,候选数量大幅减少,但质量明显提升。这在代码实现上只是一行条件判断的事,但逻辑本质从"抓取瞬间信号"变成了"确认持续状态",效果差别非常大。

3.3 板块联动:不只看个股,还要看"同伴"

我还在 stock_analysis 里加了一个比较朴素的分析维度:把同行业股票放在一起看,如果多只股票同时出现放量突破,说明这个板块可能正在被资金关注。这个功能最初实现起来很麻烦,因为需要行业分类数据,后来我直接从公开数据源里抓取了行业板块列表,然后对每个板块做"达标家数统计"。

实现思路不复杂,就是遍历板块中的每只股票,运行选股规则,统计达标数量。如果某板块里超过三成成分股同时满足趋势+动量+量能条件,就标记为"强势板块",再重点看板块中的龙头。这种分析方式比单纯看个股指标更全面,也让我在复盘时能更快抓住主线。

4. 回测与实盘的落差:我踩过的几个关键坑

4.1 未来函数:回测收益虚高的头号元凶

写了回测代码之后,第一版结果出来吓了我一跳:按策略跑过去三年,年化收益率高得离谱。冷静下来一查,发现是未来函数在作祟。当时计算 MACD 信号时,我在第 T 天收盘时用了收盘价格,但判断条件里又引用了下一个交易日的数据。简单说就是"提前知道了明天的结果",回测自然完美。

排查未来函数有个土办法:打印出信号触发日期和第二天价格,肉眼看有没有明显的不合理。更规范的做法是把所有指标计算严格限制在"截至当日收盘可得数据"范围内。我花了一天时间重构代码,把所有计算都放进一个循环里,保证每天只用到过去的数据,改完之后的收益曲线变得真实可信,虽然没那么惊艳,但至少不会自欺欺人。

4.2 手续费和滑点:不加这两项就是耍流氓

另一个让回测失真的因素是交易成本。刚开始我自己写的回测模型里,买入价直接用第二天开盘价,卖出也直接用当天收盘价,完全没考虑手续费和滑点。结果实盘跑起来之后,策略的收益明显比回测差一截,因为每次交易都有佣金和印花税支出。

后来我给回测加了固定成本模型:买入时按成交金额加收万分之二点五佣金,卖出时加收万二点五佣金外加千一的印花税,同时每次交易额外计提千一的滑点成本。这一调整把年化收益直接打掉了好几个点,但也让回测结果更接近真实。我建议任何回测都别省这一步,哪怕你用的模拟盘没有真实手续费,也请务必在代码里加上成本参数,否则策略评估完全失真。

4.3 接口限流与数据缺失:实盘跑批的隐藏炸弹

当我把 stock_analysis 从回测切换到每日实盘扫描时,发现原来代码不一定扛得住。免费接口对调用频率有严格限制,一开始我全市场扫描时每分钟请求几百次,直接被封禁,导致当天差点没跑出结果。后来我调整为分批拉取,每只股票之间加 sleep,并且做了请求失败自动重试,才稳定下来。

另外,新股上市初期数据不足,没法计算20日均线,如果不做特殊处理,程序就会报 KeyError 或者返回 NaN。我的处理方式是:计算指标时检查数据量是否满足所需窗口,如果不够就直接剔除,不参与候选。这个逻辑听起来很简单,但如果不加判断,程序跑到某只次新股时会直接崩溃,整个扫描流程都会中断。

5. stock_analysis 的模块划分与后续扩展思路

5.1 现在的代码结构:数据层、指标层、策略层三件套

目前这套工具不算大,但模块边界很清晰。数据层负责从接口拉取数据并清洗,指标层负责计算各类技术指标并缓存计算结果,策略层负责把指标组合成筛选规则并输出结果。三层之间只通过标准化的 DataFrame 传递数据,互不干扰。

这种结构最大的好处是:想加一个新策略,不需要改数据层和指标层,只要在策略层写一个新函数,把已有的指标当输入用就行。我现在的策略层已经有五六个不同规则的筛选器,分别针对中长线趋势、短线放量、超跌反弹等场景,每个筛选器输出一批股票代码,再汇总到一个表格里,方便对比。

5.2 后续可以加的方向:基本面因子和情绪面因子

纯技术指标的局限性很明显,它只反映价格和量的历史规律,无法衡量一家公司的实际盈利能力。我接下来的计划是在 stock_analysis 里加入基本面因子,比如市盈率、市净率、毛利率和净利润增速,把这些数据也拉下来,作为第二层过滤器。

情绪面因子则更难量化,但可以从换手率、涨跌停家数、连续涨停天数等数据间接推测。虽然不能直接给出"情绪温度计"这种玄学结论,但至少能看到市场活跃度是否有极端异动,帮我在执行策略时更谨慎地控制仓位。

5.3 建议:不要追求大而全,先解决自己最痛的环节

很多刚接触股市分析的人,一开始就幻想着做一个全自动决策系统,输入一个代码,输出买卖信号,还能自动交易。我觉得这个目标太大,而且也没有必要。我的建议是先明确自己最痛的点,比如"每天复盘太费时""不知道如何从几百只股票里快速找候选",然后针对这个点写代码,跑通之后再逐步扩展。

stock_analysis 这个项目到今天也没有实现自动下单,因为我始终觉得交易执行层面的东西更需要谨慎,涉及资金安全和稳定性,不是靠个人兴趣项目就能搞定的。作为分析辅助工具,它能帮我省下大量的复盘时间,让我把精力更多放在研究逻辑和风险控制上,这已经足够有价值了。


最后分享一个我在实际使用过程中摸索出的小技巧:给扫描结果加一列信号首次出现日期,而不是只显示今天的信号。这样一来,如果某只股票的信号是今天刚出现的,属于首次启动,可以重点关注;如果已经连续出现5天,可能已经涨幅不小,追高就要谨慎。这个改动只花了几行代码,但对决策时的感觉帮助很大。说白了,代码是做减法的,把这个工具当作一个纪律化的筛选助手,往往比东看一眼西看一眼靠谱得多。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询