实战案例七:波动率自适应做市策略

做市策略最怕什么?怕市场突然变脸。

你按着低波动环境设的参数,突然来一波剧烈行情,库存直接被打穿。反过来,高波动时你设的窄价差,又会被来回打脸。我早年做加密货币做市时就吃过这个亏——BTC一夜波动率翻倍,我的策略还在用原来的参数,结果一晚上亏了半个月的利润。

所以这一章,我们来解决这个问题。核心思路很简单:让策略自己感知波动率,动态调整报价

波动率自适应的基本逻辑

说白了,就是让策略根据市场状态切换行为模式:

  • 波动率低的时候,价差收窄,增加报价频率
  • 波动率高的时候,价差拉宽,降低风险敞口
  • 极端波动时,直接暂停做市

这个思路不新鲜,但实现细节里全是坑。我一个个说。

第一步:波动率怎么算?

很多人上来就用历史波动率,但做市策略需要的是实时感知。我个人习惯用已实现波动率(Realized Volatility),基于过去N笔交易的收益率计算:

def calc_realized_vol(prices, window=20):
    log_returns = np.log(np.array(prices[1:]) / np.array(prices[:-1]))
    vol = np.std(log_returns[-window:]) * np.sqrt(252 * 24 * 60)  # 年化
    return vol

这里有个细节——窗口大小怎么选?我试过5、10、20、50。窗口太小,波动率跳来跳去,策略也跟着乱动;窗口太大,反应太慢。最终我选了20笔交易作为窗口,大概对应5-10分钟,算是个平衡点。

第二步:波动率分档

拿到实时波动率后,需要把它映射到几个档位上。我一般分三档:

档位波动率范围策略行为
低波动vol < 20%窄价差,高频率
中波动20% ≤ vol < 60%正常做市
高波动vol ≥ 60%宽价差,降低仓位

注意,这个阈值不是拍脑袋定的。我建议你回测时做个敏感性分析,看看不同阈值下策略的表现。我曾经在一个项目里直接用默认阈值,结果回测漂亮,实盘一跑就崩——因为那个市场的波动率分布跟回测数据完全不同。

第三步:动态调整价差和仓位

有了波动率档位,接下来就是调整核心参数。我常用的公式是这样的:

def adaptive_params(vol_level, base_spread=0.001, base_size=1.0):
    if vol_level == 'low':
        spread_mult = 0.8
        size_mult = 1.2
    elif vol_level == 'mid':
        spread_mult = 1.0
        size_mult = 1.0
    else:  # high
        spread_mult = 1.5
        size_mult = 0.5
    
    return base_spread * spread_mult, base_size * size_mult

嗯,这里要注意:价差和仓位要联动调整。高波动时价差拉宽,同时仓位减半,这样即使被吃单,损失也有限。低波动时价差收窄,仓位加大,赚取更多流动性收益。

第四步:极端波动保护

这是最容易忽略的部分。当波动率超过某个上限(比如年化120%),策略应该暂停做市。为什么?因为这时候市场可能处于崩盘或暴涨状态,任何做市行为都是在赌方向。

我见过有人在高波动时继续做市,结果被连续吃单,库存直接变成负数。后来我加了一个保护逻辑:

if current_vol > MAX_VOL_THRESHOLD:
    cancel_all_orders()
    set_status('PAUSED')
    log_warning(f'极端波动,暂停做市,当前波动率: {current_vol:.2%}')

这个阈值设多少?我个人习惯是年化120%。但不同市场不一样,比特币和山寨币的波动率分布完全不同,你得自己测。

完整策略流程

把上面这些串起来,整个策略的流程图是这样的:

开始做市 获取最新行情数据 计算已实现波动率 波动率 > 120%? 暂停做市 波动率分档 低波动 价差×0.8 中波动 正常参数 高波动 价差×1.5 生成并提交订单 循环

核心要点:波动率自适应不是锦上添花,而是做市策略的生存保障。没有这个机制,你的策略在极端行情下就是裸奔。

回测中的注意事项

回测波动率自适应策略时,有几个坑我踩过:

  • 前视偏差:计算波动率时只能用历史数据,不能用未来数据。这个错误我犯过,回测曲线漂亮得不行,实盘一塌糊涂。
  • 参数过拟合:阈值和窗口大小不要对着历史数据硬调。我建议用滚动窗口验证,比如用前6个月数据调参,后3个月验证。
  • 交易成本:波动率高时滑点也会变大,回测时要把这个因素考虑进去。我一般会在高波动场景下额外加20%的滑点成本。

个人经验:波动率自适应策略最适合在趋势+震荡混合的市场中运行。纯趋势行情下,它表现一般;但一旦市场切换,它能帮你保住大部分利润。

代码实现要点

最后给一个完整的策略骨架,你可以直接拿去改:

class VolAdaptiveMarketMaker:
    def __init__(self, base_spread=0.001, base_size=1.0):
        self.base_spread = base_spread
        self.base_size = base_size
        self.price_history = []
        self.vol_window = 20
        
    def on_tick(self, tick):
        # 更新价格历史
        self.price_history.append(tick.price)
        if len(self.price_history) > self.vol_window * 2:
            self.price_history.pop(0)
        
        # 计算波动率
        vol = self.calc_vol()
        
        # 极端波动保护
        if vol > 1.2:
            self.cancel_orders()
            return
        
        # 自适应参数
        spread, size = self.adaptive_params(vol)
        
        # 生成订单
        self.place_orders(tick.price, spread, size)
    
    def calc_vol(self):
        # 已实现波动率计算
        prices = self.price_history[-self.vol_window:]
        if len(prices) < 2:
            return 0
        returns = np.diff(np.log(prices))
        return np.std(returns) * np.sqrt(252 * 24 * 60)
    
    def adaptive_params(self, vol):
        if vol < 0.2:
            return self.base_spread * 0.8, self.base_size * 1.2
        elif vol < 0.6:
            return self.base_spread, self.base_size
        else:
            return self.base_spread * 1.5, self.base_size * 0.5

警告:这个代码只是演示框架。实盘时你还需要处理订单状态管理、重连机制、风控检查等。千万别直接复制就跑实盘,我吃过这个亏。

好了,波动率自适应做市策略的核心就这些。下一章我们会聊另一个实战案例——库存风险对冲策略,到时候见。


无相订单流研究社 微信Lucian808555