2. 监控系统架构设计:数据采集层、计算引擎层、告警通知层、可视化展示层

做统计套利实盘,最怕什么?

不是策略亏钱,而是系统崩了你不知道。我见过太多人,策略跑得好好的,突然某天行情异常,结果监控没跟上,几分钟亏掉几个月的利润。所以今天咱们聊聊监控系统的架构设计。

这套架构我拆成四层:数据采集层、计算引擎层、告警通知层、可视化展示层。每一层都有坑,我一个个说。

统计套利监控系统架构 数据采集层 行情数据 · 订单数据 · 账户数据 · 日志数据 计算引擎层 价差计算 · 协整检验 · 信号生成 · 风险指标 告警通知层 阈值告警 · 异常检测 · 分级通知 · 自动熔断 可视化展示层 实时仪表盘 · 历史回放 · 报表导出 · 移动端

2.1 数据采集层:地基不牢,地动山摇

数据采集层是整个监控系统的起点。说白了,你后面所有计算、告警、展示,都依赖这层的数据质量。数据脏了,后面全是垃圾。

我个人习惯把数据源分成四类:

  • 行情数据:Tick级、1秒级、1分钟级。做统计套利,至少需要1分钟K线,但如果你做高频,Tick数据是必须的。
  • 订单数据:成交记录、挂单状态、撤单记录。我遇到过一个问题:订单状态更新延迟,导致重复计算持仓,差点爆仓。
  • 账户数据:可用资金、持仓市值、保证金占用。这些数据通常从券商API拉取,注意频率限制。
  • 日志数据:策略运行日志、系统错误日志。嗯,这个很多人忽略,但排查问题时它就是救命稻草。
⚠️ 避坑指南
我曾经因为行情数据源切换时没做校验,导致价差计算连续错了3个小时。后来我强制要求:每个数据源必须做「数据新鲜度校验」和「数值合理性校验」。比如价格不能为负,时间戳不能比当前时间晚5秒以上。

数据采集的代码框架,我一般这样写:

class DataCollector:
    def __init__(self, sources):
        self.sources = sources  # 数据源列表
        self.buffer = deque(maxlen=10000)
    
    def fetch(self):
        for src in self.sources:
            data = src.get_data()
            if self._validate(data):
                self.buffer.append(data)
            else:
                self._alert("数据异常: " + src.name)
    
    def _validate(self, data):
        # 校验逻辑
        return True

2.2 计算引擎层:核心大脑,别让它过载

计算引擎层负责把原始数据加工成有意义的指标。统计套利里,核心计算包括:

  • 价差计算:配对交易的核心,实时计算两个品种的价差。
  • 协整检验:定期检验配对是否还保持协整关系。我一般每30分钟跑一次。
  • 信号生成:根据价差偏离均值多少个标准差,生成开平仓信号。
  • 风险指标:最大回撤、夏普比率、当前敞口等。

你想想看,如果计算引擎卡住了,告警层拿不到最新指标,那监控还有什么意义?所以这里我特别强调性能优化。

💡 个人经验
我建议把计算引擎做成「无状态」的。每次计算只依赖输入数据,不依赖历史状态。这样即使重启,也能快速恢复。另外,用NumPy做向量化计算,比for循环快10倍以上。

一个简单的价差计算示例:

import numpy as np

def calculate_spread(price_a, price_b, hedge_ratio):
    """
    计算价差
    price_a, price_b: 两个品种的价格序列
    hedge_ratio: 对冲比率
    """
    spread = price_a - hedge_ratio * price_b
    z_score = (spread - np.mean(spread)) / np.std(spread)
    return spread, z_score

2.3 告警通知层:别让告警变成噪音

告警层是最容易「过度设计」的地方。我见过有人给每个指标都设了告警,结果一天收到几百条消息,最后全被忽略了。

我的原则是:告警要分级

级别 触发条件 通知方式 响应要求
INFO 价差偏离1个标准差 日志记录 无需处理
WARNING 价差偏离2个标准差 微信/邮件 关注即可
CRITICAL 价差偏离3个标准差 或 系统异常 电话+短信+微信 立即处理
EMERGENCY 账户爆仓风险 或 数据源中断 自动熔断+人工确认 强制干预
⚠️ 避坑指南
我曾经把告警阈值设得太敏感,结果半夜被电话吵醒,发现只是网络抖动导致数据延迟了2秒。后来我加了「连续确认」机制:只有连续3次采样都触发告警,才真正发出通知。

2.4 可视化展示层:让数据会说话

可视化展示层是给「人」看的。你算了一堆指标,如果展示得乱七八糟,等于白做。

我个人习惯把仪表盘分成三个区域:

  • 实时监控区:当前价差、持仓、盈亏。用大号数字显示,一眼就能看到。
  • 趋势分析区:价差走势图、协整关系图。用折线图展示最近24小时的变化。
  • 风险概览区:最大回撤、当前敞口、告警历史。用红黄绿三色标识风险等级。

嗯,这里要注意:移动端和PC端的展示逻辑完全不同。PC端可以展示很多细节,但移动端必须「精简再精简」。我一般只把「当前持仓盈亏」和「告警状态」放到手机端。

💡 个人经验
可视化工具我推荐用Grafana + InfluxDB的组合。Grafana的仪表盘模板很丰富,InfluxDB处理时序数据又快又稳。如果你不想搭环境,直接用Python的Plotly Dash也能快速出原型。

一个简单的实时监控代码片段:

import plotly.graph_objects as go
from dash import Dash, dcc, html

app = Dash(__name__)

app.layout = html.Div([
    html.H1("统计套利监控面板"),
    dcc.Graph(
        figure={
            'data': [
                go.Scatter(x=timestamps, y=spread_values, mode='lines', name='价差')
            ],
            'layout': {
                'title': '实时价差走势',
                'yaxis': {'title': '价差'}
            }
        }
    )
])

if __name__ == '__main__':
    app.run_server(debug=True)

2.5 各层之间的协作:别让数据断流

四层架构不是孤立的。数据采集层把数据喂给计算引擎,计算引擎产出指标后触发告警,同时把结果推送给可视化层。任何一个环节出问题,整个监控就失效了。

我建议用消息队列(比如RabbitMQ或Kafka)来解耦各层。这样即使某一层挂了,其他层还能继续工作。数据不会丢,系统不会崩。

📌 核心要点
- 数据采集层:保证数据质量和时效性
- 计算引擎层:追求性能和稳定性
- 告警通知层:分级管理,避免噪音
- 可视化展示层:简洁直观,适配多端

好了,这套架构我用了三年,实盘跑了十几个策略,没出过大问题。你照着搭,至少能避开我踩过的那些坑。


公众号:蓝海数据掘金营,微信deep3321