简介:这份资源面向股票量化分析与K线可视化学习者,提供一套可运行的Python行情展示程序,解决历史行情读取、K线绘制及KDJ、MACD、RSI等技术指标联动显示的问题,适合具备Python基础、希望理解指标计算与图表绘制流程的开发者参考。压缩包共18个文件,约103KB,以10个py源码文件为核心,按主程序、全局配置、数据读取、指标库与绘图模块分层组织,另附4张jpg界面截图、2个ico图标、1份docx说明文档和1份txt自述文件,便于快速了解运行效果与模块职责。资源已有5876人学习下载,代码兼顾Python 2与3的兼容设计,模块化结构清晰,读者可据此扩充指标公式、切换股票数据源,并参考说明文档完成环境配置与二次开发。
1. 从一份能直接跑的 K 线源码说起
很多人第一次接触量化分析,卡住的地方不是策略,而是画图。数据拉下来了,KDJ、MACD 也算出来了,可一到把 K 线、均线、指标副图拼到一张图上,就开始在各种绘图库里反复翻车。这份「通通股票K线及KDJ、MACD指标显示完整源代码」解决的正是这个环节:它把股票 K 线图的绘制、KDJ 与 MACD 两个经典指标的计算和副图展示,做成了一套能直接运行、能改数据源、能二次开发的完整代码。关键词里写着 python2/3,说明它同时兼顾了两个 Python 版本,这在老项目迁移和新环境部署之间留了余地。适合谁?适合刚学量化、想先把「数据 → 指标 → 图形」这条链路跑通的新手,也适合手里有行情数据、想找个干净绘图底座往里塞自己策略的熟手。下面按「它是什么 → 怎么跑起来 → 怎么改」的顺序拆。
2. 项目定位与技术选型:为什么是这套组合
2.1 它到底解决什么问题
股票行情可视化看起来简单,真做起来有三层活:第一层是数据,开盘、最高、最低、收盘、成交量,字段要对齐,时间要排序,缺失要处理;第二层是指标,KDJ 要算 RSV、K、D、J 三条线,MACD 要算快慢 EMA、DIF、DEA 和柱状图;第三层是绘图,主图叠 K 线和均线,副图放指标,坐标轴、颜色、图例都得协调。这份源码把三层都覆盖了,核心价值不在算法多高深,而在于「一条龙跑通、结构清晰、方便替换」。你拿到手,改一下数据读取那几行,就能把自己的行情接进去;改一下指标参数,就能验证不同周期下的效果。
从工程角度看,它属于典型的「单文件或少量文件脚本型项目」,不是框架型系统。这类项目的好处是门槛低、依赖少、读起来快;代价是模块边界靠约定而非强制,二次开发时容易越改越乱。所以读它的正确姿势是:先认清哪几段是数据层、哪几段是指标层、哪几段是绘图层,再动手。
2.2 技术栈与依赖判断
标题和关键词给出的信息是 Python2/3 兼容、股票 K 线、KDJ、MACD、量化分析。按这个场景下合格开发最常见的做法,绘图部分大概率落在 matplotlib 上,因为它是 Python 生态里画金融图最通用的选择,支持多子图、支持自定义 K 线样式;数据处理部分通常用 pandas 做时间序列对齐和滚动计算,用 numpy 做向量化运算。KDJ 和 MACD 都是递推型指标,用 pandas 的ewm或手写循环都能实现。
一个典型的依赖清单长这样:
# 常见依赖,按项目实际 import 为准 pip install pandas numpy matplotlib # 如果数据来自网络接口,可能还需要 pip install requests这里要提醒一句:Python2 和 Python3 在字符串、除法、print 语法上有差异,源码里如果出现print "xxx"这种写法,在 Python3 下会直接报语法错误。判断项目实际跑在哪个版本,最快的办法是看文件头的from __future__ import和 print 写法,别想当然。
2.3 目录与模块的合理划分
这类项目通常不会有很多层目录,但内部逻辑应该能分成几块。读源码时建议按下面的心智模型去对照:
| 逻辑层 | 典型职责 | 常见函数/代码位置 |
|---|---|---|
| 数据层 | 读取行情、字段重命名、时间排序、缺失处理 | read_csv/ 接口请求 /DataFrame预处理 |
| 指标层 | KDJ 计算、MACD 计算 | calc_kdj/calc_macd之类函数 |
| 绘图层 | 主图 K 线、副图指标、坐标与图例 | plot_kline/subplot相关代码 |
| 入口层 | 串起上面三层、设置参数、显示或保存 | if __name__ == '__main__'附近 |
如果源码里没有这么清晰的函数划分,而是从头到尾一段脚本,也不用慌,按「哪几行在读数据、哪几行在算指标、哪几行在画图」自己切一刀,改造时就有了抓手。这也是我读任何脚本型项目的第一动作:先画这条逻辑线,再谈优化。
3. 核心模块拆解:从行情数据到 KDJ、MACD 副图
3.1 数据准备:字段对齐是第一步
K 线图对数据的要求很固定:每根蜡烛需要开盘价、最高价、最低价、收盘价,通常还要成交量。指标计算则依赖收盘价序列。所以数据层的第一件事不是算,而是把字段名统一、把时间列转成日期类型、按时间升序排好。常见做法是这样:
import pandas as pd # 读取行情数据,假设列名为 date/open/high/low/close/volume df = pd.read_csv('stock.csv') df['date'] = pd.to_datetime(df['date']) # 时间列转日期类型 df = df.sort_values('date').reset_index(drop=True) # 按时间升序,重置索引 df = df[['date', 'open', 'high', 'low', 'close', 'volume']] # 固定列顺序 df = df.dropna(subset=['open', 'high', 'low', 'close']) # 关键价格缺失直接丢这段代码的逻辑很直白:to_datetime保证后续按时间切片和绘图横轴正确;sort_values是因为很多数据源导出的顺序不保证,指标是递推的,顺序错了结果全错;reset_index是为了让后面按下标取数不出错;dropna只针对价格列,成交量缺失有时可以容忍。参数上,如果你的数据源字段叫trade_date、vol,就在这一步改名,别拖到指标函数里再处理,否则后面每处都要兼容,越改越乱。
3.2 KDJ 计算:RSV 到 K、D、J 的递推
KDJ 的标准算法是:先算 RSV,即(收盘价 − N 日最低价)/(N 日最高价 − N 日最低价)× 100;再对 RSV 做平滑得到 K,对 K 再平滑得到 D,J = 3K − 2D。常见参数是 N=9,平滑系数 1/3。用 pandas 写出来大致是:
def calc_kdj(df, n=9, m1=3, m2=3): low_n = df['low'].rolling(window=n, min_periods=1).min() # N 日最低 high_n = df['high'].rolling(window=n, min_periods=1).max() # N 日最高 rsv = (df['close'] - low_n) / (high_n - low_n) * 100 # RSV rsv = rsv.fillna(50) # 分母为 0 或前期数据不足时给中性值 # K、D 用递推平滑,等价于 ewm(alpha=1/m) df['K'] = rsv.ewm(alpha=1.0/m1, adjust=False).mean() df['D'] = df['K'].ewm(alpha=1.0/m2, adjust=False).mean() df['J'] = 3 * df['K'] - 2 * df['D'] return df逻辑说明:rolling(...).min()/.max()取的是滚动窗口极值,min_periods=1让开头数据不足时也能出值,避免前 N 行全是 NaN 导致图上前段空白。fillna(50)处理的是最高价等于最低价(一字板)时分母为零的情况,给 50 是中性处理,你也可以按业务改成前值填充。ewm(alpha=1/m, adjust=False)是 KDJ 里 K、D 平滑的标准等价写法,adjust=False保证递推而不是全局加权,这点很关键,写错了曲线形状会明显不同。参数n、m1、m2就是常说的 9、3、3,改小更灵敏、改大更平滑,验证时建议先固定其他两个只动一个。
3.3 MACD 计算:EMA 差值与柱状图
MACD 的核心是两条指数移动平均线之差。标准参数 12、26、9:快线 EMA12 减慢线 EMA26 得到 DIF,DIF 再做 9 日 EMA 得到 DEA,柱状图是 (DIF − DEA) × 2。代码:
def calc_macd(df, fast=12, slow=26, signal=9): ema_fast = df['close'].ewm(span=fast, adjust=False).mean() # 快线 ema_slow = df['close'].ewm(span=slow, adjust=False).mean() # 慢线 df['DIF'] = ema_fast - ema_slow # 差离值 df['DEA'] = df['DIF'].ewm(span=signal, adjust=False).mean() # 信号线 df['MACD'] = (df['DIF'] - df['DEA']) * 2 # 柱状图 return df逻辑说明:ewm(span=...)用的是 span 形式,和 KDJ 里的 alpha 形式是同一套指数平滑的两种参数化,adjust=False同样是为了递推。乘 2 是国内行情软件的习惯画法,让柱子更醒目,如果你要和别的软件对齐数值,先确认对方是否也乘了 2。参数fast、slow、signal改动会直接改变金叉死叉的位置,做回测验证时这三个值要记录在案,否则结果没法复现。
3.4 绘图:主图 K 线加副图指标
绘图层是整个项目最「见功夫」的地方。常见结构是三个子图:主图放 K 线和均线,副图一放 KDJ,副图二放 MACD,共享横轴。matplotlib 里用subplots配gridspec控制高度比例。K 线本身 matplotlib 没有原生蜡烛图,常见做法是用vlines画影线、用bar或矩形画实体,或者借助第三方封装。示意代码:
import matplotlib.pyplot as plt import matplotlib.gridspec as gridspec fig = plt.figure(figsize=(14, 9)) gs = gridspec.GridSpec(3, 1, height_ratios=[3, 1, 1], hspace=0.05) ax_main = fig.add_subplot(gs[0]) # 主图 ax_kdj = fig.add_subplot(gs[1], sharex=ax_main) # KDJ 副图 ax_macd = fig.add_subplot(gs[2], sharex=ax_main) # MACD 副图 # 主图:影线 + 实体,涨红跌绿是常见配色 for i, row in df.iterrows(): color = 'red' if row['close'] >= row['open'] else 'green' ax_main.vlines(i, row['low'], row['high'], color=color, linewidth=0.8) ax_main.bar(i, abs(row['close'] - row['open']), bottom=min(row['open'], row['close']), color=color, width=0.6) # KDJ 副图三条线 ax_kdj.plot(df.index, df['K'], label='K') ax_kdj.plot(df.index, df['D'], label='D') ax_kdj.plot(df.index, df['J'], label='J') # MACD 副图:DIF、DEA 线 + 柱状图 ax_macd.plot(df.index, df['DIF'], label='DIF') ax_macd.plot(df.index, df['DEA'], label='DEA') ax_macd.bar(df.index, df['MACD'], color=['red' if v >= 0 else 'green' for v in df['MACD']]) plt.show()逻辑说明:height_ratios=[3,1,1]让主图占大头,符合看盘习惯;sharex让三个子图横轴联动,缩放时一起动;hspace=0.05压小子图间距,视觉上更紧凑。逐行iterrows画蜡烛在数据量大时会慢,几千行以内问题不大,上万行建议改成向量化的vlines批量调用或换专业 K 线库。颜色上红涨绿跌是国内习惯,如果你面向海外用户,记得反过来。这段代码是骨架,实际源码里通常还会加均线、成交量、图例、日期刻度格式化,按需往里补即可。
4. 跑起来:环境、数据与第一次出图
4.1 环境准备与版本确认
第一步永远是确认 Python 版本。源码标题写 python2/3,意味着它可能用了兼容写法,也可能只是「两个版本都试过」。实操建议:先用 Python3 建虚拟环境,跑一遍,报语法错再考虑 Python2。命令如下:
python3 -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate pip install pandas numpy matplotlib python main.py # 换成源码实际入口文件名如果报SyntaxError且指向 print 语句,说明是 Python2 写法,要么装 Python2 环境,要么手动改 print 语法。如果报ModuleNotFoundError,按缺什么装什么,别一次性把网上所有量化库都装上,依赖越多越难排查。
4.2 数据从哪来、怎么接
源码要跑起来,必须有数据。常见三种来源:本地 CSV、本地数据库、网络接口。最稳的是先用本地 CSV 验证绘图链路,因为网络接口有频率限制、字段变动、偶发失败,会把「代码问题」和「数据问题」混在一起,排查起来很痛苦。准备一个至少几十行的 CSV,列名对齐date/open/high/low/close/volume,把读取路径改成你的文件,先跑通出图。确认图形正确后,再换成接口数据,这时如果出问题,基本能定位在数据获取环节。
提示:指标计算对数据长度有要求,MACD 的慢线是 26 周期,太短的数据前段会大量 NaN,图上看起来像「缺一块」,不是代码坏了,是数据不够。
4.3 第一次出图的检查清单
图出来之后别急着说「跑通了」,按这几点核对:K 线实体和影线位置对不对,最高价是否在影线顶端;KDJ 的 J 值是否会出现负值或超过 100,这是正常现象,别当成 bug;MACD 柱状图零轴上下颜色是否和正负值一致;三个子图横轴是否对齐。任何一项不对,回到对应模块单独打印中间结果,比如把df[['K','D','J']].head(20)打出来看数值走势,比盯着图猜快得多。
5. 避坑与常见问题:那些第一次跑必踩的坑
5.1 现象:图是空的或只有一条直线
原因通常是数据没读进来,或者列名不匹配导致取到全 NaN。read_csv默认把第一行当表头,如果你的文件没有表头,列名会错位;如果字段叫Close而代码取close,pandas 不会报错,只会给你 NaN。解决:读完后立刻print(df.head())和print(df.columns.tolist()),确认列名和数据类型,再往下走。
5.2 现象:KDJ 曲线前段剧烈跳动
原因是rolling的min_periods设置不当,前几行窗口内样本太少,极值不稳定,RSV 被放大。解决:给min_periods=1并配合fillna中性值,或者干脆把前 N 行指标置为 NaN 不画。两种做法各有取舍,前者图完整但前段不可信,后者诚实但图有缺口,按展示需求选。
5.3 现象:MACD 数值和别人软件对不上
原因多半是adjust参数或乘 2 的处理不一致。ewm默认adjust=True,是加权平均的另一种口径,和递推公式不等价;国内软件普遍乘 2 画柱。解决:统一用adjust=False,并确认对方是否乘 2,把口径写进注释,避免以后自己都忘了。
5.4 现象:数据量大时绘图卡死
原因是逐行iterrows画蜡烛,Python 层循环在万行级别会明显变慢。解决:改用向量化的vlines批量绘制,或换用专门的 K 线绘图库;也可以只画最近几百根,交互式查看时按需切片。这是脚本型项目最常见的性能瓶颈,早改早省心。
5.5 现象:中文标签显示成方块
原因是 matplotlib 默认字体不含中文。解决:在绘图前设置plt.rcParams['font.sans-serif'] = ['SimHei']之类的可用中文字体,并处理负号显示plt.rcParams['axes.unicode_minus'] = False。字体名要按操作系统实际有的填,填错不报错但依然显示方块,这点很玄学,得试。
6. 二次开发:把这份源码改成自己的分析底座
6.1 先做结构重构,再加功能
拿到能跑的版本后,第一件事不是加策略,而是把脚本拆成函数或类:数据加载一个函数、指标计算一个函数、绘图一个函数、入口只负责串流程。这样你后面加 RSI、BOLL 或者换数据源时,改动范围可控。我一般会先抽一个load_data(path)和一个plot_all(df),中间指标各自独立,函数之间只传 DataFrame,不传全局变量。这一步花半小时,后面能省几小时。
6.2 参数化与配置外置
把 KDJ 的 9/3/3、MACD 的 12/26/9、绘图窗口长度这些硬编码值提到函数参数或配置文件里。验证不同周期时,只改参数不改代码,结果才可复现。一个简单的做法是用字典集中管理:
CONFIG = { 'kdj': {'n': 9, 'm1': 3, 'm2': 3}, 'macd': {'fast': 12, 'slow': 26, 'signal': 9}, 'plot': {'tail': 250}, # 只画最近 250 根 }改参数时连注释一起改,记录这次验证用的什么值,否则过两天回头看图,根本不知道当时跑的是哪套参数。
6.3 验证改造是否正确的三个方法
改完指标或绘图,怎么确认没改坏?第一,用同一份数据跑改造前后两版,把指标列做差值对比,理论上应该完全一致;第二,挑几个已知形态的区间人工核对,比如某段明显金叉的位置,看 DIF 是否上穿 DEA;第三,把中间结果落盘成 CSV,和行情软件导出的指标值抽样比对。这三步走完,心里才有底。
6.4 一个具体技巧:把绘图和计算解耦
很多人改造时把计算和绘图揉在一起,导致想批量算指标做回测时,被迫连图一起跑,慢且没必要。我的习惯是让计算函数只返回 DataFrame,绘图函数只接收 DataFrame,两者通过数据契约连接。这样同一套指标代码既能出图,也能直接喂给回测逻辑,一份代码两处用。改造时先定好这个契约:输入哪些列、输出哪些列、索引是什么,写进函数 docstring,后面谁来接手都不容易改乱。
血泪经验是:每次动指标参数或数据口径,我都强制走一遍「改造前后差值对比 + 抽样人工核对」,不跳步。有一次图看着没问题,结果是因为前段 NaN 被 fillna 掩盖了,差点把错误结论当成策略信号。希望帮到你,少走这段弯路。
本文还有配套的精品资源,点击获取