上一篇我们介绍了整个系统的功能概览,这一篇来聊聊架构设计。一个好的架构,是系统稳定运行的基石。
架构设计的核心挑战
在开始设计之前,我们先明确几个核心挑战:
1. 数据量大
沪深A股 5000+ 只股票
每只股票 5年日K线 ≈ 1200条记录
总数据量:5000 × 1200 = 600万条(仅日K线)
还有分钟K线、财务数据、资金流向...
2. 实时性要求高
行情延迟要控制在 3秒 以内
用户操作要有即时反馈
预警触发要及时推送
3. 计算密集
技术指标计算(MACD/KDJ/RSI)
多条件选股筛选
策略回测模拟
4. 并发访问
多用户同时查看行情
多用户同时执行选股
WebSocket长连接维护
️ 整体架构设计
基于以上挑战,我设计了如下分层架构:
┌─────────────────────────────────────────────────────────────────────┐
│ 用户层(Client Layer) │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ PC Web端 │ │ 移动端 App │ │ Tablet端 │ │
│ │ (Vue3 + AntD) │ │ (Vue3 + Vant) │ │ (响应式布局) │ │
│ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │
│ │ │ │ │
│ └──────────────────────┼───────────────────────┘ │
│ │ │
└──────────────────────────────────┼─────────────────────────────────┘
│
HTTP/HTTPS + WebSocket
│
┌──────────────────────────────────┼─────────────────────────────────┐
│ 接入层(Gateway Layer) │
├──────────────────────────────────┼─────────────────────────────────┤
│ │ │
│ ┌────────▼────────┐ │
│ │ Nginx 反向代理 │ │
│ │ 负载均衡 + SSL │ │
│ └────────┬────────┘ │
│ │ │
└──────────────────────────────────┼─────────────────────────────────┘
│
┌──────────────────────────────────┼─────────────────────────────────┐
│ 应用层(Application Layer) │
├──────────────────────────────────┼─────────────────────────────────┤
│ │ │
│ ┌───────────────────────────────▼───────────────────────────┐ │
│ │ FastAPI 应用服务(Python) │ │
│ ├─────────────────────────────────────────────────────────────┤ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ 行情模块 │ │ 分析模块 │ │ 策略模块 │ │ 预警模块 │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │用户管理 │ │数据导出 │ │WebSocket │ │API限流 │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
│
┌──────────────────────────┼──────────────────────────┐
│ │ │
┌───────▼───────┐ ┌─────────▼────────┐ ┌─────────▼─────────┐
│ 业务逻辑层 │ │ 数据处理层 │ │ 任务调度层 │
│ (Service) │ │ (Data Process) │ │ (Celery) │
├───────────────┤ ├──────────────────┤ ├───────────────────┤
│ │ │ │ │ │
│ ┌───────────┐ │ │ ┌──────────────┐ │ │ ┌───────────────┐ │
│ │行情服务 │ │ │ │数据采集服务 │ │ │ │数据更新任务 │ │
│ │分析服务 │ │◄───────┤ │清洗转换服务 │ │◄─────┤ │回测任务 │ │
│ │选股服务 │ │ │ │指标计算服务 │ │ │ │预警监控任务 │ │
│ │回测服务 │ │ │ └──────────────┘ │ │ │定时任务 │ │
│ │预警服务 │ │ │ │ │ └───────────────┘ │
│ └───────────┘ │ │ ┌──────────────┐ │ │ │
│ │ │ │外部数据接口 │ │ │ ┌───────────────┐ │
│ │ │ │ - Tushare │ │ │ │Celery Beat │ │
│ │ │ │ - AKShare │ │ │ │(定时调度器) │ │
│ │ │ └──────────────┘ │ │ └───────────────┘ │
└───────────────┘ └──────────────────┘ └───────────────────┘
│ │ │
└──────────────────────────┼──────────────────────────┘
│
┌──────────────────────────────────┼─────────────────────────────────┐
│ 数据层(Data Layer) │
├──────────────────────────────────┼─────────────────────────────────┤
│ │ │
│ ┌─────────────────────┐ ┌─────▼──────────┐ ┌────────────────┐ │
│ │ PostgreSQL │ │ Redis │ │ 文件存储 │ │
│ │ (关系型数据库) │ │ (缓存+队列) │ │ (导出文件) │ │
│ ├─────────────────────┤ ├────────────────┤ ├────────────────┤ │
│ │ - 用户数据 │ │ - 行情缓存 │ │ - Excel导出 │ │
│ │ - 股票基础信息 │ │ - 会话管理 │ │ - 回测报告 │ │
│ │ - 财务数据 │ │ - 任务队列 │ │ - 日志文件 │ │
│ │ - 策略配置 │ │ - 计算结果缓存 │ │ │ │
│ │ - 预警配置 │ │ - WebSocket会话│ │ │ │
│ │ - 日K线数据 │ │ │ │ │ │
│ └─────────────────────┘ └────────────────┘ └────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
各层职责详解
1️⃣ 用户层(Client Layer)
技术选型:Vue 3 + TypeScript + Ant Design Vue
// 前端项目结构
frontend/
├── src/
│ ├── views/ # 页面视图
│ │ ├── market/ # 行情模块
│ │ ├── analysis/ # 分析模块
│ │ ├── strategy/ # 策略模块
│ │ └── alert/ # 预警模块
│ ├── components/ # 通用组件
│ │ ├── charts/ # 图表组件(K线图等)
│ │ └── common/ # 公共组件
│ ├── stores/ # Pinia状态管理
│ ├── api/ # API接口封装
│ └── utils/ # 工具函数
为什么选择 Vue 3?
特性 | 优势 |
|---|---|
Composition API | 逻辑复用更方便,代码组织更清晰 |
响应式系统 | 自动追踪依赖,数据变化自动更新UI |
TypeScript支持 | 类型安全,IDE提示友好 |
生态丰富 | Ant Design Vue、ECharts等组件库成熟 |
2️⃣ 接入层(Gateway Layer)
技术选型:Nginx
# nginx.conf 核心配置
upstream backend {
server backend:8000;
}
server {
listen 80;
server_name localhost;
# 前端静态资源
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
}
# API代理
location /api/ {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# WebSocket代理
location /ws/ {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
Nginx的作用:
反向代理:统一入口,隐藏后端服务
负载均衡:支持多实例部署
静态资源服务:高效分发前端文件
SSL终结:HTTPS加密
3️⃣ 应用层(Application Layer)
技术选型:FastAPI
# 后端项目结构
backend/
├── app/
│ ├── api/v1/ # API路由
│ │ ├── market.py # 行情接口
│ │ ├── capital_flow_selector.py # 资金流向选股
│ │ ├── screener.py # 选股接口
│ │ ├── backtest.py # 回测接口
│ │ └── alert.py # 预警接口
│ ├── services/ # 业务逻辑
│ │ ├── capital_flow_selector.py
│ │ ├── momentum_stock_selector.py
│ │ └── backtest.py
│ ├── models/ # 数据模型
│ ├── core/ # 核心配置
│ └── websocket/ # WebSocket处理
为什么选择 FastAPI?
# FastAPI 示例:自动生成API文档
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
app = FastAPI(title="A股分析系统API", version="1.0.0")
classStockQuery(BaseModel):
stock_code: str
start_date: str
end_date: str
@app.post("/api/v1/market/kline")
asyncdefget_kline(query: StockQuery):
"""
获取K线数据
- **stock_code**: 股票代码,如 000001.SZ
- **start_date**: 开始日期,格式 YYYYMMDD
- **end_date**: 结束日期,格式 YYYYMMDD
"""
# 业务逻辑...
return {"data": [...]}
特性 | 优势 |
|---|---|
异步支持 | 原生async/await,高并发性能好 |
自动文档 | Swagger UI自动生成,方便调试 |
类型校验 | Pydantic自动校验请求参数 |
WebSocket | 原生支持,无需额外插件 |
4️⃣ 数据层(Data Layer)
PostgreSQL - 主数据库
-- 核心表结构示例
CREATETABLE stock_daily (
idSERIAL PRIMARY KEY,
stock_code VARCHAR(20) NOT,
trade_date DATENOT,
openDECIMAL(10,2),
highDECIMAL(10,2),
lowDECIMAL(10,2),
closeDECIMAL(10,2),
volume BIGINT,
amount DECIMAL(20,2),
turnover_rate DECIMAL(10,4),
pe_ratio DECIMAL(10,2),
pb_ratio DECIMAL(10,2),
total_mv DECIMAL(20,2),
circ_mv DECIMAL(20,2),
created_at TIMESTAMPDEFAULTCURRENT_TIMESTAMP
);
-- 关键索引:加速查询
CREATEINDEX idx_stock_date ON stock_daily(stock_code, trade_date DESC);
CREATEINDEX idx_trade_date ON stock_daily(trade_date);
Redis - 缓存层
# 缓存策略示例
import redis
import json
redis_client = redis.Redis(host='localhost', port=6379, db=0)
defget_realtime_quote(stock_code: str):
"""获取实时行情(带缓存)"""
cache_key = f"quote:{stock_code}"
# 1. 先查缓存
cached = redis_client.get(cache_key)
if cached:
return json.loads(cached)
# 2. 缓存未命中,查数据源
data = fetch_from_tushare(stock_code)
# 3. 写入缓存,3秒过期
redis_client.setex(cache_key, 3, json.dumps(data))
return data
数据流设计
实时行情数据流
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ Tushare │────▶│ Celery │────▶│ Redis │────▶│ WebSocket│
│ 数据源 │ │ 定时任务 │ │ 缓存 │ │ 推送 │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
│ │
│ ▼
│ ┌──────────┐
└───────────────────────────▶│ 前端 │
写入PostgreSQL持久化 │ 展示 │
└──────────┘
流程说明:
Celery定时任务每3秒从Tushare拉取最新行情
数据写入Redis缓存(3秒过期)
同时写入PostgreSQL持久化存储
WebSocket服务监听Redis变化,推送给订阅用户
前端实时更新UI
选股请求数据流
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ 前端 │────▶│ FastAPI │────▶│ Service │────▶│PostgreSQL│
│ 请求 │ │ API │ │ 业务逻辑 │ │ 查询 │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
│
▼
┌──────────┐
│ Redis │
│ 结果缓存 │
└──────────┘
WebSocket实时推送架构
# WebSocket连接管理器
classConnectionManager:
def__init__(self):
# 连接池:{user_id: {websocket1, websocket2}}
self.active_connections: Dict[str, Set[WebSocket]] = {}
# 订阅关系:{stock_code: {user_id1, user_id2}}
self.subscriptions: Dict[str, Set[str]] = {}
asyncdefconnect(self, websocket: WebSocket, user_id: str):
"""用户连接"""
await websocket.accept
if user_id notin self.active_connections:
self.active_connections[user_id] = set
self.active_connections[user_id].add(websocket)
asyncdefsubscribe(self, user_id: str, stock_codes: list):
"""订阅股票"""
for code in stock_codes:
if code notin self.subscriptions:
self.subscriptions[code] = set
self.subscriptions[code].add(user_id)
asyncdefbroadcast_quote(self, stock_code: str, data: dict):
"""推送行情"""
if stock_code in self.subscriptions:
for user_id in self.subscriptions[stock_code]:
for ws in self.active_connections.get(user_id, []):
await ws.send_json({
"type": "quote",
"code": stock_code,
"data": data
})
架构图:
数据源更新
│
▼
┌────────────┐
│ 数据采集 │ ◄────── Celery定时任务(每3秒)
└─────┬──────┘
│
▼
┌────────────┐
│ Redis发布 │ ────── Pub/Sub模式
└─────┬──────┘
│
▼
┌────────────────────┐
│ WebSocket Server │
│ (FastAPI) │
├────────────────────┤
│ 连接管理器 │
│ - 用户连接池 │
│ - 订阅关系维护 │
│ - 心跳检测 │
└─────┬──────────────┘
│
├──────┬──────┬──────┐
│ │ │ │
▼ ▼ ▼ ▼
[User1] [User2] [User3] [User N]
│ │ │ │
订阅: 订阅: 订阅: 订阅:
600519 000001 601318 全市场
000858 600036
⚡ 性能优化策略
1. 数据库查询优化
# ❌ 错误示例:N+1查询问题
for code in stock_codes:
data = db.query(StockDaily).filter(
StockDaily.stock_code == code
).all
# ✅ 正确示例:批量查询
data = db.query(StockDaily).filter(
StockDaily.stock_code.in_(stock_codes),
StockDaily.trade_date == date
).all
2. 缓存策略
数据类型 | 缓存时间 | 说明 |
|---|---|---|
实时行情 | 3秒 | 保证实时性 |
日K线 | 1天 | 收盘后不变 |
股票列表 | 1小时 | 变化频率低 |
选股结果 | 5分钟 | 相同条件复用 |
3. 异步任务
# 耗时操作放入Celery异步执行
@celery_app.task
defrun_backtest(strategy_id: str, params: dict):
"""异步执行回测任务"""
# 1. 加载历史数据
# 2. 执行策略回测
# 3. 计算收益指标
# 4. 保存结果
return result
项目目录结构
trading_system/
├── frontend/ # 前端项目
│ ├── src/
│ │ ├── views/ # 页面视图
│ │ ├── components/ # 组件
│ │ ├── stores/ # 状态管理
│ │ ├── api/ # API接口
│ │ └── utils/ # 工具函数
│ └── package.json
│
├── backend/ # 后端项目
│ ├── app/
│ │ ├── api/v1/ # API路由
│ │ ├── services/ # 业务逻辑
│ │ ├── models/ # 数据模型
│ │ ├── tasks/ # Celery任务
│ │ └── websocket/ # WebSocket
│ └── requirements.txt
│
├── docker-compose.yml # Docker编排
├── nginx.conf # Nginx配置
└── README.md
架构设计原则
在设计这个系统时,我遵循了以下原则:
1. 分层清晰
每层只关注自己的职责
层与层之间通过接口通信
便于独立开发和测试
2. 松耦合
前后端分离,独立部署
服务之间通过消息队列解耦
数据源可替换(Tushare/AKShare)
3. 可扩展
新增功能只需添加新模块
支持水平扩展(多实例部署)
预留了AI分析等扩展接口
4. 高可用
Redis缓存降低数据库压力
Celery异步处理耗时任务
完善的错误处理和日志
总结
本文介绍了A股分析系统的整体架构设计:
层级 | 技术选型 | 核心职责 |
|---|---|---|
用户层 | Vue 3 + AntD | 界面展示、用户交互 |
接入层
| Nginx | 反向代理、负载均衡 |
应用层 | FastAPI | API服务、WebSocket |
业务层 | Python Services | 核心业务逻辑 |
数据层 | PostgreSQL + Redis | 数据存储、缓存 |
任务层 | Celery | 异步任务、定时调度 |
下期预告: 《10分钟用Docker启动整个系统》
我会手把手教你:
Docker环境准备
一键启动所有服务
Tushare Token配置
常见问题解决
有问题欢迎留言讨论
