25、订单流与机器学习:用订单流特征预测价格方向

说实话,做量化交易这些年,我越来越觉得纯价格分析有点「不够用」了。价格是结果,订单流才是原因。今天我们就聊聊怎么把订单流数据喂给机器学习模型,让它帮我们预测价格方向。

嗯,这章内容有点硬核,但我尽量讲得接地气。你想想看,如果我们能提前几秒知道大资金在干嘛,那胜率不就上来了吗?

为什么订单流特征适合做ML特征?

传统技术指标(比如MACD、RSI)都是价格和成交量的衍生品,说白了是「二手信息」。而订单流数据是「一手信息」——它直接告诉你谁在买、谁在卖、挂单深度如何。

我个人习惯把订单流特征分成三类:

  • Delta类特征:主动买盘 vs 主动卖盘的差值
  • 失衡率类特征:买卖力量的不平衡程度
  • 深度变化类特征:盘口挂单的厚度变化

这三类特征组合起来,基本能覆盖市场微观结构的核心信息。我在实盘项目中测试过,加入这些特征后,模型准确率提升了大概6-8个百分点。

特征工程详解

1. Delta特征

Delta就是主动买成交量减去主动卖成交量。但直接拿原始Delta做特征,噪声太大。我一般会做几个处理:

  • 累计Delta:过去N笔的Delta累加,比如过去100笔
  • Delta斜率:Delta随时间的变化速率
  • Delta标准差:衡量Delta的波动程度

举个例子,如果累计Delta持续为正且斜率在增大,说明买方在加速进场,价格大概率要涨。

核心经验:Delta特征对高频行情(tick级别)效果最好,对1分钟以上K线效果会衰减。我曾经试过用5分钟K线的Delta做预测,结果模型几乎失效——因为时间窗口太长,微观信号被抹平了。

2. 失衡率特征

失衡率(Imbalance Ratio)计算的是买卖力量的相对强弱。公式很简单:

失衡率 = (主动买量 - 主动卖量) / (主动买量 + 主动卖量)

这个值在-1到1之间。正值表示买方占优,负值表示卖方占优。

但我发现直接用这个值做特征,效果一般。为什么?因为市场在震荡时,失衡率会频繁正负切换,产生大量噪声。

我的改进方法是:

  • 阈值化处理:只有失衡率绝对值超过0.3时才视为有效信号
  • 加权移动平均:给近期数据更高权重,比如用EMA而不是SMA
  • 多时间尺度:同时计算10笔、50笔、200笔的失衡率

避坑指南:我曾经把失衡率直接作为唯一特征训练模型,结果过拟合严重。后来发现,失衡率在趋势行情中很准,但在震荡行情中就是「噪音制造机」。所以一定要结合其他特征一起用。

3. 深度变化特征

盘口深度变化,说白了就是看买单和卖单的厚度变化。这里我关注三个维度:

特征名称 计算方式 含义
买一深度变化 当前买一量 - 前N笔买一量均值 最近买单是否在堆积
卖一深度变化 当前卖一量 - 前N笔卖一量均值 最近卖单是否在堆积
深度差 买一深度 - 卖一深度 买卖双方谁在「加厚」
深度斜率 深度差随时间的变化率 力量转换的速度

嗯,这里有个细节要注意:深度变化要结合价格位置来看。如果价格在高位,买一深度突然增加,可能是主力在「托单」出货,而不是真的想买。这个坑我踩过好几次。

Python实现ML模型

好了,理论说完了,我们直接上代码。我用的是LightGBM,因为它对表格数据效果好,训练速度快,而且能处理缺失值。

数据准备

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
import lightgbm as lgb

# 假设我们已经有了订单流数据
# 字段:timestamp, price, volume, side(buy/sell), bid_depth, ask_depth

