⚠ 交易存在重大亏损风险。本网站的所有内容仅供教育用途,不构成财务建议。
第 10 课,共 13 课 · 免费

用于分析的绘图:带指标的价格图、资金曲线与回撤图、收益率分布以及导出图表

使用 matplotlib 的“图形与坐标轴”接口构建每份回测报告都需要的四种图表,正确解读它们,并以印刷质量导出。

作者: Moustafa Hijazi内容审核日期: 2026-10-30阅读约 8 分钟自学课程

你将学到什么

  • fig, ax = plt.subplots() 模式,以及为什么对于任何需要复用的图表,它都优于快捷的 series.plot()。
  • 如何堆叠共享同一时间轴的价格、指标和资金面板,以及何时把资金轴切换为对数刻度。
  • 如何绘制回撤图和收益率直方图,以及在每种图中应该关注什么。
  • 图形尺寸、DPI 和文件格式如何决定导出图像的效果。

讲解

研究中的图表不是装饰;它们是检查数字是否正确的最快方法。一条在一天内跳升 30% 的资金曲线,通常意味着数据错误,而不是一笔绝佳的交易。本课通过 matplotlib(pandas 在底层调用的绘图库)的面向对象接口来使用它。

图形、坐标轴与共享时间轴

图形(figure)是整块画布;坐标轴(axes)对象是其中的一个绘图区域。fig, axes = plt.subplots(3, 1, figsize=(10, 8), sharex=True, height_ratios=[3, 1, 1]) 会创建三个高度不同、上下堆叠并能同步缩放的面板。每个面板的套路都相同:调用 ax.plot(x, y, label=...),然后调用 ax.set_ylabel、ax.legend() 和 ax.grid(True, alpha=0.3)。为每个面板加一个简短的标题,并标注单位(€、%、点)。

带指标的价格图

  • fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 6), sharex=True, height_ratios=[3, 1])
  • ax1.plot(df.index, df.close, lw=1, label='Close')
  • ax1.plot(df.index, df.sma50, lw=1, label='SMA 50')
  • ax1.fill_between(df.index, df.bb_lo, df.bb_hi, alpha=0.15, label='Bollinger')
  • ax1.legend(loc='upper left'); ax1.set_ylabel('Price (€)')
  • ax2.plot(df.index, df.rsi, lw=1); ax2.axhline(70, ls='--'); ax2.axhline(30, ls='--')
  • ax2.set_ylabel('RSI'); fig.autofmt_xdate(); fig.tight_layout()

fill_between为一个区间着色;axhline 绘制参考水平线;autofmt_xdate 旋转日期标签,使它们不会重叠。若要标出第 8 课交易清单中的交易,入场用 ax1.scatter(entries.index, entries.price, marker='^'),离场则用向下的三角形。

资金曲线与回撤

只要账户在整个期间内增长超过一倍,就请用 ax.set_yscale('log') 绘制资金曲线。在线性坐标轴上,从 €10,000 到 €11,000 的变动与后来从 €40,000 到 €44,000 的变动相比显得微不足道,尽管两者都是 +10%。回撤面板绘制 dd = equity / equity.cummax() - 1 并为其填色:ax.fill_between(dd.index, dd, 0, alpha=0.4)。解读时关注三点:最深处(最大回撤)、低于零的最长时段(水下时间,往往比深度更令人痛苦),以及回撤是否集中在某一种市场状态中。

收益率分布

ax.hist(returns, bins=50, density=True) 显示日收益率或每笔交易收益率的分布形状。叠加一条均值和标准差相同的正态曲线,就能看到肥尾:真实收益率中的极端日子比钟形曲线预测的更多。对于交易清单,请改为绘制 R 倍数:一个健康的趋势系统会显示出大量接近 −1R 的小额亏损和一条长长的右尾;一个做空波动率的系统则呈现镜像形态,这是一个警示信号。用 returns.skew() 和 returns.kurt() 报告偏度和峰度(pandas 返回的是超额峰度,因此 0 表示尾部接近正态)。

导出

fig.savefig('equity.png', dpi=150, bbox_inches='tight') 写出一张栅格图像;像素尺寸 = 英寸 × DPI,因此一张 10 × 6 英寸、150 DPI 的图形为 1,500 × 900 像素。若要在报告中保持清晰,请使用 .svg 或 .pdf 矢量格式输出,并使用 bbox_inches='tight' 裁掉白边。在循环中保存后务必调用 plt.close(fig),否则一个生成 40 张观察列表图表的脚本(第 12 课)会在内存中保留 40 个图形。用 plt.rcParams['figure.dpi'] = 110 一次性设定默认值,而不是在每次调用中设定。

