第二十四讲:订单簿与风险管理:VaR 计算、压力测试、极端行情应对
做量化交易这些年,我越来越觉得一个道理——赚钱靠策略,活下来靠风控。订单簿这东西,平时看着是流动性的源泉,可一到极端行情,它就成了风险的放大器。你想想看,当市场瞬间崩塌,买单像退潮一样消失,订单簿上那点深度根本不够看。
这一讲,我们就来聊聊怎么用订单簿数据做风险管理。说白了,就是回答三个问题:我最多可能亏多少?最坏的情况会怎样?真遇到了怎么办?
1. 基于订单簿的 VaR 计算
VaR,全称是 Value at Risk,风险价值。我习惯把它理解为「在某个置信水平下,未来一段时间内可能的最大损失」。比如 95% VaR 是 100 万,意思就是有 95% 的把握,明天亏的钱不会超过 100 万。
传统的 VaR 计算通常用历史数据或参数模型。但订单簿给了我们一个更实时的视角——用当前的流动性来估算潜在损失。
1.1 流动性调整的 VaR (L-VaR)
传统 VaR 假设你可以按市价无限成交,这显然不现实。订单簿告诉我们,你吃掉的深度越深,滑点越大。我管这个叫「流动性成本」。
计算思路很简单:
- 从当前价格开始,沿着订单簿的深度一层层吃单
- 每吃一层,记录累计成交量和对应的加权价格
- 直到吃掉你设定的头寸规模
- 计算成交均价与当前市价的差值,这就是流动性成本
举个例子,假设你想卖出 1000 个 ETH:
# 伪代码示意
def calc_lvar(order_book, position_size, confidence=0.95):
# 从买一价开始,逐层吃单
cumulative_qty = 0
total_cost = 0
for level in order_book['bids']:
price = level[0]
qty = level[1]
take = min(qty, position_size - cumulative_qty)
cumulative_qty += take
total_cost += price * take
if cumulative_qty >= position_size:
break
avg_price = total_cost / cumulative_qty
current_price = order_book['mid_price']
liquidity_cost = (current_price - avg_price) / current_price
# 结合波动率调整
vol = estimate_volatility()
var = (liquidity_cost + confidence * vol) * position_size * current_price
return var
嗯,这里要注意:订单簿是动态变化的。你计算 VaR 的那一刻,和实际成交的那一刻,订单簿可能已经面目全非了。所以我一般会加一个「深度衰减因子」,假设你吃单的过程中,对手方也在撤单。
核心要点:订单簿 VaR 的核心思想,是把「流动性不足」这个风险量化成具体的金额。它比传统 VaR 更贴近真实交易场景。
2. 压力测试:模拟极端行情
VaR 只能覆盖「正常」市场下的风险。但真正杀死你的,往往是那些「不可能发生」的事件。比如 2010 年的闪电崩盘,2020 年 3 月的流动性枯竭。
压力测试,就是主动去模拟这些极端情况。我个人习惯把压力测试分成两类:
2.1 历史情景模拟
找历史上最极端的几个事件,把当时的订单簿变化「回放」到当前市场。比如:
- 2020 年 3 月 12 日:比特币一天跌 50%,订单簿深度缩水 90%
- 2021 年 5 月 19 日:中国监管消息导致瞬间抛压,买单被一层层击穿
- 2022 年 LUNA 崩盘:订单簿完全失效,价差扩大到离谱
怎么做?把历史事件的价格变化曲线和深度变化曲线,叠加到当前的订单簿上。说白了就是问:如果今天再来一次 312,我的仓位会怎样?
2.2 合成情景模拟
历史不会简单重复。有时候我们需要自己构造极端情景。我常用的几个:
| 情景名称 | 描述 | 对订单簿的影响 |
|---|---|---|
| 流动性枯竭 | 所有限价单瞬间撤走 80% | 价差扩大 5-10 倍,深度几乎为零 |
| 巨量市价单 | 出现一个相当于日均成交量 10 倍的市价单 | 价格瞬间穿透多层深度,滑点巨大 |
| 多市场联动 | 多个交易所同时出现异常 | 套利机制失效,价差无法收敛 |
我的经验:合成情景不要只盯着价格看。订单簿的「形状」变化往往比价格变化更致命。我曾经遇到过一个情景,价格只跌了 5%,但买单深度消失了 90%,导致我的止损单根本无法成交。
3. 极端行情应对策略
好了,现在你知道风险在哪了。接下来就是怎么应对。我把它总结成三个层次:
3.1 事前预防
在极端行情来临之前,就把防护网架好:
- 动态调整仓位:当订单簿深度变薄时,自动降低仓位。我习惯用一个「深度健康度指标」,当它低于阈值时,强制减仓。
- 设置多层止损:不止一个止损价。我会设三个级别——预警、减仓、清仓。每个级别对应不同的订单簿状态。
- 分散流动性:不要把鸡蛋放在一个订单簿里。多交易所、多交易对分散,哪怕一个交易所挂了,还有别的。
3.2 事中应对
极端行情发生时,每一秒都宝贵。这时候别想着优化价格了,活着最重要:
# 极端行情下的应急逻辑
def emergency_response(order_book, position):
# 1. 检查订单簿是否还有有效深度
if order_book.bid_depth < MIN_DEPTH:
# 深度不够,改用冰山订单
place_iceberg_order(position, max_visible=MIN_QTY)
# 2. 如果价差过大,放弃市价单
if order_book.spread > MAX_SPREAD:
# 改用限价单,但价格要激进
aggressive_price = order_book.best_bid * 0.99
place_limit_order(aggressive_price, position)
# 3. 如果所有方法都失效
if order_book.is_stale():
# 暂停交易,等待恢复
cancel_all_orders()
set_trading_paused(True)
我曾经在 2021 年 5 月 19 日那天,亲眼看着一个策略因为坚持用市价单止损,结果滑点达到了 3%。那 3% 的额外损失,比策略一个月的利润还多。从那以后,我的应急逻辑里永远有一个分支——当流动性不足时,宁可慢一点,也要用限价单。
3.3 事后复盘
极端行情过去后,别急着松口气。这是最好的学习机会:
- 回放当时的订单簿数据,看看你的风控逻辑是否按预期触发
- 检查有没有「漏网之鱼」——那些没被覆盖到的风险点
- 更新压力测试的情景库,把这次事件加进去
警告:不要过度优化。我见过有人把一次极端行情当成常态来设计风控,结果导致策略在正常行情下根本无法运行。风控是安全带,不是铁笼子。
4. 知识体系总览
下面这张图,是我对本章内容的一个梳理。你可以把它当成一张「风控地图」:
你看,整个体系其实就三个环环相扣的部分:先算清楚风险有多大,再模拟最坏的情况,最后准备好应对方案。缺了任何一个环节,你的风控都是漏风的。
最后说一句实在话:订单簿风控不是让你不亏钱,而是让你亏钱的时候还能活着。我见过太多人,策略赚钱时意气风发,一次黑天鹅就彻底出局。别做那个人。