第三章 库存监控系统设计:实时数据流架构、风险阈值设置、告警机制、可视化仪表盘

做市商的库存风险,说白了就是「货砸手里了」或者「货不够卖了」。

我见过太多团队,策略模型跑得飞起,但库存监控这块做得稀烂。结果呢?一波行情下来,库存偏离到姥姥家,亏得连手续费都赚不回来。

这一章,我们就来聊聊怎么把库存监控这件事做扎实。从数据怎么流进来,到阈值怎么设,再到告警怎么发,最后到仪表盘怎么看——一条龙讲清楚。

3.1 实时数据流架构:让数据跑起来

库存监控的第一步,是数据得实时。延迟超过100毫秒,基本就废了。

我个人习惯用这样的分层架构:

数据采集层 → 数据清洗层 → 计算引擎层 → 存储层 → 展示层

每一层都有讲究。我画了一张图,你看一眼就明白了:

库存监控实时数据流架构 数据采集层 交易所WebSocket / 订单簿快照 / 成交回报 数据清洗层 去重 / 排序 / 时间戳对齐 / 异常值过滤 计算引擎层 库存偏离度 / 风险敞口 / 盈亏计算 / 阈值判定 存储层 时序数据库(InfluxDB) / Redis缓存 / 历史归档 展示层 Grafana仪表盘 / 实时告警推送 / 移动端监控 延迟要求:<10ms 延迟要求:<5ms 延迟要求:<20ms 写入延迟:<50ms 刷新频率:1s

嗯,这张图基本就是我的标准模板了。每一层我都踩过坑,下面细说。

3.1.1 数据采集层

这里我建议直接用交易所的WebSocket流。别用REST轮询,延迟太大。

我曾经有个项目,一开始用REST接口每500ms拉一次订单簿,结果行情剧烈波动时,库存数据滞后了整整3秒。那次教训让我明白:做市商的数据采集,WebSocket是唯一选择。

3.1.2 数据清洗层

交易所发来的数据,有时候会乱序,有时候会重复。你想想看,如果成交回报的顺序乱了,你的库存计算就全错了。

我的做法是:每条数据带一个序列号,在清洗层做排序和去重。代码大概长这样:

class DataCleaner:
    def __init__(self):
        self.buffer = []
        self.last_seq = 0

    def process(self, msg):
        # 去重:跳过已处理的序列号
        if msg.seq <= self.last_seq:
            return None
        # 排序:按序列号插入
        self.buffer.append(msg)
        self.buffer.sort(key=lambda x: x.seq)
        # 返回有序数据
        return self.buffer.pop(0)
小技巧: 清洗层最好用无锁队列实现,比如Disruptor。Java项目用LMAX Disruptor,Python可以用multiprocessing.Queue。别用线程锁,性能会掉一个数量级。

3.2 风险阈值设置:红线在哪里?

阈值设得太松,风险敞口太大;设得太紧,频繁告警把人搞疯。

我个人习惯把阈值分成三级:

级别 库存偏离度 风险敞口 操作建议
黄色预警 ±10% ~ ±20% 总资产的2% 调整报价价差,缓慢回补
橙色预警 ±20% ~ ±40% 总资产的5% 启动对冲策略,减少挂单量
红色预警 ±40%以上 总资产的10% 暂停做市,强制平仓

这里有个关键点:阈值不是拍脑袋定的。我建议用历史回测来校准。

我曾经帮一个团队调参,他们一开始把红色预警设在±30%。结果回测发现,在2018年的大波动行情中,这个阈值一天触发了20多次,交易员根本来不及反应。后来改到±45%,才找到一个合理的平衡点。

注意: 阈值要动态调整。市场波动率上升时,适当放宽;波动率下降时,收紧。别一套参数用一年,那是找死。

3.3 告警机制:别让告警变成噪音

告警这件事,我踩过最大的坑就是「告警疲劳」。

一开始我把所有异常都发告警,结果一天几百条。交易员直接把告警群屏蔽了。真正出事的时候,没人看到。

后来我学乖了,告警机制要分层:

  • P0级(致命): 库存偏离超过红色阈值,或者系统宕机。直接电话+短信+钉钉,必须人工确认。
  • P1级(严重): 橙色阈值触发,或者网络延迟超过500ms。发钉钉/微信,要求5分钟内响应。
  • P2级(警告): 黄色阈值触发,或者某个币对流动性下降。只记录日志,不主动推送。

代码实现上,我推荐用这样的逻辑:

def check_alert(inventory_deviation):
    if abs(inventory_deviation) > 0.40:
        send_alert("P0", f"库存偏离严重:{inventory_deviation:.2%}")
        call_on_call()
    elif abs(inventory_deviation) > 0.20:
        send_alert("P1", f"库存偏离较大:{inventory_deviation:.2%}")
    elif abs(inventory_deviation) > 0.10:
        log_alert("P2", f"库存偏离预警:{inventory_deviation:.2%}")
    else:
        pass  # 正常状态,不打扰
避坑指南: 告警一定要有「防抖」机制。比如连续3次采样都超过阈值,才发告警。避免因为瞬时抖动导致误报。我曾经因为没加防抖,半夜被告警吵醒三次,结果都是虚惊一场。

3.4 可视化仪表盘:一眼看清全局

仪表盘不是越花哨越好。我见过有人把几十个指标堆在一个屏幕上,花花绿绿的,根本不知道看哪里。

我的原则是:一屏之内,三秒看懂

核心指标就这几个:

  1. 当前库存偏离度: 用进度条显示,绿色正常,黄色预警,红色危险。
  2. 实时盈亏: 折线图,展示过去1小时/24小时的盈亏变化。
  3. 风险敞口: 饼图,按币种展示库存分布。
  4. 告警历史: 列表,显示最近10条告警记录。
  5. 系统状态: 绿灯/红灯,显示数据流是否正常。

我个人习惯用Grafana搭仪表盘。数据源接InfluxDB,刷新频率设1秒。嗯,够用了。

核心原则: 仪表盘是给交易员看的,不是给程序员炫技的。每个指标都要问自己一句:「这个指标能帮我做决策吗?」不能?那就删掉。

好了,库存监控系统的基本框架就是这样。数据流架构保证数据实时到位,阈值设置划清风险边界,告警机制确保问题不被忽略,仪表盘让全局一目了然。这四个环节缺一不可。

下一章,我们会聊聊库存对冲策略的具体实现。不过那是后话了,先把监控系统搭好,这是做市商的命根子。


专注资料整理