第1章:时间序列基础——平稳性、自相关与差分操作

各位同学,咱们今天聊聊时间序列分析里最基础、也最要命的一块内容。说实话,我入行高频交易那会儿,第一个坑就栽在平稳性上。那时候我拿了一堆价格数据直接建模,结果模型跑出来漂亮得很,一上线就亏钱。后来才明白——数据不平稳,模型就是个笑话。

所以这一章,咱们把地基打牢。我会带着大家把平稳性检验、自相关函数、偏自相关函数、滞后算子和差分操作这几个核心概念,一个一个掰开揉碎了讲清楚。

1.1 平稳性:时间序列的“定海神针”

什么叫平稳性?说白了,就是一个时间序列的统计性质不随时间变化。均值不变、方差不变、自相关结构也不变。你想想看,如果一条序列的均值在漂移,你用历史数据训练的模型,能预测未来吗?显然不能。

平稳性分两种:

  • 严平稳:联合分布不随时间平移而变化。这个条件太强,实际中几乎用不到。
  • 弱平稳(也叫宽平稳):均值恒定、方差恒定、自协方差只依赖于时间间隔。咱们平时说的平稳,基本都指这个。

核心要点:高频交易中,价格序列几乎都是非平稳的,但收益率序列通常是弱平稳的。所以别拿价格直接建模,先算收益率。

1.2 ADF检验:给平稳性“把脉”

ADF检验(Augmented Dickey-Fuller Test)是检验平稳性的标准工具。它的原假设是“序列存在单位根”,也就是非平稳。如果p值小于0.05,就拒绝原假设,认为序列平稳。

我在项目中遇到过一件事:有一次用ADF检验某只股票的5分钟收益率,p值0.03,我以为是平稳的。结果回测时发现模型在特定时间段失效。后来仔细一看,原来是那个时间段有分红除权,导致均值发生了跳跃。所以啊,ADF检验不是万能的,它只能检测特定类型的非平稳性。

# Python代码示例:ADF检验
from statsmodels.tsa.stattools import adfuller
import numpy as np

# 生成一个随机游走序列(非平稳)
np.random.seed(42)
n = 1000
random_walk = np.cumsum(np.random.randn(n))

# ADF检验
result = adfuller(random_walk)
print(f'ADF统计量: {result[0]:.4f}')
print(f'p值: {result[1]:.4f}')
print(f'临界值: {result[4]}')

# 对差分后的序列做ADF检验
diff_series = np.diff(random_walk)
result_diff = adfuller(diff_series)
print(f'\n差分后ADF统计量: {result_diff[0]:.4f}')
print(f'差分后p值: {result_diff[1]:.4f}')

避坑指南:我曾经在检验时忘了加常数项和趋势项,结果把平稳序列误判为非平稳。ADF检验有三个版本:无常数项、有常数项、有常数项+趋势项。高频数据一般用有常数项的版本就够了。

1.3 自相关与偏自相关:序列的“记忆”有多长?

自相关函数(ACF)衡量的是序列与其滞后值之间的相关性。偏自相关函数(PACF)则是在剔除了中间滞后项的影响后,衡量两个时间点之间的直接相关性。

这两个函数有什么用?嗯,它们能帮你判断ARIMA模型的阶数。ACF拖尾、PACF截尾——适合AR模型;ACF截尾、PACF拖尾——适合MA模型;两者都拖尾——适合ARMA模型。

我记得刚学那会儿,总搞不清截尾和拖尾的区别。后来自己画了几百张图,才真正看明白。截尾就是突然掉到置信区间内,拖尾就是慢慢衰减。

# Python代码示例:ACF和PACF
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
import matplotlib.pyplot as plt

# 生成AR(1)过程
phi = 0.7
n = 500
ar1 = np.zeros(n)
for t in range(1, n):
    ar1[t] = phi * ar1[t-1] + np.random.randn()

