news 2026/10/17 8:50:53

做市策略研究:从最优报价模型到强化学习与多智能体仿真

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
做市策略研究:从最优报价模型到强化学习与多智能体仿真

做市策略研究这些年,我经常被人问到一个问题:做市商的报价到底是拍脑袋还是有公式可依?更具体一点:手上库存一多、波动率一上来,买价和卖价到底该挂在哪里,才不会一边被对手单打穿、一边把所有利润变成浮亏?

这个标题其实把做市这件事拆成了三条明确的主线:最优报价理论,解决的是单笔报价怎么定;学习型算法,解决的是策略怎么在复杂市场里自主进化;经济机制,解决的是我们这些微观报价决策,放到整个市场里会引发什么涌现结果。这篇文章就沿着这三条线完整展开,从数学模型讲到 Python 实现,再到多智能体市场仿真,最后落回实操层的经验和坑。适合正在做量化研究、金融工程方向,以及想从规则式做市策略转向学习型策略的算法工程师。

1. 做市到底在做什么:一门靠风险补偿赚钱的生意

很多人第一次接触做市,觉得逻辑特别简单:买一挂单,卖一挂单,买价比卖价低一点,价格来回震荡时两边轮流成交,价差就是利润。听起来像是无风险套利,但真做起来你会发现,价差本质上不是白捡的钱,而是市场付给你的风险补偿。

1.1 价差收益的本质是承担库存风险的报酬

以一只流动性一般的股票为例,你同时报出 9.99 买入、10.01 卖出,中间价在 10.00 附近波动。如果买方主动卖给你 1000 股,你的账户里就凭空多出价值 1 万块的库存。这时候你不再是一个单纯赚价差的中间商,而是一个持有多头仓位的交易者。

问题在于,你并不知道接下来价格会往哪里走。如果中间价跌到 9.90,你的库存立刻产生 100 块浮亏。虽然你还可以把货在 9.99 卖掉,但卖价已经比当初的买价低,这就是库存风险。因此在做市收益的拆解公式里,永远不能只看价差:

做市净收益 = 价差收益 - 库存价格变动损失 - 信息不对称损失 - 手续费与滑点

也就是说,报价价差需要足够宽,才能覆盖掉后面三项潜在损失。如果价差过窄,成交是多了,但一次库存方向的剧烈波动就能吃掉很多天的价差利润,这是新手最容易栽的第一道坎。

1.2 逆向选择:在你报价的另一侧藏着更聪明的人

比库存风险更隐蔽的是逆向选择。假设市场上有一部分交易者掌握着尚未公开的信息,他们会在你报出买价后毫不犹豫地卖给你,或者在你报出卖价后毫不犹豫地买走。

举个例子:某只股票即将发布一个重大利空,知情交易者心里清楚价格很快会跌,他们会顺手把你挂出的买单一口气全砸掉。你以为自己在正常提供流动性,实际上你正站在信息流对面接飞刀。等消息公开、中间价跳空下跌,你手里的库存瞬间贬值,这时你连止损都来不及。

所以做市商在处理订单流时,必须假设对手方的成交意愿里包含信息成分。如果主动卖出量异常放大,你的买价就得相应下调,甚至在极端情况下降报价、停止做市。经典市场微观结构理论里,这个成分通常被称为“信息冲击”,它直接决定了价差里至少一档的宽度。

理解了这两类风险,再看后面的报价公式和算法,就会比较有抓手:所谓最优报价,其实是在价差收益、库存风险和逆向选择三者之间找平衡点。

2. 经典最优报价模型:从一个学术味很浓的框架说起

做市报价最早被系统化,靠的并不是拍脑袋经验,而是一套很经典的随机最优控制框架。市面上常被简称为 AS 模型,量化从业者基本都接触过。它解决的核心问题是:已知当前库存和盘口状态,应该把买卖价各挂多远。

2.1 模型直觉:把报价拆成价差宽度和库存偏移两部分

AS 框架对盘口做了很多理想化假设,但最终给出的报价形式非常直观。它把最优价格拆成两部分:一个关于剩余到期时间的价差基础项,一个关于当前库存的偏移项。

