用Python一步一步绘制股票K线图:从数据获取到实战技巧

发布时间:2026/10/6 16:53:28
用Python一步一步绘制股票K线图:从数据获取到实战技巧 1. K线图能做什么先搞懂它到底在表达什么很多人第一次接触K线图看到红红绿绿的柱体和上下伸出的细线第一反应是这玩意儿跟蜡烛似的。实际上K线的原型就是日本的蜡烛图最早是大阪米商用来记录米价走势的后来被引入证券市场成了技术分析里最基本也最普及的表达工具。做股票走势图本质上就是把价格数据翻译成这种直观的蜡烛语言让任何人一眼就能看到某个时间段内的价格博弈结果。既然标题叫一步一步教你写股票走势图——K线图一概述我打算用一篇能直接落地复现的实战文章来开头把这门系列课的地基打牢。这篇不会堆太多复杂指标而是围绕从零到一画出第一张能看的K线图这个目标把数据、工具、代码、排错串起来。适合三类人看一是刚学Python、想拿真实数据练手的人二是做数据分析但没见过金融数据长什么样的朋友三是已经会画折线图、想往量化方向迈一步的投资者。先解决一个最基础的问题K线到底在画什么任何一根K线都包含四个价格——开盘价、收盘价、最高价、最低价分别用Open、Close、High、Low表示。以日K为例开盘价是交易日第一笔成交的价格收盘价是最后一笔成交的价格最高价和最低价则是当天价格曾经触碰过的上下边界。这四者组合起来就有了K线的实体和影线收盘价高于开盘价实体是阳线国内习惯红涨绿跌海外很多市场相反收盘价低于开盘价实体是阴线上影线的顶端是最高价下影线的底端是最低价。把一根根的K线按时间顺序排开就是股票走势图的核心骨架。别小看这个排列它把无序的价格波动压缩成了有节奏的形态序列后面学到的什么锤子线、吞没形态、头肩顶全都是在这个骨架上衍生出来的。换句话说你先把骨架画对后面所有技术分析才有地方挂。2. 数据从哪来画图之前必须先解决数据源问题代码写起来其实半天就能跑通但80%的新手会卡在数据上。要么拿到的字段对不上要么数据源不稳定要么日期格式错乱。画K线图之前数据源这块花点心思是值得的。2.1 常见数据源与获取方式我平时常用的数据获取方式有三种开源库直接拉取、文件导入、自己爬接口。三种各有优缺点适合不同的场景。第一种是直接用Python的金融数据接口库比如akshare、tushare、baostock这类库封装了数据请求逻辑几行代码就能拿到沪深股票的日线数据。以akshare为例ak.stock_zh_a_hist()可以拿到历史行情字段包含了日期、开盘、收盘、最高、最低、成交量等基本开箱即用。baostock的好处是不需要注册token对于新手尤其是只想画个图的人来说更友好。tushare需要注册获取token但数据质量高、字段丰富后续做量化研究的话值得投入这个成本。第二种是文件导入。券商软件一般都能导出Excel或CSV格式的历史行情导出来之后用pandas.read_csv()读进来就能用。这种方式的优点是数据来源可靠缺点是需要手动更新适合做一次性回顾分析。需要注意的是券商导出的表头可能带各种前缀和特殊字符加载后通常要手工整理字段名这块我会在后面数据清洗里详细讲。第三种是自己写爬虫请求公开行情接口。这种方式灵活但坑最多接口经常变、有访问频率限制、反爬策略也不确定。除非你已经有稳定的数据通道否则我不建议在入门阶段碰它。绘图的核心是理解数据结构和K线表达逻辑别把时间耗在跟反爬机制斗智斗勇上。2.2 数据清洗与字段确认不管数据从哪来画K线之前必须先确认几件事第一个是字段名统一。至少要有date、open、close、high、low、volume这六列。如果是从文件导入经常遇到列名是中文的情况比如日期开盘收盘最高最低成交量先用df.columns看一眼然后重命名import pandas as pd df pd.read_csv(stock_data.csv) df.columns [date, open, close, high, low, volume]第二个是日期格式处理。金融数据里日期最常见的问题是2024-01-05被读成字符串或者Excel导出的日期是数字格式。处理方式也简单df[date] pd.to_datetime(df[date]) df df.sort_values(date) # 确保按时间正序排列第三个是缺失值和除权处理。停牌的日子在数据里可能直接缺行也可能该行数据为空。缺行不影响绘图但如果空值行留着某些绘图库会渲染异常保险起见直接dropna()。除权除息这一块比较复杂简单做法是优先使用各家接口里默认的前复权或后复权数据不要拿未复权的原始价直接画长期走势否则碰到大比例分红送股图形会出现明显跳空看起来像暴涨暴跌。提示新手最容易忽略的是日期是否排序。很多接口返回的数据是倒序的最新在前直接画图会把时间轴搞反。养成先sort_values(date)再绘图的好习惯。3. 环境准备与工具选型别一上来就写代码数据问题解决后下一步是选工具。K线图的绘制在Python生态里有几种常见方案我逐个说一下我的使用感受方便你根据自己的情况选。3.1 用哪个库画K线最省心mplfinance这是matplotlib的金融扩展模块算是画K线图的专业户。它内置了K线、成交量副图、移动均线等基础功能代码量非常少适合快速出图。缺点是可定制性相对受限如果你想画非常复杂的自定义图形底层还得切回matplotlib。matplotlib 手写用matplotlib的bar和vlines自己拼K线。这种方式灵活度最高但代码量大坐标轴刻度、颜色、图形间距都要自己处理。好处是一旦你手动实现过一遍K线逻辑你对K线图的理解会比直接用库深刻得多后续遇到任何奇葩需求都能改。plotly交互式绘图库K线画出来可以鼠标悬停查看OHLC数值适合做网页端展示和数据探索。缺点是静态输出和打印场景下不如matplotlib方便学习成本也略高。我的建议很直接入门阶段用mplfinance但至少要确保自己能用matplotlib手搓一遍K线。这篇文章我会两条路线都走通先给你看mplfinance怎么五分钟出图再带你用matplotlib手动实现核心逻辑让你既看得懂结果也掌握原理。3.2 环境搭建与依赖安装环境这一步比较枯燥但所有后续操作都建立在它之上。我默认你用的是Python 3.9以上版本建议直接用Anaconda创建独立环境别把包装到系统Python里后面项目多了会打架。conda create -n kline python3.10 -y conda activate kline pip install pandas matplotlib mplfinance akshare如果你的机器装包比较慢可以换国内镜像源pip install pandas matplotlib mplfinance akshare -i https://pypi.tuna.tsinghua.edu.cn/simple装完验证一下import pandas as pd import matplotlib import mplfinance as mpf import akshare as ak print(pandas:, pd.__version__) print(matplotlib:, matplotlib.__version__) print(mplfinance:, mpf.__version__) print(akshare:, ak.__version__)能正常输出版本号就说明环境没问题。如果import akshare报错常见原因是依赖包冲突可以试试升级setuptools或者用pip install akshare --upgrade --force-reinstall重装一次。经验之谈用Anaconda的人经常遇到conda和pip混装导致的包冲突我的习惯是能用pip就用pipconda只负责创建环境。混装时优先级乱了很容易把依赖搞坏。4. 核心代码实现一步一步画出第一张K线图环境、数据都就绪了现在进入重头戏画图。这一节我按照实际操作的顺序把完整流程拆成三个环节来写每个环节都给了可跑通的代码。4.1 数据获取与预处理我以akshare获取某只A股日线数据为例。为了避免选到退市和停牌的股票这里用一只流动性比较好的标的来做演示。注意实际使用时请自行替换股票代码。import akshare as ak import pandas as pd # 获取A股日线数据前复权 stock_code 000001 # 平安银行仅作示例 df ak.stock_zh_a_hist(symbolstock_code, perioddaily, start_date20240101, end_date20241231, adjustqfq) # 列名整理 df.rename(columns{ 日期: date, 开盘: open, 收盘: close, 最高: high, 最低: low, 成交量: volume }, inplaceTrue) df[date] pd.to_datetime(df[date]) df df[[date, open, close, high, low, volume]] df df.sort_values(date).reset_index(dropTrue) print(df.head()) print(df.tail())跑完之后你应该能看到类似这样的输出date open close high low volume 0 2024-01-02 9.42 9.50 9.56 9.36 872345 1 2024-01-03 9.51 9.45 9.55 9.40 651234 ...这里要注意adjustqfq是前复权。前复权的意思是把历史价格按最新价进行调整这样图形上价格是连续的不会因为分红除权出现断层。新手画图一律建议用复权数据。4.2 用mplfinance快速画基础K线数据准备好后mplfinance要求索引必须是DatetimeIndex所以先把date列设为索引df_plot df.set_index(date) import mplfinance as mpf mpf.plot(df_plot, typecandle, volumeTrue, titlef{stock_code} 日K线图, stylecharles, figsize(12, 8))运行这段代码顺利的话会弹出一个窗口里面是标准的红绿K线图下面还带成交量副图。整个操作不到十行代码这就是专业库的价值。这里简单解释一下参数typecandle指定绘制蜡烛图K线图。mplfinance还支持line折线、ohlc美国式K线等类型。volumeTrue在下方显示成交量子图。stylecharles预置配色方案。mplfinance自带多套风格比如binance、yahoo、nightclouds等可以多试几套选自己喜欢的。figsize(12, 8)画布大小单位是英寸。如果你想把图保存成文件而不是弹窗显示加一个参数即可mpf.plot(df_plot, typecandle, volumeTrue, titlef{stock_code} 日K线图, stylecharles, figsize(12, 8), savefigdict(fnamekline_demo.png, dpi150, bbox_inchestight))savefig里的dpi是清晰度公开发布或写报告建议设150以上否则放大后会有锯齿。4.3 用matplotlib手动绘制搞懂每一根K线是怎么画出来的mplfinance虽然方便但它把很多细节封装了。为了让你真正理解K线的绘图逻辑我再用matplotlib手动实现一遍。其实原理很简单每根K线的实体是一个矩形上下影线是两条竖线。import matplotlib.pyplot as plt import matplotlib.dates as mdates import numpy as np # 取最近60个交易日 df_plot_60 df_plot[-60:].copy() df_plot_60.reset_index(inplaceTrue) # 判断阳线还是阴线 up df_plot_60[close] df_plot_60[open] down df_plot_60[close] df_plot_60[open] # 设定颜色红涨绿跌中国习惯 up_color #d62728 down_color #2ca02c fig, ax plt.subplots(figsize(14, 8)) # 先画影线上下影线 for i in range(len(df_plot_60)): row df_plot_60.iloc[i] color up_color if row[close] row[open] else down_color # 从最高价画到最低价的竖线 ax.plot([i, i], [row[high], row[low]], colorcolor, linewidth1) # 再画实体开盘价到收盘价的矩形 for i in range(len(df_plot_60)): row df_plot_60.iloc[i] color up_color if row[close] row[open] else down_color bottom min(row[open], row[close]) height abs(row[close] - row[open]) # height为0时做了个最小化处理避免画不出十字星 if height 0: height 0.001 ax.add_patch(plt.Rectangle((i - 0.3, bottom), 0.6, height, facecolorcolor, edgecolorcolor)) # 设置横轴刻度 ax.set_xticks(range(len(df_plot_60))) ax.set_xticklabels(df_plot_60[date].dt.strftime(%m-%d), rotation45) ax.set_title(f{stock_code} 日K线图手动实现) ax.grid(True, alpha0.3) plt.tight_layout() plt.show()这段代码最关键的一步是先画影线、再画实体顺序不能反。如果先画实体影线会被实体的色块遮住一部分看起来就像断了一样。这个细节用mplfinance体会不到自己实现一遍就记住了。另外十字星是开盘价等于收盘价的特殊情况。如果用plt.Rectangle画高度为0的矩形就什么都显示不出来所以我对height做了一个0.001的最小处理保证十字星中间那条横线能露出来。如果用的是ax.bar直接把height设为abs(close-open)就行bar本身能处理0高度的情况。4.4 加均线和成交量副图手动画法掌握之后加点技术指标就水到渠成了。最多人用的是5日均线MA5和20日均线MA20表示短中期趋势。继续上面代码的基础上加均线df_plot_60[MA5] df_plot_60[close].rolling(5).mean() df_plot_60[MA20] df_plot_60[close].rolling(20).mean() ax.plot(df_plot_60.index, df_plot_60[MA5], color#f39c12, labelMA5, linewidth1.5) ax.plot(df_plot_60.index, df_plot_60[MA20], color#8e44ad, labelMA20, linewidth1.5) ax.legend()成交量副图则需要用gridspec把整个画布分成上下两块上面的画K线和均线下面的画成交量柱状图。这里给一个整体代码框架这也是我日常用的完整雏形from matplotlib.gridspec import GridSpec fig plt.figure(figsize(14, 10)) gs GridSpec(2, 1, height_ratios[3, 1], hspace0.08) ax1 plt.subplot(gs[0]) ax2 plt.subplot(gs[1], sharexax1) # 上面的ax1画K线均线代码同前略 # 下面的ax2画成交量 colors [up_color if c o else down_color for c, o in zip(df_plot_60[close], df_plot_60[open])] ax2.bar(df_plot_60.index, df_plot_60[volume], colorcolors, alpha0.7) ax2.set_ylabel(成交量)sharexax1让两个子图共享横轴这样缩放和拖动时K线图和成交量能同步移动。这是看盘类图表的标配不然上下错位看着太难受。提示均线在计算初期会因为窗口不满而出现NaN比如前4行算不出MA5。画图时matplotlib会自动跳过NaN所以不需要额外处理但如果要对NaN做运算就会报错注意区分场景。5. 常见问题与排查技巧实录代码跑通很容易但把图画得顺手、用得舒服还是有几个坑要趟一遍。我整理了自己和身边朋友最常见的几个问题按问题—原因—解法列出来方便你直接对照。问题现象可能原因解决方案图表横轴日期乱序数据源返回的是倒序数据加载后必须sort_values(date)并重置索引mplfinance报错DatetimeIndex required没有将日期列设置为索引df.set_index(date)注意要确保列本身是datetime类型K线颜色和预期相反中国与欧美市场红绿规则不一致mplfinance里显式传marketcolors来定义涨跌颜色日期刻度重叠严重数据点太多且横轴刻度过密只显示一部分刻度比如每隔N天显示一个或用MaxNLocator限制刻度数量图形中文乱码matplotlib默认字体不支持中文设置中文字体见下方示例成交量柱状图上下颠倒用了负值做数据检查数据是否有负成交量若为除权调整数据则不宜直接绘图中文乱码是新手遇到最多的问题。在Windows上可以在画图前加这段代码plt.rcParams[font.sans-serif] [SimHei, Microsoft YaHei, PingFang SC] plt.rcParams[axes.unicode_minus] False第一行指定中文字体第二行防止坐标轴上的负号显示成方块。Mac用户把字体换成PingFang SC或者Arial Unicode MS即可。如果字体设置后还是乱码可以执行import matplotlib.font_manager查看可用字体列表把实际存在的字体名填进去。另一个容易被忽视的问题是坐标轴压缩变形。比如股票价格长期在10块到12块之间波动如果用折线图画细微波动会被拉伸得很夸张但K线图默认会保留原始比价价格一平缓图形看起来就像一条直线。很多人误以为数据错了其实只是价格没怎么动。如果想让平稳走势也能看出波动可以设置坐标轴起点或使用对数坐标但这个方法会改变图形解读方式不建议新手使用。最后说一个与数据精度相关的小坑akshare返回的复权价有时候小数位会比较多比如9.419999999。直接绘图会显得K线上下影线有细微锯齿不影响分析但如果要做数值判断就会踩坑。稳妥做法是围绕价格数据统一做一次rounddf[open] df[open].round(2) df[close] df[close].round(2) df[high] df[high].round(2) df[low] df[low].round(2)6. 从静态图到可交互让K线图更贴近实战画完静态K线图之后很多人的下一步需求是能不能鼠标放上去看具体数值或者能不能拖动看历史区间。这个需求用静态matplotlib很难满足但切换到plotly只需要改一小段代码。import plotly.graph_objects as go fig go.Figure(data[go.Candlestick( xdf_plot.index, opendf_plot[open], highdf_plot[high], lowdf_plot[low], closedf_plot[close], increasing_line_colorred, # 阳线颜色 decreasing_line_colorgreen # 阴线颜色 )]) fig.update_layout(titlef{stock_code} 日K线图, xaxis_rangeslider_visibleFalse, width1000, height600) fig.show()这段代码生成的图表可以直接在浏览器里缩放、平移、悬停查看数值。xaxis_rangeslider_visibleFalse表示隐藏最下面那个范围滑块如果你希望快速浏览整段历史数据把False改成True会好用很多。plotly还支持添加均线、成交量柱状图等交互效果比matplotlib好一大截。但它在处理大数据量时性能会下降几千根K线以上就能感到明显的卡顿。如果只是数据分析预测一两年的日K完全够用如果想看十几年的分钟级数据建议还是回到matplotlib做抽样展示或者引入其他大数据可视化方案。我个人在实盘分析中习惯这样分工快速浏览用plotly正式报告和论文插图用matplotlib或mplfinance。plotly适合自我探索matplotlib出图干净利落排版更好控制。7. 把这张K线图用起来基于形态的初步判断图已经画出来了总该说几句怎么用。K线图的作用不是预测明天涨跌而是通过形态帮你梳理多空力量的对比。实际上K线形态分析是有一套逻辑在里面的。最基础的是看实体与影线的比例。长阳线实体很长、影线很短说明买方全天占优收盘价接近最高价长阴线说明卖方主导上下影线都很长的K线比如长十字星说明多空分歧巨大往往是变盘的前兆。这个逻辑并不神秘它就是价格在后来的交易时段能走多远的记录而走得远不远全看买卖双方当时谁更有底气。然后可以看连续几根K线的组合。比如上升趋势中出现一根长长的上影线阳线随后紧跟一根阴线并跌破了前一根阳线的实体中点这种冲高回落组合在实战中经常被当作短期滞涨信号。再比如连续几根小阴小阳横盘后突然出一根长阳拉升意图往往就藏在这个横盘蓄力的过程里。不过要提醒一句单看K线形态的胜率很有限最好结合成交量和均线一起判断。成交量是K线形态的验证器——突破时放量、缩量回调形态的可信度会显著提高。这也是为什么上面画图时特地加了成交量副图。趋势方向则可以用均线来辅助股价在MA20以上时偏多以下时偏空这是最简单也常用的过滤条件。到了这一步你已经拥有了一张能看懂的K线图而不是一张能画出来但不知道在看什么的图。这是从绘图走向分析的关键一步。根据我个人经验画K线图这件事最大的门槛从来不在代码而在数据理解和形态感知。代码只是把已经存在的信息可视化出来真正有价值的是你看到图形之后能不能做出合理的判断。所以这篇概述里我花了一半篇幅讲数据和原理原因也在这里——数据不干净画出来的图再漂亮也没法用原理不清楚代码抄得再熟也只会照葫芦画瓢。在下一篇文章里我打算接着讲如何叠加更多技术指标比如MACD、KDJ以及如何把均线策略做成可回测的雏形。画图只是起点用图辅助决策才是真正好玩的部分。