4、特征工程基础:价格序列特征、成交量特征、订单簿不平衡指标、波动率计算

好,咱们进入正题。特征工程这块,说白了就是给模型喂「有营养」的数据。你想想看,原始订单簿数据就像一堆乱码,模型根本看不懂。我刚开始做量化那会儿,也犯过傻——直接把原始数据扔进模型,结果预测效果惨不忍睹。后来才明白,特征工程才是预测模型的灵魂。

4.1 价格序列特征

价格序列特征,我习惯从三个维度去提取:原始价格、价格变化、价格形态

4.1.1 原始价格特征

最基础的就是买卖一档价格。但注意,别只盯着最新成交价。我个人习惯把买一价、卖一价、最新成交价、开盘价、收盘价都纳入特征池。为什么?因为不同价格反映的市场信息不同。比如买一价代表买方意愿,卖一价代表卖方意愿,两者差距就是市场分歧。

核心特征列表:
  • 买一价 (bid_price_1)
  • 卖一价 (ask_price_1)
  • 最新成交价 (last_price)
  • 当日开盘价 (open_price)
  • 前N笔交易均价 (vwap_N)

4.1.2 价格变化特征

价格本身没意义,价格变化才有。我常用的是价格差分价格变化率。举个例子:

# 价格差分(一阶差分)
df['price_diff'] = df['last_price'].diff()

# 价格变化率(对数收益率)
df['log_return'] = np.log(df['last_price'] / df['last_price'].shift(1))

# 价格变化率(百分比)
df['pct_return'] = df['last_price'].pct_change()

这里有个坑:对数收益率比百分比收益率更稳定。我在做高频策略时,发现对数收益率的时间序列统计特性更好,尤其适合做波动率建模。

避坑指南:我曾经在回测时直接用百分比收益率,结果模型在极端行情下预测偏差巨大。后来换成对数收益率,效果明显改善。原因是对数收益率具有可加性,且分布更接近正态。

4.1.3 价格形态特征

除了数值,价格形态也很重要。我常用移动平均线、布林带、RSI等技术指标。但注意,别一股脑全用上。我建议只选3-5个最有效的。

# 移动平均线
df['ma_5'] = df['last_price'].rolling(window=5).mean()
df['ma_20'] = df['last_price'].rolling(window=20).mean()

# 布林带
df['bb_mid'] = df['last_price'].rolling(window=20).mean()
df['bb_std'] = df['last_price'].rolling(window=20).std()
df['bb_upper'] = df['bb_mid'] + 2 * df['bb_std']
df['bb_lower'] = df['bb_mid'] - 2 * df['bb_std']

4.2 成交量特征

成交量是市场的「燃料」。没有成交量的价格变动,就像没有观众的表演——不可持续。我总结成交量特征有三个核心维度:绝对量、相对量、形态

4.2.1 绝对成交量特征

最直接的就是买卖一档的挂单量。但注意,挂单量不等于成交量。挂单量是「意愿」,成交量是「行动」。我习惯把两者都纳入特征。

成交量特征清单:
  • 买一量 (bid_volume_1)
  • 卖一量 (ask_volume_1)
  • 最近N笔成交量 (volume_N)
  • 累计成交量 (cum_volume)

4.2.2 相对成交量特征

绝对量受时间影响大,相对量更有意义。我常用成交量变化率成交量与均值的比值

# 成交量变化率
df['volume_change'] = df['volume'].pct_change()

# 成交量与20期均值的比值
df['volume_ratio'] = df['volume'] / df['volume'].rolling(window=20).mean()

嗯,这里要注意:成交量比值大于1.5时,往往意味着市场情绪异常。我在实盘中遇到过,当比值超过2.0时,价格反转的概率显著增加。

4.2.3 成交量形态特征

成交量也有形态。比如放量上涨、缩量下跌这些经典形态。我习惯用成交量与价格的协动关系来刻画。

# 成交量与价格的相关性(滚动窗口)
df['vol_price_corr'] = df['volume'].rolling(window=10).corr(df['last_price'])

4.3 订单簿不平衡指标

这个指标是我个人非常看重的。订单簿不平衡,说白了就是买卖双方的力量对比。你想想看,如果买一档有1000手,卖一档只有100手,那价格大概率要往上走。

4.3.1 经典不平衡指标

最常用的就是订单簿不平衡率 (Order Book Imbalance, OBI)

# 订单簿不平衡率
df['obi'] = (df['bid_volume_1'] - df['ask_volume_1']) / (df['bid_volume_1'] + df['ask_volume_1'])

