2. 监控系统架构设计:数据采集层、计算引擎层、告警通知层、可视化展示层
做统计套利实盘,最怕什么?
不是策略亏钱,而是系统崩了你不知道。我见过太多人,策略跑得好好的,突然某天行情异常,结果监控没跟上,几分钟亏掉几个月的利润。所以今天咱们聊聊监控系统的架构设计。
这套架构我拆成四层:数据采集层、计算引擎层、告警通知层、可视化展示层。每一层都有坑,我一个个说。
2.1 数据采集层:地基不牢,地动山摇
数据采集层是整个监控系统的起点。说白了,你后面所有计算、告警、展示,都依赖这层的数据质量。数据脏了,后面全是垃圾。
我个人习惯把数据源分成四类:
- 行情数据:Tick级、1秒级、1分钟级。做统计套利,至少需要1分钟K线,但如果你做高频,Tick数据是必须的。
- 订单数据:成交记录、挂单状态、撤单记录。我遇到过一个问题:订单状态更新延迟,导致重复计算持仓,差点爆仓。
- 账户数据:可用资金、持仓市值、保证金占用。这些数据通常从券商API拉取,注意频率限制。
- 日志数据:策略运行日志、系统错误日志。嗯,这个很多人忽略,但排查问题时它就是救命稻草。
⚠️ 避坑指南
我曾经因为行情数据源切换时没做校验,导致价差计算连续错了3个小时。后来我强制要求:每个数据源必须做「数据新鲜度校验」和「数值合理性校验」。比如价格不能为负,时间戳不能比当前时间晚5秒以上。
我曾经因为行情数据源切换时没做校验,导致价差计算连续错了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倍以上。
我建议把计算引擎做成「无状态」的。每次计算只依赖输入数据,不依赖历史状态。这样即使重启,也能快速恢复。另外,用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秒。后来我加了「连续确认」机制:只有连续3次采样都触发告警,才真正发出通知。
2.4 可视化展示层:让数据会说话
可视化展示层是给「人」看的。你算了一堆指标,如果展示得乱七八糟,等于白做。
我个人习惯把仪表盘分成三个区域:
- 实时监控区:当前价差、持仓、盈亏。用大号数字显示,一眼就能看到。
- 趋势分析区:价差走势图、协整关系图。用折线图展示最近24小时的变化。
- 风险概览区:最大回撤、当前敞口、告警历史。用红黄绿三色标识风险等级。
嗯,这里要注意:移动端和PC端的展示逻辑完全不同。PC端可以展示很多细节,但移动端必须「精简再精简」。我一般只把「当前持仓盈亏」和「告警状态」放到手机端。
💡 个人经验
可视化工具我推荐用Grafana + InfluxDB的组合。Grafana的仪表盘模板很丰富,InfluxDB处理时序数据又快又稳。如果你不想搭环境,直接用Python的Plotly Dash也能快速出原型。
可视化工具我推荐用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