第二章 最大回撤控制:守住利润的生命线

做轮动策略这些年,我最大的感悟是什么?

不是赚了多少,而是回撤来临时你扛不扛得住。

2018年那次,我亲眼见过一个朋友的策略,三个月翻了一倍,结果一周回撤就吞掉了80%的利润。为什么?因为他没设回撤止损线。说白了,回撤控制就是策略的「安全带」——平时觉得碍事,真出事时能救命。

2.1 定义最大回撤:先搞清楚你在说什么

最大回撤,英文叫Max Drawdown,简称MDD。它衡量的是:从历史最高点跌到最低点,你亏了多少。

公式其实很简单:

最大回撤 = (波峰净值 - 波谷净值) / 波峰净值 × 100%

举个例子:

你的策略净值从1.0涨到1.5,然后跌到1.2。那么最大回撤就是 (1.5 - 1.2) / 1.5 = 20%。

嗯,这里要注意——最大回撤只看「从最高点到最低点」这一段,中间的小波动不算。我个人习惯用「滚动窗口」来计算,比如取过去60天的最高点和最低点。

核心要点:

  • 最大回撤是「事后指标」,只能告诉你过去发生了什么
  • 它不代表未来,但能反映策略的「抗摔能力」
  • 回撤越大,恢复需要的涨幅就越大——跌50%需要涨100%才能回本

为什么我特别强调这个?因为很多新手只看年化收益,不看回撤。你想想看,一个年化30%但回撤40%的策略,和一个年化20%但回撤只有10%的策略,哪个更安全?答案很明显。

2.2 设置硬性回撤止损线:给策略上把锁

硬性回撤止损线,说白了就是「跌到某个位置,无条件清仓」。

这个线怎么设?我一般分三步:

  1. 看历史最大回撤:回测中策略的最大回撤是多少?比如是15%,那止损线可以设在18%-20%。
  2. 加一个安全垫:历史最大回撤是15%,不代表未来不会到20%。所以我习惯加3-5个点的缓冲。
  3. 考虑市场环境:震荡市和趋势市,止损线应该不一样。震荡市可以设紧一点,趋势市可以松一点。

我曾经犯过一个错误:把止损线设得太紧,结果策略频繁触发止损,白白亏了手续费。后来我学乖了——止损线不是越紧越好,要留出「合理波动」的空间。

我的经验:

硬性止损线建议设在「历史最大回撤 × 1.2」的位置。比如历史最大回撤15%,止损线就是18%。这样既不会太紧,也不会太松。

代码实现其实不复杂:

def check_hard_stop(net_value, stop_line=0.18):
    """
    检查是否触发硬性止损
    :param net_value: 当前净值
    :param stop_line: 止损线,默认18%
    """
    peak = max(net_value)  # 历史最高净值
    current = net_value[-1]  # 当前净值
    drawdown = (peak - current) / peak
    
    if drawdown >= stop_line:
        print(f"⚠️ 触发硬性止损!当前回撤:{drawdown:.2%}")
        return True
    return False

这段代码的逻辑很简单:每次更新净值时,计算从最高点跌了多少。如果超过止损线,就触发清仓信号。

注意:

硬性止损一旦触发,不要犹豫。我见过太多人「再等等看」,结果越等越深。止损就是止损,没有「再看看」这回事。

2.3 动态回撤止损策略:让止损线跟着市场走

硬性止损有个问题:它是一根死线。市场在变,你的止损线也应该变。

动态回撤止损,就是让止损线「活起来」。常见的做法有两种:

方法 原理 适用场景
移动止损 净值创新高时,止损线上移 趋势行情
波动率止损 根据近期波动率调整止损幅度 震荡行情

移动止损:比如你设了10%的止损线。净值从1.0涨到1.2,止损线就从0.9上移到1.08。这样既能锁定利润,又给了策略足够的波动空间。

波动率止损:市场波动大的时候,止损线放宽;波动小的时候,止损线收紧。我一般用过去20天的ATR(平均真实波幅)来调整。

代码实现如下:

def dynamic_stop(net_value, atr_period=20, atr_multiplier=2):
    """
    动态止损策略
    :param net_value: 净值序列
    :param atr_period: ATR计算周期
    :param atr_multiplier: ATR倍数
    """
    import numpy as np
    
    # 计算每日收益率
    returns = np.diff(net_value) / net_value[:-1]
    
    # 计算ATR(这里用标准差近似)
    atr = np.std(returns[-atr_period:]) * np.sqrt(252)
    
    # 动态止损线 = 当前净值 - ATR × 倍数
    current = net_value[-1]
    stop_price = current * (1 - atr * atr_multiplier)
    
    # 检查是否触发
    if net_value[-1] <= stop_price:
        print(f"⚠️ 触发动态止损!当前净值:{current:.4f},止损价:{stop_price:.4f}")
        return True
    return False

我个人更偏爱移动止损。为什么?因为它简单、直观,而且效果不错。波动率止损虽然更「科学」,但参数调起来很麻烦,容易过拟合。

两种策略对比:

  • 硬性止损:简单粗暴,适合新手。缺点是可能被「假突破」骗出场。
  • 动态止损:灵活智能,适合老手。缺点是参数多,需要持续优化。

我建议刚开始做轮动策略的朋友,先用硬性止损。等跑顺了,再慢慢加入动态止损。一口吃不成胖子,风控也是。

2.4 本章知识体系

下面这张图,是我自己总结的回撤控制框架。你看一眼,基本就明白这章在讲什么了:

最大回撤控制框架 最大回撤控制 定义最大回撤 硬性回撤止损线 动态回撤止损策略 波峰到波谷的跌幅 滚动窗口计算 历史最大回撤 × 1.2 无条件清仓 移动止损 / 波动率止损 参数需持续优化

这张图把本章的核心逻辑串起来了。你从「最大回撤控制」出发,左边是定义,中间是硬性止损,右边是动态止损。每个分支下面还有具体的实现方法。

做轮动策略,回撤控制不是「要不要做」的问题,而是「怎么做」的问题。我见过太多人,策略收益做得漂亮,但一次回撤就回到解放前。记住:控制回撤,就是保护你的本金和利润

嗯,这一章就到这里。下一章我们聊聊「仓位管理」——怎么在控制回撤的同时,还能让收益跑起来。


专注资料整理