3. 板块短期涨幅偏离度与追高风险阈值设定
偏离度指标的定义与计算口径
本节把“追高风险”落到一个可计算的量上:板块收盘价相对其均线的偏离度。定义两个口径,均以百分比表示,正号代表价格在均线之上:
- 短期偏离度 D20 = (Ct / MA20t − 1) × 100%,刻画近一个月内的加速程度,对追高最敏感。
- 中期偏离度 D60 = (Ct / MA60t − 1) × 100%,刻画季度级别的趋势透支程度,用于区分“短期脉冲”与“趋势末端”。
均线一律使用含当日收盘的简单移动平均,且只用 t 日及以前的数据,避免未来函数。计算前需确认板块指数为不复权或统一复权口径,否则除权日会造成偏离度假跳变。
用历史分位数把偏离度转成阈值
偏离度的绝对值在不同板块间不可比:高波动成长板块常年 D20 在 5% 以上,低波动红利板块 3% 已属极端。因此阈值不能拍一个固定数字,而应按板块自身历史分布取分位数。做法是:对每个板块,用过去 N 个交易日(建议 N ≥ 500,覆盖至少一轮完整涨跌)的 D20 序列,取 80%、90%、95% 分位作为三档阈值。
下面用一段可直接运行的 Python 代码完成“偏离度计算 → 分位数阈值 → 触发频率统计”的完整链路。示例数据由固定随机种子生成,仅用于演示流程与判读方法,不代表任何真实板块行情。
import numpy as np
import pandas as pd
rng = np.random.default_rng(20240603)
def make_sector(n=900, mu=0.0004, sigma=0.014, jump_prob=0.03, jump=0.035):
"""生成示例板块日线:带偶发脉冲上涨的几何随机游走"""
ret = rng.normal(mu, sigma, n)
mask = rng.random(n) < jump_prob
ret[mask] += jump
close = 1000 * np.exp(np.cumsum(ret))
return pd.DataFrame({"close": close})
def deviation(df, win):
ma = df["close"].rolling(win, min_periods=win).mean()
return (df["close"] / ma - 1) * 100
df = make_sector()
df["D20"] = deviation(df, 20)
df["D60"] = deviation(df, 60)
# 用前 500 个交易日建立分位数基准,之后为样本外观察期
base = df["D20"].iloc[:500].dropna()
qs = base.quantile([0.80, 0.90, 0.95])
print("D20 历史分位阈值:", qs.round(2).to_dict())
obs = df.iloc[500:].copy()
for name, q in zip(["T80", "T90", "T95"], qs.values):
obs[name] = obs["D20"] > q
# 触发频率
freq = {c: obs[c].mean() for c in ["T80", "T90", "T95"]}
print("样本外触发频率:", {k: round(v, 3) for k, v in freq.items()})
# 触发后 5 日、10 日的前向最大回撤(相对触发日收盘)
def fwd_drawdown(close, i, horizon):
seg = close[i+1 : i+1+horizon]
if len(seg) < horizon:
return np.nan
return (seg.min() / close[i] - 1) * 100
for c in ["T80", "T90", "T95"]:
idx = np.where(obs[c].values)[0]
dd5 = [fwd_drawdown(obs["close"].values, i, 5) for i in idx]
dd10 = [fwd_drawdown(obs["close"].values, i, 10) for i in idx]
print(f"{c}: 触发{len(idx)}次, 5日均回撤{np.nanmean(dd5):.2f}%, "
f"10日均回撤{np.nanmean(dd10):.2f}%")
分位数基准窗口与观察窗口必须严格分离。若用全样本算分位数再回看触发,阈值会“偷看”未来分布,触发频率与回撤统计都会失真。上例用前 500 日定阈值、后 400 日做样本外观察,就是这个约束的最小实现。
阈值—频率—回撤的权衡关系
三档阈值不是“越高越好”。阈值抬高,触发次数下降、信号更稀有,但被筛掉的往往是温和上涨,留下的样本更集中于极端脉冲,后续回撤均值通常更大;阈值降低,覆盖更多上涨,但混入大量正常趋势,回撤信号被稀释。真正要读的是“单位触发次数所对应的回撤幅度”这一性价比,而不是单看回撤均值。
结果判读与阈值落地
跑完上面的代码,会得到三组数字:各档阈值、样本外触发频率、触发后 5/10 日平均回撤。判读时按以下顺序看,而不是只盯回撤均值:
- 先看频率是否可用。若 T90 在样本外触发频率低于 1%,说明该板块历史上极少出现这种偏离,阈值对实盘过于苛刻,应回退到 T80 或改用 D60 辅助确认。
- 再看回撤是否随阈值单调放大。若 T95 的回撤均值反而不高于 T90,通常意味着样本量太小(触发次数个位数),统计不稳健,此时不应据此抬高阈值。
- 最后看性价比。用“10 日平均回撤 ÷ 触发频率”比较三档,选数值明显占优且触发次数足够(建议 ≥ 20 次)的一档作为该板块的主阈值。
偏离度阈值是板块专属的,不能跨板块套用同一个百分比。同一市场里,成长板块的 P90 可能对应 8%,红利板块的 P90 可能只有 3%。若必须横向比较多个板块的追高风险,应先把各板块 D20 转换为其自身历史分位(0–100 的分位值),再比较分位值而非原始偏离度。
可直接套用的阈值设定检查表
| 检查项 | 要求 | 不满足时的处理 |
|---|---|---|
| 均线口径 | 含当日收盘的 SMA,复权口径统一 | 除权日前后偏离度需剔除或重算 |
| 基准窗口长度 | ≥ 500 个交易日,覆盖完整涨跌周期 | 缩短窗口会低估极端分位,阈值偏低 |
| 基准与观察分离 | 定阈值窗口与验证窗口不重叠 | 重叠即引入未来信息,频率与回撤失真 |
| 触发样本量 | 样本外触发 ≥ 20 次 | 不足则合并档位或延长观察期 |
| 双口径交叉 | D20 触发时检查 D60 是否同向偏高 | 仅 D20 高、D60 平,多为短期脉冲,可降级处理 |
| 阈值更新频率 | 按季度或半年度滚动重估分位 | 长期不更新会使阈值随波动率漂移而失效 |
完成以上步骤后,每个板块都应输出一组可执行参数:{板块, D20_P80, D20_P90, D20_P95, 样本外触发频率, 10日平均回撤, 主阈值档位}。这组参数就是后续量能异动修正与滚动回测的输入基础。