10. 波动率微观结构:已实现波动率、微观结构噪声、最优采样频率

波动率这东西,做量化的没人不碰。但你要是用高频数据算波动率,很快就会发现——数据越细,结果越离谱。这不是你算错了,是市场微观结构在捣乱。

我刚开始做高频策略那会儿,拿着1秒一笔的Tick数据算已实现波动率,结果出来一个年化200%的数字。我当时还兴奋了一下,以为发现了什么大机会。后来才发现,那根本不是波动,是噪声。

这一节,我们就来拆解这个核心问题:如何从高频数据中提取真实的波动率

10.1 已实现波动率:最直观的高频波动度量

先说说已实现波动率(Realized Volatility, RV)。它的思想很简单——把一天切成很多小段,每段算一个收益率,然后把这些收益率的平方加起来。

数学上长这样:

RV = Σ (r_i)²   (i = 1, 2, ..., n)

其中 r_i 是第 i 个时间间隔内的对数收益率,n 是一天内的采样次数。

举个例子。假设你每5分钟采样一次,一天有288个5分钟段。你算出288个收益率,平方求和,就得到了当天的已实现波动率。

理论上,采样频率越高,RV 越接近真实波动率。但现实呢?

核心矛盾:采样频率越高,微观结构噪声越严重。你以为是波动,其实是买卖价差、订单簿跳动、数据延迟这些乱七八糟的东西。

10.2 微观结构噪声:藏在Tick数据里的陷阱

什么是微观结构噪声?说白了,就是价格在真实价值附近的随机抖动。

我举个例子你就明白了。你看一只股票,真实价值可能是100.00元。但因为买卖价差的存在,你看到的成交价可能是100.01元(买方主动吃单),下一秒又变成99.99元(卖方主动砸盘)。

这两笔交易之间,股票的基本面没有任何变化。但如果你用这两笔数据算收益率,会得到一个不小的波动值。这就是噪声。

噪声的来源主要有几个:

  • 买卖价差(Bid-Ask Spread):价格在买一和卖一之间来回跳
  • 订单簿不连续:价格只能以最小变动单位跳动
  • 交易异步性:不同股票的交易时间不同步
  • 数据错误:交易所的撮合延迟、数据商的记录错误

我曾经处理过一组美股Tick数据,发现某只股票在1秒内出现了3笔完全相同的成交价。后来查了一下,是交易所的重复推送。这种噪声如果不处理,你的波动率模型直接报废。

注意:微观结构噪声不是白噪声。它往往有自相关性,而且和真实波动率相关。这就意味着,你不能简单地用滤波方法把它去掉。

10.3 最优采样频率:Merton's Rule 与实战选择

既然采样太密有噪声,采样太疏又丢失信息,那到底该用多高的频率?

这就引出了最优采样频率的问题。学术界有个经典结论叫 Merton's Rule

Merton's Rule 的核心思想是:采样频率应该与市场的流动性相匹配。具体来说,最优采样间隔应该大于等于市场的「有效交易间隔」。

怎么理解?

你看,如果一只股票平均每10秒成交一次,那你用1秒采样一次,大部分采样点其实没有新交易,价格是前一笔的重复。这些重复点会引入虚假的零收益率,压低波动率估计。

反过来,如果一只股票每秒成交100次,你每5分钟采样一次,那中间的大量信息就全丢了。

所以,Merton's Rule 给出的建议是:采样频率应该和交易频率匹配

实战中,我一般这样操作:

  1. 先统计每只股票的平均成交间隔(比如过去20天的中位数)
  2. 把采样间隔设在这个中位数的1.5到2倍之间
  3. 对于流动性极好的股票(比如SPY),我习惯用1分钟采样
  4. 对于流动性差的股票,可能用到10分钟甚至更长

下面这个表格是我个人总结的经验值:

股票流动性 日均成交笔数 推荐采样频率 典型例子
极高 > 10万笔 1分钟 SPY, AAPL
1万 - 10万笔 5分钟 大部分标普500成分股
中等 1000 - 1万笔 10分钟 中小盘股
< 1000笔 30分钟或更长 冷门股

我的经验:别死磕一个固定频率。我习惯用「多频率对比法」——同时算1分钟、5分钟、15分钟的RV,如果三个结果差异很大,说明噪声污染严重,需要降频。

10.4 噪声校正方法:从理论到代码

光选对采样频率还不够。有时候你不得不使用高频数据(比如做高频策略),这时候就需要对噪声进行校正。

常用的方法有几种:

  • 子采样平均法(Subsampling):用多个偏移的采样网格,分别算RV,然后取平均
  • 核估计法(Kernel-based):给不同滞后的自协方差加权,类似Newey-West调整
  • 两时间尺度法(Two-Scales):同时用高频和低频数据,把噪声部分分离出来

我个人最常用的是子采样平均法。实现起来简单,效果也稳定。下面是一个Python示例:

import numpy as np
import pandas as pd

def subsampled_rv(prices, base_freq='1min', n_subsamples=5):
    """
    子采样平均法计算已实现波动率
    prices: 包含datetime和price的DataFrame
    base_freq: 基础采样频率
    n_subsamples: 子采样网格数量
    """
    # 生成n_subsamples个偏移的采样网格
    offsets = np.linspace(0, 1, n_subsamples, endpoint=False)
    
    rv_list = []
    for offset in offsets:
        # 按偏移量采样
        sampled = prices.resample(
            base_freq, on='datetime', 
            offset=f'{offset}s'
        ).last().dropna()
        
        # 计算收益率
        returns = sampled['price'].pct_change().dropna()
        
        # 计算RV
        rv = np.sum(returns ** 2)
        rv_list.append(rv)
    
    # 取平均
    return np.mean(rv_list)

# 使用示例
# rv_clean = subsampled_rv(tick_data, '1min', 5)

这段代码的核心思路是:不只用整点采样,而是用5个不同的偏移量(比如0秒、12秒、24秒、36秒、48秒)分别采样,然后取平均。这样能有效降低噪声的影响。

关键点:子采样平均法不是万能的。如果噪声本身有强烈的自相关结构,效果会打折扣。这时候可以考虑用核估计法,但实现起来复杂一些。

10.5 知识体系总览

说了这么多,我把这一节的核心逻辑画成了一张图,方便你理解:

波动率微观结构知识体系 核心问题:高频数据中的波动率估计 已实现波动率 (RV) 微观结构噪声 最优采样频率 • 收益率平方求和 • 理论:频率越高越精确 • 现实:噪声污染严重 • 买卖价差抖动 • 订单簿不连续 • 交易异步性 • Merton's Rule • 匹配交易频率 • 多频率对比法 解决方案:噪声校正 + 最优频率选择

这张图把三个核心概念串起来了。你从「高频数据中的波动率估计」出发,会遇到三个分支问题。每个分支都有自己的坑,但最终都要汇聚到同一个解决方案上。

嗯,这一节的内容就到这里。波动率微观结构是个大话题,我们只讲了最核心的部分。记住一句话:高频数据不是越细越好,关键是找到那个「恰到好处」的频率