# 画图
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 8))
plot_acf(ar1, lags=30, ax=ax1)
plot_pacf(ar1, lags=30, ax=ax2)
plt.show()

注意:高频数据通常有微观结构噪声,ACF/PACF在滞后1期或2期会出现异常值。我建议对原始数据做预白化处理,或者使用稳健估计方法。

1.4 滞后算子:时间序列的“代数工具”

滞后算子L,也叫后移算子,定义是:L y_t = y_{t-1}。就这么简单。但它的威力在于,可以把差分、季节调整等操作写成简洁的代数形式。

比如一阶差分:Δ y_t = y_t - y_{t-1} = (1 - L) y_t

季节差分:Δ_s y_t = y_t - y_{t-s} = (1 - L^s) y_t

你想想看,有了滞后算子,ARMA模型就可以写成:Φ(L) y_t = Θ(L) ε_t。这种表示法在理论推导中非常方便。

个人经验:我在写高频交易策略时,经常用滞后算子来构造特征。比如用(1-L)(1-L^5)来捕捉日内的周度模式。这种组合差分操作,用滞后算子写起来特别清晰。

1.5 差分操作:让非平稳变平稳的“手术刀”

差分是处理非平稳序列最常用的方法。一阶差分可以消除线性趋势,二阶差分可以消除二次趋势。对于高频数据,通常一阶差分就够了。

但要注意:差分会损失信息。每做一次差分,就少一个观测值。而且过度差分会导致序列变得“太干净”,丢失了有用的低频成分。

差分阶数 适用场景 注意事项
一阶差分 价格→收益率 最常用,适用于大多数金融时间序列
二阶差分 加速度或变化率的变化 高频数据中很少用,噪声放大严重
季节差分 消除周期性模式 高频数据中注意周期长度选择
# Python代码示例:差分操作
import pandas as pd

# 模拟价格序列
dates = pd.date_range('2024-01-01', periods=1000, freq='5min')
price = 100 + np.cumsum(np.random.randn(1000) * 0.1)

# 创建DataFrame
df = pd.DataFrame({'price': price}, index=dates)

# 一阶差分(收益率)
df['return'] = df['price'].diff()

# 季节差分(假设日周期,252个5分钟bar)
df['seasonal_diff'] = df['price'].diff(252)

# 组合差分
df['combined'] = df['price'].diff().diff(252)

print(df.head(10))

实战技巧:我建议在做差分之前,先做ADF检验确定差分阶数。另外,高频数据中我常用对数收益率(log return)而不是简单收益率,因为对数收益率在统计性质上更接近正态分布。

1.6 本章知识体系

下面这张图总结了本章的核心逻辑,我画了很久,希望能帮大家理清思路:

时间序列基础:知识体系 时间序列分析 平稳性检验 ACF / PACF 滞后算子 差分操作 严平稳 弱平稳 ACF PACF L y_t = y_{t-1} 一阶差分 季节差分 核心目标:将非平稳序列转化为平稳序列 为ARIMA等模型奠定基础

这张图把本章的四个核心概念串起来了。你从中心出发,先理解平稳性,然后学会用ACF/PACF分析序列结构,再用滞后算子做代数表达,最后用差分操作实现平稳化。每一步都是下一步的基础。

1.7 本章小结

好了,这一章的内容就到这里。咱们回顾一下:

  • 平稳性是时间序列建模的前提,ADF检验是判断平稳性的标准工具
  • ACF和PACF能帮你识别序列的依赖结构,是模型定阶的关键
  • 滞后算子让复杂的差分和模型表达变得简洁
  • 差分操作是把非平稳序列变平稳的实用方法

说实话,这些内容看起来简单,但真正用好需要大量实践。我建议你找一段真实的高频数据,自己动手跑一遍ADF检验,画一画ACF/PACF图,再做几次差分操作。只有亲手做过,才能真正理解。

一句话总结:不平稳的数据,再漂亮的模型也是空中楼阁。先把地基打牢,后面的事情自然水到渠成。

专注资料整理