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分位的天数占比,衡量信号稀疏度)、与次日轮动收益的相关性(衡量预测有效性)。参数选择的目标不是追求最高相关性,而是找到在不同市场状态下都稳定的区间。

敏感性测试的判读原则:自相关过高(>0.9)说明指标过于迟钝,轮动拐点会被延迟;极值触发频率过高(>25%)说明信号太频繁、缺乏区分度;与次日收益相关性在样本内外差异过大,说明参数过拟合。理想参数应让三个诊断量都落在合理区间,且在趋势市与震荡市下表现不出现剧烈反转。
轮动强度指标构建与参数敏感性测试 ① 分量计算 排名变动 rank_chg mean(|rank_t − rank_t−N|) 收益离散 disp std(板块日收益率) 资金迁移 flow_chg Σ|Δ成交额占比| / 2 加权合成 w1·z₁ + w2·z₂ + w3·z₃ 0.4 / 0.3 / 0.3 EMA 平滑 窗口 M 日 M ∈ {1,3,5,10} RotStr 序列 轮动强度指标 N ∈ {1,3,5,10,20} ② 参数敏感性测试矩阵(N × M) N \ M M=1 M=3 M=5 M=10 N=1 噪声大 偏敏感 可用 可用 N=3 偏敏感 推荐 推荐 可用 N=5 可用 推荐 推荐 可用 N=10 可用 可用 偏钝化 过钝化 N=20 偏钝化 偏钝化 过钝化 过钝化 ③ 诊断量判读 信号自相关(一阶滞后) 合理区间 0.5–0.85;>0.9 拐点延迟,<0.3 噪声主导 极值触发频率(>80分位占比) 合理区间 10%–20%;>25% 信号泛滥,<5% 过于稀疏 与次日轮动收益相关性 样本内外差异 <0.1 视为稳定;差异过大提示过拟合 推荐区间:趋势市 N=5~10, M=3~5;震荡市 N=3~5, M=3

参数区间的确定与市场状态适配

敏感性矩阵给出的是“可用/推荐/过钝化”的定性分区,但真正落地时需要把参数与市场状态绑定。做法是:先用滚动窗口把样本划分为趋势市与震荡市(例如用板块收益离散度的20日均值是否高于中位数来区分),然后分别在两类状态下统计各参数组合的三个诊断量,取交集得到推荐区间。

根据上图的测试逻辑,一个可操作的参数选择规则是:

市场状态N(排名窗口)M(平滑)理由
趋势市(分化持续)5–103–5轮动节奏较慢,需要较长窗口捕捉真实迁移,平滑抑制假信号
震荡市(快速切换)3–53轮动频繁,短窗口更灵敏,但需适度平滑避免噪声
过渡期(状态不明)53折中参数,兼顾灵敏度与稳定性
实操建议:不要用全样本一次性选参数。用前60%样本做参数筛选,后40%样本做样本外验证,观察三个诊断量是否发生结构性漂移。如果样本外自相关骤降或相关性反转,说明参数对市场状态敏感,应改为状态自适应参数,而非固定参数。

关键实现片段

下面给出指标计算与敏感性扫描的核心逻辑(以日频板块收益率与成交额数据框为输入,列名为板块代码):

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 使用滚动窗口标准化而非全样本标准化,是为了避免未来信息泄漏——这一点在参数敏感性测试中尤其重要,否则诊断量会被前视偏差污染。