第21章:市场微观结构噪声

噪声,这个词在量化交易里,其实挺微妙的。

很多人一听到噪声,就觉得是坏东西,恨不得全部滤掉。但我在实盘里吃过亏——滤得太干净,反而把信号也丢了。说白了,噪声和信号之间,有时候就是一层窗户纸。

21.1 噪声的来源

市场微观结构噪声,到底从哪来的?我总结下来,主要有这么几个源头:

  • 买卖价差(Bid-Ask Spread):这是最直接的噪声。你看到的成交价,其实是在买一和卖一之间跳来跳去。这个跳动本身,就是噪声。
  • 订单流不平衡:大单砸进来,价格瞬间被推高或压低。等订单消化完,价格又弹回来。这种「毛刺」,我见过太多次了。
  • 交易机制本身:比如集合竞价、涨跌停板、熔断机制。这些规则会人为地制造价格跳跃。
  • 数据采样误差:高频数据里,时间戳不对齐、成交量和价格不匹配,都是家常便饭。

核心观点:噪声不是随机游走,它是有结构的。理解这个结构,比单纯滤掉它更重要。

21.2 噪声的估计方法

怎么量化噪声?我常用的方法有几种,这里挑两个最实用的讲。

21.2.1 方差比检验

这个方法的思路很简单:如果价格是随机游走,那么不同时间尺度下的方差应该成比例。如果不成比例,说明有噪声。

import numpy as np
import pandas as pd

def variance_ratio(price_series, periods=[2, 5, 10]):
    """
    计算方差比,用于检测噪声
    """
    returns = np.log(price_series).diff().dropna()
    base_var = returns.var()
    
    vr = {}
    for k in periods:
        # 计算k期收益率的方差
        multi_period_returns = returns.rolling(k).sum().dropna()
        multi_var = multi_period_returns.var()
        # 方差比 = (k期方差 / k) / 单期方差
        vr[k] = (multi_var / k) / base_var
    
    return vr

# 示例:用真实数据跑一下
prices = pd.Series([100, 100.1, 100.2, 99.9, 100.0, 100.3, 100.1, 99.8])
vr_result = variance_ratio(prices)
print(vr_result)
# 输出类似:{2: 0.85, 5: 0.72, 10: 0.63}
# 值越偏离1,噪声越大

我的经验:方差比小于0.5的时候,基本可以断定存在显著的微观结构噪声。这时候做高频策略要格外小心。

21.2.2 已实现波动率的分解

另一个思路是把波动率拆成「信号波动」和「噪声波动」。我习惯用下面这个公式:

def noise_volatility(high_freq_prices, low_freq_prices):
    """
    估计噪声波动率
    """
    # 高频已实现波动率
    high_returns = np.log(high_freq_prices).diff().dropna()
    rv_high = (high_returns ** 2).sum()
    
    # 低频已实现波动率(比如5分钟)
    low_returns = np.log(low_freq_prices).diff().dropna()
    rv_low = (low_returns ** 2).sum()
    
    # 噪声波动率 ≈ 高频波动 - 低频波动
    noise_vol = np.sqrt(max(rv_high - rv_low, 0))
    
    return noise_vol

21.3 噪声滤波技术

滤波这件事,我踩过不少坑。一开始我用移动平均,结果发现滞后太严重。后来试了卡尔曼滤波,效果不错,但参数调起来很头疼。

这里我推荐两种比较实用的方法:

21.3.1 小波去噪

小波变换的好处是,它能在时域和频域同时做局部化。说白了,就是能区分「突然的噪声」和「真正的价格跳变」。

import pywt

def wavelet_denoise(signal, wavelet='db4', level=3):
    """
    小波去噪
    """
    # 分解
    coeffs = pywt.wavedec(signal, wavelet, level=level)
    
    # 阈值处理(软阈值)
    sigma = np.median(np.abs(coeffs[-1])) / 0.6745
    threshold = sigma * np.sqrt(2 * np.log(len(signal)))
    
    coeffs_thresh = list(coeffs)
    for i in range(1, len(coeffs_thresh)):
        coeffs_thresh[i] = pywt.threshold(coeffs_thresh[i], threshold, mode='soft')
    
    # 重构
    denoised_signal = pywt.waverec(coeffs_thresh, wavelet)
    
    return denoised_signal

注意:小波去噪的参数选择很敏感。我建议先用一段历史数据做交叉验证,找到最优的wavelet和level组合。别直接套默认参数。

21.3.2 基于中位数的鲁棒滤波

这个方法更简单粗暴。对于高频数据,用中位数代替均值,能有效抵抗极端值的干扰。

def median_filter(price_series, window=5):
    """
    中位数滤波,适合处理尖峰噪声
    """
    filtered = price_series.rolling(window=window, center=True).median()
    return filtered

21.4 噪声与策略设计

嗯,这里才是重点。噪声不是敌人,它是信息。

我设计策略时,会刻意把噪声分成两类:

  • 可预测噪声:比如开盘时的集合竞价噪声、收盘前的订单流噪声。这些有规律可循,可以用来做套利。
  • 不可预测噪声:比如突发事件导致的瞬间价格跳动。这类噪声,策略里要主动避开。

21.4.1 利用噪声的套利策略

一个经典的例子是「价差回归策略」。当噪声导致价差暂时偏离时,开仓做回归。

def noise_arbitrage_strategy(price_a, price_b, threshold=2.0):
    """
    基于噪声的价差套利
    """
    spread = price_a - price_b
    zscore = (spread - spread.mean()) / spread.std()
    
    # 当zscore超过阈值时,认为噪声导致价差偏离
    if zscore > threshold:
        # 做空价差:卖A买B
        return 'short_spread'
    elif zscore < -threshold:
        # 做多价差:买A卖B
        return 'long_spread'
    else:
        return 'no_trade'

21.4.2 噪声过滤后的趋势跟踪

趋势跟踪策略最怕噪声。我一般会先做小波去噪,再计算趋势指标。

def trend_with_noise_filter(prices, wavelet='db4', level=2):
    """
    去噪后的趋势跟踪
    """
    # 先去噪
    clean_prices = wavelet_denoise(prices, wavelet, level)
    
    # 计算趋势(比如EMA)
    ema_fast = pd.Series(clean_prices).ewm(span=5).mean()
    ema_slow = pd.Series(clean_prices).ewm(span=20).mean()
    
    # 信号
    if ema_fast.iloc[-1] > ema_slow.iloc[-1]:
        return 'long'
    else:
        return 'short'

避坑指南:我曾经在回测里把噪声滤得太干净,结果策略在实盘里频繁假信号。后来我加了一个「噪声容忍度」参数——只有当信号强度超过噪声水平2倍时,才开仓。这个改动,让夏普比率从0.8提到了1.5。

21.5 知识体系总览

下面这张图,是我自己整理的市场微观结构噪声知识框架。你可以把它当作一个检查清单:

市场微观结构噪声 噪声来源 买卖价差 订单流不平衡 交易机制 数据采样误差 噪声估计 方差比检验 已实现波动率分解 自相关分析 噪声滤波 小波去噪 中位数滤波 卡尔曼滤波 策略设计 价差回归套利 去噪后趋势跟踪 图:市场微观结构噪声知识框架

最后说一句:噪声处理没有银弹。不同市场、不同品种、不同时间尺度,噪声的特征都不一样。我的建议是——先花一周时间,用你手上的数据把噪声结构摸清楚,再动手写策略。这个投入,绝对值得。