第八章:做市报价引擎设计
报价引擎,说白了就是做市商的「心脏」。你策略再牛,模型再准,最后都得靠它把价格报出去。我见过太多团队,策略逻辑写得漂漂亮亮,结果报价引擎一上线就崩——要么报价频率太高被交易所限流,要么买卖价差设得太死被套利者反复收割。
今天咱们就把报价引擎拆开揉碎,从四个维度来讲:报价频率怎么定、价差怎么调、订单簿怎么管、库存怎么控。嗯,这些都是我踩过坑之后才真正搞明白的东西。
核心观点:报价引擎不是越快越好,也不是越慢越好。它是在「流动性提供」和「风险暴露」之间找平衡。
8.1 报价频率优化
先问个问题:你每秒报多少次价合适?
我刚开始做结构化产品做市时,总觉得报价越快越好。你想啊,报价快意味着流动性好,能吸引更多订单。结果呢?被交易所警告了三次,说我们「过度报价」。后来我才明白,报价频率不是拍脑袋定的,它受三个因素约束:
- 交易所规则:很多交易所对报价更新频率有硬性限制,比如每秒最多10次
- 市场波动率:波动大的时候需要高频更新,波动小的时候可以降低频率
- 计算延迟:你的定价模型跑一次要多久?如果模型跑一次要50ms,那每秒最多报20次
我个人习惯的做法是:先做压力测试,摸清系统的极限。比如,我曾在某次做市项目中,把报价频率从每秒5次逐步提升到每秒20次,观察成交率和撤单率的变化。结果发现,超过每秒12次后,成交率不再提升,反而因为频繁撤单增加了成本。
实战技巧:用「自适应报价频率」策略。市场波动率低时,每秒报3-5次;波动率高时,提升到每秒10-15次。这样既节省系统资源,又能保证流动性。
这里给一段简单的频率控制代码,我用的是Python伪代码,实际生产环境会用C++或Rust:
class QuoteFrequencyManager:
def __init__(self, max_freq=10):
self.max_freq = max_freq # 每秒最大报价次数
self.last_quote_time = 0
self.quote_count = 0
def should_quote(self, current_time, volatility):
# 根据波动率动态调整频率
if volatility > 0.05: # 高波动
target_freq = min(self.max_freq, 15)
elif volatility > 0.02: # 中波动
target_freq = min(self.max_freq, 10)
else: # 低波动
target_freq = min(self.max_freq, 5)
# 检查是否达到频率上限
if current_time - self.last_quote_time < 1.0 / target_freq:
return False
return True
8.2 买卖价差动态调整
价差怎么定?这是做市商的核心利润来源。价差太宽,没人来交易;价差太窄,赚不到钱还容易亏。
我记得有一次,我们给一个雪球产品做市,初始价差设了0.5%。结果市场一波动,价差瞬间被套利者吃掉,一晚上亏了十几万。后来我学乖了,价差必须动态调整。
动态调整的核心逻辑其实就三个维度:
- 市场波动率:波动越大,价差越宽。因为你要覆盖更大的风险
- 库存水平:库存偏离目标越远,价差越宽。这是为了吸引反向订单
- 订单簿深度:深度越浅,价差越宽。流动性差的时候要保护自己
我常用的一个公式是这样的:
spread = base_spread * (1 + alpha * volatility) * (1 + beta * inventory_deviation) * (1 + gamma / depth)
其中alpha、beta、gamma是调参系数。我在项目中一般先用历史数据回测,找到最优参数组合,再上线实盘。
避坑指南:我曾经把gamma设得太大,导致深度浅的时候价差变得极宽,完全失去了竞争力。后来发现,gamma控制在0.1-0.3之间比较合理。
下面是一个动态价差调整的示例表:
| 市场状态 | 波动率 | 库存偏离 | 订单簿深度 | 建议价差 |
|---|---|---|---|---|
| 平静 | 低 (0.01) | 低 (0.1) | 深 (1000) | 0.3% |
| 波动 | 中 (0.03) | 中 (0.3) | 中 (500) | 0.6% |
| 危机 | 高 (0.08) | 高 (0.6) | 浅 (100) | 1.5% |
8.3 订单簿管理
订单簿管理,说白了就是你怎么在盘口上摆单子。是只摆一档?还是摆多档?是挂限价单还是用市价单?
我个人的经验是:结构化产品做市,最好用「分层报价」策略。什么意思呢?就是在买一、买二、买三,以及卖一、卖二、卖三都挂上单子。这样既能提供流动性,又能捕捉到不同价格区间的订单。
举个例子,假设某结构化产品的理论价格是100元:
- 卖三:100.6元,挂5手
- 卖二:100.4元,挂10手
- 卖一:100.2元,挂15手
- 买一:99.8元,挂15手
- 买二:99.6元,挂10手
- 买三:99.4元,挂5手
这样做的目的是:如果市场突然上涨,你的卖一被吃掉,卖二、卖三还能继续提供流动性,同时给你时间重新调整报价。我曾经见过只用一档报价的团队,市场一波动,单子瞬间被吃光,然后就没有然后了。
小技巧:订单簿的层数和每层的手数,可以根据你的风险偏好来调。保守型就多摆几层,每层少一点;激进型就少摆几层,每层多一点。
订单簿管理还有一个关键点:撤单和重报。你报出去的单子,如果市场变了,必须及时撤掉重新报。我一般设置一个「最大驻留时间」,比如500ms。超过这个时间,不管单子有没有成交,都撤掉重报。这样能避免「过时报价」被套利者盯上。
8.4 做市商库存控制
库存控制,这是做市商的风控命门。你库存太多,万一市场暴跌,直接爆仓;库存太少,又赚不到钱。
我记得有一次,我们给一个挂钩中证500的雪球产品做市,那天市场突然跳水,我们的库存从目标值的+5%一下子飙到了+25%。为什么?因为我们的买单一直在成交,卖单却没人接。要不是及时启动了「库存紧急平仓」机制,那天可能就交代了。
库存控制的核心思路就一句话:让库存围绕目标值波动,偏离越大,纠正力度越强。
具体怎么做?我一般用三个工具:
- 价差偏移:库存偏多时,降低买价、提高卖价,吸引卖出订单
- 报价量调整:库存偏多时,减少买单量、增加卖单量
- 对冲交易:如果库存偏离太大,直接用期货或期权对冲
下面是一个库存控制的流程图,我用SVG画出来,方便你理解:
库存控制还有一个重要概念:库存目标值。这个目标值不是固定的,它取决于你的风险承受能力和市场预期。比如,如果你看好后市,可以把目标库存设为正(偏多);如果你看空,就设为负(偏空)。
重要提醒:库存控制不是越精确越好。我见过有人把库存目标设得非常精确,比如「必须控制在±2%以内」,结果频繁调整报价,反而增加了交易成本。一般来说,±5%到±10%的容忍区间是比较合理的。
最后,说一个我自己的经验:库存控制要和价差调整联动。你不能只调价差不管库存,也不能只调库存不管价差。我一般用一个「综合评分」来决策:
def adjust_quote(inventory_deviation, volatility, depth):
# 计算价差调整系数
spread_factor = 1 + 0.5 * abs(inventory_deviation) + 0.3 * volatility
# 计算报价量调整系数
volume_factor = 1 - 0.8 * inventory_deviation # 偏多时减少买单
# 综合决策
if inventory_deviation > 0.1: # 库存偏多超过10%
# 降低买价,减少买单量
bid_price = fair_price * (1 - 0.001 * spread_factor)
bid_volume = base_volume * max(0, volume_factor)
# 提高卖价,增加卖单量
ask_price = fair_price * (1 + 0.001 * spread_factor)
ask_volume = base_volume * (2 - volume_factor)
elif inventory_deviation < -0.1: # 库存偏空超过10%
# 反向操作
bid_price = fair_price * (1 + 0.001 * spread_factor)
bid_volume = base_volume * (2 - volume_factor)
ask_price = fair_price * (1 - 0.001 * spread_factor)
ask_volume = base_volume * max(0, volume_factor)
else:
# 正常报价
bid_price = fair_price * (1 - 0.001)
ask_price = fair_price * (1 + 0.001)
bid_volume = base_volume
ask_volume = base_volume
return bid_price, ask_price, bid_volume, ask_volume
嗯,这套逻辑我用了好几年,虽然中间也翻过车,但整体上还是比较稳健的。你拿去用的时候,记得根据你的产品特性和市场环境调参。没有一套参数能通吃所有市场,这是做市商的宿命,也是乐趣所在。
交易系统化学习资料 微信Strategy888888