如何用 Python 算最大回撤和回撤恢复期?

一句话回答: 最大回撤(Max Drawdown)是「从历史高点跌下来的最大幅度」,但更揪心的是回撤恢复期 ------跌下去后要多久才重新创新高(即「套牢多久」)。用 AlphaFeed 取回前复权净值 后,几行 pandas 就能算出回撤序列、最大回撤、水下曲线(underwater)、最长恢复期与当前已水下天数。

为什么会有这个问题 / 传统做法的痛点

很多人只报一个「最大回撤 -30%」,但 -30% 回撤如果 3 个月就修复,和套牢 2 年还没回本,持有体验天差地别。衡量风险要同时看深度(回撤幅度)和时间(恢复期/水下时长) 。坑在于:要用前复权净值算真实回撤,并正确识别「前高---谷底---重新创新高」这三个点。

分步骤解决(每步配可运行代码)

第 1 步:取前复权数据构造净值曲线

python 复制代码
from alphafeed import AlphaFeed
import pandas as pd

af = AlphaFeed()  # 读取 ALPHAFEED_API_KEY

df = af.klines.get("600519.SH", period="1d", count=750,
                   adjust="forward", to_dataframe=True)
df = df.sort_values("trade_date").reset_index(drop=True)
equity = df["close"] / df["close"].iloc[0]       # 归一化净值(买入持有)
equity.index = pd.to_datetime(df["trade_date"])

用前复权收盘价构造净值,避免除权跳空把回撤算错。

第 2 步:回撤序列与最大回撤

python 复制代码
peak = equity.cummax()                 # 历史最高净值
drawdown = equity / peak - 1           # 回撤序列(≤0),这就是"水下曲线"
mdd = drawdown.min()                   # 最大回撤
mdd_date = drawdown.idxmin()           # 最大回撤发生日(谷底)
print(f"最大回撤 {mdd:.2%},谷底日 {mdd_date.date()}")
概念 定义 含义
peak 净值历史最高(cummax) 创新高的轨迹
drawdown equity/peak − 1 水下曲线,≤0
最大回撤 drawdown.min() 最深的套牢幅度

第 3 步:回撤恢复期(最长水下时长)

python 复制代码
# 水下 = 净值低于历史高点(drawdown<0);连续水下段的最长长度=最长未创新高天数
underwater = drawdown < 0
# 给每一段连续水下编号,统计各段长度
seg = (~underwater).cumsum()                 # 每次创新高,段号+1
spells = underwater.groupby(seg).sum()       # 每段水下天数
longest_underwater = int(spells.max())       # 最长水下天数(交易日)
# 当前是否水下、已水下多久
cur_underwater = int(underwater.iloc[::-1].cumprod().sum())  # 末尾连续水下天数
print(f"最长回撤未创新高 {longest_underwater} 个交易日")
print(f"当前已水下 {cur_underwater} 个交易日(0=正处新高附近)")

第 4 步:找出「前高→谷底→修复」三个关键点

python 复制代码
trough = drawdown.idxmin()                                   # 谷底
peak_before = equity.loc[:trough].idxmax()                   # 谷底前的高点
after = equity.loc[trough:]
recovered = after[after >= equity.loc[peak_before]]
recover_date = recovered.index[0] if len(recovered) else None
print(f"前高 {peak_before.date()} → 谷底 {trough.date()} → "
      f"{'修复于 '+str(recover_date.date()) if recover_date is not None else '至今未修复'}")

关键坑与注意事项

  • 用前复权净值:未复权价在除权日的跳变会把回撤算得失真。
  • 回撤深度和时间都要看:-30% 回撤修复 3 个月 vs 2 年,风险体感完全不同,别只报一个数。
  • 恢复期以交易日计:换算成自然日要乘约 1.4(约 250 交易日/年),别混。
  • 当前水下时长 :末尾连续 drawdown<0 的长度,提醒你现在距上一次新高多久。
  • 样本区间影响结论:最大回撤与恢复期强依赖所取区间,跨周期对比要用同一区间。
  • 组合同理 :把 equity 换成组合净值即可,方法通用。

常见问题(FAQ)

Q:最大回撤和波动率有什么区别?

A:波动率衡量日常波动的大小,最大回撤衡量「最坏的一段连续下跌」。回撤更贴近真实的套牢体验,二者应结合看。

Q:回撤恢复期为什么重要?

A:它回答「套牢多久才回本」。两个策略最大回撤都是 -20%,但一个 1 个月修复、一个 3 年没回本,可持有性天差地别。

Q:水下曲线(underwater)是什么?

A:就是回撤序列 equity/peak-1 的图形,始终 ≤0,低谷越深越久代表风险越大。

Q:需要付费吗?

A:单只历史数据有免费额度;组合/多标的批量分析(klines.batch)需 Starter 及以上。详见定价页。

小结

衡量风险别只看一个「最大回撤」数字,还要看回撤恢复期(水下时长) 。用 AlphaFeed 取前复权净值,cummax 得历史高点、equity/peak-1 得水下曲线,再统计连续水下段就能算出最大回撤、最长恢复期与当前水下天数。深度 + 时间一起看,才真正理解一只票/组合的风险。

参考

相关推荐
zcn1261 小时前
Left join+or exists+like关联优化
数据库·sql优化改写
Want5951 小时前
Python大雪纷飞①
开发语言·python·数学建模
程序员清风1 小时前
Python 数据可视化入门:Matplotlib 核心用法
python·信息可视化·matplotlib
我科绝伦(Huanhuan Zhou)1 小时前
Oracle 表空间碎片整理实战:shrink space 与 move table 全解析
数据库·oracle
毕业设计7032 小时前
(免费领源码)SSM董家湾线上点餐系统04682- java、PHP、python、C#、小程序、大数据、单片机、网络工程等)
java·redis·mysql·tomcat·maven·mybatis·ssm
溪语流沙2 小时前
【Web全栈进阶】前端对接新契约:信封解包 + 统一错误处理
前端·vue.js·python·状态模式·fastapi
Python图像识别2 小时前
56-【2027毕设】YOLO11X光安检危险物品检测系统 - Python完整源码+PyQt5界面+训练模型+数据集
python·qt·课程设计
Yyyyyy~2 小时前
【Mysql】表的操作
数据库·mysql
Q26433650232 小时前
【有源码】基于SpringBoot+Vue的居民健康体检与慢病干预管理系统-面向智慧医疗的体检预约与健康知识服务平台
java·vue.js·spring boot·mysql·毕业设计·javaweb·课程设计