25、订单流与机器学习:用订单流数据训练分类/回归模型

说实话,做了这么多年订单流分析,我越来越觉得传统规则策略有天花板。你想想看,人工定义的支撑阻力、失衡、Delta背离,这些模式虽然有效,但市场在变,参数需要不断调。后来我开始尝试把订单流数据喂给机器学习模型,让算法自己去发现规律。效果嘛,比我想象中要好。

这一章,我就带你走一遍完整的流程——从订单流数据清洗、特征工程,到训练一个分类模型(预测方向)和一个回归模型(预测幅度)。代码我会贴出来,你直接拿去跑就行。

为什么订单流数据适合机器学习?

订单流数据本质上是高频的、多维度的市场微观结构数据。每一笔Tick都包含了价格、成交量、买卖方向、挂单深度等信息。这些数据有几个特点:

  • 高信噪比:相比裸K线,订单流数据包含了更多未成交的博弈信息
  • 时序依赖性:当前时刻的订单流特征往往与后续价格运动有因果关系
  • 非线性关系:比如大单吃单后,有时会引发跟风,有时会引发反转,规则很难描述

我个人习惯把订单流数据看作「市场的X光片」。机器学习模型就是那个读片的医生。你喂给它足够多的病例,它就能学会哪些「阴影」是良性的,哪些是恶性的。

核心思路:用过去N根K线的订单流特征(如累积Delta、大单占比、失衡比率、POC偏移等)作为输入特征,预测未来M根K线的价格方向(分类)或价格变化幅度(回归)。

第一步:数据准备与特征工程

我们先从Tick数据开始。假设你已经有了一组逐笔成交数据,包含时间、价格、成交量、买卖方向(Bid/Ask)。

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor
from sklearn.metrics import accuracy_score, mean_absolute_error

# 模拟订单流数据
np.random.seed(42)
n = 10000
data = pd.DataFrame({
    'timestamp': pd.date_range('2024-01-01', periods=n, freq='1s'),
    'price': 100 + np.cumsum(np.random.randn(n) * 0.1),
    'volume': np.random.randint(1, 100, n),
    'side': np.random.choice(['B', 'S'], n, p=[0.5, 0.5])
})
data['delta'] = np.where(data['side'] == 'B', data['volume'], -data['volume'])
print(data.head())

嗯,这里要注意:真实数据中买卖方向需要从交易所的逐笔数据中解析,有些平台会直接提供Delta字段。我建议你至少积累1个月以上的数据,样本量太少模型容易过拟合。

构建特征矩阵

我们需要把原始Tick数据聚合到K线级别,然后计算订单流特征。下面这个函数是我项目中常用的,你直接复用就行:

def build_orderflow_features(df, freq='5min'):
    # 聚合K线
    ohlc = df.resample(freq, on='timestamp').agg({
        'price': 'ohlc',
        'volume': 'sum',
        'delta': 'sum'
    })
    ohlc.columns = ['open', 'high', 'low', 'close', 'volume', 'delta']
    ohlc.dropna(inplace=True)
    
    # 特征1:累积Delta
    ohlc['cum_delta'] = ohlc['delta'].cumsum()
    
    # 特征2:Delta与成交量的比率(衡量资金强度)
    ohlc['delta_ratio'] = ohlc['delta'] / (ohlc['volume'] + 1e-8)
    
    # 特征3:大单占比(假设单笔成交量>50为大单)
    large_trades = df[df['volume'] > 50].resample(freq, on='timestamp')['volume'].sum()
    ohlc['large_trade_ratio'] = large_trades / (ohlc['volume'] + 1e-8)
    
    # 特征4:价格变化率
    ohlc['ret'] = ohlc['close'].pct_change()
    
    # 特征5:波动率(用高低价差衡量)
    ohlc['volatility'] = (ohlc['high'] - ohlc['low']) / ohlc['close']
    
    # 特征6:POC偏移(假设POC是当根K线成交量最大的价格,这里简化用close代替)
    ohlc['poc_offset'] = (ohlc['close'] - ohlc['open']) / ohlc['open']
    
    return ohlc.dropna()

features = build_orderflow_features(data)
print(features.tail())

经验之谈:特征不是越多越好。我曾经一口气加了30多个特征,结果模型训练慢,还容易过拟合。建议先选5-8个核心特征,比如Delta、大单占比、失衡比率、POC偏移、波动率。这些特征在订单流分析里已经被证明是有效的。

第二步:构建标签(分类与回归)

分类任务:预测未来1根K线的价格方向(上涨/下跌/横盘)。回归任务:预测未来1根K线的价格变化幅度。

# 分类标签:未来1根K线涨跌
features['target_cls'] = np.where(features['ret'].shift(-1) > 0.001, 1,
                                  np.where(features['ret'].shift(-1) < -0.001, -1, 0))

# 回归标签:未来1根K线的收益率
features['target_reg'] = features['ret'].shift(-1)

# 去掉最后一行(没有未来数据)
features = features.dropna()
print(features[['ret', 'target_cls', 'target_reg']].head())