如果只用一句话概括:当你库存为零时,买卖报价围绕中间价对称分布,价差宽度主要和波动率、风险容忍度以及剩余时间有关;当你库存偏多时,整个报价系统会朝着卖出方向偏移,也就是降低卖价促进出货,同时提高买价阻止继续买入。

库存偏移项的核心思想其实和普通人处理风险的习惯是一样的:手里货越多,越担心价格下跌,就越要加快速度把货出掉。做市商处理库存的速度越快,也就意味着他愿意让出的价格越多。

这个框架最让我欣赏的地方,是它没有把报价做成一个静态答案。它把“时间”和“风险偏好”都放了进去。剩余时间越短,不确定性越小,价差可以收窄;风险厌恶系数越大,库存惩罚就越重,策略会更积极地回到零仓位附近。

2.2 关键参数怎么定:波动率、风险厌恶系数和订单流速

实际使用这个模型时,最麻烦的是标定参数。比较核心的几个参数如下:

参数含义实践标定方式
波动率 sigma中间价的短期波动水平用最近 30 分钟到 1 小时的回报标准差,滚动计算
风险厌恶系数 gamma对库存风险的容忍程度按目标持仓上限反推,例如愿意承受的最大亏损占净值比例
订单流速 alpha订单到达强度统计近期主动买入卖出单的到达频率
成交强度 kappa报价偏离越远成交概率越低根据历史挂单距离与成交率的拟合曲线估计

这里最值得多说两句的是 gamma。它不是一个可以直接观测到的量,而是要和你的风险预算挂钩。比如账户资金 100 万,你允许单次做市策略最大回撤 5000 块,那么 gamma 可以按照“最大库存 5000 股、波动率 2% 时,库存风险惩罚恰好等于 5000 块”这个约束反推。这样算出来的参数不会凭空飘着,而是跟真实资金曲线绑定。

2.3 经典模型的边界:理想市场里很强,现实市场里不够用

AS 模型好用,但它的假设在真实盘中并不能完全成立。它假设订单到达是泊松过程,价格波动是简单的随机扩散,但实际上订单流是有聚集效应的,重大消息发布时的价格是带跳的,做市商之间的策略也互相影响。

在我自己的实践中,AS 模型更像是报价系统的一个基准锚。它告诉你一个合理的报价区间,但紧接着还需要叠加一些工程性修正:比如日内交易时段效应、订单流不平衡特征、市场冲击估计。这些修正如果全靠手工规则,写起来会非常长,而且很难覆盖所有情况。这正是后面切换成学习型算法的原因之一:我们希望策略自己从数据中提取那部分“规则之外”的信息。

3. 亲手实现一个最优报价策略:搭建、回测、踩坑

看公式容易眼高手低,真写代码时很多细节会冒出来。这一章我会从一个简化版的模拟环境开始,把最优报价策略在 Python 里完整跑一遍,再说明回测中必须注意的坑。

3.1 先造一个模拟订单簿

做市回测最缺的往往是可靠的订单簿历史数据,尤其是刚起步做研究时,Level 2 数据的采购成本不低。所以早期阶段可以用模拟数据做开发验证。我们先构造一个简化版本:中间价按几何随机游走生成,主动买盘和主动卖盘按泊松过程到达,策略报价挂在离中间价一定距离的位置。

import numpy as np import pandas as pd np.random.seed(42) # 模拟参数 n_steps = 5000 dt = 1.0 / 240 # 每分钟 240 个 tick,模拟 1 分钟级别粒度 mu = 0.0001 # 漂移项 sigma = 0.02 # 波动率 mid_price = 100.0 # 生成中间价路径 prices = [mid_price] for _ in range(n_steps): ret = mu * dt + sigma * np.sqrt(dt) * np.random.randn() prices.append(prices[-1] * np.exp(ret)) # 生成主动买卖单 buy_arrivals = np.random.poisson(lam=3.0, size=n_steps) sell_arrivals = np.random.poisson(lam=3.0, size=n_steps)

