4. 金融数据与时间序列

金融AI模型的效果,很大程度上取决于对数据时间结构的理解。与图像、文本等静态数据不同,金融数据本质上是按时间顺序排列的随机过程,具有趋势、周期、波动聚集和结构突变等特征。本节围绕金融时间序列的核心特性、平稳性、自相关、波动率建模、缺失值与异常值处理以及高频数据展开,为后续特征工程与模型训练奠定基础。

一、金融时间序列的核心特性

金融时间序列通常指资产价格、收益率、成交量、买卖价差等按时间戳记录的数据。其典型特性包括:

  • 非平稳性:价格序列常含趋势与单位根,均值与方差不恒定。
  • 波动聚集:大幅波动往往成簇出现,小幅波动同样聚集,表现为条件异方差。
  • 自相关与长记忆:收益率序列自相关较弱,但绝对值或平方收益率常呈现显著长记忆。
  • 尖峰厚尾:收益率分布峰度高于正态分布,极端事件概率不可忽略。
  • 日历与微观结构效应:开盘、收盘、周末、财报日等会带来周期性或跳跃性变化。
核心判断:价格通常不平稳,收益率更接近平稳;建模前应先做平稳性检验,再决定差分、变换或直接使用收益率。

二、平稳性与自相关

平稳性分为严平稳与弱平稳。弱平稳要求均值、方差恒定,且自协方差只与时间间隔有关。常用检验方法包括ADF检验、KPSS检验和PP检验。若序列非平稳,可通过一阶差分、对数差分或去趋势处理。自相关函数(ACF)与偏自相关函数(PACF)用于识别序列的记忆结构,是AR、MA、ARMA等模型定阶的重要依据。

from statsmodels.tsa.stattools import adfuller
import numpy as np

ret = np.diff(np.log(price))          # 对数收益率
adf_stat, p_value, _, _, crit, _ = adfuller(ret)
print("ADF统计量:", adf_stat)
print("p值:", p_value)
print("临界值:", crit)
# p值小于0.05通常拒绝单位根,认为序列平稳

在实际建模中,收益率序列往往本身已近似平稳,但波动率序列仍具有条件异方差。因此,均值方程与方差方程需要分开处理。

三、波动率建模:从ARCH到GARCH

波动率是金融风险度量、期权定价和仓位管理的核心变量。Engle提出的ARCH模型用过去残差平方解释当前条件方差,Bollerslev将其扩展为GARCH,引入方差自身的滞后项,使模型更简洁。GARCH(p,q)的一般形式为:

σ_t² = ω + Σ α_i ε_{t-i}² + Σ β_j σ_{t-j}²

其中ω为常数项,α捕捉冲击影响,β刻画波动持续性。α+β接近1表示波动冲击衰减缓慢。实际应用中还需考虑EGARCH、GJR-GARCH等非对称模型,以刻画杠杆效应:负收益冲击往往比正收益冲击带来更大波动。

模型 核心思想 适用场景
ARCH 用过去残差平方解释条件方差 波动聚集明显、阶数较低
GARCH 加入方差滞后项,提升持续性刻画 股票、指数、汇率日频波动
EGARCH 对数方差建模,允许非对称冲击 存在杠杆效应的市场
GJR-GARCH 用虚拟变量区分正负冲击 风险管理和VaR计算
收益率序列与条件波动率 收益率 r_t 条件波动率 σ_t 波动聚集:大波动后常跟大波动 GARCH:σ_t² 依赖 ε_{t-1}² 与 σ_{t-1}² α+β 越接近1,持续性越强

四、缺失值与异常值处理

金融数据常因停牌、网络中断、交易所差异或字段错误出现缺失与异常。处理原则是:先判断缺失机制,再选择填充或剔除策略,避免引入未来信息。

  1. 缺失值识别:区分随机缺失、完全随机缺失与非随机缺失。
  2. 填充方法:前向填充适合价格类低频数据;线性插值适合连续指标;模型插值适合复杂场景。
  3. 异常值检测:可用3σ法则、IQR、MAD或滚动Z-score;高频数据更适合用中位数绝对偏差。
  4. 异常值处理:先核实是否为真实极端事件,再决定缩尾、替换或保留。
常见误区:直接用全样本均值填充缺失值,会引入未来信息并造成数据泄露;对收益率异常值一律删除,可能抹掉真实风险事件。

五、高频数据简介

高频数据通常指秒级、毫秒级甚至逐笔成交与委托数据。其特点包括:非同步交易、买卖价差、微观结构噪声、日内周期性(U型成交量与波动率)以及数据量巨大。高频分析常用于市场微观结构研究、执行成本优化、做市策略和短期风险监控。处理时需注意时间对齐、去噪、重采样和特征构造,例如实现波动率、已实现半方差、买卖不平衡等。

# 高频数据重采样示例
import pandas as pd

ticks = pd.read_csv("ticks.csv", parse_dates=["timestamp"])
ticks = ticks.set_index("timestamp")
bars = ticks["price"].resample("1min").ohlc()
bars["volume"] = ticks["size"].resample("1min").sum()
print(bars.head())
复盘建议:拿到任何金融时间序列,先画价格与收益率图,再做ADF与ACF/PACF,最后检查缺失与异常。顺序错了,后续模型很容易建立在错误假设上。

综上,金融时间序列建模的关键在于尊重数据的时间依赖结构:用平稳性检验决定变换方式,用自相关分析识别记忆结构,用GARCH族模型刻画波动聚集,用稳健方法处理缺失与异常,并在高频场景中关注微观结构噪声。只有把这些基础打牢,金融AI模型才可能具备稳定的泛化能力。