1. 板块轮动追高风险的识别与量化框架搭建
为什么追高风险需要“框架”而不是“感觉”
板块轮动中的追高风险,本质是“短期涨幅已经透支了轮动动能”的状态。单看涨幅会误判:强势板块可能继续加速,弱势板块也可能只是超跌反弹。因此需要一个可复用的量化框架,把风险拆成三个可观测维度,再合成一个每日可比的评分。
本框架定义三类指标,全部基于板块指数日线数据(收盘价、成交量)与大盘基准指数计算:
- 轮动强度 R:板块相对大盘的超额收益在近 N 日横截面排名中的变化速度,刻画“资金是否正在加速涌入”。
- 涨幅偏离 D:板块收盘价相对其 20 日均线的偏离度,刻画“短期价格是否已远离中枢”。
- 量能异动 V:当日成交量相对其 20 日均量的放大倍数,刻画“是否出现情绪化放量”。
三者分别做横截面标准化(Z-score),加权合成追高风险评分 RiskScore,取值范围经压缩后落在 0~100,便于跨日、跨板块比较。
框架结构与数据流
下图展示从原始日线数据到每日风险评分的完整链路:三条指标支路并行计算,各自标准化后进入加权合成,最终输出板块×日期的评分矩阵,并给出风险分档。
指标定义与计算口径
为避免“看起来合理但算不出来”,先把每个指标的口径固定下来。以下以单个板块 s、交易日 t 为例,close 为收盘价,vol 为成交量。
| 指标 | 计算式 | 方向含义 | 典型阈值 |
|---|---|---|---|
| 轮动强度 R | 超额收益 ex = ret_s − ret_bench;对 ex 做 5 日累计后取横截面排名,R = rank_t − rank_{t−5} | R 越大,排名上升越快,资金加速流入 | R ≥ 3 视为轮动加速 |
| 涨幅偏离 D | D = (close_t − MA20_t) / MA20_t | D 越大,价格越偏离 20 日中枢 | D ≥ 0.08 视为短期偏离偏高 |
| 量能异动 V | V = vol_t / VOL_MA20_t | V 越大,放量越明显 | V ≥ 1.5 视为放量异动 |
三个指标都做了“越大越危险”的方向统一,因此合成时直接加权即可,无需再翻转符号。
可复用的计算实现
下面是一段自洽的 Python 实现,输入为宽表格式的板块收盘价与成交量(行=日期,列=板块),以及大盘收盘价序列。函数返回每日每板块的 RiskScore。
import numpy as np
import pandas as pd
def build_chase_risk(close_wide, vol_wide, bench_close,
w=(0.4, 0.4, 0.2), ma_win=20, rank_win=5):
"""
close_wide : DataFrame, index=日期, columns=板块, 收盘价
vol_wide : DataFrame, 同形状, 成交量
bench_close: Series, index=日期, 大盘收盘价
w : (w_R, w_D, w_V) 权重
返回: DataFrame, 同形状, 追高风险评分 0~100
"""
# 1) 轮动强度 R:超额收益的横截面排名变化
ret_s = close_wide.pct_change()
ret_b = bench_close.pct_change().reindex(close_wide.index)
ex = ret_s.sub(ret_b, axis=0) # 每日超额收益
ex_cum = ex.rolling(rank_win).sum() # 5日累计超额
rank = ex_cum.rank(axis=1, ascending=False) # 1=最强
R = rank.shift(rank_win) - rank # 排名上升为正
# 2) 涨幅偏离 D
ma20 = close_wide.rolling(ma_win).mean()
D = (close_wide - ma20) / ma20
# 3) 量能异动 V
vma20 = vol_wide.rolling(ma_win).mean()
V = vol_wide / vma20
# 4) 横截面 Z-score 标准化
def zscore(df):
mu = df.mean(axis=1)
sd = df.std(axis=1).replace(0, np.nan)
return df.sub(mu, axis=0).div(sd, axis=0)
ZR, ZD, ZV = zscore(R), zscore(D), zscore(V)
# 5) 加权合成并压缩到 0~100
raw = w[0]*ZR + w[1]*ZD + w[2]*ZV
score = 50 + 15 * raw # 均值50, 1个标准差约15分
return score.clip(0, 100)
关键点说明:rank.shift(rank_win) - rank 中,排名数值变小代表变强,所以“旧排名 − 新排名”为正表示排名上升;zscore 按行(每个交易日)做横截面标准化,保证不同日期的评分可比;50 + 15*raw 是线性映射,使评分集中在 0~100 且便于分档。
用示例数据验证框架输出
构造 4 个板块、60 个交易日的示例数据,其中“板块A”在第 40 日后出现连续放量拉升,用于检验评分是否能识别追高风险。
np.random.seed(7)
dates = pd.bdate_range("2024-01-01", periods=60)
names = ["板块A", "板块B", "板块C", "板块D"]
# 基础随机游走
base = pd.DataFrame(
np.cumprod(1 + np.random.normal(0.0005, 0.012, (60, 4)), axis=0),
index=dates, columns=names) * 1000
# 板块A 后20日加速上涨并放量
base["板块A"].iloc[40:] *= np.linspace(1.0, 1.18, 20)
vol = pd.DataFrame(
np.random.normal(1.0, 0.15, (60, 4)).clip(0.4),
index=dates, columns=names) * 1e6
vol["板块A"].iloc[40:] *= 1.9
bench = pd.Series(
np.cumprod(1 + np.random.normal(0.0003, 0.008, 60)), index=dates) * 3000
score = build_chase_risk(base, vol, bench)
print(score.tail(3).round(1))
预期现象(示例数据下的合理结果,非实测):板块A 在加速段后期,其 RiskScore 应显著高于其他板块,通常进入 70 以上区间;而板块B/C/D 因无放量加速,评分多在 40~60 附近波动。若板块A 评分未抬升,应检查 rank_win 是否过长导致排名变化被平滑,或 vol 单位是否与均量一致。
评分分档与使用边界
- 0~40 低风险:轮动、偏离、量能均未共振,通常不构成追高风险。
- 40~60 关注:单项指标偏高,需结合板块基本面与市场环境判断。
- 60~80 高风险:多项指标共振,短期追入的回撤概率上升。
- 80~100 极高风险:典型“加速末端”特征,应重点警惕。
框架输出的是风险提示,不是卖出或做空信号;它的价值在于把“这个板块是不是涨得太急了”转化为每日可扫描、可回溯、可调参的数值,为后续的阈值设定与信号验证提供统一底座。