Appearance
用Python画K线图
K线图(Candlestick Chart)是股票技术分析中最基础也最重要的图表类型。每一根K线记录了一个交易周期(如一天)内的四个关键价格:开盘价(Open)、最高价(High)、最低价(Low)、收盘价(Close),合称 OHLC 数据。
通过 Python,我们可以用代码自动绘制专业的K线图,而无需依赖券商软件。这不仅灵活性更高,还能将K线图嵌入到量化策略的回测报告和研究成果中。
环境准备
在开始之前,请确保安装了以下核心库:
bash
pip install mplfinance matplotlib pandas akshare各库的作用说明:
| 库名 | 作用 |
|---|---|
mplfinance | 专门绘制金融图表(K线、成交量等)的 matplotlib 扩展 |
matplotlib | Python 最基础的绘图库,用于高级自定义 |
pandas | 数据处理框架,几乎所有金融数据都以 DataFrame 形式操作 |
akshare | 免费 A 股数据获取库,作为本文的数据源 |
获取股票数据
我们以获取 A 股数据为例,使用 akshare 获取日线数据:
python
import akshare as ak
import pandas as pd
# 获取贵州茅台(600519)近120个交易日的日K数据
df = ak.stock_zh_a_hist(
symbol="600519",
period="daily",
start_date="20240101",
end_date="20241231",
adjust="qfq" # 前复权,保证K线连续性
)
# akshare 返回的列名为中文,需要重命名为 mplfinance 要求的格式
df = df.rename(columns={
"日期": "Date",
"开盘": "Open",
"收盘": "Close",
"最高": "High",
"最低": "Low",
"成交量": "Volume",
"成交额": "Turnover"
})
# 将 Date 列设为索引,并转换为日期类型
df["Date"] = pd.to_datetime(df["Date"])
df = df.set_index("Date")
# 只保留需要的列
df = df[["Open", "High", "Low", "Close", "Volume"]]
print(df.head())前复权(qfq):以最新价格为基准,向前调整历史价格。复权后的K线能真实反映持股期间的收益情况,不会有因除权除息导致的跳空缺口。
使用 mplfinance 画基础K线图
mplfinance 是 matplotlib 专门为金融数据设计的扩展包,原名 mpl_finance,后独立维护。它能用极少的代码画出专业级K线图。
最简K线图
python
import mplfinance as mpf
# 一行代码画出K线图
mpf.plot(df, type="candle", title="贵州茅台日K线")type 参数支持的图表类型:
"candle"— K线图(蜡烛图)"ohlc"— OHLC 线条图"line"— 折线图(通常只显示收盘价)
添加成交量柱状图
成交量是K线分析的重要辅助信息。通过 volume 参数可以在K线下方叠加成交量柱:
python
mpf.plot(
df,
type="candle",
volume=True, # 显示成交量
title="贵州茅台 - K线与成交量",
ylabel="价格(元)",
ylabel_lower="成交量"
)自定义颜色和样式
A股的习惯配色与美股不同:A股中红色代表上涨(收盘价 > 开盘价),绿色代表下跌(收盘价 < 开盘价),而美股恰好相反。mplfinance 默认使用美股配色,我们需要自定义。
使用 style 预设
mplfinance 内置了多种样式,常用的有:
python
# 经典黑白背景
mpf.plot(df, type="candle", style="classic")
# 查尔斯·道风格(黑白K线)
mpf.plot(df, type="candle", style="charles")
# 白色背景蓝色主题
mpf.plot(df, type="candle", style="yahoo")自定义 A 股风格(红涨绿跌)
python
# 定义自定义样式:红涨绿跌,白色背景
my_style = mpf.make_mpf_style(
base_mpf_style="yahoo",
marketcolors=mpf.make_marketcolors(
up="red", # 上涨:红色
down="green", # 下跌:绿色
edge="inherit", # K线边框颜色跟随涨跌
wick="inherit", # 影线颜色跟随涨跌
volume="inherit" # 成交量柱颜色跟随涨跌
),
gridstyle=":",
gridcolor="#e0e0e0"
)
mpf.plot(
df,
type="candle",
volume=True,
style=my_style,
title="贵州茅台 - A股风格K线图"
)这样输出的K线图就完全符合A股投资者的视觉习惯了。
叠加移动均线
移动均线(Moving Average,简称均线或 MA)是最常用的技术指标之一。它通过计算一定周期内的平均收盘价来平滑价格波动,帮助判断趋势方向。
在 mplfinance 中添加均线非常简单,只需通过 mav 参数指定均线的周期:
python
mpf.plot(
df,
type="candle",
volume=True,
style=my_style,
mav=(5, 10, 20), # 添加5日、10日、20日均线
title="贵州茅台 - K线 + 均线 + 成交量"
)mav 参数接受一个元组,每个元素代表一条均线的计算周期。mplfinance 会自动计算并在图上绘制,还会在左上角显示图例。
手动计算均线
有时我们需要手动计算均线(比如要用在策略中),可以用 pandas 的滚动计算:
python
# 计算5日、10日、20日简单移动均线
df["MA5"] = df["Close"].rolling(window=5).mean()
df["MA10"] = df["Close"].rolling(window=10).mean()
df["MA20"] = df["Close"].rolling(window=20).mean()
print(df[["Close", "MA5", "MA10", "MA20"]].tail(10))简单移动均线(SMA):将最近 N 个交易日的收盘价求算术平均。例如 MA5 = (C1 + C2 + C3 + C4 + C5) / 5。
matplotlib 高级用法:多子图布局
mplfinance 适合快速出图,但当我们需要更灵活的布局(比如多个子图、标注买卖点)时,需要回到 matplotlib 的底层 API。
下面展示如何用 matplotlib 手动绘制包含K线、成交量、MACD 三个子图的高级图表:
准备K线绘制数据
python
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from matplotlib.patches import Rectangle
import numpy as np
# 为了在 matplotlib 中绘制K线,我们需要将日期转为数字
dates = mdates.date2num(df.index.to_pydatetime())
opens = df["Open"].values
highs = df["High"].values
lows = df["Low"].values
closes = df["Close"].values
volumes = df["Volume"].values手动绘制K线图
python
fig, axes = plt.subplots(
3, 1,
figsize=(14, 10),
height_ratios=[3, 1, 1], # K线区:成交量:MACD = 3:1:1
sharex=True # 共享X轴
)
ax_kline = axes[0]
ax_vol = axes[1]
ax_macd = axes[2]
# 设置中文字体
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False
# 绘制K线(矩形实体 + 影线)
bar_width = 0.6
for i in range(len(dates)):
color = "red" if closes[i] >= opens[i] else "green"
# 影线(最高到最低的竖线)
ax_kline.plot(
[dates[i], dates[i]],
[lows[i], highs[i]],
color=color,
linewidth=0.8
)
# 实体(开盘到收盘的矩形)
body_bottom = min(opens[i], closes[i])
body_height = abs(closes[i] - opens[i])
rect = Rectangle(
(dates[i] - bar_width / 2, body_bottom),
bar_width, body_height,
facecolor=color,
edgecolor=color
)
ax_kline.add_patch(rect)
# 叠加均线
ma5 = df["Close"].rolling(5).mean()
ma20 = df["Close"].rolling(20).mean()
ax_kline.plot(dates, ma5, color="blue", linewidth=1, label="MA5")
ax_kline.plot(dates, ma20, color="orange", linewidth=1, label="MA20")
ax_kline.set_title("贵州茅台 - 多子图K线分析", fontsize=14)
ax_kline.legend(loc="upper left")
ax_kline.grid(True, alpha=0.3)
# 绘制成交量柱
for i in range(len(dates)):
color = "red" if closes[i] >= opens[i] else "green"
ax_vol.bar(dates[i], volumes[i], width=bar_width, color=color, alpha=0.7)
ax_vol.set_ylabel("成交量")
ax_vol.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()标注买卖点
在实际策略回测中,我们需要在K线图上标注买入和卖出的信号位置。matplotlib 提供了 annotate 方法来实现这一功能:
python
# 模拟买卖信号(这里用均线金叉/死叉作为示例)
signals = pd.DataFrame(index=df.index)
signals["MA5"] = df["Close"].rolling(5).mean()
signals["MA20"] = df["Close"].rolling(20).mean()
# 金叉买入信号:MA5 从下方穿越 MA20
signals["buy"] = (
(signals["MA5"].shift(1) < signals["MA20"].shift(1)) &
(signals["MA5"] > signals["MA20"])
)
# 死叉卖出信号:MA5 从上方穿越 MA20
signals["sell"] = (
(signals["MA5"].shift(1) > signals["MA20"].shift(1)) &
(signals["MA5"] < signals["MA20"])
)
# 在K线图上标注买卖点
buy_dates = signals[signals["buy"]].index
sell_dates = signals[signals["sell"]].index
for bd in buy_dates:
idx = df.index.get_loc(bd)
ax_kline.annotate(
"买",
xy=(dates[idx], lows[idx]),
xytext=(dates[idx], lows[idx] * 0.96),
fontsize=10,
fontweight="bold",
color="red",
arrowprops=dict(arrowstyle="->", color="red", lw=1.5),
ha="center"
)
for sd in sell_dates:
idx = df.index.get_loc(sd)
ax_kline.annotate(
"卖",
xy=(dates[idx], highs[idx]),
xytext=(dates[idx], highs[idx] * 1.04),
fontsize=10,
fontweight="bold",
color="green",
arrowprops=dict(arrowstyle="->", color="green", lw=1.5),
ha="center"
)金叉:短期均线从下方穿越长期均线,通常被视为买入信号。死叉:短期均线从上方穿越长期均线,通常被视为卖出信号。
添加 MACD 子图
在第三个子图中绘制 MACD 指标(关于 MACD 的详细计算,请参考下一篇《用Python计算技术指标》):
python
# 计算 MACD
ema12 = df["Close"].ewm(span=12, adjust=False).mean()
ema26 = df["Close"].ewm(span=26, adjust=False).mean()
dif = ema12 - ema26
dea = dif.ewm(span=9, adjust=False).mean()
macd_bar = (dif - dea) * 2
# 绘制 MACD 柱状图
for i in range(len(dates)):
color = "red" if macd_bar.iloc[i] >= 0 else "green"
ax_macd.bar(dates[i], macd_bar.iloc[i], width=bar_width, color=color, alpha=0.7)
ax_macd.plot(dates, dif, color="blue", linewidth=1, label="DIF")
ax_macd.plot(dates, dea, color="orange", linewidth=1, label="DEA")
ax_macd.axhline(y=0, color="gray", linestyle="--", linewidth=0.5)
ax_macd.set_ylabel("MACD")
ax_macd.legend(loc="upper left")
ax_macd.grid(True, alpha=0.3)
# 格式化X轴日期显示
ax_macd.xaxis.set_major_formatter(mdates.DateFormatter("%Y-%m"))
ax_macd.xaxis.set_major_locator(mdates.MonthLocator())
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()保存图表到文件
在自动化分析流程中,我们通常需要将图表保存为图片文件,而不是弹窗显示:
python
# mplfinance 保存图片
mpf.plot(
df,
type="candle",
volume=True,
style=my_style,
mav=(5, 20),
title="贵州茅台",
savefig="kline_maotai.png",
figsize=(14, 8)
)
# matplotlib 保存图片
fig.savefig("kline_analysis.png", dpi=150, bbox_inches="tight")支持的格式包括 PNG、JPG、SVG、PDF 等。dpi 参数控制图片分辨率(默认 100,印刷建议 300),bbox_inches="tight" 可以避免图表边缘被裁切。
常见问题与解决方案
中文字体显示为方块
matplotlib 默认不支持中文,需要手动设置字体:
python
# Windows 系统
plt.rcParams["font.sans-serif"] = ["SimHei"] # 黑体
# macOS 系统
# plt.rcParams["font.sans-serif"] = ["Arial Unicode MS"]
# Linux 系统(需要先安装字体)
# plt.rcParams["font.sans-serif"] = ["WenQuanYi Micro Hei"]
plt.rcParams["axes.unicode_minus"] = False # 解决负号显示问题图表显示空白窗口
在脚本中使用 matplotlib 时,确保 plt.show() 在所有绑制代码之后调用。如果在 Jupyter Notebook 中使用,可以在开头加上魔法命令:
python
%matplotlib inline # 在Notebook中直接显示图片日期轴过于密集
当数据量较大时,X 轴的日期标签可能重叠。可以通过以下方式调整:
python
# 方法1:自动旋转日期标签
fig.autofmt_xdate()
# 方法2:手动设置日期间隔
ax.xaxis.set_major_locator(mdates.WeekdayLocator(interval=2)) # 每2周显示一个标签小结
本文介绍了用 Python 绘制K线图的两种主要方式:
- mplfinance 快速绑制:适合快速出图,几行代码即可得到带均线和成交量的专业K线图。
- matplotlib 手动绘制:适合高级场景,可以自由控制子图布局、标注买卖信号、叠加自定义指标。
掌握K线图绘制是量化分析可视化的第一步。在后续的文章中,我们将学习如何计算技术指标、构建交易策略,并将这些可视化技巧整合到策略回测的完整流程中。
示例:K线图示例
红色蜡烛表示上涨(收盘>开盘),绿色蜡烛表示下跌(收盘<开盘)
免责声明:本文所有代码仅用于技术教学目的,文中涉及的股票代码仅为数据示例,不构成任何投资建议。投资有风险,入市需谨慎。