【Python量化数据可视化 #02】均线 MACD 看不清?主副图叠加才是专业打开方式
均线画在 K 线上总对不齐日期MACD、KDJ 各画一张图来回切换这篇文章带你把蜡烛图 MA 均线 MACD KDJ 压进同一张图券商软件那个一图看全部的三面板布局自己 80 行代码就能画出来。一、单图看一个指标是可视化最累的姿势上一篇我们画出了标准的K线 成交量双面板还没看的建议先看 #01 打底。但实际盯盘没人只看裸K均线 MA5/10/20 要叠在蜡烛上才能一眼看出金叉死叉MACD 要单独一个副图红绿柱和 DIF/DEA 线才能看清多空转换KDJ 还要再一个副图超买超卖线一压高低位一目了然。三个指标三张图来回切换早已看晕。正确的做法是共享同一条时间轴的主副图布局主图画K线和均线下方依次挂 MACD、KDJ 副图所有面板的日期严格对齐。本文你将得到三面板共享 x 轴的完整布局代码主图:副图:副图 3:1:1MA / MACD / KDJ 三组指标的纯 Python pandas 现算实现不依赖 TA-Lib一张券商软件同款的成图和每个面板的解读方法指标窗口期导致前 N 行 NaN 的处理技巧。二、准备环境pipinstallmairui matplotlib pandas numpy数据同样通过行情数据 API 的Client取日线证书换成你自己的即可拿到真实行情。三、完整代码已实测跑通frommairuiimportClientimportrandomimportpandasaspdimportmatplotlib matplotlib.use(Agg)importmatplotlib.pyplotaspltfrommatplotlib.patchesimportRectangle plt.rcParams[font.sans-serif][SimHei,Microsoft YaHei]plt.rcParams[axes.unicode_minus]FalseLICENCELICENCE-66D8-9F96-0C7F0FBCD073# 演示证书请换成你自己的正式证书UP,DOWN#d43f3a,#3a9d5d# A股惯例红涨绿跌defperturb(bars,seed20260916):# 演示证书返回固定样例数据做确定性 ±5% 扰动让图形有起伏# 换成正式证书后删掉本函数调用即可。rngrandom.Random(seed)out[]forbinbars:k1.0(rng.random()-0.5)*0.10nbdict(b)forfin(o,c,h,l):iffinnbandnb[f]isnotNone:nb[f]round(float(nb[f])*k,2)out.append(nb)returnoutdeffetch_df(code600519):barsClient(LICENCE).stock_history(codecode,st,et,periodd,dividendf)ifnotbars:raiseRuntimeError(未获取到数据请检查证书是否有效)barsperturb(bars)dfpd.DataFrame(bars)forcolin(o,c,h,l,v):df[col]pd.to_numeric(df[col])returndfdefadd_ma(df):fornin(5,10,20):df[fma{n}]df[c].rolling(n).mean()returndfdefadd_macd(df,fast12,slow26,sig9):ema_fdf[c].ewm(spanfast,adjustFalse).mean()ema_sdf[c].ewm(spanslow,adjustFalse).mean()df[dif]ema_f-ema_s df[dea]df[dif].ewm(spansig,adjustFalse).mean()df[macd]2*(df[dif]-df[dea])returndfdefadd_kdj(df,n9):low_ndf[l].rolling(n).min()high_ndf[h].rolling(n).max()rsv(df[c]-low_n)/(high_n-low_n)*100df[k]rsv.ewm(com2,adjustFalse).mean()# K 2/3 前K 1/3 RSVdf[d]df[k].ewm(com2,adjustFalse).mean()df[j]3*df[k]-2*df[d]returndfdefplot_all(df,title600519 主副图指标叠加,outindicator.png):nlen(df)xsrange(n)fig,(ax1,ax2,ax3)plt.subplots(3,1,figsize(12,9),sharexTrue,gridspec_kw{height_ratios:[3,1,1]},)# --- 主图蜡烛 三条均线 ---fori,rindf.iterrows():colorUPifr[c]r[o]elseDOWN ax1.vlines(i,r[l],r[h],colorcolor,linewidth1)ax1.add_patch(Rectangle((i-0.3,min(r[o],r[c])),0.6,max(abs(r[c]-r[o]),0.01),facecolorcolor,edgecolorcolor))forn,cin((5,#e6a23c),(10,#409eff),(20,#909399)):ax1.plot(xs,df[fma{n}],labelfMA{n},linewidth1.2,colorc)ax1.legend(locupper left,fontsize9)ax1.set_title(title,fontsize14)ax1.set_ylabel(价格元)ax1.grid(alpha0.25)# --- 副图1MACD ---colors[UPifv0elseDOWNforvindf[macd].fillna(0)]ax2.bar(xs,df[macd],colorcolors,width0.6,alpha0.7)ax2.plot(xs,df[dif],labelDIF,color#e6a23c,linewidth1.1)ax2.plot(xs,df[dea],labelDEA,color#409eff,linewidth1.1)ax2.axhline(0,color#999,linewidth0.8)ax2.legend(locupper left,fontsize9,ncol3)ax2.set_ylabel(MACD)ax2.grid(alpha0.25)# --- 副图2KDJ ---ax3.plot(xs,df[k],labelK,color#e6a23c,linewidth1.1)ax3.plot(xs,df[d],labelD,color#409eff,linewidth1.1)ax3.plot(xs,df[j],labelJ,color#b37feb,linewidth1.1)ax3.axhline(80,color#d43f3a,linewidth0.8,linestyle--)ax3.axhline(20,color#3a9d5d,linewidth0.8,linestyle--)ax3.legend(locupper left,fontsize9,ncol3)ax3.set_ylabel(KDJ)ax3.grid(alpha0.25)stepmax(n//8,1)ax3.set_xticks(list(xs)[::step])ax3.set_xticklabels([str(t)[5:]fortindf[t][::step]])plt.tight_layout()plt.savefig(out,dpi120)plt.close(fig)print(f图表已保存:{out})if__name____main__:dfadd_kdj(add_macd(add_ma(fetch_df(600519))))lastdf.iloc[-1]print(f条数:{len(df)}| 区间:{df[t].iloc[0]}~{df[t].iloc[-1]})print(fMA5/10/20 {last[ma5]:.2f}/{last[ma10]:.2f}/{last[ma20]:.2f})print(fDIF {last[dif]:.4f}| DEA {last[dea]:.4f}| MACD柱 {last[macd]:.4f})print(fK {last[k]:.2f}| D {last[d]:.2f}| J {last[j]:.2f})plot_all(df)四、真实运行结果在 Python 3.9 环境实测运行控制台输出条数: 50 | 区间: 2025-09-15 ~ 2025-12-01 MA5/10/20 11.21 / 11.24 / 11.23 DIF 0.0030 | DEA 0.0513 | MACD柱 -0.0966 K 32.56 | D 38.57 | J 20.55 图表已保存: indicator.png生成的indicator.png从上到下三个面板主图蜡烛上叠着黄、蓝、灰三条均线多空排列一眼可辨MACD 副图里红绿柱围绕零轴起伏DIF/DEA 两线交叉清晰KDJ 副图三条线在 80超买和 20超卖两条虚线之间摆动。最后一天的 MACD 柱为负-0.0966、J 值落到 20.55短线下行动能在图上一目了然。五、两个必须懂的实现细节EMA 与 SMA 不一样MACD 的 DIF/DEA 用的是指数移动平均ewm(span...)不是普通均线rolling。adjustFalse是与主流行情软件口径一致的关键参数漏掉会导致数值与软件对不上。前 N 行 NaN 要处理MA20 前 19 行、RSV 前 8 行没有足够窗口结果为 NaN。画线时 matplotlib 会自动跳过 NaN 断点这正好是想要的效果但 MACD 红绿柱的配色列表必须fillna(0)否则 NaN 参与比较会报错。六、小结与下篇预告至此你已经有了一张主图看价格、副图看动能、副图看摆动的全景图三面板共享时间轴任何一天的K线形态都能和两个副图的指标状态对齐着看。这套布局是后续所有进阶可视化多股对比、回测绩效、监控看板的母版。下篇预告《【Python量化数据可视化 #03】多只股票怎么比走势归一化对比相关性热力图》——把多只标的的涨跌拉到同一起跑线再算出谁跟谁同涨同跌两张图回答该盯哪几只的问题。免责声明本文所有代码与数据仅用于技术学习与演示不构成任何投资建议。股市有风险投资需谨慎。代码与文档SDK 与更多语言版本https://github.com/MaiRuiApi