回撤与最大回撤
直觉
「你的组合从最高点跌了多少?」——这就是回撤。它是投资者心理上最直接的风险感受:账面富贵缩水的痛苦。最大回撤(MDD) 衡量这段历史上最惨的一次「从巅峰到谷底」有多深,是评估策略「能不能拿得住」的关键。
数学原理
权益曲线 ,截至 的历史最高点(running max)为 。回撤序列:
最大回撤取其绝对值的最深点:
「人话」解释:回撤和波动率哪个更该看?
波动率把所有涨跌一视同仁地累加;回撤只盯「从高点往下跌」的部分,更贴近「真实亏损体验」。 一个策略可能年化波动不高,但某次回撤 −50%——意味着你要承受资产腰斩的煎熬,很多人此刻就割肉了。 所以最大回撤常被当作「能不能拿住」的底线指标。
可运行案例:画出「水下曲线」
读取 spy_daily.csv,构造买入持有权益,画出回撤序列(underwater curve),并报告最大回撤及其发生位置。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
df = pd.read_csv('/data/spy_daily.csv', parse_dates=['date']).set_index('date')
equity = (df['adj_close'] / df['adj_close'].iloc[0])
running_max = equity.cummax()
drawdown = equity / running_max - 1 # 负值序列
mdd = -drawdown.min()
trough = drawdown.idxmin()
peak = equity.loc[:trough].idxmax()
print(f"最大回撤 : {mdd:.2%}")
print(f"峰值日期 : {peak.date()} 价格={equity.loc[peak]:.3f}")
print(f"谷底日期 : {trough.date()} 价格={equity.loc[trough]:.3f}")
fig, ax = plt.subplots(2, 1, figsize=(9, 5.5), sharex=True,
gridspec_kw={'height_ratios':[2,1]})
ax[0].plot(equity, color="#2563eb"); ax[0].plot(running_max, color="#94a3b8", ls='--', lw=1)
ax[0].set_title("权益曲线(蓝) 与 历史最高点(灰虚线)")
ax[1].fill_between(drawdown.index, drawdown, 0, color="tab:red", alpha=0.5)
ax[1].set_title("回撤(水下曲线)"); ax[1].set_ylabel("回撤")
plt.tight_layout(); plt.show()
动手改一改
权益曲线里,灰虚线(历史最高点)和蓝线之间的「缝隙」就是回撤。试着在脑中标记最宽的缝隙——它对应的就是最大回撤时刻,和上方打印的谷底日期一致。
小结
- 回撤 = 当前权益相对历史最高点的跌幅,永远 ;
- 最大回撤 = 历史上最深的一次「巅峰到谷底」;
- 回撤比波动率更贴近「亏损体验」,是「能不能拿住策略」的核心指标。