第一张 K 线图 — matplotlib + mplfinance 实战

两行代码画折线,五行代码画 K 线。附完整源码,复制即用。


数据拉下来了,数据库也建好了。今天让数据「看得见」。

效果预览:收盘价图 → 量价双面板 → 专业 K 线图 + 均线叠加,三步走。


环境准备

bash 复制代码
pip install matplotlib mplfinance akshare pandas

⚠️ 服务器环境必须先设置 Agg 后端 ,否则会报错 no display name and no $DISPLAY environment variable

python 复制代码
import matplotlib
matplotlib.use('Agg')  # ← 必须在 import pyplot 之前

1. 收盘价折线图

python 复制代码
import matplotlib.pyplot as plt
import akshare as ak
import pandas as pd

# 拉数据
df = ak.stock_zh_a_hist(symbol='000001', period='daily')
df['trade_date'] = pd.to_datetime(df['日期'])
df = df.sort_values('trade_date')

# 只取最近半年
recent = df[df['trade_date'] > '2025-11-01']

# 画图
plt.figure(figsize=(12, 5))
plt.plot(recent['trade_date'], recent['收盘'],
         color='#1f77b4', linewidth=1.5)
plt.title('平安银行 (000001) --- 收盘价走势', fontsize=14)
plt.xlabel('日期')
plt.ylabel('价格 (元)')
plt.grid(alpha=0.3, linestyle='--')
plt.tight_layout()
plt.savefig('000001_price.png', dpi=150, bbox_inches='tight')
plt.close()

🔑 关键参数

  • bbox_inches='tight' → 自动裁掉多余白边
  • dpi=150 → 屏幕画质和文件大小的平衡点
  • 画完记得 plt.close() 释放内存

2. 价格 + 成交量双面板

成交量是价格的「燃料」。缩量上涨可能是假突破,放量下跌才是真恐慌。

python 复制代码
fig, (ax1, ax2) = plt.subplots(
    2, 1, figsize=(12, 8),
    sharex=True,                          # 共享 X 轴
    gridspec_kw={'height_ratios': [3, 1]} # 3:1 比例
)

# 上图:收盘价
ax1.plot(recent['trade_date'], recent['收盘'],
         color='#1f77b4', linewidth=1.5, label='Close')
ax1.set_title('000001 平安银行 --- 价格与成交量', fontsize=14)
ax1.set_ylabel('收盘价 (¥)')
ax1.legend(loc='upper left')
ax1.grid(alpha=0.3)

# 下图:成交量 --- 红涨绿跌
colors = [
    '#e74c3c' if recent['涨跌幅'].iloc[i] >= 0
    else '#2ecc71' for i in range(len(recent))
]
ax2.bar(recent['trade_date'], recent['成交量'],
        color=colors, alpha=0.7, width=0.8)
ax2.set_ylabel('成交量 (股)')
ax2.grid(alpha=0.3)

plt.xticks(rotation=30)
plt.tight_layout()
plt.savefig('000001_volume.png', dpi=150, bbox_inches='tight')
plt.close()

📌 A 股习惯:红涨绿跌,别跟美股搞混了。


3. mplfinance 专业 K 线图

手写 K 线太繁琐,直接用 mplfinance ------ 金融图表专用库,一行代码出图。

数据格式转换

mplfinance 要求列名严格为 Date, Open, High, Low, Close, Volume

python 复制代码
import mplfinance as mpf

# 准备数据
df_kline = recent[['trade_date', '开盘', '最高', '最低', '收盘', '成交量']].copy()
df_kline.columns = ['Date', 'Open', 'High', 'Low', 'Close', 'Volume']
df_kline.set_index('Date', inplace=True)

# ⚠️ 确保数值类型正确
for col in ['Open', 'High', 'Low', 'Close', 'Volume']:
    df_kline[col] = pd.to_numeric(df_kline[col], errors='coerce')

出图

python 复制代码
mpf.plot(
    df_kline,
    type='candle',         # K线模式
    volume=True,           # 带成交量
    title='000001 平安银行 --- 日线 K 线图',
    style='charles',       # 配色方案
    figsize=(14, 8),
    savefig='000001_kline.png'
)

这张图已经达到专业交易软件的水准了。


4. 叠加均线

python 复制代码
# 方式一:mav 参数(最简单)
mpf.plot(
    df_kline,
    type='candle',
    volume=True,
    mav=(5, 20, 60),          # 自动计算并叠加
    title='000001 --- K线 + MA5/MA20/MA60',
    style='charles',
    figsize=(14, 8),
    savefig='000001_ma.png'
)

方式二:addplot 自定义

需要更精细的控制(颜色、线宽、EMA)时用 addplot

python 复制代码
# 计算指标
df_kline['MA5']   = df_kline['Close'].rolling(5).mean()
df_kline['MA20']  = df_kline['Close'].rolling(20).mean()
df_kline['EMA12'] = df_kline['Close'].ewm(span=12, adjust=False).mean()

# 叠加
apds = [
    mpf.make_addplot(df_kline['MA5'],   color='orange', width=1.0),
    mpf.make_addplot(df_kline['MA20'],  color='blue',   width=1.5),
    mpf.make_addplot(df_kline['EMA12'], color='cyan',   width=1.0,
                     linestyle='--'),
]