def create_orderflow_features(df):
    """生成订单流特征"""
    features = pd.DataFrame(index=df.index)
    
    # 1. Delta特征
    df['delta'] = np.where(df['side'] == 'buy', df['volume'], -df['volume'])
    features['cum_delta_100'] = df['delta'].rolling(100).sum()
    features['delta_slope'] = features['cum_delta_100'].diff(10) / 10
    features['delta_std'] = df['delta'].rolling(50).std()
    
    # 2. 失衡率特征
    buy_vol = np.where(df['side'] == 'buy', df['volume'], 0)
    sell_vol = np.where(df['side'] == 'sell', df['volume'], 0)
    features['imbalance_ratio'] = (buy_vol - sell_vol) / (buy_vol + sell_vol + 1e-8)
    features['imbalance_ema'] = features['imbalance_ratio'].ewm(span=20).mean()
    
    # 3. 深度变化特征
    features['bid_depth_change'] = df['bid_depth'] - df['bid_depth'].rolling(50).mean()
    features['ask_depth_change'] = df['ask_depth'] - df['ask_depth'].rolling(50).mean()
    features['depth_diff'] = features['bid_depth_change'] - features['ask_depth_change']
    features['depth_slope'] = features['depth_diff'].diff(10)
    
    return features.dropna()

# 生成标签:未来N笔价格是否上涨
def create_labels(df, lookahead=20):
    """预测未来20笔的价格方向"""
    future_price = df['price'].shift(-lookahead)
    labels = (future_price > df['price']).astype(int)
    return labels[:-lookahead]  # 去掉最后无法预测的部分

模型训练

# 加载数据
df = pd.read_csv('orderflow_data.csv')
features = create_orderflow_features(df)
labels = create_labels(df)

# 对齐数据
common_idx = features.index.intersection(labels.index)
X = features.loc[common_idx]
y = labels.loc[common_idx]

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, shuffle=False
)

# 标准化
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# 训练LightGBM模型
model = lgb.LGBMClassifier(
    n_estimators=200,
    max_depth=5,
    learning_rate=0.05,
    class_weight='balanced',
    random_state=42
)

model.fit(
    X_train_scaled, y_train,
    eval_set=[(X_test_scaled, y_test)],
    eval_metric='auc',
    early_stopping_rounds=20,
    verbose=False
)

# 特征重要性
importance = pd.DataFrame({
    'feature': X.columns,
    'importance': model.feature_importances_
}).sort_values('importance', ascending=False)

print(importance.head(10))

重要提醒:这里我用了shuffle=False,因为时间序列数据不能随机打乱。如果你打乱了,模型会「偷看」未来数据,回测结果会虚高。这个错误我刚开始做的时候犯过,回测收益曲线漂亮得不行,实盘直接被打脸。

模型评估与调优

模型训练完了,怎么评估?我一般看三个指标:

  • 准确率:整体预测正确的比例,但要注意类别平衡
  • AUC:衡量模型区分正负样本的能力,0.6以上算可用
  • 盈亏比:预测正确时的平均收益 / 预测错误时的平均亏损

我个人最看重盈亏比。为什么?因为准确率再高,如果赚的时候赚1块,亏的时候亏10块,那也没用。我在实盘中要求盈亏比至少达到1.5以上才敢上策略。

知识体系总览

下面这张图是我自己总结的订单流ML预测框架,你可以照着这个思路搭建自己的系统:

订单流ML预测框架 原始订单流数据 特征工程 Delta特征 失衡率特征 深度变化特征 ML模型训练 模型评估 实盘部署 反馈优化 核心逻辑:原始数据 → 特征提取 → 模型训练 → 评估优化 → 实盘部署 注意:反馈循环是必须的,市场在变,模型也要跟着变

一些实战心得

最后分享几个我在实战中踩过的坑:

  • 特征不要太多:我一开始搞了50多个特征,结果模型训练慢,还容易过拟合。后来精简到15个核心特征,效果反而更好。
  • 注意数据频率:订单流数据通常是毫秒级的,但模型预测不需要那么高频。我一般用1秒或5秒聚合一次,既保留了微观信息,又减少了计算量。
  • 模型要定期重训:市场微观结构会变,半年前有效的特征现在可能就失效了。我每周会重训一次模型,用最近一个月的数据。

核心总结:订单流+机器学习这条路走得通,但别指望一上来就赚钱。先做好特征工程,再选对模型,最后用实盘数据反复验证。记住,模型只是工具,对市场的理解才是核心。


无相订单流研究社 微信Lucian808555