第三章:高阶特征工程(下)——频域与微观结构的实战密码
好,咱们接着聊。上一节我们把时域特征玩了个遍,什么滑动窗口、自相关、滞后项,说白了都是在时间轴上做文章。但金融市场这东西,很多时候藏在频率里。你想想看,一个日内的锯齿波动和一个周级别的趋势,它们能是一回事吗?
我个人习惯,拿到一条价格序列,第一件事不是算均线,而是先做一次FFT,看看能量集中在哪些频段。这就像医生听诊,先听个大概,再对症下药。
3.1 频域特征:把时间序列翻个面
为什么要做频域分析?因为很多市场行为有周期性。比如股指期货的隔夜效应、国债期货的月末调仓、甚至某些商品的季节性。这些规律在时域里可能被噪声淹没,但在频域里,它们就是几根清晰的谱线。
3.1.1 FFT:最朴素的频谱工具
快速傅里叶变换,说白了就是把一段信号拆成不同频率的正弦波叠加。我建议你直接用numpy的fft模块,别自己造轮子,容易出bug。
import numpy as np
import matplotlib.pyplot as plt
# 模拟一段包含趋势+周期+噪声的价格序列
np.random.seed(42)
t = np.linspace(0, 100, 1000)
price = 100 + 0.05 * t + 5 * np.sin(2 * np.pi * 0.02 * t) + 2 * np.sin(2 * np.pi * 0.1 * t) + np.random.randn(1000) * 0.5
# 做FFT
fft_vals = np.fft.fft(price)
freqs = np.fft.fftfreq(len(price), d=1) # d是采样间隔,这里是1个时间单位
# 只取正频率部分
pos_mask = freqs > 0
freqs_pos = freqs[pos_mask]
amplitude = np.abs(fft_vals[pos_mask])
# 找前几个主频
top_idx = np.argsort(amplitude)[-5:]
print("主频频率:", freqs_pos[top_idx])
print("对应振幅:", amplitude[top_idx])
核心要点:FFT输出的频率是归一化的。比如采样间隔是1分钟,那频率0.02就对应50分钟一个周期。我在项目中遇到过,有人把频率直接当周期用,结果算出来的周期单位全错了。记住:周期 = 1 / 频率。
实际交易中,我常用FFT做两件事:一是识别隐藏的周期性,比如某只股票每45分钟出现一次脉冲式放量;二是做滤波,把高频噪声切掉,留下趋势成分。但要注意,FFT假设信号是平稳的,而金融数据显然不是。所以别指望它一劳永逸。
3.1.2 小波变换:给频率加上时间标签
FFT有个硬伤——它不知道某个频率成分出现在什么时候。比如一个突发利好消息带来的高频波动,FFT只会把它平均到整个频谱里。这时候小波变换就派上用场了。
小波变换,你可以理解成「带放大镜的频谱分析」。它用不同尺度的小波基函数去匹配信号,既能看全局,又能聚焦局部。我个人偏好用Daubechies小波族,尤其是db4,对金融数据的突变比较敏感。
import pywt
# 用db4小波做3层分解
coeffs = pywt.wavedec(price, 'db4', level=3)
cA3, cD3, cD2, cD1 = coeffs
# 重构细节信号(高频成分)
detail_d1 = pywt.waverec([None, None, None, cD1], 'db4')
detail_d2 = pywt.waverec([None, None, cD2, None], 'db4')
# 看高频细节的方差变化
volatility_d1 = np.std(detail_d1[~np.isnan(detail_d1)])
volatility_d2 = np.std(detail_d2[~np.isnan(detail_d2)])
print(f"第一层细节方差: {volatility_d1:.4f}")
print(f"第二层细节方差: {volatility_d2:.4f}")
实战技巧:小波变换的层数不是越多越好。层数太多,低频成分被过度平滑,高频细节又太碎。我一般设3-5层,具体看数据长度。另外,重构时注意边界效应,尤其是数据首尾部分,我习惯丢掉前几个和后几个点。
我曾经用db4小波做过一个股指期货的择时策略。把价格序列分解后,发现第三层细节信号在重大行情启动前会出现明显的能量聚集。说白了,就是市场在「蓄力」的时候,某些频段的波动会先躁动起来。这个特征加到模型里,胜率提升了大概6个百分点。
3.2 微观结构特征:从订单簿里挖金子
频域特征是从数学角度切入,而微观结构特征是从市场机制本身出发。你想想看,价格是怎么形成的?是买卖双方在订单簿上博弈的结果。如果你只看收盘价,等于只看结果不看过程。
3.2.1 订单簿特征:盘口的语言
订单簿数据通常包含多个档位的买卖挂单量和价格。我建议至少用5档,太浅了信息不够,太深了噪声太多。常用的特征包括:
- 买卖价差(Spread):卖一价 - 买一价。价差突然扩大,说明流动性枯竭,往往是变盘前兆。
- 订单簿不平衡(Order Imbalance):(买一量 - 卖一量) / (买一量 + 卖一量)。正值表示买方强势,负值反之。
- 加权平均价格(VWAP):按各档位挂单量加权计算的平均价格,比中间价更真实。
- 深度斜率(Depth Slope):不同档位挂单量的变化率。斜率陡峭说明某一方在密集挂单。
# 假设order_book是一个DataFrame,包含bid_price1-5, bid_size1-5, ask_price1-5, ask_size1-5
def compute_order_book_features(ob):
spread = ob['ask_price1'] - ob['bid_price1']
imbalance = (ob['bid_size1'] - ob['ask_size1']) / (ob['bid_size1'] + ob['ask_size1'] + 1e-8)
# 计算前5档的加权平均价格
total_bid_vol = ob['bid_size1'] + ob['bid_size2'] + ob['bid_size3'] + ob['bid_size4'] + ob['bid_size5']
total_ask_vol = ob['ask_size1'] + ob['ask_size2'] + ob['ask_size3'] + ob['ask_size4'] + ob['ask_size5']
vwap_bid = (ob['bid_price1']*ob['bid_size1'] + ob['bid_price2']*ob['bid_size2'] + ...) / total_bid_vol
vwap_ask = (ob['ask_price1']*ob['ask_size1'] + ob['ask_price2']*ob['ask_size2'] + ...) / total_ask_vol
return spread, imbalance, vwap_bid, vwap_ask
避坑指南:我曾经在回测中直接用原始订单簿数据,结果发现回测表现极好,实盘却一塌糊涂。后来排查发现,订单簿数据有延迟——你看到的挂单可能已经成交了。所以一定要用快照数据,并且做时间对齐。另外,盘口数据在开盘和收盘时异常活跃,我习惯剔除前5分钟和后5分钟的数据。
3.2.2 成交量分布:谁在买,谁在卖
成交量分布(Volume Profile)比传统成交量更有价值。它告诉你:在什么价格区间成交了多少量。这能帮你找到市场的「价值区域」和「关键价位」。
我常用的几个指标:
- 价值区域(Value Area):成交量占比70%的价格区间。价格突破价值区域上沿,说明趋势可能延续。
- 控制点(Point of Control, POC):成交量最大的那个价格。这是多空双方争夺最激烈的位置。
- 成交量加权平均价(VWAP):机构常用的参考线,很多算法交易会围绕VWAP执行。
# 计算VWAP(日内累计)
def compute_vwap(price, volume):
cumulative_pv = (price * volume).cumsum()
cumulative_vol = volume.cumsum()
vwap = cumulative_pv / cumulative_vol
return vwap
# 计算价格偏离VWAP的程度
def vwap_deviation(price, vwap):
return (price - vwap) / vwap * 100 # 百分比
我记得有一次做商品期货的策略,发现价格每次偏离VWAP超过1.5%后,大概率会在30分钟内回归。这个规律持续了大概两个月,后来市场结构变了才失效。所以微观结构特征有个特点——时效性强,需要定期重新验证。
3.3 知识体系总览
说了这么多,咱们用一张图把本章的核心逻辑串起来。频域特征和微观结构特征,一个从数学变换入手,一个从市场机制入手,两者互补。
嗯,到这里,高阶特征工程的两大块内容就讲完了。频域特征帮你从「频率」角度理解市场,微观结构特征帮你从「博弈」角度理解市场。两者结合,你就能构建出比单纯价格和成交量丰富得多的特征集。
我个人建议,在实际项目中,先跑一遍FFT看看数据里有没有明显的周期成分,再结合订单簿数据做日内微观特征。别一上来就堆特征,容易过拟合。记住,特征工程的核心不是数量,而是质量——每个特征都要有清晰的逻辑支撑。
本章核心收获:
- FFT适合识别全局周期性,小波变换适合捕捉局部突变
- 订单簿特征反映市场微观博弈,成交量分布揭示价值区域
- 频域+微观结构,双剑合璧,特征质量大幅提升
公众号:蓝海资料掘金营,微信deep3321