mpf.plot(df_kline, type='candle', volume=True,
         addplot=apds, style='charles',
         figsize=(16, 9), savefig='000001_full.png')

5. 内置配色方案速查

style 效果
charles 白底 + 红涨绿跌(A 股首选)
binance 深色背景(暗色主题)
yahoo 仿 Yahoo Finance
blueskies 蓝色调清新风
nightclouds 深色 + 柔和色
default 极简默认

自定义配色:

python 复制代码
custom = mpf.make_mpf_style(
    base_mpf_style='charles',
    marketcolors=mpf.make_marketcolors(
        up='red', down='green',
        edge='inherit', wick='inherit', volume='inherit'
    ),
    gridcolor='#e0e0e0',
    gridstyle='--',
)

6. 完整工具脚本

python 复制代码
#!/usr/bin/env python3
"""plot_kline.py --- 一键生成三张图:收盘价 / 量价 / K线+均线"""

import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import mplfinance as mpf
import akshare as ak
import pandas as pd
from datetime import timedelta
import os


def plot_all(symbol: str, days: int = 180, out_dir: str = './charts'):
    os.makedirs(out_dir, exist_ok=True)

    # 1. 拉数据
    df = ak.stock_zh_a_hist(symbol=symbol, period='daily')
    df['trade_date'] = pd.to_datetime(df['日期'])
    df = df.sort_values('trade_date')
    cutoff = df['trade_date'].max() - timedelta(days=days)
    recent = df[df['trade_date'] >= cutoff].copy()

    # 2. 收盘价图
    fig, ax = plt.subplots(figsize=(12, 5))
    ax.plot(recent['trade_date'], recent['收盘'], color='#1f77b4', lw=1.5)
    ax.set_title(f'{symbol} 收盘价', fontsize=14)
    ax.set_ylabel('¥'); ax.grid(alpha=0.3)
    plt.xticks(rotation=30); plt.tight_layout()
    plt.savefig(f'{out_dir}/{symbol}_price.png', dpi=150); plt.close()

    # 3. 量价图
    fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8),
        sharex=True, gridspec_kw={'height_ratios': [3, 1]})
    ax1.plot(recent['trade_date'], recent['收盘'], color='#1f77b4', lw=1.5)
    ax1.set_title(f'{symbol} 量价', fontsize=14)
    ax1.set_ylabel('¥'); ax1.grid(alpha=0.3)
    colors = ['#e74c3c' if recent['涨跌幅'].iloc[i] >= 0
              else '#2ecc71' for i in range(len(recent))]
    ax2.bar(recent['trade_date'], recent['成交量'], color=colors, alpha=0.7)
    ax2.set_ylabel('Vol'); ax2.grid(alpha=0.3)
    plt.xticks(rotation=30); plt.tight_layout()
    plt.savefig(f'{out_dir}/{symbol}_volume.png', dpi=150); plt.close()

    # 4. K线 + 均线
    kline = recent[['trade_date','开盘','最高','最低','收盘','成交量']].copy()
    kline.columns = ['Date','Open','High','Low','Close','Volume']
    for c in ['Open','High','Low','Close','Volume']:
        kline[c] = pd.to_numeric(kline[c], errors='coerce')
    kline.set_index('Date', inplace=True)
    mpf.plot(kline, type='candle', volume=True, mav=(5,20,60),
             title=f'{symbol} K线+MA', style='charles',
             figsize=(14,8), savefig=f'{out_dir}/{symbol}_kline.png')

    print(f'✅ {symbol}: 3 张图已保存到 {out_dir}/')


if __name__ == '__main__':
    plot_all('000001', days=180)
    plot_all('600519', days=180)
bash 复制代码
python plot_kline.py
# ✅ 000001: 3 张图已保存到 ./charts/
# ✅ 600519: 3 张图已保存到 ./charts/

常见踩坑

问题 原因 解决
no display name 没设 Agg 后端 matplotlib.use('Agg')
中文乱码 服务器缺中文字体 apt install fonts-wqy-microhei
K 线只有框没颜色 mplfinance 版本太旧 pip install --upgrade mplfinance
成交量数值过大显示科学计数 没设置 ticklabel_format ax.ticklabel_format(style='plain', axis='y')

相关推荐
爱勇宝7 小时前
我做了一个亲子成长小程序:想把“催孩子”变成“看见孩子”
微信小程序·产品·全栈
用户559135782639 小时前
量化系统定时任务实战:Cron + APScheduler + 企业微信通知
产品
用户559135782631 天前
量化系统 Docker 部署实战:docker-compose 一键拉起 PostgreSQL + 策略引擎
产品
修己xj2 天前
项目代号:吞金兽1.0 —— 从立项到半岁,一个家庭的项目管理实战纪实
产品
极客三刀流2 天前
idea执行maven里的生命周期,报错信息'powershell' 不是内部或外部命令,也不是可运行的程序 或批处理文件。 Cannot start maven from wrapper
产品
用户559135782632 天前
量化交易 PostgreSQL 建表指南:K 线数据 + 信号记录 + 性能优化
产品
极客三刀流3 天前
windows版jdk版本管理工具
产品
用户559135782636 天前
四大免费数据源代码实测
产品
用户559135782637 天前
Python + PostgreSQL + Docker 技术选型实战
产品