halo 的技术博客

返回

你盯着一张 K 线图,能一眼分出「这段在走趋势」和「这段在随机乱晃」。但机器怎么分?一个朴素的想法是用波动率:趋势市波动大、随机市波动小,或者反过来。可惜波动率对两者几乎是瞎的——一段匀速上涨(标准趋势)可以波动极低,一段剧烈无序震荡(标准混沌)也可以波动极高,两者在波动率轴上大量重叠。

真正的区别不在「幅度」,在「结构」。趋势市的收益序列有秩序:方向可预测、排列有规律;随机市的收益序列是白噪声:每一步独立、毫无记忆。信息论里早就有一个衡量「结构有多少」的工具——熵。本文用两种熵把「混沌」和「秩序」钉成两个可计算的数字,再把它变成一条能直接当过滤器用的状态序列。

一、为什么用熵:波动率是瞎的,熵是亮的#

熵(entropy)度量一个分布的「不确定性」或「无序程度」:越确定、越有结构,熵越低;越随机、越混乱,熵越高。我们不直接对价格算熵,而是先对收益对数价格的局部形态做量化,再算熵。

两种熵,侧重点不同:

  • Shannon 熵:看收益分布有多「胖」多「散」。把日收益按固定分箱,算每个箱概率 p_i,归一化熵 H = -Σ p_i·log2(p_i) / log2(箱数)。趋势市收益集中在某一侧(分布窄),熵低;随机市收益均匀铺开(分布胖),熵高。
  • 置换熵(Bandt-Pompe 2002):不只看「分布」,还看时间先后次序。对对数价格做嵌入,把每一小段映射成一种「序数模式」(谁最大谁最小),数各种模式出现的频率再算熵。趋势市的序数模式高度集中(总是「低→高」或「高→低」),熵低;随机市的序数模式均匀乱跳,熵高。

直觉一句话:Shannon 量「分布胖瘦」,置换熵还量「次序规律」——所以它对趋势更敏感。

二、合成一个「秩序 / 混沌」交替的市场#

为了看清熵到底在量什么,造一段 1500 天、6 段交替的行情:偶数段是趋势市(小幅漂移 + 低噪声),奇数段是随机市(无漂移 + 高噪声)。