实例演算

假设示例:一个回测资金序列(以欧元计,数字为编造)及其图表。资金数值中不计手续费和税费。

  1. 各年末资金:€10,000、€13,000、€11,700、€16,000、€24,000。回撤序列:峰值为 10,000;13,000;13,000;16,000;24,000 → 回撤为 0;0;11,700 / 13,000 − 1 = −10.0%;0;0。最大回撤 −10%,水下时间约一年。
  2. 在线性坐标轴上,最后一段(+€8,000)主导了整个画面;在对数坐标轴上,+30%、−10%、+36.8%、+50% 这几步以其真实的相对大小显示,−10% 的那一年也清晰可见,而不会被压平。
  3. 日收益率:均值 0.06%,标准差 1.1%,超额峰度 4.2。在具有该标准差的正态分布下,−3.3% 的一天(三个标准差)大约每 740 天才出现一次;而直方图显示在 1,000 天中出现了七次。这一差距就是肥尾,也是止损可能被跳空越过的原因(第 8 课)。
  4. 导出:figsize=(8, 5)、dpi=200 得到 1,600 × 1,000 像素,足以用于幻灯片;同一图形保存为 SVG 后与分辨率无关,文件通常小于 100 kB。

常见错误

用线性刻度绘制资金曲线,并从中解读出“加速”一个年收益率恒定为 15% 的策略,在线性图上会呈现一条越来越陡地向上弯曲的曲线,看起来像是绩效在不断改善。在对数刻度上,它是一条直线。请在对数资金轴上比较不同策略、时期和回撤;线性坐标轴只用于短时期或展示欧元金额。

练习活动

在纸上完成:(a) 一条资金曲线依次为 20,000 → 26,000 → 19,500 → 28,000(以欧元计,四个点)。计算每个点的回撤。(b) 你想要一张在 100 DPI 下恰好为 1,200 × 800 像素的图形;应传入什么 figsize?(c) 某策略 R 倍数直方图的最高柱位于 +0.2R 到 +0.4R 之间,而一条细长的左尾延伸到 −6R。用一句话说明这种形态暗示了该策略的什么特点,以及夏普比率无法显示的风险。

显示答案

(a) 峰值:20,000;26,000;26,000;28,000。回撤:0;0;19,500 / 26,000 − 1 = −25.0%;0。

(b) figsize = (1,200 / 100, 800 / 100) = (12, 8) 英寸。

(c) 大量小额盈利加上罕见的巨额亏损,是一个出售风险的策略(例如卖出期权或摊低成本加仓)的典型特征;夏普比率由均值和标准差构成,会被频繁的小额盈利拉高,从而低估一次 −6R 的日子抹去数月收益的可能性。

局限性:观测值少于大约 100 个的直方图噪声太大,无法判断尾部形状;此时请改为报告实际的最差数值。

要点回顾

  • 为价格、指标、资金和回撤面板使用共享 x 轴的 plt.subplots;标注单位。
  • 对数刻度的资金曲线能诚实地显示百分比变动;回撤图显示深度和水下时间。
  • 收益率或 R 倍数的直方图能揭示汇总统计量所掩盖的肥尾和不对称性。
  • 像素 = 英寸 × DPI;报告优先使用 SVG 或 PDF,并在循环中关闭图形。

下一步

第 11 课从单一品种扩展到多个品种:相关系数矩阵和协方差矩阵、由权重计算投资组合波动率,以及在 pandas 中进行再平衡模拟。

自测

回答问题后核对答案。你可以随意重试多次。

1. 你对一个用 figsize=(6, 4) 创建的图形调用 fig.savefig('out.png', dpi=300)。图像的像素尺寸是多少?

2. 两个策略在十年内都把 €10,000 增长到 €40,000。在对数刻度的资金曲线图上,策略 A 几乎是一条直线,而策略 B 八年来一直走平,随后急剧上升。这说明了什么?

3. 一个脚本为包含 60 个品种的观察列表中的每个代码生成一张图表,每次运行都变得更慢、占用更多内存。最可能的修复方法是什么?

供您自行复习的自动自测。您的答案在浏览器中核对,我们不会查看或评估。这不是考试,也不是资格证书。

您的进度

“已完成”仅表示您将本课标记为已学完,并不是对您理解程度的测试。 学习进度和笔记仅保存在此设备的此浏览器中,而非账户中。