2. 系统架构设计:整体架构分层
好,咱们进入第二章。这一章我打算聊聊系统架构。
说实话,很多做风控的同学,一开始就扎进模型和算法里。结果呢?系统跑起来卡得要命,数据对不上,展示层半天刷不出来。我见过太多这样的案例了。
我个人习惯是,先想清楚架构,再动手写代码。架构就像盖房子的骨架,骨架歪了,装修再漂亮也没用。
2.1 整体架构分层
这套投资组合风险监控系统,我把它分成三层:数据层、计算层、展示层。为什么这么分?说白了,就是各司其职,互不干扰。
核心原则:每一层只关心自己的事。数据层只管存和取,计算层只管算,展示层只管画。这样出了问题,你一眼就能知道是哪里崩了。
来,先看一张图,这是我用 SVG 画的架构图,帮你快速建立整体认知。
嗯,这张图你看懂了吗?从上到下,数据从数据层流到计算层,再到展示层。反过来,用户的指令从展示层往下传。双向的。
2.2 模块划分
每一层里面,我又拆了几个模块。我习惯按功能切,而不是按技术切。
2.2.1 数据层模块
- 行情数据模块:负责拉取股票、债券、期货的实时/历史行情。我用的是 MySQL 做持久化,Redis 做热点缓存。
- 持仓数据模块:记录每个投资组合的持仓明细。包括股票代码、数量、成本价、当前市值。
- 用户配置模块:存用户的预警阈值、风险偏好、通知方式等。
我的经验:行情数据千万别全放 MySQL。高频查询用 Redis,日终归档再刷进 MySQL。我曾经有个项目,直接把实时行情写 MySQL,结果数据库连接池被打满了,整个系统挂了半小时。
2.2.2 计算层模块
- 风险指标计算引擎:这是核心。计算 VaR(在险价值)、夏普比率、最大回撤、波动率等。
- 相关性分析模块:计算资产之间的相关系数矩阵。用于分散化分析。
- 预警引擎:实时监控指标是否超过阈值。超过就触发告警。
你想想看,如果计算层和展示层混在一起,每次刷新页面都要重新算一遍 VaR,那得多慢?所以我把计算层独立出来,用 Redis 做缓存。算好的结果直接扔 Redis,展示层秒级读取。
2.2.3 展示层模块
- 仪表盘:总览全局。显示总市值、总风险敞口、当日盈亏。
- 风险热力图:用颜色深浅表示各资产的风险贡献度。
- 持仓明细表:可排序、可筛选的表格。
- 预警弹窗:实时推送风险告警。
2.3 技术选型
技术选型这块,我踩过不少坑。直接说结论吧。
| 层级 | 技术 | 选型理由 |
|---|---|---|
| 数据层 | MySQL + Redis | MySQL 稳定可靠,适合结构化数据。Redis 快,适合缓存和计数器。 |
| 计算层 | Python | 生态丰富,pandas、numpy、scipy 做金融计算太方便了。 |
| 展示层 | Flask | 轻量、灵活。比 Django 更适合做 API 后端。 |
| 缓存/队列 | Redis | 既当缓存,又当消息队列。一鱼两吃。 |
注意:别用 Flask 做计算密集型任务。Flask 是同步的,一个耗时请求会阻塞其他请求。我建议把计算任务丢到 Redis 队列里,用 Celery 或 RQ 异步执行。
2.4 代码示例:数据层连接配置
来,看一段实际代码。这是我项目里用的数据库连接配置。
# config.py
import redis
import pymysql
# MySQL 配置
MYSQL_CONFIG = {
'host': 'localhost',
'port': 3306,
'user': 'risk_user',
'password': 'risk_pass_2024',
'database': 'portfolio_risk',
'charset': 'utf8mb4'
}
# Redis 配置
REDIS_CONFIG = {
'host': 'localhost',
'port': 6379,
'db': 0,
'decode_responses': True
}
# 初始化连接
def get_mysql_conn():
return pymysql.connect(**MYSQL_CONFIG)
def get_redis_client():
return redis.Redis(**REDIS_CONFIG)
嗯,这里要注意。密码别写死在代码里。我一般用环境变量或者配置文件管理工具。曾经有一次,我把密码提交到了 Git 仓库,结果被安全团队通报了...尴尬。
2.5 数据流示例
我举个例子,看看一次风险计算请求是怎么走的。
- 用户点击「计算 VaR」 → 展示层发送 POST 请求到 /api/calc_var
- Flask 接收请求 → 把任务 ID 和参数写入 Redis 队列
- Python 后台进程 → 从 Redis 队列取出任务,从 MySQL 读取持仓数据
- 计算 VaR → 用历史模拟法或参数法算出结果
- 结果写回 Redis → 设置过期时间 5 分钟
- 展示层轮询 → 每隔 2 秒检查 Redis 是否有结果,有就展示
你看,这样设计,用户点击后页面不会卡死。后台慢慢算,前台优雅等待。
核心要点:异步 + 缓存,是这套架构的灵魂。计算层不阻塞展示层,展示层不等待计算层。
2.6 避坑指南
最后,分享几个我踩过的坑。
- Redis 内存爆炸:缓存数据一定要设置过期时间。我见过有人把全量历史数据塞 Redis,结果 16G 内存两天就满了。
- MySQL 连接泄漏:每次查询后记得关闭连接。用 with 语句或者连接池。
- Flask 跨域问题:前后端分离时,别忘了配置 CORS。不然前端调接口会报错。
好了,第二章就到这里。架构设计是地基,地基稳了,后面写代码才踏实。
公众号:蓝海资料掘金营,微信deep3321