
简介这是一套基于Python开发的股票交易系统完整源码面向计算机与金融交叉方向的学生及初学者适用于毕业设计、课程实践或量化交易入门学习帮助掌握数据获取、策略回测、风险控制与GUI开发等核心能力。压缩包共143个文件含29个Python主程序模块实现行情抓取、指标计算与策略执行、34个JavaScript前端交互脚本、19个HTML页面与19个CSS样式文件构成Web可视化界面另有Shell定时任务脚本、Docker配置、Nginx与Supervisord服务部署文件等整体仅2.19MB轻量易部署。已有516人学习下载资源结构清晰包含备份文件.bk、多粒度配置conf/yml、字体与图标资源woff/ttf及Bokeh可视化组件便于理解前后端协同逻辑与工程化部署流程。 最近整理手头代码的时候翻出一份放在硬盘角落很久的 Python 股票系统源码zip 后缀安安静静躺着。周围一直有朋友问我要一套“拿到就能改”的股票分析系统既能拉行情、算指标又能出买卖点、做回测最好还不是那种只有几百行演示代码的玩具。这份源码差不多就是这样一个东西几千行 Python把数据、策略、可视化三条线串成了一条完整链路。这篇文章直接以这套源码为例从下载后的解压检查开始到 Python 环境搭建、源码结构拆解、指标公式翻译、数据源选型、回测验证再到高频问题的排查完整走一遍。不管你是刚接触 Python 股票分析的新手还是想拿现成代码做二次开发的进阶玩家都能从里面找到可以直接落地的内容。1. 拿到源码包先别急着解压三步体检1.1 下载下来的 zip先做三个检查很多人拿到源码包的第一反应是双击解压但我建议你先花一分钟做三个检查能省掉后面大半的折腾。第一是看文件大小。一套完整的 Python 股票系统源码通常包含多个模块文件、配置文件、说明文档压缩包大小至少几十 KB 到几 MB。如果你下载的 zip 只有 2KB 左右大概率是页面下载失败或者分享者只放了一个 README 进去真正的代码在其他链接里。这时候解压出来的东西往往让人失望。第二是核对校验值。如果原作者在说明页给了 SHA-256 或者 MD5下载完顺手验一下。命令行就是一条指令sha256sum stock_system.zipWindows 用户可以在 PowerShell 里用 Get-FileHashGet-FileHash stock_system.zip -Algorithm SHA256这一步能确认下载过程中文件有没有被截断、篡改。源码被植入后门的情况虽然不常见但对一个要拿来跑交易策略的代码该有的谨慎不能省。第三是查压缩包完整性。ZIP 文件末尾有一条叫 EOCDEnd of Central Directory的记录相当于整本书的目录页。如果下载中断或者网盘下载工具“假完成”文件尾部缺失解压工具就会报 “file is not a zip file” 或 “could not find EOCD”。用 Python 内置的 zipfile 模块可以快速体检import zipfile try: with zipfile.ZipFile(stock_system.zip) as z: for name in z.namelist(): print(name) bad z.testzip() if bad is None: print(压缩包完整所有文件校验通过) else: print(f存在损坏文件: {bad}) except zipfile.BadZipFile as e: print(f压缩包无法读取: {e})顺带说一句如果压缩包打开时需要密码而这不是你自己加密的最稳妥的做法是回头找原作者要密码。网上流传的“zip 密码移除”工具真要处理的是自己忘记密码的合法备份用 hashcat 结合字典跑一跑没问题但拿它去爆破别人收费源码那就是纯浪费时间而且没什么意义。1.2 解压方式和中文文件名的坑ZIP 格式本身对文件名字节编码要求很宽松没有强制指定 UTF-8 还是 GBK这就导致一个很经典的问题同一个压缩包在 macOS/Linux 上生成时文件名是 UTF-8 编码拿 Windows 自带的右键“全部解压”去解中文目录名全变成乱码。如果你只是本地看代码乱码倒还能忍最麻烦的是有些模块依赖固定的目录路径目录名一变import 就崩了。我试过几种方案最省事的是按平台选工具Windows用 Bandizip 或 7-Zip对 UTF-8 文件名支持比系统自带解压好很多。Linuxunzip 直接解遇到乱码时加编码参数unzip stock_system.zip -d stock_system如果文件名乱码尝试用 GBK 编码解压unzip -O gbk stock_system.zip -d stock_systemmacOS系统自带的归档工具兼容性不错也可以用 dittoditto -x -k stock_system.zip stock_system还有一种情况是解压到一半报 “caused by: invalid zip archive: could not find eocd”这通常不是密码问题而是文件没下载完整。别马上去找什么“修复工具”先把 zip 删掉重新下载一次换一个下载通道很多时候源站上的文件本身就是坏的。如果重新下载了几次都一样再考虑用 zip -FF 去尝试挽救zip -FF damaged.zip --out repaired.zip总之源码包落地这一步的规则很简单先体检再解压解压后先看目录结构确认 README 和数据目录都在再进入环境搭建环节。2. 把 Python 环境搭到能跑为止2.1 Python 版本选型与虚拟环境隔离这套股票系统源码的依赖里pandas、numpy、matplotlib、akshare 都属于更新迭代比较快的库Python 版本太老会出现依赖装不上或者装上了运行报错的尴尬局面。个人建议用 Python 3.10 或 3.113.8 也能跑但没必要给自己设限。环境隔离这件事是很多人忽略的重头戏。直接把依赖装进系统全局 Python短期是方便后面写别的项目时A 项目要 pandas 1.5B 项目要 pandas 2.0全局环境就会打架。用虚拟环境把每个项目的依赖隔开是成本最低的运维手段。python3 -m venv stock_env source stock_env/bin/activate # Windows 下执行 stock_env\Scripts\activate激活之后命令行前面会出现 (stock_env) 前缀后面所有 pip install 都只影响这个环境跟系统 Python 完全隔离。2.2 requirements.txt 装到一半失败怎么办源码如果写得规整一般会带一份 requirements.txt。这套系统的核心依赖大概是这样的pandas1.5.3 numpy1.23.5 matplotlib3.6.0 mplfinance0.12.10b0 requests2.28.1 akshare1.11.0 pandas_ta0.3.14b0 schedule1.2.0 openpyxl3.0.0安装命令pip install -r requirements.txt新手最容易卡在几个地方。第一个是 ta-lib很多股票指标库依赖这个 C 扩展包Windows 上安装需要预编译二进制经常编译失败。这套源码里我特意用了 pandas_ta它是纯 Python 实现pip 直接装就能用不需要额外装 C 库。如果你确实需要 ta-lib 的某些函数再单独去配二进制环境没必要一开始就给自己挖坑。第二个坑是网络问题。国内 pip 源经常超时解决办法是换镜像源或加超时参数pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ --timeout 60安装完成后强烈建议先在 Python 交互环境里验证一遍python -c import pandas, numpy, matplotlib, akshare, pandas_ta; print(依赖环境 OK)这一步能提前暴露版本冲突而不是等你跑完整套代码才发现某个库导入失败。3. 源码内部是怎么组织起来的3.1 一份股票系统源码的标准目录长什么样环境搭好之后先别急着跑 main.py花十分钟把目录结构看懂后面改代码会顺手很多。这套源码的目录组织比较典型stock_system/ ├── config.py ├── main.py ├── fetcher/ │ ├── __init__.py │ └── akshare_fetcher.py ├── indicators/ │ ├── __init__.py │ ├── base.py │ ├── reversal.py │ └── three_step.py ├── strategy/ │ ├── __init__.py │ ├── ma_cross.py │ └── backtest.py ├── draw/ │ ├── __init__.py │ └── kline.py └── data/ └── cache/各模块的职责划分很清晰config.py 管参数fetcher 管数据获取indicators 管指标计算strategy 管策略和回测draw 管可视化data 目录放本地缓存。main.py 是入口把整个流程串起来。这套分层设计的好处是“数据、逻辑、展示”三者解耦。你想换一个数据源只需要改 fetcher 目录想加一个指标在 indicators 里新增一个文件就行想调整买卖规则策略模块单独改。如果你拿到手的源码不是这种结构而是所有代码堆在几个大文件里我建议你也按这个思路做一次重构后续维护会轻松非常多。3.2 行情数据获取与本地缓存设计数据层是整套系统的地基。这套源码用的是 akshare 来获取 A 股历史行情一个非常典型的调用长这样import akshare as ak import pandas as pd def fetch_daily(symbol: str, start_date: str 20200101, end_date: str 20240101): raw ak.stock_zh_a_hist( symbolsymbol, perioddaily, start_datestart_date, end_dateend_date, adjustqfq ) df raw.rename(columns{ 日期: date, 股票代码: code, 开盘: open, 收盘: close, 最高: high, 最低: low, 成交量: volume, 成交额: amount, 振幅: amplitude, 涨跌幅: pct_change, 涨跌额: change, 换手率: turnover }) df[date] pd.to_datetime(df[date]) df df.sort_values(date).reset_index(dropTrue) return df为什么要把中文列名重命名成英文小写因为后续所有指标计算、回测代码都会统一用 open/close/high/low/volume 这套字段不提前统一后面每个函数都要处理中文列名平白增加心智负担。本地缓存设计也很重要。股票行情数据在每天收盘后是相对固定的每次运行都从接口全量拉一次一是慢二是容易触发接口的频率限制。这套源码的做法是把拉下来的数据存成 CSV下一次运行先读本地再按需增量更新import os def load_or_fetch(symbol: str, cache_dir: str data/cache): os.makedirs(cache_dir, exist_okTrue) path os.path.join(cache_dir, f{symbol}.csv) if os.path.exists(path): df pd.read_csv(path, parse_dates[date]) last_date df[date].max().strftime(%Y%m%d) else: df pd.DataFrame() last_date 20000101 new_df fetch_daily(symbol, start_datelast_date) if not new_df.empty: df pd.concat([df, new_df.drop_duplicates(subset[date])], ignore_indexTrue) df.to_csv(path, indexFalse) return df注意增量更新时一定要对 date 做去重否则重复运行几次后数据里同一个交易日会出现多条记录滚动指标算出来全是错的。3.3 把通达信/同花顺指标公式翻译成 pandas热词里那些“顶底信号98%指标源码”“三步点金指标源码”“量能饱和度圆圈1.00指标公式源码”看起来高大上本质上都是技术指标公式。它们原本大多是给通达信、同花顺这类行情软件用的公式语法而我们的目标是把它们翻译成 pandas 能算的 Python 代码。“顶底信号98%”这类指标逻辑上几乎都是超买超卖指标的变体比如 RSI 进入极端区域时提示见顶进入超卖区域时提示见底再叠加一条趋势均线做过滤。翻译成 pandas 不算复杂import pandas as pd def calc_rsi(close: pd.Series, period: int 6): delta close.diff() gain delta.clip(lower0).rolling(period).mean() loss (-delta.clip(upper0)).rolling(period).mean() rs gain / loss.replace(0, float(inf)) return 100 - (100 / (1 rs)) def add_reversal_signal(df: pd.DataFrame): df df.copy() df[rsi6] calc_rsi(df[close], period6) df[ma20] df[close].rolling(20).mean() df[top_signal] (df[rsi6] 85) (df[close] df[ma20]) df[bottom_signal] (df[rsi6] 20) (df[close] df[ma20]) return df“三步点金”的名字很花哨拆开看一般就是三种条件共振均线多头排列、MACD 金叉再加上成交量倍量突破。在 pandas 里写就是多列条件的布尔组合def add_three_step_signal(df: pd.DataFrame): df df.copy() df[ma5] df[close].rolling(5).mean() df[ma10] df[close].rolling(10).mean() df[ma20] df[close].rolling(20).mean() ema12 df[close].ewm(span12, adjustFalse).mean() ema26 df[close].ewm(span26, adjustFalse).mean() df[dif] ema12 - ema26 df[dea] df[dif].ewm(span9, adjustFalse).mean() df[macd] (df[dif] - df[dea]) * 2 df[macd_cross] (df[dif] df[dea]) (df[dif].shift(1) df[dea].shift(1)) df[volume_boost] df[volume] df[volume].rolling(5).mean() * 1.5 df[trend_up] (df[ma5] df[ma10]) (df[ma10] df[ma20]) df[signal] df[trend_up] df[macd_cross] df[volume_boost] return df翻译这类公式时最大的坑是“未来函数”。很多行情软件里的指标公式在盘中会把当前这根 K 线算进去看起来信号非常准但你要做回测时信号必须也只能基于历史数据。如果你的策略是当天收盘确认信号、次日开盘买入那信号出现的位置就必须在当天 K 线收盘后。代码里 shift(1) 这个操作就是用来规避未来函数的把信号往后挪一天再参与收益计算。3.4 K 线图上自动标注买卖点指标算出来之后直接看数字很抽象画图是最直观的验证方式。mplfinance 这个库专门用来画金融 K 线图对 pandas DataFrame 的列名有约定必须包含 open、high、low、close、volume 这几列索引类型必须是 DatetimeIndex。import mplfinance as mpf def plot_kline_with_signals(df: pd.DataFrame): plot_df df.copy() plot_df.index pd.DatetimeIndex(plot_df[date]) buy plot_df[plot_df[bottom_signal]] sell plot_df[plot_df[top_signal]] apds [ mpf.make_addplot(buy[close], typescatter, marker^, markersize120, colorred), mpf.make_addplot(sell[close], typescatter, markerv, markersize120, colorgreen), ] mpf.plot( plot_df, typecandle, mav(5, 20), volumeTrue, addplotapds, styleyahoo, titleK线买卖点标注, figsize(16, 9) )画完之后你会看到 K 线图上的红箭头和绿箭头。买点出现在价格从超卖区域企稳的位置卖点出现在超买回落的位置。光看图形可能觉得信号挺准但请绷紧一根弦视觉上的准确和统计上的收益完全是两码事这时候就需要第四步把策略放进回测里量化验证。4. 数据源选型与数据质量4.1 免费数据接口横向对比这套源码默认数据源是 akshare但在实际项目中很多人会换用更稳定的数据渠道。这里把常见的免费数据源拉出来对比一下数据源类型A股支持复权支持稳定性注意点akshare爬虫封装/公开接口好前复权、后复权中接口偶尔失效免费、接口多需要本地缓存tushare积分制接口好前复权、后复权较高新用户需要积分部分接口积分门槛baostock免费接口好前复权、后复权较高更新频率稍慢数据字段没那么多yfinance爬虫封装可用按需处理中A股字段不够细更适合美股/港股几个免费源我实测下来的感受是akshare 上手最快适合研究和原型验证tushare 数据质量更稳定适合长期跑的策略baostock 适合做回测因为它自带比较规范的前复权数据不用自己处理除权跳空。最忌讳的是把一个免费接口当成生产环境的基础设施它随时可能改版、限流、失效。所以源码里一定要有本地缓存做缓冲。4.2 行情数据里最容易踩的四个坑第一个是复权问题。用不复权数据做回测碰到除权除息日股价直接向下跳空一大截均线、MACD 全被带偏策略盈亏算出来完全失真。建议统一用前复权数据但要注意前复权是一个动态值新股上市时间越久历史价格调整幅度越大缓存的 CSV 需要定期清理重建。第二个是停牌。股票停牌时没有交易数据DataFrame 里直接缺行rolling 窗口计算时会对不上时间轴。可以考虑把停牌日期补上行df df.set_index(date) df df.resample(D).last()但补出来的空值需要 fillna否则后续计算会全部变成 NaN。第三个是时区。A 股本身没时区问题但如果你把 YFinance 的美股数据混进来美股用的是美东时间日期边界要对齐。最简单的办法是统一将数据保存为本地时区的日期时间并在缓存文件名里带上交易所标识。第四个是涨跌停。涨跌停当天的成交量、换手率都处于非正常状态很多短线信号在这种情况下是钝化的。处理办法要么是直接剔掉涨跌停日的信号要么在策略里加一个“非涨停/非跌停”过滤条件。5. 从信号触发到回测验证把策略闭环跑通5.1 双均线策略的回测框架源码自带一个最简单的双均线策略非常适合用来验证整个数据链路是否通顺。逻辑很简单快线上穿慢线时买入快线下穿慢线时卖出。向量化回测的核心代码非常短def backtest_ma_cross(df: pd.DataFrame, fast: int 5, slow: int 20): df df.copy() df[ma_fast] df[close].rolling(fast).mean() df[ma_slow] df[close].rolling(slow).mean() df[signal] (df[ma_fast] df[ma_slow]).astype(int) df[position] df[signal].shift(1).fillna(0) df[daily_return] df[close].pct_change() df[strategy_return] df[daily_return] * df[position] df[cumulative] (1 df[strategy_return]).cumprod() return df这里面最关键的是 position signal.shift(1)。原因很简单今天的信号要等到收盘才能确定决定你今天持仓的必须是昨天收盘时的信号不然就构成了未来函数。这一步不处理好回测结果会虚高到离谱。跑完之后看两个数字累计收益率和回撤。源码里可以算最大回撤cumulative df[cumulative] running_max cumulative.cummax() drawdown cumulative / running_max - 1 max_drawdown drawdown.min()个人经验是年化收益可以虚高最大回撤通常是策略真实体验的最佳标尺。一个动不动回撤 30% 的策略实盘中根本没几个资金扛得住再高的收益也没什么意义。5.2 参数不是越复杂越好很多人拿到源码后的第一件事是疯狂调参想找到一套“最优参数”。我实测下来均线策略最值得试的参数组合就那几组5/20、10/30、20/60。你把这三个组合换着几只不同风格的股票跑一遍能明显看出参数对结果的敏感性。这里想提醒一下如果一个参数从 19 改成 21结果就从盈利变成亏损说明策略和参数过度契合历史行情这不是好事。稳健的策略应该是参数在合理区间内连续变化时绩效是平滑变化的而不是悬崖式波动。5.3 回测结果“好看”的三个陷阱第一是未来函数正文前面已经反复提到这是回测界最常见的错误。信号当天、信号次日这两者必须明确。代码里凡是出现 shift(-1)、用当天收盘价算收益、或者用未来多少根 K 线取极值的情况都要打个问号。第二是幸存者偏差。回测股票池如果只包含“现在还活着”的股票把退市股全部排除掉收益肯定虚高。严谨的做法是从历史某个时点开始用当时市场上全部股票做回测但这对数据要求很高个人开发者很难做到。折中的办法是回测结果要打个折扣别把历史收益直接线性外推到未来。第三是过拟合。在一只股票上反复调参回测曲线越画越完美换一只股票立刻翻车。避免过拟合的唯一正道是把股票池拆成“训练集”和“验证集”参数在训练集上调出来的结论要在验证集上检验一遍。如果验证集上的表现远差于训练集那就要怀疑这个策略是不是只是拟合了历史噪声。6. 高频问题排查实录6.1 解压报错速查表很多人在解压这一步就被劝退这里把最常见的几个报错整理成速查表报错信息真实原因解决办法file is not a zip file文件头不是 PK 开头或文件是 HTML 伪装用 file 命令看真实类型重新下载could not find EOCDzip 尾部损坏/下载不完整重新下载或 zip -FF 修复解压后中文文件名乱码zip 文件名编码与系统默认编码不一致Linux 下 unzip -O gbk需要密码但不知道密码原作者加密联系原作者只对自己加密的文件做恢复解压到一半提示 CRC 错误文件损坏或存储介质问题用 zipfile 的 testzip 定位损坏文件我遇到过一次特别奇葩的情况压缩包用 Bandizip 能正常打开但 Python zipfile 读取时报错。最后发现是文件被网盘客户端中途改过重新上传下载才解决。所以排查这类问题先考虑“重下大法”再考虑工具问题大多数时候都有效。6.2 运行时报错速查表解压这关过了环境也搭好了代码运行时还会踩雷。这里列几个出现频率最高的报错信息常见原因解决办法ModuleNotFoundError: No module named akshare依赖未安装或装进了别的环境检查虚拟环境是否激活pip list 确认SSL: CERTIFICATE_VERIFY_FAILED本地证书过期或网络代理干扰升级 certifi或检查代理设置DataFrame has no attribute xxx数据没有按预期做列重命名打印 df.columns 核对字段名UnicodeDecodeError/中文乱码Windows 控制台编码问题运行前 set PYTHONIOENCODINGutf-8布尔运算报错DataFrame 多条件比较没加括号每个条件单独用括号包裹再 连接信号全空没有任何买点数据时间范围不对或停牌缺口过大打印数据头尾检查 start_date 是否晚于上市日期还有一个经常被忽略的问题数据接口返回的 date 列是 object 类型没有转成 datetime。在这种情况下做 set_index 或者 resample 都会报错。拿到数据后第一件事永远是处理日期列这是所有计算的前置条件。如果你把上面这些坑都踩了一遍大概率遇到的不是代码问题而是项目之间环境依赖冲突。这时候别硬刚最有效的手段是删掉虚拟环境重新建一个按 requirements.txt 重新装一遍十几分钟就能恢复到干净状态。最后分享一个我自己的习惯拿到别人的源码第一件事是跑通主线主线通了再谈优化、换模型、加指标。那些在行情软件里名字很玄乎的指标公式落到代码里也就是几行 pandas 操作关键不在指标本身而在数据是否干净、信号有没有未来函数、回测有没有过拟合。数据对齐这个环节我从来不敢省宁可慢一点也要确认每一根 K 线的日期序列是连续且复权一致的。这套源码我还在继续维护后面打算把板块联动和北向资金因子加进去到时候再单独写一篇展开聊。本文还有配套的精品资源点击获取