这里我把主动买卖单的到达强度设成 3,也就是每个 tick 平均有 3 笔主动成交意愿。你可以按自己研究的品种去调整这个数字,比如热门股票比冷门股票高很多,期权接近到期时也可能爆发式变化。

3.2 实现基础报价逻辑

接下来按简化版最优报价公式来算买卖价。核心逻辑分两步:第一步算基础半价差,第二步根据库存做价格偏移调整。

def compute_quotes(mid, inventory, kappa, gamma, sigma, horizon, alpha): # 基础半价差:波动越大、剩余时间越短时价差越宽 base_half_spread = 0.5 * gamma * sigma**2 * horizon + alpha * np.sqrt(horizon) # 库存偏移:库存为正时整体报价向上移动,鼓励卖出 inventory_offset = gamma * sigma**2 * inventory bid = mid - base_half_spread + inventory_offset ask = mid + base_half_spread + inventory_offset return bid, ask

这个函数虽然不够严谨,但足够作为原型演示。重点在于那个inventory_offset:库存为正,意味着你手里买入了太多货,需要让买价和卖价同时往上移,这样才能吸引更多卖出报价成交,阻止更多买入报价成交。库存为负则相反,整体下移以鼓励回补。

拼成策略后,我写一个循环模拟:先更新中间价,生成买卖到达量,再根据当前库存调用报价函数,检查是否有主动单穿越报价,穿越则按对应方向成交。

inventory = 0 cash = 0 volume = 100 # 每笔成交的股数 gamma = 0.01 kappa = 1.5 alpha = 0.5 horizon = 1.0 for t in range(n_steps): mid = prices[t] bid, ask = compute_quotes(mid, inventory, kappa, gamma, sigma, horizon, alpha) # 主动买单是否吃穿卖价 if buy_arrivals[t] > 0 and mid >= ask: inventory -= volume * buy_arrivals[t] cash += ask * volume * buy_arrivals[t] # 主动卖单是否打穿买价 if sell_arrivals[t] > 0 and mid <= bid: inventory += volume * sell_arrivals[t] cash -= bid * volume * sell_arrivals[t]

这个模拟显然很粗糙,但用来理解核心逻辑已经足够了。真实回测中还需要处理订单簿深度、限价单排队位置、部分成交、撤单等细节。

3.3 回测结果怎么看:不能只盯着总收益

跑完 5000 个 tick 之后,我习惯看以下几个指标:

  • 累计 PnL:等于现金加上库存按最新中间价折算的价值减去初始资金
  • 最大回撤:看资金曲线从峰值到谷底的跌幅
  • 库存绝对值上限:反映持仓敞口控制能力
  • 成交笔数与成交率:判断报价有没有挂到可以成交的位置

如果发现库存长期停留在 5000 股以上不回落,即使 PnL 是正的,我也会怀疑参数有问题。因为这意味着策略本质上变成了方向性交易,做市赚到的价差只是顺便的。

3.4 回测中最容易骗人的三个地方

第一个坑是成交判定过于理想。现实里你挂的限价单即使穿越了,也不一定立即成交,因为订单簿里你前面还排着别人。如果不模拟队列位置,回测成交率会明显偏高,收益曲线虚胖。这个误差在流动性极好的品种上相对小,但在冷门标的上会被放大很多倍。

第二个坑是手续费和滑点没留足。做市策略本身是薄利多销,千分之一的手续费看起来不高,但叠加高频报撤单后,一天下来的费率损耗足以把一个正收益策略拖成负收益。回测里必须把撮合费用、结算费用和借券成本全部算进去。

第三个坑是参数过拟合。夏普比率在样本内做得越好看,往往越危险。我个人的习惯是固定留出一段完全没有参与参数调优的样本,等策略和参数都定稿后才在那一小段数据上跑一次终验。如果终验结果和开发期相差悬殊,基本就是过拟合了。

4. 从规则式报价走向学习型报价:强化学习做市实战

AS 模型这类规则模型的优点是可解释、容易排查,但到了高频变化的环境里,订单流的非线性、市场冲击的路径依赖,都不是几个公式能完全覆盖的。这也是我转向强化学习做市路线的直接原因。

