2、实时监控系统架构设计:系统整体架构图、数据流设计、模块划分
好,咱们进入第二章。这一章我打算把整个系统的骨架给你搭起来。
你想想看,做价差回归策略,最怕什么?不是策略亏钱,而是系统跑着跑着突然挂了,你还在睡大觉。我早期做量化时吃过这个亏——半夜三点,服务器内存爆了,价差数据全丢了,第二天起来一看,账户亏了六个点。从那以后,我对架构设计就特别较真。
2.1 系统整体架构图
先上一张图,这是我个人习惯的架构风格——分层清晰,职责单一。说白了,就是每个模块只管自己的事,别越界。
这张图我画得比较简洁,但核心逻辑都在里面了。从上到下分四层:数据层、计算层、展示层、存储层。每一层之间通过消息队列解耦,这样即使某一层挂了,其他层还能继续工作。
2.2 数据流设计
数据流这块,我踩过的坑最多。刚开始做的时候,我图省事,让每个模块直接去数据库拿数据。结果呢?数据库连接数爆了,查询慢得像蜗牛。后来我学乖了,用消息队列做缓冲。
具体的数据流是这样的:
- 行情数据接入:通过WebSocket实时接收交易所的tick数据,丢到Kafka里。
- 价差计算:计算引擎从Kafka消费数据,算出现货和期货之间的价差。
- 信号检测:把价差数据喂给回归模型,判断是否触发开仓/平仓信号。
- 结果推送:信号结果同时写入Redis(给前端展示用)和InfluxDB(给历史分析用)。
嗯,这里要注意一个细节——数据的时间戳必须统一。我见过有人用本地时间,有人用交易所时间,结果价差对不上,白白亏了手续费。我个人习惯全部用交易所的撮合时间,精确到毫秒。
source_ts,记录数据产生时的原始时间戳。这样不管后面怎么处理,你都能回溯到最原始的时间点。
2.3 模块划分
模块划分这件事,说白了就是「高内聚、低耦合」。我见过不少新手把代码写成一个大泥球,所有逻辑揉在一起,改一个地方崩一片。咱们别那样干。
我把系统拆成六个模块,每个模块独立部署、独立升级:
| 模块名称 | 职责 | 技术选型 |
|---|---|---|
| 数据采集器 | 连接交易所,接收实时行情 | WebSocket + asyncio |
| 价差计算引擎 | 计算价差、统计指标 | Pandas + NumPy |
| 信号生成器 | 检测回归机会,生成交易信号 | scikit-learn + 自定义规则 |
| 风险控制器 | 检查仓位、资金、最大回撤 | 独立进程,定时检查 |
| Web展示端 | 实时仪表盘、K线图、告警 | Flask + Socket.IO + ECharts |
| 数据持久化 | 存储历史数据、交易日志 | InfluxDB + MySQL |
每个模块之间通过API或者消息队列通信。举个例子,价差计算引擎算完价差后,不是直接调用信号生成器,而是把结果写到Kafka的一个topic里。信号生成器自己去消费。这样做的好处是——如果信号生成器挂了,数据不会丢,等它恢复后继续消费就行。
2.4 模块间通信协议
通信协议这块,我推荐用Protobuf。为什么?因为JSON虽然方便,但解析起来慢,而且容易出错。我早期用JSON传行情数据,有一次字段名拼错了,整个系统静默地跑了一天错误数据。用Protobuf的话,字段类型和名称都是强约束的,编译期就能发现问题。
下面是一个简单的Protobuf定义示例:
syntax = "proto3";
message SpreadData {
string symbol_pair = 1; // 合约对,比如 "BTC-USDT"
double spot_price = 2; // 现货价格
double futures_price = 3; // 期货价格
double spread = 4; // 价差
int64 timestamp = 5; // 毫秒时间戳
double z_score = 6; // Z-score
}
message TradeSignal {
string symbol_pair = 1;
enum SignalType {
ENTER_LONG = 0;
ENTER_SHORT = 1;
EXIT = 2;
}
SignalType type = 2;
double price = 3;
double quantity = 4;
int64 timestamp = 5;
}
你看,字段名、类型、取值范围都定义得清清楚楚。消费方拿到数据后,直接反序列化就能用,不用做任何校验。这比JSON省心多了。
2.5 部署架构要点
最后聊两句部署。我个人习惯用Docker Compose来编排所有服务。每个模块一个容器,资源限制好,日志统一收集到ELK。这样出了问题,直接看Kibana的日志,不用一台台机器去翻。
还有一个容易被忽略的点——网络延迟。如果你的数据采集器部署在A机房,计算引擎在B机房,中间的网络延迟可能让你错过交易机会。我建议把核心模块(数据采集、价差计算、信号生成)部署在同一台物理机或者同一个K8s节点上,用localhost通信,延迟控制在1毫秒以内。
好了,架构设计这块就聊到这儿。下一章咱们开始动手写代码,先从数据采集器开始。
公众号:蓝海数据掘金营,微信deep3321