OBI的取值范围是[-1, 1]。正值表示买方力量强,负值表示卖方力量强。绝对值越大,力量越悬殊。

4.3.2 深度加权不平衡指标

经典OBI只考虑一档,太浅了。我建议用深度加权不平衡指标,把多档价格和量都考虑进去。

# 深度加权不平衡(前5档)
def depth_weighted_imbalance(df, levels=5):
    bid_vol = 0
    ask_vol = 0
    for i in range(1, levels+1):
        bid_vol += df[f'bid_volume_{i}'] / i
        ask_vol += df[f'ask_volume_{i}'] / i
    return (bid_vol - ask_vol) / (bid_vol + ask_vol)

df['dwi'] = depth_weighted_imbalance(df)
经验之谈:我在做BTC永续合约预测时,发现深度加权不平衡指标比经典OBI的预测能力高出约15%。原因是多档信息能更全面反映市场深度。

4.3.3 价格加权不平衡指标

还有一种思路:把价格也加权进去。毕竟,离当前价格越近的档位,影响力越大。

# 价格加权不平衡
def price_weighted_imbalance(df, levels=5):
    bid_vol = 0
    ask_vol = 0
    for i in range(1, levels+1):
        bid_vol += df[f'bid_volume_{i}'] * df[f'bid_price_{i}']
        ask_vol += df[f'ask_volume_{i}'] * df[f'ask_price_{i}']
    return (bid_vol - ask_vol) / (bid_vol + ask_vol)

4.4 波动率计算

波动率是市场的「心跳」。没有波动率,价格预测就失去了意义。我常用的波动率计算方法有四种:历史波动率、已实现波动率、GARCH波动率、Parkinson波动率

4.4.1 历史波动率

最简单,也最常用。就是过去N期的收益率标准差。

# 历史波动率(20期)
df['hist_vol'] = df['log_return'].rolling(window=20).std() * np.sqrt(252)

注意:乘以sqrt(252)是为了年化。如果是高频数据,要换成对应的交易频率。

4.4.2 已实现波动率

这个更精细。它利用日内高频数据计算,能捕捉到日内波动细节。

# 已实现波动率(5分钟频率)
df['rv_5min'] = df['log_return'].rolling(window=12).apply(lambda x: np.sqrt(np.sum(x**2)))

4.4.3 GARCH波动率

GARCH模型能捕捉波动率的聚集效应。说白了,就是大波动后面往往跟着大波动

from arch import arch_model

# 拟合GARCH(1,1)模型
model = arch_model(df['log_return'].dropna(), vol='Garch', p=1, q=1)
results = model.fit(disp='off')
df['garch_vol'] = results.conditional_volatility
避坑指南:我曾经直接用GARCH预测高频波动率,结果模型经常不收敛。后来发现,GARCH更适合日频数据。对于高频数据,我建议用已实现波动率或Parkinson波动率。

4.4.4 Parkinson波动率

这个利用了最高价和最低价的信息,比只用收盘价的历史波动率更高效。

# Parkinson波动率
def parkinson_vol(high, low, window=20):
    log_hl = np.log(high / low)
    return np.sqrt((1 / (4 * np.log(2))) * log_hl.rolling(window=window).mean())

df['park_vol'] = parkinson_vol(df['high'], df['low'])

4.5 特征工程知识体系

说了这么多,我画个图帮你理清思路。特征工程不是孤立的技术,而是一个完整的体系。

特征工程知识体系 订单簿特征工程 价格序列特征 成交量特征 订单簿不平衡 波动率计算 原始价格 价格变化 价格形态 绝对成交量 相对成交量 成交量形态 经典OBI 深度加权 价格加权 历史波动率 已实现波动率 GARCH/Parkinson 特征工程核心原则 相关性 + 稳定性 + 可解释性

这张图把咱们讲的内容串起来了。你想想看,四个大类下面各有子特征,最终都服务于一个核心目标:让模型更好地理解市场微观结构

我的建议:刚开始做特征工程时,别贪多。先选2-3个核心特征,跑通流程。等模型稳定了,再逐步添加新特征。我在项目中吃过亏,一开始就搞了50多个特征,结果模型过拟合得一塌糊涂。

好了,特征工程基础就讲到这里。记住:好的特征胜过复杂的模型。把基础打牢,后面的模型构建才能事半功倍。


公众号:蓝海资料掘金营,微信deep3321