4.1 为什么需要让策略自己学习

传统策略的工作方式,是研究员先总结一堆规则,再写一堆 if-else 去执行。比如订单流不平衡超过某阈值就收窄买价,波动率突然放大就拉宽价差。这套方式的问题在于市场特征一变,规则就要重写,维护成本非常高。

强化学习的思路正好相反。研究员只需要定义好状态、动作和奖励,策略通过与模拟环境的交互逐步逼近最优行为。换句话说,策略在市场里多待一段时间,自己就会生成更复杂的推测:比如在特定市场微观结构下,最优报价并不一定遵循简单的价差加偏移规则,还可能需要结合近期订单流的方向性和排队位置。

4.2 做市 RL 环境的三个设计要素

设计做市 RL 环境,核心是三件事:状态表征、动作空间和奖励函数。

状态表征决定策略能看见什么。我常用的状态维度包括:

  • 库存量及其相对于持仓上限的比例
  • 当前买一卖一价距离中间价的偏移
  • 近期已实现成交量和成交流
  • 波动率滚动估计
  • 日内相对时间,用来捕捉开盘收盘效应

动作空间定义策略可以怎么干预报价。最简单的方式是离散步长组合:把买价偏移和卖价偏移都离散成若干档,例如从 -5 tick 到 +5 tick,这样动作空间是一个二维离散网格。更进阶的版本可以加入撤单、改单等操作。

奖励函数是做市成败的关键。它不能只等于瞬时盈亏,因为库存风险是后续的隐忧。我通常使用:

reward = realized_pnl - penalty_rate * (inventory ** 2)

这里penalty_rate控制了对库存风险的厌恶程度,配合动作空间的使用,最终策略会学会在“多赚一点价差”和“别留太多货”之间做权衡。

4.3 一个简单的 DQN 做市核心片段

以 DQN 为例,训练一个简单的报价偏移选择器,核心循环大概是这样的:

import torch import torch.nn as nn class MarketMakerNet(nn.Module): def __init__(self, state_dim, n_actions): super().__init__() self.net = nn.Sequential( nn.Linear(state_dim, 64), nn.ReLU(), nn.Linear(64, 64), nn.ReLU(), nn.Linear(64, n_actions) ) def forward(self, x): return self.net(x)

训练时,每个环境步从模拟盘口抽一批状态,用 epsilon-greedy 选择动作,进入环境后拿奖励、转移状态,存进回放缓冲区做小批量梯度更新。

实际操作中,DQN 在更复杂动作空间下收敛速度会比较慢,我自己更常用 PPO 类算法,它对超参数的敏感性相对低一点。不过 DQN 架构简单,适合用来理解做市 RL 的核心逻辑。

4.4 RL 做市训练中的三个稳定性问题

这里必须多说几句,因为训练做市 RL 策略比训练游戏 AI 麻烦得多,主要原因在于市场环境的非平稳性。

第一个问题是奖励尺度不稳定。市场价格波动大时,一天的利差收益可能明显高于其他时间,神经网络训练的梯度也会忽大忽小。我的做法是把奖励做标准化,减去滚动均值再除以滚动标准差,同时限制单步奖励的绝对值范围,防止个别极端样本主导梯度更新。

第二个问题是单环境采样效率太低。做市是顺序决策过程,一个 episode 跑完才能学到一点点经验。建议至少并行开十几个模拟环境,批量采数据再统一训练。没有并行环境,光是探索动作空间就要花很久。

第三个问题是策略容易在训练后期“忘记旧技能”。市场状态分布会变化,如果训练样本分布总是偏向最新近的数据,策略可能过度适应近期波动。我一般会在经验回放里保留一部分早期样本,同时定期用不同参数组合的环境做对抗性验证,确认策略不是在某个特定随机种子下才表现好。

5. 学习型市场:当所有参与者都在同时适应

单智能体 RL 解决的是“一个聪明的做市商该怎么行动”。但真实市场里有大量做市商、套利者、趋势交易者,以及无数高频流动性提供者,每个人都在学习、都在适应。这就涉及到标题里的后半段:学习型市场。