rng = np.random.default_rng(20260716)
N_DAYS, SEG = 1500, 250
sigma_low, sigma_high = 0.003, 0.020
ret = np.zeros(N_DAYS); regime = np.zeros(N_DAYS, dtype=int)
for s in range(N_DAYS // SEG):
    a, b = s * SEG, (s + 1) * SEG
    if s % 2 == 0:
        drift = 0.0020 * (1 if (s // 2) % 2 == 0 else -1)   # 趋势市
        ret[a:b] = drift + sigma_low * rng.standard_normal(b - a)
        regime[a:b] = 0
    else:
        ret[a:b] = sigma_high * rng.standard_normal(b - a)   # 随机市
        regime[a:b] = 1
price = 100 * np.exp(np.cumsum(ret))
python

滑窗 W=60 天,分别算 Shannon 熵和置换熵:

合成价格 + 熵率序列:趋势段熵低(秩序),随机段熵高(混沌)

绿底=趋势市,红底=随机市。注意熵率序列完美贴着两种体制切换:趋势段两条熵都趴在低位,随机段都弹到高位。这就是「把混沌和秩序分开」的机器版本——不用看价格,光看熵率就知道现在处在哪种体制。

三、两种熵,谁更灵敏?#

把两条熵率单拎出来对比就清楚了:

Shannon 熵 vs 置换熵:置换熵把趋势的「方向秩序」也量化了

  • Shannon 熵只看「分布胖瘦」。趋势市因为低噪声、收益挤在漂移附近,分布确实窄,熵低;但它对漂移方向无感。
  • 置换熵还看「先后次序」。趋势市的序数模式高度一致(一路低→高或高→低),所以哪怕波动不大,它的「次序集中度」也极高、熵更低,对趋势的区分度通常比 Shannon 更干净。

实测两段分布的均值(归一化熵):

体制Shannon 熵置换熵
趋势段(秩序)0.5340.776
随机段(混沌)0.9280.928

两种熵在趋势段 / 随机段的分布:明显分离

趋势段的 Shannon 均值(0.53)和随机段(0.93)几乎不重叠——分离度很好。置换熵的区分稍弱(趋势段 0.78 vs 随机段 0.93),说明在我们的设定里次序信息被高噪声部分掩盖,但两者都显著可分。实操中常把两个熵拼成一个特征,比单用一个稳。

四、把熵率当过滤器:只在「有秩序」时持仓#

熵率最值钱的用法不是画图,是当交易开关。逻辑很朴素:在低熵(有秩序、有趋势)的时段持有方向仓,在高熵(混沌、噪声主导)的时段空仓——相当于只做「市场自己已经走出结构」的那部分。

用 20 日动量做信号,仅在熵率低于 40% 分位(即「秩序最强」的时段)才持仓:

look = 20
mom = np.zeros(N_DAYS)
for t in range(look, N_DAYS):
    mom[t] = np.sign(np.sum(ret[t - look:t]))          # 动量方向
thr = np.nanpercentile(H_shannon[~np.isnan(H_shannon)], 40)
pos_filtered = np.where(H_shannon < thr, mom, 0.0)    # 高熵时段强制空仓
eq_un = np.cumprod(1 + mom * ret)                      # 不过滤
eq_fi = np.cumprod(1 + pos_filtered * ret)             # 低熵过滤
python

净值与 Sharpe:只在低熵(有秩序)时段持仓,Sharpe 从 0.36 拉到 4.68

结果刺眼:不过滤的动量 Sharpe 只有 0.36(随机市里反复被打脸),而只在低熵时段持仓的版本 Sharpe 冲到 4.68。差距不是来自多赚,而是来自少亏——高熵随机段本来就是动量的坟场,熵过滤器把这部分直接剔掉了。

提醒:4.68 是合成数据里「体制标签完美 ⇒ 过滤器近乎作弊」的结果,实战绝不会有这种数字。它的真正价值是证明熵率携带了可被交易的结构信息,而不是给你一个能实盘的圣杯。

五、真实陷阱(别直接照抄)#

  1. 窗口长度 W 是玄学参数。W 太短→熵被噪声主导、抖动剧烈;W 太长→状态切换滞后、等熵反应过来行情已走完。要对 W 做稳健性扫描,别只报一个「最好看」的窗口。

  2. 分箱边界决定 Shannon 熵的绝对值。箱太多→每个箱样本少、熵被高估;箱太少→抹掉结构、熵被低估。固定分箱在波动率 regime 切换时会漂移,建议用自适应分箱(按滚动分位数切)。

  3. 置换熵的嵌入维 m 与延迟 τ 要选。m 太小(如 2)区分力弱,m 太大需要更长窗口才统计得稳;τ 跳过相关性也跳过信息。这俩是另一个需要调的参数对,不是免费的。

  4. 熵是「状态描述」不是「方向预测」。低熵只告诉你「现在结构强」,不告诉你结构是涨是跌——所以上面才要用动量给方向、用熵给「该不该下注」的开关。把熵当方向信号用是常见错误。

  5. 非平稳市场的伪状态切换。一次性的跳空、流动性事件会让熵瞬时飙升,被误判成「进入混沌」。要加平滑(如对熵率再做 EWMA)或要求连续 K 根确认,避免被单日异常骗。

  6. 幸存者偏差与过拟合。本文用已知体制造数据,过滤器当然显灵。实盘要样本外滚动验证,并且熵阈值(40% 分位)这种数字必须固化在回测前,不能事后挑。

六、小结#

市场状态识别的本质问题,是「怎么用一个数描述『现在有没有结构』」。波动率量的是幅度、方向量的是偏移,而熵量的是秩序本身——这才是对「趋势 vs 随机」最正交的刻画。

Shannon 熵管「分布胖瘦」,置换熵多管一层「时间次序」,两者拼起来就是一条可计算、可监控、可当开关用的熵率序列。它不预言涨跌,但它能告诉你:此刻市场是在「有秩序地走」,还是在「无记忆地晃」——而前者才值得你下注。

至此,我们从一个能区分混沌与秩序的熵率,走到用波动率刻画风险(GARCH)、用相关网络刻画传染——量化的每一步,都是在给「看不见的市场结构」找一个可计算的替身。

熵率市场状态识别:用信息熵把『混沌』和『秩序』分开
https://blog.halo26812.eu.org/blog/entropy-market-regime
Author halo
Published at 2026年7月16日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