这里我设了一个阈值0.1%来区分横盘。你可以根据品种的波动率调整。比如比特币波动大,阈值可以设到0.5%。

第三步:训练分类模型

我个人比较喜欢用随机森林做基线。它不需要太多调参,对异常值也鲁棒。先试试分类:

# 准备特征和标签
feature_cols = ['cum_delta', 'delta_ratio', 'large_trade_ratio', 'ret', 'volatility', 'poc_offset']
X = features[feature_cols]
y_cls = features['target_cls']

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

# 训练随机森林分类器
clf = RandomForestClassifier(n_estimators=200, max_depth=10, random_state=42)
clf.fit(X_train, y_train)

# 预测与评估
y_pred = clf.predict(X_test)
print(f"分类准确率: {accuracy_score(y_test, y_pred):.3f}")

# 特征重要性
importance = pd.DataFrame({
    'feature': feature_cols,
    'importance': clf.feature_importances_
}).sort_values('importance', ascending=False)
print(importance)

跑完之后你会发现,delta_ratiolarge_trade_ratio往往排在前两位。这符合直觉——资金强度和大单行为对短期价格影响最大。

避坑指南:千万不要用shuffle=True!时间序列数据一旦打乱顺序,模型会学到未来信息,导致回测成绩虚高。我曾经犯过这个错误,实盘亏得很惨。记住:时间序列必须按时间顺序划分训练集和测试集。

第四步:训练回归模型

分类模型只能告诉你方向,但无法告诉你幅度。如果你想做仓位管理,回归模型更有用:

# 回归任务
y_reg = features['target_reg']
X_train_r, X_test_r, y_train_r, y_test_r = train_test_split(X, y_reg, test_size=0.2, shuffle=False)

reg = RandomForestRegressor(n_estimators=200, max_depth=10, random_state=42)
reg.fit(X_train_r, y_train_r)

y_pred_r = reg.predict(X_test_r)
mae = mean_absolute_error(y_test_r, y_pred_r)
print(f"回归MAE: {mae:.5f}")

# 看看预测值与真实值的散点图
import matplotlib.pyplot as plt
plt.scatter(y_test_r[:200], y_pred_r[:200], alpha=0.5)
plt.xlabel('真实收益率')
plt.ylabel('预测收益率')
plt.title('回归模型预测效果')
plt.show()

回归模型的MAE大概在0.002左右,意味着平均预测误差约0.2%。对于5分钟K线来说,这个精度已经可以用于仓位计算了。

第五步:模型融合与策略落地

我建议你把分类和回归模型结合起来用:

  • 分类模型给出方向信号(做多/做空/观望)
  • 回归模型给出预期收益率,用于计算仓位大小
  • 当分类信号与回归预测方向一致时,才开仓

举个例子:分类模型预测上涨(1),回归模型预测收益率为+0.3%,那么你可以开多单,仓位大小与预测收益率成正比。如果分类预测上涨但回归预测收益率为负,说明模型之间存在分歧,最好观望。

核心逻辑:分类模型负责「做什么方向」,回归模型负责「做多少仓位」。两者互相验证,能有效降低假信号。

知识体系总览

下面这张图概括了本章的核心流程,从原始Tick数据到最终策略信号:

订单流机器学习建模流程 第一阶段:数据层 Tick数据 → 聚合K线 → 计算订单流特征(Delta/大单占比/失衡比率/POC偏移) 输入:原始逐笔数据 | 输出:特征矩阵(N行 × M列) 第二阶段:标签构建 分类标签:未来K线方向(+1 / 0 / -1) 回归标签:未来K线收益率(连续值) 第三阶段:模型训练 分类模型(RandomForestClassifier)→ 预测方向 回归模型(RandomForestRegressor)→ 预测幅度 第四阶段:策略融合 → 方向信号 + 仓位管理 分类与回归信号一致时开仓,不一致时观望 数据流方向

几点补充建议

最后,我想分享几个实战中容易踩的坑:

  1. 特征滞后性:订单流特征对价格的反应非常快。如果你用当前K线的特征预测同一根K线的价格变化,那是未来函数。一定要用过去K线的特征预测未来K线的标签。
  2. 模型更新频率:市场结构会变。我建议每周重新训练一次模型,用滚动窗口的方式。比如用过去30天的数据训练,预测未来1天。
  3. 不要过度依赖准确率:分类准确率60%看起来不高,但如果你的盈亏比能做到2:1,长期下来收益非常可观。关注夏普比率和最大回撤,比关注准确率更有意义。
  4. 试试其他模型:随机森林只是起点。你可以试试XGBoost、LSTM,甚至Transformer。但记住:复杂模型不一定更好。我在项目中用XGBoost替换随机森林后,准确率只提升了1.2%,但训练时间增加了10倍。

好了,这一章的内容就到这里。代码你拿回去跑一跑,看看自己的数据上效果如何。记住,订单流数据是金矿,机器学习是挖掘机,两者结合才能挖出真正的价值。

无相订单流研究社 微信Lucian808555