
用Python和matplotlib画股价图,真有那么难吗?
很多人觉得画股价图是程序员的事,离自己很远。其实只要搞清楚几个关键点,普通人也能用Python画出像样的股价图。这篇文章不讲复杂术语,只告诉你每一步在做什么,以及为什么这么做。
第一步 准备数据
画图之前先要有数据。股票数据可以从雅虎财经、Tushare、AKShare等渠道获取。最常用的字段是日期、开盘价、最高价、最低价、收盘价、成交量。这里以收盘价为例,因为收盘价最能反映一天的多空博弈结果。
假设你已经拿到一个CSV文件,里面有两列:date和close。用pandas读进来,把date转成日期格式,并设置为索引。这样做的好处是画图时x轴自动按时间排列,不会乱序。
import pandas as pd
import matplotlib.pyplot as plt
df = pd.read_csv('stock_data.csv')
df['date'] = pd.to_datetime(df['date'])
df.set_index('date', inplace=True)
读取数据后,先看一眼前五行,确认没有缺失值或异常值。如果有缺失,可以用前向填充或直接删除。这一步不能省,脏数据画出来的图会骗人。

第二步 画一条最简单的收盘价折线
matplotlib画折线图的核心就三行代码:创建画布、画线、显示。
plt.figure(figsize=(12, 6))
plt.plot(df.index, df['close'], color='blue', linewidth=1.5, label='Close Price')
plt.title('Stock Closing Price')
plt.xlabel('Date')
plt.ylabel('Price')
plt.legend()
plt.grid(True)
plt.show()
这样一张股价图就出来了。蓝色线代表每日收盘价,x轴是时间,y轴是价格。看上去简单,但已经能看出趋势方向。
有人会问,为什么不用蜡烛图?蜡烛图当然更专业,但matplotlib原生不带蜡烛图函数,需要自己画矩形和影线,代码量会翻倍。对于刚入门的人,折线图足够表达主要信息。
第三步 加入移动平均线
单独一条收盘价线波动太剧烈,看不出中期趋势。加上移动平均线能过滤噪音。常用的是5日、20日、60日均线。
df['MA5'] = df['close'].rolling(window=5).mean()
df['MA20'] = df['close'].rolling(window=20).mean()
df[['close', 'MA5', 'MA20']].plot(figsize=(12, 6))
plt.title('Stock Price with Moving Averages')
plt.show()
rolling(window=5).mean()的意思是,从当前行往前数5天,求收盘价平均值。第一天到第四天没有足够数据,会显示为NaN,画图时自动忽略。
移动平均线交叉常被用作买卖信号。短期均线上穿长期均线叫金叉,下穿叫死叉。期货交易中同样适用,只是期货有杠杆,信号需要更谨慎。
第四步 加上成交量
股价图不配成交量,就像开车不看油表。成交量反映资金参与程度。matplotlib可以用子图把价格和成交量画在一起。
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8), sharex=True, gridspec_kw={'height_ratios': [3, 1]})
ax1.plot(df.index, df['close'], color='blue', label='Close')
ax1.plot(df.index, df['MA5'], color='orange', label='MA5')
ax1.plot(df.index, df['MA20'], color='green', label='MA20')
ax1.legend()
ax1.set_ylabel('Price')
ax1.grid(True)
ax2.bar(df.index, df['volume'], color='gray', width=0.8)
ax2.set_ylabel('Volume')
ax2.grid(True)
plt.xlabel('Date')
plt.show()
sharex=True让两个子图共用x轴,缩放时同步。height_ratios让价格图占3份高度,成交量图占1份。柱状图宽度0.8避免柱子重叠。
第五步 处理日期显示和中文
日期太密集会挤成一团。用matplotlib.dates模块自动旋转和格式化。
import matplotlib.dates as mdates
ax1.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))
ax1.xaxis.set_major_locator(mdates.MonthLocator(interval=3))
plt.xticks(rotation=45)
这样每3个月显示一个标签,格式为年-月。中文显示需要设置字体,否则会变成方框。
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
SimHei是黑体,Windows系统自带。Mac系统可以用Arial Unicode MS。axes.unicode_minus用来正常显示负号。
第六步 保存和复用
画好的图需要保存成图片或嵌入报告。
plt.savefig('stock_chart.png', dpi=300, bbox_inches='tight')
dpi=300保证高清,bbox_inches='tight'去掉多余白边。保存后再show,否则可能保存空白图。
如果每天都要画,可以把上面步骤封装成函数,传入股票代码和日期范围,自动获取数据并画图。
期货价格图有什么不同
期货价格图和股票价格图在matplotlib层面几乎没有区别,都是时间序列。区别在于数据源和合约换月。期货有主力合约连续价格,需要做后复权处理,否则换月时会出现跳空缺口。画图前要确认数据已经做过复权。
期货还有夜盘,时间轴更复杂。如果只画日线,夜盘并入下一个交易日,不影响。如果画分钟线,需要处理跨日时间戳。
常见坑点
第一个坑是日期没排序。数据乱序画出来的线会来回折返。用df.sort_index()解决。
第二个坑是收盘价有零或负值。股票不会,但期货某些品种可能接近零。画图前检查数据范围。
第三个坑是移动平均线窗口太大,前几十天全是空白。可以截取有均线值的区间再画。
第四个坑是内存不够。如果数据量几十万行,matplotlib会卡。用df.resample('W').last()降采样到周线再画。
掌握了这些,你就能用Python和matplotlib画出清晰、专业、能辅助决策的股价图。股票和期货都适用,关键是把数据搞干净,把图层的逻辑理清楚。