19、机器学习信号:线性回归、决策树、随机森林

说到机器学习在量化交易里的应用,很多人第一反应就是「高大上」。其实没那么玄乎。说白了,机器学习就是帮我们从历史数据里找规律,然后用这些规律去预测未来。

在高频数据里,价格信号提取是个老难题。传统方法比如移动平均线、布林带,它们能捕捉一些趋势,但面对复杂市场时经常失灵。这时候,机器学习就派上用场了。

我个人习惯把机器学习模型分成三类:线性回归、决策树、随机森林。它们各有各的脾气,也各有各的适用场景。今天咱们就一个一个聊。

19.1 线性回归:最简单的预测器

线性回归,说白了就是找一条直线,让这条直线尽可能拟合历史数据。在高频交易里,我们常用它来预测下一时刻的价格。

举个例子。假设我们想用过去5个tick的价格预测下一个tick的价格。那输入就是5个特征,输出就是1个目标值。模型会学到一个权重向量,告诉我们每个历史价格对预测结果的影响有多大。

代码实现其实很简单。用scikit-learn的话,几行就搞定:

from sklearn.linear_model import LinearRegression
import numpy as np

# 假设我们有1000个tick的价格数据
prices = np.random.randn(1000)

# 构造特征:过去5个tick的价格
X = []
y = []
for i in range(5, len(prices)):
    X.append(prices[i-5:i])
    y.append(prices[i])

X = np.array(X)
y = np.array(y)

# 训练模型
model = LinearRegression()
model.fit(X, y)

# 预测下一个tick
last_5 = prices[-5:].reshape(1, -1)
pred = model.predict(last_5)
print(f"预测下一个价格: {pred[0]:.4f}")

我在项目中遇到过一个问题:直接用原始价格做线性回归,效果很差。为什么?因为价格序列是非平稳的。你想想看,价格一直在变,均值也在变,模型根本学不到稳定的关系。

解决办法很简单——用收益率代替价格。收益率是平稳的,模型学起来就靠谱多了。

小技巧: 用差分价格或对数收益率作为输入,模型稳定性会大幅提升。

19.2 决策树:非线性关系的利器

线性回归有个硬伤——它假设特征和目标之间是线性关系。但市场哪有这么简单?很多时候,价格和特征之间是非线性的。

比如,当成交量特别大时,价格可能剧烈波动;当成交量很小时,价格可能横盘。这种关系,线性回归很难捕捉。这时候,决策树就登场了。

决策树的工作原理,说白了就是不断问问题。比如:「成交量大于1000吗?」「如果是,那价格变化大于0.5%吗?」一层层问下去,最后落到一个叶节点,给出预测值。

代码也很直接:

from sklearn.tree import DecisionTreeRegressor

# 假设我们有特征:过去5个tick的收益率和成交量
returns = np.random.randn(1000)
volumes = np.random.randint(100, 10000, 1000)

X = np.column_stack([returns, volumes])
y = np.random.randn(1000)  # 下一时刻的收益率

# 训练决策树
tree = DecisionTreeRegressor(max_depth=5)
tree.fit(X, y)

# 预测
pred = tree.predict([[0.02, 5000]])
print(f"预测收益率: {pred[0]:.4f}")

决策树有个好处——可解释性强。你可以把树画出来,看看它到底是怎么做决策的。这对于理解市场行为很有帮助。

但决策树也有个致命缺点:容易过拟合。树太深了,它会把噪声也学进去。我曾经吃过这个亏。有一次,我用深度为20的决策树做回测,结果训练集上准确率99%,测试集上直接崩了。嗯,从那以后,我严格控制树的深度,一般不超过5层。

注意: 决策树对数据变化非常敏感。训练集里稍微改几个样本,树的结构可能完全不一样。这就是为什么我们需要随机森林。

19.3 随机森林:集成学习的威力

随机森林,说白了就是一群决策树投票。每棵树用不同的样本子集和特征子集训练,最后取平均值作为预测结果。

这样做的好处很明显:单棵树容易过拟合,但很多棵树一起投票,过拟合的风险就大大降低了。而且,随机森林对异常值不敏感,稳定性很好。

在高频数据里,随机森林是我用得最多的模型之一。为什么?因为它能处理高维特征,而且不需要太多调参。

代码示例:

from sklearn.ensemble import RandomForestRegressor

# 构造特征:过去10个tick的收益率、成交量、买卖价差
n_samples = 1000
returns = np.random.randn(n_samples, 10)
volumes = np.random.randint(100, 10000, (n_samples, 10))
spreads = np.random.randn(n_samples, 10)

X = np.column_stack([returns, volumes, spreads])
y = np.random.randn(n_samples)

# 训练随机森林
rf = RandomForestRegressor(n_estimators=100, max_depth=5)
rf.fit(X, y)

# 特征重要性
importances = rf.feature_importances_
print(f"特征重要性: {importances[:5]}")

随机森林还有一个隐藏技能——特征重要性排序。你可以看看哪些特征对预测贡献最大。我在项目中就发现,买卖价差的重要性往往比成交量还高。这说明在高频交易里,流动性成本比交易活跃度更关键。

核心要点: 随机森林的泛化能力比单棵决策树强很多,但训练速度也慢很多。在高频数据里,如果数据量特别大(比如百万级),建议用LightGBM或XGBoost替代。

19.4 三种模型的对比

说了这么多,咱们来做个对比。我整理了一个表格,方便你快速决策:

模型 优点 缺点 适用场景
线性回归 简单、快速、可解释 只能捕捉线性关系 收益率预测、趋势跟踪
决策树 非线性、可解释 容易过拟合、不稳定 特征筛选、规则提取
随机森林 稳定、泛化好、特征重要性 训练慢、模型大 高频信号提取、风控模型

我个人习惯是:先用线性回归快速验证想法,如果效果不好,再上随机森林。决策树用得少,但偶尔用来做特征工程——看看哪些特征被树频繁选中。

19.5 实战中的避坑指南

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

  • 数据泄露: 千万别用未来数据训练模型。我见过有人用t+1的数据预测t时刻的价格,回测结果漂亮得不行,实盘直接亏光。记住,训练集和测试集必须严格按时间分割。
  • 特征选择: 不是特征越多越好。高频数据里,很多特征之间高度相关,比如不同时间窗口的移动平均。用太多相关特征,模型会不稳定。我一般先用相关性矩阵筛选一遍。
  • 模型更新: 市场在变,模型也要变。我建议每天重新训练一次模型,或者至少每周一次。别指望一个模型用一年。
  • 过拟合检测: 训练集和测试集的性能差距超过10%,基本就是过拟合了。这时候减少特征数量或降低模型复杂度。
我的经验: 在高频数据里,简单模型往往比复杂模型更可靠。线性回归+几个精心挑选的特征,有时候比随机森林100棵树效果还好。别迷信模型复杂度。

好了,关于机器学习信号提取,咱们就聊到这儿。这三种模型是基础,但也是核心。掌握了它们,你就能应对大部分高频数据场景了。

机器学习信号提取流程 高频价格数据 特征工程(收益率、成交量等) 模型选择:线性回归 / 决策树 / 随机森林 线性回归 决策树 随机森林