3、风险因子建模:价格风险因子(跳变、滑点)、流动性风险因子(买卖价差、深度衰减)、相关性风险因子(跨资产传染)

做市策略的压力测试,说白了就是一场「极限生存挑战」。你得先搞清楚,到底哪些东西能把你的策略搞死。我个人习惯把风险因子分成三类:价格上的、流动性上的、以及相关性上的。这三类因子,就像三把悬在头顶的剑,每一把落下来,都够你喝一壶的。

3.1 价格风险因子:跳变与滑点

价格风险因子,是压力测试里最直观、也最容易被低估的一块。很多人觉得价格波动嘛,无非就是涨涨跌跌。但真正致命的,是「跳变」和「滑点」这两个东西。

3.1.1 跳变风险

跳变,就是价格在一瞬间从一个点位跳到另一个点位,中间没有任何成交。为什么会这样?通常是因为重大消息发布、流动性瞬间枯竭,或者干脆就是交易所的撮合引擎抽风了。

我在项目中遇到过最夸张的一次,是某个小币种在凌晨三点,因为一条假新闻,价格直接从 0.5 美元跳到了 0.05 美元。我的做市策略还在傻乎乎地挂着双边订单,结果瞬间被吃掉了所有买单,亏损惨重。

建模跳变风险,我建议用「跳跃扩散过程」来模拟。简单来说,就是在常规的布朗运动基础上,叠加一个泊松跳跃过程。代码实现起来也不复杂:

import numpy as np

def jump_diffusion(S0, mu, sigma, lam, jump_mean, jump_std, T, N):
    """
    模拟跳跃扩散过程
    S0: 初始价格
    mu: 漂移率
    sigma: 波动率
    lam: 跳跃强度(平均每秒跳跃次数)
    jump_mean: 跳跃幅度的均值
    jump_std: 跳跃幅度的标准差
    T: 总时间
    N: 时间步数
    """
    dt = T / N
    prices = np.zeros(N)
    prices[0] = S0
    for i in range(1, N):
        # 常规扩散部分
        dW = np.random.normal(0, np.sqrt(dt))
        # 跳跃部分
        dJ = 0
        if np.random.poisson(lam * dt) > 0:
            dJ = np.random.normal(jump_mean, jump_std)
        prices[i] = prices[i-1] * (1 + mu * dt + sigma * dW + dJ)
    return prices

嗯,这里要注意:跳跃强度 lam 这个参数,千万别拍脑袋定。我建议用历史数据里的极端事件频率来校准。比如过去一年里,价格单日波动超过 5% 的次数,除以总交易天数,就是一个比较靠谱的基准值。

3.1.2 滑点风险

滑点,就是你的订单成交价格,和你预期的价格之间的偏差。在流动性好的市场里,滑点可能只有零点几个 tick。但在压力场景下,滑点可以大到让你怀疑人生。

我记得有一次做回测,策略在正常行情下年化收益 30%,滑点设了 0.01%。结果一上实盘,遇到一次小规模闪崩,实际滑点达到了 0.5%,当天就把一个月的利润全吐回去了。

建模滑点,我习惯用「市场冲击模型」。一个比较实用的方法是:

def slippage_model(order_size, order_book_depth, volatility):
    """
    估算滑点
    order_size: 订单数量
    order_book_depth: 订单簿深度(前N档的总量)
    volatility: 当前波动率
    """
    base_slippage = order_size / order_book_depth
    # 波动率越高,滑点越大
    vol_adjustment = 1 + 2 * volatility
    return base_slippage * vol_adjustment
避坑指南: 我曾经犯过一个错误,就是把滑点设成了一个固定值。实际上,滑点是非线性的——订单越大、市场越波动,滑点增长得越快。压力测试里,一定要把滑点建模成动态的,否则你的测试结果会严重失真。

3.2 流动性风险因子:买卖价差与深度衰减

流动性风险,是做市商的「命门」。你想想看,做市商赚的就是买卖价差,如果价差突然变大,或者深度突然变浅,你的盈利模型就全变了。

3.2.1 买卖价差

买卖价差,就是买一价和卖一价之间的差值。正常市场里,价差可能只有 0.01%。但在压力场景下,价差可以扩大到 1% 甚至更高。

建模价差,我建议用「自回归条件异方差模型」来拟合。说白了,就是价差本身也有波动率,而且这个波动率会聚集——大价差之后往往跟着更大的价差。

def spread_simulation(current_spread, spread_vol, shock):
    """
    模拟价差变化
    current_spread: 当前价差
    spread_vol: 价差的波动率
    shock: 外部冲击(比如新闻事件)
    """
    # 价差均值回归特性
    mean_spread = 0.0001  # 0.01%
    # 冲击会放大价差
    new_spread = current_spread + 0.3 * (mean_spread - current_spread) + \
                 spread_vol * np.random.normal() + shock
    return max(new_spread, 0.00001)  # 价差不能为负
