21、做市算法中的机器学习:强化学习做市(DQN、PPO)、监督学习预测订单流、特征工程与标签设计
做市算法走到今天,纯规则驱动的策略已经摸到天花板了。我自己的体会是,市场微观结构里那些非线性、高维的交互关系,靠人手工写if-else根本抓不住。所以这一章,咱们聊聊机器学习怎么嵌入做市算法。
说白了,就是两件事:用强化学习学怎么做决策,以及用监督学习预测订单流。这两条线各有各的坑,我一个个说。
强化学习做市:DQN与PPO
先问个问题:做市商的核心任务是什么?是报单、撤单、调整价差。这本质上是一个序列决策问题。你当前的动作会影响后续的库存、盈亏、甚至对手方的行为。强化学习天然适合干这个。
我个人习惯把做市问题建模成一个马尔可夫决策过程(MDP):
- 状态(State):当前订单簿快照、持仓量、已实现盈亏、市场波动率等。
- 动作(Action):报单价格偏移、报单数量、是否撤单等。
- 奖励(Reward):通常用PnL + 库存惩罚项。库存惩罚很关键,我见过有人只设PnL奖励,结果模型学会了扛着巨大库存赌方向,一崩就崩到底。
DQN:离散动作空间的经典选择
DQN适合动作空间不大的场景。比如你只允许报单价格偏移5档,每档一个动作,总共也就10-20个动作。DQN用深度网络拟合Q值函数,然后贪心地选最大Q值的动作。
但有个坑:做市数据是高度非平稳的。今天训练好的Q网络,明天市场结构一变,可能就失效了。我建议在DQN里加优先经验回放,多采样那些“意外”的样本——比如大单冲击时的状态转移。
库存量 / 目标库存上限的平方,这样惩罚是非线性的,库存越大越难受。
PPO:连续动作空间的利器
如果你想让模型自己决定报单价格偏移量(比如偏移0.1个tick),那就得用PPO了。PPO是策略梯度方法,它直接优化策略网络,输出动作的概率分布。
PPO有个好处:训练稳定。它通过裁剪(clip)策略更新的幅度,防止一步更新太大导致崩溃。我在实盘模拟中试过,PPO比DQN更容易收敛,尤其是在动作空间连续时。
但PPO也有代价——计算量更大。你需要同时维护策略网络和价值网络,而且每次更新要用多个时间步的数据。如果你的交易延迟要求很高,PPO可能不太适合在线学习。
监督学习预测订单流
强化学习解决的是“怎么做”的问题,但“市场接下来会怎样”同样重要。监督学习可以用来预测订单流的不平衡、大单出现的概率、甚至短期价格方向。
我自己的经验是:预测订单流比预测价格更容易。价格是随机游走的,但订单流有很强的自相关性。你想想看,一个大买盘进来后,往往跟着更多买盘——这是订单流聚集效应。
特征工程:从原始数据到有效信号
特征工程是做市算法里最吃经验的部分。我列几个我常用的特征:
| 特征类别 | 具体特征 | 说明 |
|---|---|---|
| 订单簿结构 | 买卖价差、深度不平衡比、订单簿斜率 | 反映市场流动性状况 |
| 订单流动态 | 逐笔成交的买卖方向、订单到达率、撤销率 | 捕捉微观层面的供需变化 |
| 时间序列 | 过去N笔的成交量加权价格、波动率、自相关 | 刻画短期趋势和波动 |
| 事件驱动 | 大单出现标志、新闻情绪得分、隔夜跳空 | 捕捉异常事件的影响 |
嗯,这里要注意:特征不是越多越好。我见过有人堆了200多个特征,结果模型过拟合得一塌糊涂。我的习惯是先用特征重要性排序(比如随机森林的feature importance),只保留前20-30个最重要的。
标签设计:预测什么?
标签设计直接决定了模型能学到什么。我常用的标签有几种:
- 订单流不平衡标签:未来1秒内,净买入量 / 总成交量。这个标签比较平滑,适合回归任务。
- 大单出现标签:未来N笔中是否出现超过阈值的大单。这是个二分类问题,适合做预警。
- 价格方向标签:未来1秒价格是涨还是跌。这个标签噪声很大,我一般不直接用,而是作为辅助任务。
强化学习与监督学习的结合
我个人觉得,最实用的做法是把监督学习的预测结果作为强化学习的状态输入。比如:
- 训练一个LSTM模型,预测未来1秒的订单流不平衡。
- 把这个预测值作为一个特征,喂给PPO的策略网络。
- PPO根据当前订单簿和预测的订单流,决定报单策略。
这样做的好处是:监督学习负责“看”,强化学习负责“做”。两者各司其职,比单独用任何一个都强。
class MarketMakingState:
def __init__(self, orderbook, inventory, flow_prediction):
self.bid_depth = orderbook.bid_volumes[:5] # 前5档买单深度
self.ask_depth = orderbook.ask_volumes[:5] # 前5档卖单深度
self.spread = orderbook.ask_price[0] - orderbook.bid_price[0]
self.inventory_ratio = inventory / MAX_INVENTORY
self.predicted_flow = flow_prediction # 监督学习输出
# 拼接成向量
self.state = np.concatenate([
self.bid_depth, self.ask_depth,
[self.spread, self.inventory_ratio, self.predicted_flow]
])
知识体系总览
下面这张图是我自己梳理的本章知识结构,你可以对照着看:
好了,这一章的内容就这些。记住:特征工程决定上限,模型选择决定下限。把订单流预测做好,你的做市策略就已经赢了一半。