第一张 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')

相关推荐
cliff17812 小时前
逆向驯服“赛博惰性”:一次大模型技能设计的实战复盘与经验总结
产品
自在的LEE2 天前
乒乓球底板防护方案对比:护木液 vs 指甲油 vs 其他方案
产品
chenment11 天前
别再为每个模型单独写一套队列了:用 200 行代码封装多模态统一调用层
人工智能·python·产品
静Yu11 天前
上线只是一个产品的开始
产品
kismet78712 天前
fetch 正常,页面却 404?Nuxt 3 + CDN 跨域下的 preload CORS 陷阱
前端·产品
时光不负努力15 天前
适应AI 带来的变化与挑战
产品
爱勇宝20 天前
我做了一个亲子成长小程序:想把“催孩子”变成“看见孩子”
微信小程序·产品·全栈
用户5591357826321 天前
量化系统定时任务实战:Cron + APScheduler + 企业微信通知
产品
用户5591357826322 天前
量化系统 Docker 部署实战:docker-compose 一键拉起 PostgreSQL + 策略引擎
产品