个人经验: 我习惯在压力测试里,把价差设置成「正常值的 5 倍」作为基准场景。为什么是 5 倍?因为根据我的回测,大多数流动性危机里,价差扩张到 5 倍是一个比较常见的阈值。超过这个数,策略基本就停摆了。

3.2.2 深度衰减

深度,就是订单簿上各个价位的挂单量。深度衰减,指的是在压力场景下,订单簿上的挂单量急剧减少。这比价差扩大更可怕——价差大至少还能成交,深度没了,你连成交都做不到。

我记得有一次,某个交易所的做市商集体撤单,导致一个主流币种的订单簿深度在 10 秒内下降了 80%。我的策略还在按正常深度计算风险敞口,结果一执行就发现根本平不了仓。

建模深度衰减,我建议用「指数衰减模型」:

def depth_decay(initial_depth, decay_rate, time_elapsed):
    """
    模拟深度衰减
    initial_depth: 初始深度
    decay_rate: 衰减速率
    time_elapsed: 经过的时间(秒)
    """
    return initial_depth * np.exp(-decay_rate * time_elapsed)

这个模型的关键在于 decay_rate 的设定。我一般会取历史数据里,深度下降最快的那 5% 的时段,计算平均衰减速率,然后把这个值作为压力场景的输入。

3.3 相关性风险因子:跨资产传染

相关性风险,是压力测试里最容易被忽视、但破坏力最大的因子。很多人觉得,我做的是 BTC 的做市,跟 ETH 有什么关系?嗯,关系大了去了。

在正常市场里,不同资产之间的相关性可能很低。但在危机时刻,相关性会急剧上升——所有资产一起跌,这就是所谓的「系统性风险」。我见过最典型的例子是 2020 年 3 月 12 日,比特币和标普 500 指数的相关性从 0.1 飙到了 0.8。

建模相关性风险,我建议用「动态条件相关模型」。这个模型的核心思想是:相关性不是固定的,它会随着市场状态变化而变化。

def dynamic_correlation(rho_0, market_vol, shock):
    """
    动态相关性模型
    rho_0: 基准相关性
    market_vol: 市场波动率
    shock: 外部冲击
    """
    # 市场波动率越高,相关性越强
    rho = rho_0 + 0.5 * (market_vol - 0.2) + shock
    # 相关性不能超过 [-1, 1] 的范围
    return np.clip(rho, -1, 1)
核心要点: 在压力测试里,一定要把相关性设置成「动态的」。我见过太多人用固定的相关系数矩阵做测试,结果完全没捕捉到「传染效应」。说白了,危机来临时,所有资产都是「一根绳上的蚂蚱」。

另外,跨资产传染还有一个更隐蔽的形式——「流动性传染」。比如,当 BTC 的流动性枯竭时,做市商为了回笼资金,会抛售 ETH,导致 ETH 的流动性也出问题。这种连锁反应,在压力测试里必须建模进去。

我个人习惯的做法是:建立一个「流动性传染矩阵」,记录每个资产对另一个资产流动性的影响系数。这个系数可以通过历史数据里的「流动性同步下降」事件来估算。

# 流动性传染矩阵示例
contagion_matrix = {
    'BTC': {'BTC': 1.0, 'ETH': 0.3, 'SOL': 0.1},
    'ETH': {'BTC': 0.4, 'ETH': 1.0, 'SOL': 0.2},
    'SOL': {'BTC': 0.2, 'ETH': 0.3, 'SOL': 1.0}
}

这个矩阵的意思是:当 BTC 的流动性下降 10% 时,ETH 的流动性会额外下降 3%(因为 0.3 * 10%)。你想想看,如果多个资产同时出问题,这个传染效应会像滚雪球一样越滚越大。

避坑指南: 我曾经在压力测试里忽略了相关性风险,结果策略在单一资产上表现很好,但遇到跨市场危机时,所有持仓一起亏损,回撤直接超过了 50%。从那以后,我每次做压力测试,都会把「相关性突变」作为一个必测场景。

好了,三类风险因子都讲完了。最后用一张图来总结一下它们之间的关系:

风险因子建模核心逻辑 做市策略压力测试 价格风险因子 流动性风险因子 相关性风险因子 跳变风险 滑点风险 买卖价差 深度衰减 跨资产传染 三者相互影响,压力场景下会形成「风险共振」 流动性枯竭 → 价格跳变 价格跳变 → 相关性上升 相关性上升 → 跨资产传染 建模方法 跳跃扩散模型 | 市场冲击模型 | 动态条件相关模型

这张图展示了三类风险因子之间的「共振」关系。在压力测试里,你不能孤立地测试每一个因子,而要把它们组合起来。比如,流动性枯竭会导致价格跳变,价格跳变会推高相关性,相关性上升又会引发跨资产传染——这是一个闭环。

我个人习惯的做法是:先单独测试每个因子的极端场景,然后再做「组合压力测试」,把三个因子同时推到极限。只有通过了这种「地狱模式」的测试,你的做市策略才算真正有了抗风险能力。