5.1 从单体智能到多智能体涌现

经典经济学里的有效市场假说,隐含了一群信息处理能力很强的参与者,他们彼此竞争,最终把价格推向合理水平。但实际市场更像一个动态反馈系统:你的报价会影响别人的成交判断,别人的撤单又会改变你的库存风险暴露。

当我们把做市策略从单智能体换成多智能体,看到的现象会更有意思。假设市场里有几个做市智能体,都用类似的经验回放算法训练,它们会逐渐收敛到相近的报价策略。刚开始价差很大,大家都赚得轻松;随着训练推进,竞争加剧,价差被压得很窄,每个智能体都在承担更大库存风险来换取微薄收益。

多智能体仿真实验里可以观测到的核心变化有三个:均衡价差随做市商家数增加而收窄、成交量随之放大、但在极端冲击下流动性可能更快消失,因为所有人的策略都学会了同一套风险回避模式。

5.2 流动性公共品属性和同质化风险

如果只从单个做市商视角看,报价宽一点更安全。但从整个市场视角看,所有人的价差越宽,交易成本越高,市场活跃度就越差。这就是流动性的公共品属性:每个人都依赖他人提供的流动性,但私人最优的流动性供给水平往往低于社会最优水平。

这在经济机制设计上意味着,仅仅让做市商自由竞争,不一定能产生充分的流动性。所以很多交易所会推出做市激励计划,用回报速率补偿做市商承担的库存风险。这类机制的本质,就是把流动性供给的社会收益部分内部化给做市商。

更值得警惕的是策略同质化。多智能体场景中,同一个算法训练出的做市商,本质上共享着同一套风险偏好和反应模式。一旦行情突变,所有人会同时撤单缩价,流动性瞬间消失,价格急涨急跌的风险会显著放大。这就是我在仿真实验里最常看到的脆弱性来源。

5.3 从学习型市场中能提炼出什么经济机制启示

从做市研究员的角度看,学习型市场给我们三个启示。

一是报价策略不能只看自身风险。当你的竞争对手也在用类似模型时,你需要把策略同质化带来的极端行情纳入考虑,这本质上是一种模型风险。

二是市场机制设计必须考虑参与者的学习能力。如果激励规则长期不变,参与者会慢慢学会适应规则,甚至围绕规则进行博弈。此时规则的边际效果会被削弱,需要定期再评估。

三是做市场景往后会越来越像一个多智能体博弈问题,而不仅仅是单笔报价优化问题。研究重心会从“给定市场条件下我的最优报价是什么”转向“我与其他学习型参与者共存时,什么样的策略具备演化稳定性”。这个转变是未来做市研究最有价值的方向之一。

6. 从研究到落地:我做做市研究积累的经验清单

这一章想浓缩一些长期积累的实操经验,不一定是教科书上会写的东西,但都是我在数据、回测和模拟阶段真实踩过的坑。

6.1 订单簿数据清洗要刻意处理三个问题

第一是时间同步。不同交易所的订单簿快照和逐笔成交通常走不同通道,直接拼接会造成价格顺序错乱,所以必须统一时钟,最好是按事件发生时间对齐。

第二是脏数据。某些平台的本地快照会重复推送或漏推,价差会突然变成负数。清洗阶段至少要检查买卖价差是否为正、中间价变化率是否异常,超过阈值直接剔除。

第三是队列重建。如果你拿到的原始数据没有完整队列深度,只有买一卖一档位,那就别指望回测能准确还原排队成交过程。宁可先用简化成交概率模型,也不要假装自己有精确的队列位置。

6.2 回测系统设计永远要为“延迟”留余量

做市策略对延迟极其敏感。模拟环境中,你可能觉得行情来了下一瞬间就能撤单改单,但实盘里从收到 tick 到指令到达交易所,中间有网络延迟、队列延迟、交易所撮合延迟。回测里每笔订单都假设零延迟,结果会严重失真。

