跳到主要内容

止损止盈与波动率目标

直觉

控制风险有两条思路。被动型——止损/止盈:亏到某条线就砍仓,看似稳妥,但在趋势市场里常「砍在坑底、错过反弹」,反而拉低收益。主动型——波动率目标(vol targeting):不赌价格方向,而是动态调仓,让组合的实际波动始终贴近一个目标值——市场越乱仓位越小,越平静仓位越大。波动率目标化能稳定风险敞口、改善夏普,是大型机构最常用的风控手段。

波动率目标化

设目标年化波动 σtgt\sigma_{\text{tgt}},用滚动已实现波动 σ^t\hat\sigma_t 估计当前风险,则目标仓位:

wt=σtgtσ^t,σ^t=std(rth:t)252w_t = \frac{\sigma_{\text{tgt}}}{\hat\sigma_t},\qquad \hat\sigma_t = \text{std}(r_{t-h:t})\cdot\sqrt{252}

理论上策略年化波动 σtgt\approx \sigma_{\text{tgt}}wtw_t 与波动率成反比,正好抵消)。

「人话」解释:为什么波动率目标通常有效,而硬止损常常有害?

波动率目标做的是「风险均摊」——波动大时自动减仓,等于把高波动的日子稀释掉,让每天的「风险剂量」大致相等,夏普往往因此提升(尤其在波动聚集的市场)。它不预测方向,只控制「每单位时间承担多少风险」。 硬止损则相反:它假设「跌破某线就会继续跌」,但市场常在底部剧烈反弹——于是你卖在最低点、等创新高才敢买回,完美错过修复行情。统计上,止损在强趋势资产里多数时候降低收益,只在强均值回归(如某些配对交易)里有用。规则要匹配品种特性。

可运行案例①:波动率目标化(15% 年化)

import quant
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')
close = df['adj_close']; r = close.pct_change()
realized = r.rolling(21).std() * np.sqrt(252)
target = 0.15
pos = (target / realized).clip(0, 2)                 # 目标 15% 波动, 上限 2 倍杠杆

bt = quant.vector_backtest(close, pos, cost_bps=2)
bh = quant.vector_backtest(close, pd.Series(1.0, index=close.index), cost_bps=2)
print(f"目标 = {target:.0%} 年化波动")
print(f"波动率目标策略 实际年化波动 = {quant.volatility(bt['returns']):.2%}  夏普 = {quant.sharpe(bt['returns']):.2f}")
print(f"买入持有        实际年化波动 = {quant.volatility(bh['returns']):.2%}  夏普 = {quant.sharpe(bh['returns']):.2f}")

plt.figure(figsize=(9, 3.6))
plt.plot(bt['equity'], label='波动率目标(15%)', lw=1.5)
plt.plot(bh['equity'], label='买入持有', ls='--', lw=1.2)
plt.title('波动率目标化净值'); plt.ylabel('净值'); plt.legend(fontsize=9)
plt.tight_layout(); plt.show()

可运行案例②:硬止损(跌破 10% 离场,创新高回归)

同一资产上加一条「相对半年高点的 -10% 止损、破新高才回场」规则——观察它在趋势行情中的代价。

import quant
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')
close = df['adj_close']
peak = close.rolling(126, min_periods=1).max()
dd = close / peak - 1                                  # 相对半年高点的回撤

flat = False; pos = []
for v in dd:
  if v <= -0.10: flat = True                          # 跌破 -10%, 止损离场
  if v >= -1e-9: flat = False                         # 创新高, 回归
  pos.append(0.0 if flat else 1.0)
sig = pd.Series(pos, index=close.index)

bt = quant.vector_backtest(close, sig, cost_bps=2)
bh = quant.vector_backtest(close, pd.Series(1.0, index=close.index), cost_bps=2)
print("止损后在场比例 = {:.0%}".format(sig.mean()))
print("止损策略: 年化={:+.2%}  夏普={:.2f}  最大回撤={:.2%}".format(
  quant.performance_summary(bt['equity'], bt['returns'])['年化收益'],
  quant.sharpe(bt['returns']), quant.max_drawdown(bt['equity'])))
print("买入持有: 年化={:+.2%}  夏普={:.2f}  最大回撤={:.2%}".format(
  quant.performance_summary(bh['equity'], bh['returns'])['年化收益'],
  quant.sharpe(bh['returns']), quant.max_drawdown(bh['equity'])))
print("\n→ 在这类趋势行情里, 止损常'砍在坑底、错过反弹', 拉低夏普。")

小结

  • 波动率目标化:仓位 wt=σtgt/σ^tw_t=\sigma_{\text{tgt}}/\hat\sigma_t,让风险敞口稳定,常改善夏普;
  • 硬止损在趋势行情里多有害(卖低买高),仅对均值回归型策略有用;
  • 选风控规则要看品种:趋势类用波动率目标,回归类才适合止损。