3. 轮动强度指标的构建与参数敏感性测试
指标设计:轮动强度 RSI-Rotation 的构成
轮动强度要回答的核心问题是:当前市场里,板块之间的相对强弱排序变化得有多快、多剧烈。如果各板块排名长期稳定,说明资金集中、轮动弱;如果排名频繁大幅换位,说明资金在板块间快速迁移,轮动强。基于这个思路,我们构建一个可计算的指标 RotStr(Rotation Strength),由三个分量合成:
- 排名变动分量
rank_chg:对每个板块计算其收益率排名在相邻两日之间的绝对变动,再对所有板块取均值。数值越大,说明板块相对位置洗牌越剧烈。 - 收益离散分量
disp:当日各板块收益率的横截面标准差。离散度大意味着板块间分化明显,资金有明确的迁移方向。 - 成交集中度变化分量
flow_chg:各板块成交额占比在相邻两日之间的绝对变化之和(除以2归一化)。它捕捉资金在板块间的实际迁移量。
三个分量各自标准化后加权合成:RotStr = w1·z(rank_chg) + w2·z(disp) + w3·z(flow_chg)。默认权重取 w1=0.4, w2=0.3, w3=0.3,因为排名变动最直接反映轮动,而离散度和资金迁移是辅助确认。
参数敏感性测试:窗口长度与平滑参数
指标里有两个关键参数会显著影响输出形态:
- 排名变动窗口
N:rank_chg比较的是相隔N日的排名。N 太小(如1日)会被单日噪声主导,N 太大(如20日)会钝化轮动信号。候选区间取N ∈ {1, 3, 5, 10, 20}。 - 平滑参数
M:对合成后的RotStr做M日指数移动平均(EMA),抑制单日跳变。候选区间取M ∈ {1, 3, 5, 10}(M=1 即不平滑)。
敏感性测试的做法是:对每组 (N, M) 组合,计算指标序列,然后观察三个诊断量——信号自相关(一阶滞后,衡量平滑度)、极值触发频率(超过历史80分位的天数占比,衡量信号稀疏度)、与次日轮动收益的相关性(衡量预测有效性)。参数选择的目标不是追求最高相关性,而是找到在不同市场状态下都稳定的区间。
参数区间的确定与市场状态适配
敏感性矩阵给出的是“可用/推荐/过钝化”的定性分区,但真正落地时需要把参数与市场状态绑定。做法是:先用滚动窗口把样本划分为趋势市与震荡市(例如用板块收益离散度的20日均值是否高于中位数来区分),然后分别在两类状态下统计各参数组合的三个诊断量,取交集得到推荐区间。
根据上图的测试逻辑,一个可操作的参数选择规则是:
| 市场状态 | N(排名窗口) | M(平滑) | 理由 |
|---|---|---|---|
| 趋势市(分化持续) | 5–10 | 3–5 | 轮动节奏较慢,需要较长窗口捕捉真实迁移,平滑抑制假信号 |
| 震荡市(快速切换) | 3–5 | 3 | 轮动频繁,短窗口更灵敏,但需适度平滑避免噪声 |
| 过渡期(状态不明) | 5 | 3 | 折中参数,兼顾灵敏度与稳定性 |
关键实现片段
下面给出指标计算与敏感性扫描的核心逻辑(以日频板块收益率与成交额数据框为输入,列名为板块代码):
import numpy as np
import pandas as pd
def rotation_strength(ret_df, amt_df, N=5, M=3, w=(0.4, 0.3, 0.3)):
# 1. 排名变动分量
rank = ret_df.rank(axis=1, ascending=False)
rank_chg = rank.diff(N).abs().mean(axis=1)
# 2. 收益离散分量
disp = ret_df.std(axis=1)
# 3. 资金迁移分量:成交额占比的日变化绝对值之和 / 2
share = amt_df.div(amt_df.sum(axis=1), axis=0)
flow_chg = share.diff().abs().sum(axis=1) / 2
# 标准化(滚动z-score,避免前视)
def rz(s, win=60):
return (s - s.rolling(win).mean()) / s.rolling(win).std()
raw = w[0]*rz(rank_chg) + w[1]*rz(disp) + w[2]*rz(flow_chg)
return raw.ewm(span=M, adjust=False).mean()
def sensitivity_scan(ret_df, amt_df, Ns=(1,3,5,10,20), Ms=(1,3,5,10)):
rows = []
for N in Ns:
for M in Ms:
s = rotation_strength(ret_df, amt_df, N=N, M=M).dropna()
ac1 = s.autocorr(lag=1)
extreme_freq = (s > s.quantile(0.8)).mean()
rows.append({"N": N, "M": M, "自相关": round(ac1,3),
"极值频率": round(extreme_freq,3)})
return pd.DataFrame(rows)
运行 sensitivity_scan 后,把结果与上图的定性分区对照:自相关落在 0.5–0.85、极值频率落在 10%–20% 的组合即为候选参数。再对候选组合做样本外相关性检验,最终确定趋势市与震荡市各自的参数区间。注意 rz 使用滚动窗口标准化而非全样本标准化,是为了避免未来信息泄漏——这一点在参数敏感性测试中尤其重要,否则诊断量会被前视偏差污染。