我的做法是在回测系统里给所有订单动作加一个固定的延迟常数,比如 2 毫秒到 5 毫秒。同时对撤单成功率打折扣,假设 10% 的撤单指令实际上晚了一步,已经来不及阻止成交。这个保守设定可以帮你排除很多现实中根本赚不到钱的策略。

6.3 监控指标不能只看 PnL,还要盯住报价行为

策略上线后,我会建立一张实时监控表,至少包含以下指标:

  • 库存绝对值相对于持仓上限的占比
  • 当日成交率与撤单率
  • 买卖价差相对当日波动率的比值
  • 订单流不平衡指标,作为风险预警信号
  • 持仓市值与账户净值的比例

经验教训是:PnL 曲线是滞后指标,等你看到资金曲线大幅回撤,往往库存风险已经积累了相当长时间。真正有效的预警信号来自库存和报价行为本身。

6.4 下一阶段可以深入研究的方向

如果你已经跑通了 AS 模型、RL 做市、多智能体仿真,接下来可以考虑几个更有扩展性的方向:把订单流不平衡纳入状态特征的主动性做市策略;把做市与最优执行放在同一个框架里联合优化;研究不同做市商风险偏好差异对市场弹性的影响。这些方向没有一个能简单指向“赚更多钱”,但对理解市场结构和个人策略边界都很有帮助。

我个人在实际操作中的体会是,做市策略研究的核心困难不在于写出一个优秀的报价公式,而在于搭建一个足够真实又不至于复杂到失控的研究环境。从 AS 模型开始,逐步加入机器学习模块,再把自己放进一个模拟的多智能体市场里审视策略的稳定性,这条路跑通之后,你对市场的理解会明显比停留在纸面理论时深入得多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/17 8:50:45

提示工程架构师:2025年AI项目设计核心指南

过去一年&#xff0c;我深度参与了几个AI项目从零到上线的全过程&#xff0c;最强烈的感受是&#xff1a;很多人把“提示工程”理解成“写提示词”&#xff0c;但我越来越觉得&#xff0c;真正的重心应该放在“架构”两个字上。提示工程架构师是一个被低估的角色&#xff0c;20…

作者头像 李华
网站建设 2026/10/17 8:50:35

SRC漏洞挖掘实战:从信息收集到报告撰写的完整指南

1. 先搞清楚SRC到底在玩什么&#xff1a;从平台规则到漏洞定价的一场"寻宝游戏"很多人第一次听说SRC&#xff0c;第一反应是"是不是像CTF一样打靶场"。我可以直接告诉你&#xff0c;差得很远。CTF是一场有标准答案的开卷考试&#xff0c;SRC是在真实业务系…

作者头像 李华
网站建设 2026/10/17 8:49:55

FPGA视音频光端机工程:一芯光纤同时跑视频音频的完整实现

简介&#xff1a;基于现场可编程门阵列&#xff08;FPGA&#xff09;的视音频光端机完整工程代码&#xff0c;适合FPGA开发工程师、视频监控系统集成人员与通信设备研发者参考&#xff0c;用于解决长距离多路视音频信号实时传输和系统集成问题。代码经实际部署验证并成功商业化…

作者头像 李华
网站建设 2026/10/17 8:49:18

OSPF区域外路由计算:FA值与Type-4/5 LSA深度解析

1. 从一个让人抓头的现象说起如果你平时维护过企业内网或者数据中心的网络&#xff0c;大概率遇到过这种场景&#xff1a;明明路由表里看到了一条外部路由&#xff0c;下一跳也正确&#xff0c;但数据包就是不通。抓包一看&#xff0c;流量被丢到了错误的出口&#xff0c;或者干…

作者头像 李华
网站建设 2026/10/17 8:49:12

深度学习混合精度训练:FP16/FP32原理、显存节省与避坑指南

如果你自己从零训过超过十亿参数的大模型&#xff0c;大概率经历过这些场景&#xff1a;代码写好了&#xff0c;数据也检查过了&#xff0c;结果训练卡刚跑起来&#xff0c;显存不足的报错迎面砸过来&#xff1b;把模型换成低精度之后显存安静了&#xff0c;loss 却开始抽风&am…

作者头像 李华