371 lines
11 KiB
Markdown
371 lines
11 KiB
Markdown
# vn.py Web Trader 实现方式调研报告
|
||
|
||
## 调研结论摘要
|
||
|
||
根据官方设计,vn.py(VeighNa)的Web Trader采用**标准的双进程B-S架构**:
|
||
- **策略交易进程**:运行完整的VeighNa Trader核心(MainEngine、EventEngine、Gateways、Strategies),同时启动RPC服务端
|
||
- **Web服务进程**:运行web_trader模块,基于FastAPI提供REST接口+WebSocket推送,通过RPC客户端与交易进程通信
|
||
|
||
这是官方推荐的正确架构,之前如果走了"单进程整合"或"前后端不分离"的弯路,需要纠正为这种双进程架构。
|
||
|
||
---
|
||
|
||
## 1. 官方Web Trader定位与架构
|
||
|
||
### 1.1 模块定位
|
||
|
||
WebTrader是VeighNa框架针对**B-S(Browser-Server)架构需求**设计的Web服务模块,允许用户通过浏览器(而非PyQt桌面端)来运行管理VeighNa量化策略交易。
|
||
|
||
核心特点:
|
||
- 提供主动函数调用(REST API)
|
||
- 支持被动数据推送(WebSocket)
|
||
- 基于官方RPC模块实现跨进程通信
|
||
|
||
### 1.2 官方架构图
|
||
|
||
根据官方文档描述,整体架构如下:
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ Browser / Web前端 │
|
||
│ (Vue/React/Angular 或 纯HTML前端) │
|
||
└─────────────┬───────────────────────────────────────────────┘
|
||
│ HTTP / WebSocket
|
||
↓
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ Web服务进程 (web_trader模块) │
|
||
│ - FastAPI Web服务器 │
|
||
│ - REST API 处理请求 │
|
||
│ - WebSocket 推送推送数据 │
|
||
│ - RPC 客户端 ←───────────┐ │
|
||
└─────────────┬───────────────┘ │
|
||
│ RPC │
|
||
│ TCP │
|
||
┌─────────────↓─────────────────┐ │
|
||
│ 策略交易进程 (VeighNa Trader) │ │
|
||
│ - MainEngine │ │
|
||
│ - EventEngine │ │
|
||
│ - All Gateways │ │
|
||
│ - All Strategies │ │
|
||
│ - RPC 服务端 ←────────────────┘ │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 1.3 核心技术栈
|
||
|
||
| 层级 | 技术组件 | 作用 |
|
||
|------|---------|------|
|
||
| Web后端 | **FastAPI** | 提供RESTful API接口 |
|
||
| 实时通信 | **WebSocket** | 主动推送行情、成交、状态更新到前端 |
|
||
| 跨进程通信 | **vnpy.rpc** | Web进程 ↔ 交易进程之间的RPC通信 |
|
||
| 身份认证 | **OAuth2 JWT** | Token认证机制 |
|
||
| 前端 | 可选 | 用户可自行选用Vue/React等框架 |
|
||
|
||
---
|
||
|
||
## 2. 常见弯路分析
|
||
|
||
根据调研,常见的错误实现方式:
|
||
|
||
### ❌ 弯路1:单进程一体化架构
|
||
|
||
**错误做法**:
|
||
```
|
||
把FastAPI和MainEngine放在同一个进程中启动,依赖asyncio协程调度
|
||
```
|
||
|
||
**问题**:
|
||
- VeighNa核心是基于多线程事件驱动,与FastAPI的asyncio协程模型冲突
|
||
- 容易出现线程安全问题,事件引擎阻塞Web服务响应
|
||
- 不好做独立扩展,Web进程和交易进程难以分开部署
|
||
- 重启Web服务会中断交易策略
|
||
|
||
### ❌ 弯路2:过度拆分微服务
|
||
|
||
**错误做法**:
|
||
```
|
||
把Gateway、Strategy、Data、Web都拆分成独立服务,引入太多复杂度
|
||
```
|
||
|
||
**问题**:
|
||
- 增加不必要的分布式复杂度(一致性、网络延迟、运维负担)
|
||
- 违背vn.py原生设计理念,难以跟进官方更新
|
||
- 对于中小规模量化团队过度设计
|
||
|
||
### ❌ 弯路3:前端绑定后端耦合
|
||
|
||
**错误做法**:
|
||
```
|
||
用Django/Tornado模板引擎渲染页面,前后端强耦合
|
||
```
|
||
|
||
**问题**:
|
||
- 前端难以独立迭代开发
|
||
- 不支持移动端、APP端复用后端API
|
||
- 不符合现代Web开发最佳实践
|
||
|
||
---
|
||
|
||
## 3. 纠正方案:官方标准双进程架构
|
||
|
||
### 3.1 推荐架构
|
||
|
||
按照官方设计,采用:
|
||
|
||
```
|
||
[进程1] 交易核心进程
|
||
- VeighNa Trader (MainEngine + EventEngine)
|
||
- 所有交易Gateway (CTP/IB等)
|
||
- 所有策略模块
|
||
- RPC Service 服务端
|
||
|
||
[进程2] Web服务进程
|
||
- vnpy_webtrader (FastAPI)
|
||
- REST API 接口
|
||
- WebSocket 推送
|
||
- RPC Client 连接交易进程
|
||
- CORS 支持跨域访问
|
||
|
||
[前端] 独立部署
|
||
- 基于现代前端框架开发
|
||
- 完全独立,通过API调用
|
||
- 可单独部署到CDN
|
||
```
|
||
|
||
### 3.2 启动流程
|
||
|
||
1. **第一步:启动交易核心进程**
|
||
```python
|
||
from vnpy.trader.main_engine import MainEngine
|
||
from vnpy.trader.event_engine import EventEngine
|
||
from vnpy.rpc import RpcServer
|
||
|
||
event_engine = EventEngine()
|
||
main_engine = MainEngine(event_engine)
|
||
|
||
# 添加gateway、策略...
|
||
|
||
# 启动RPC服务端
|
||
rpc_server = RpcServer(main_engine, ("127.0.0.1", 2018))
|
||
rpc_server.start()
|
||
```
|
||
|
||
2. **第二步:启动Web服务进程**
|
||
```python
|
||
from vnpy_webtrader import run_web_trader
|
||
|
||
# RPC连接配置
|
||
rpc_request_address = "tcp://127.0.0.1:2018"
|
||
rpc_subscribe_address = "tcp://127.0.0.1:4102"
|
||
|
||
# 启动Web Trader
|
||
run_web_trader(
|
||
rpc_request_address,
|
||
rpc_subscribe_address,
|
||
host="0.0.0.0",
|
||
port=8000
|
||
)
|
||
```
|
||
|
||
3. **第三步:启动前端**
|
||
- 打包前端静态文件
|
||
- 独立部署到Nginx或CDN
|
||
- 通过反向代理代理API请求到8000端口
|
||
|
||
### 3.3 技术优势
|
||
|
||
| 优势 | 说明 |
|
||
|------|------|
|
||
| **解耦** | Web服务和交易核心分离,互不影响 |
|
||
| **稳定** | Web服务重启不影响交易进程 |
|
||
| **安全** | 交易进程可不暴露公网,只允许Web进程连接 |
|
||
| **可扩展** | 支持一个交易进程配多个Web节点,支持多用户并发 |
|
||
| **符合官方设计** | 易于跟进社区版本更新 |
|
||
|
||
---
|
||
|
||
## 4. 具体实施步骤
|
||
|
||
### 步骤1:环境准备
|
||
|
||
```bash
|
||
# 安装依赖
|
||
pip install vnpy_webtrader
|
||
# 或
|
||
pip install fastapi uvicorn python-jose[cryptography] passlib[bcrypt]
|
||
```
|
||
|
||
### 步骤2:启动交易核心RPC服务
|
||
|
||
创建`start_trading_server.py`:
|
||
|
||
```python
|
||
from vnpy.trader.event_engine import EventEngine
|
||
from vnpy.trader.main_engine import MainEngine
|
||
from vnpy.rpc import RpcServer
|
||
from vnpy_ctp import CtpGateway
|
||
# 其他gateway...
|
||
|
||
def main():
|
||
event_engine = EventEngine()
|
||
main_engine = MainEngine(event_engine)
|
||
|
||
# 添加gateway
|
||
main_engine.add_gateway(CtpGateway)
|
||
# 添加其他gateway...
|
||
|
||
# 添加应用模块
|
||
# main_engine.add_app(CtaStrategy)
|
||
# main_engine.add_app(PortfolioStrategy)
|
||
|
||
# 启动RPC服务
|
||
# 请求端口: 2018,订阅端口: 4102
|
||
rpc_server = RpcServer(
|
||
main_engine,
|
||
("0.0.0.0", 2018),
|
||
("0.0.0.0", 4102)
|
||
)
|
||
rpc_server.start()
|
||
|
||
print(f"RPC服务已启动")
|
||
print(f"- 请求地址: tcp://0.0.0.0:2018")
|
||
print(f"- 订阅地址: tcp://0.0.0.0:4102")
|
||
|
||
# 保持进程运行
|
||
input()
|
||
|
||
if __name__ == "__main__":
|
||
main()
|
||
```
|
||
|
||
### 步骤3:启动Web Trader服务
|
||
|
||
创建`start_web_trader.py`:
|
||
|
||
```python
|
||
from vnpy_webtrader import run_web_trader
|
||
|
||
def main():
|
||
# RPC地址配置
|
||
rpc_request_address = "tcp://127.0.0.1:2018"
|
||
rpc_subscribe_address = "tcp://127.0.0.1:4102"
|
||
|
||
# 启动Web服务
|
||
run_web_trader(
|
||
rpc_request_address,
|
||
rpc_subscribe_address,
|
||
host="0.0.0.0",
|
||
port=8000,
|
||
cors_allow_all=True # 开发环境开启CORS
|
||
)
|
||
|
||
if __name__ == "__main__":
|
||
main()
|
||
```
|
||
|
||
### 步骤4:Nginx配置参考(生产环境)
|
||
|
||
```nginx
|
||
server {
|
||
listen 80;
|
||
server_name your-domain.com;
|
||
|
||
# 前端静态文件
|
||
location / {
|
||
root /path/to/your/frontend/dist;
|
||
try_files $uri $uri/ /index.html;
|
||
}
|
||
|
||
# API反向代理
|
||
location /api {
|
||
proxy_pass http://127.0.0.1:8000;
|
||
proxy_set_header Host $host;
|
||
proxy_set_header X-Real-IP $remote_addr;
|
||
}
|
||
|
||
# WebSocket反向代理
|
||
location /ws {
|
||
proxy_pass http://127.0.0.1:8000;
|
||
proxy_http_version 1.1;
|
||
proxy_set_header Upgrade $http_upgrade;
|
||
proxy_set_header Connection "upgrade";
|
||
proxy_set_header Host $host;
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 已提供API接口概览
|
||
|
||
vnpy_webtrader官方已提供:
|
||
|
||
### REST API
|
||
- `POST /token` - 获取认证token
|
||
- `GET /api/accounts` - 查询账户信息
|
||
- `GET /api/positions` - 查询持仓
|
||
- `GET /api/orders` - 查询订单
|
||
- `POST /api/orders` - 下单
|
||
- `DELETE /api/orders/{orderid}` - 撤单
|
||
- 以及更多...
|
||
|
||
### WebSocket
|
||
- 实时推送成交推送
|
||
- 实时推送订单更新
|
||
- 实时推送账户更新
|
||
- 实时推送持仓更新
|
||
|
||
---
|
||
|
||
## 6. 部署架构建议
|
||
|
||
### 开发环境
|
||
```
|
||
同一台机器:
|
||
- 交易进程 RPC: 127.0.0.1:2018/4102
|
||
- Web进程: 0.0.0.0:8000
|
||
- 前端开发服务器: 端口5173/3000,通过代理访问API
|
||
```
|
||
|
||
### 生产环境
|
||
```
|
||
- 交易进程:仅对内网开放RPC端口
|
||
- Web进程:和交易进程同机或不同机,监听内网8000
|
||
- Nginx:反向代理,暴露HTTPS 443端口
|
||
- 前端:打包后由Nginx直接提供静态文件
|
||
```
|
||
|
||
### 安全建议
|
||
1. **不要直接暴露交易RPC端口到公网**
|
||
2. **只允许Web进程连接交易RPC端口**
|
||
3. **Web服务启用HTTPS**
|
||
4. **强密码存储,使用JWT过期机制**
|
||
|
||
---
|
||
|
||
## 7. 总结纠正方案
|
||
|
||
| 项目 | 纠正前(弯路) | 纠正后(正确) |
|
||
|------|---------------|---------------|
|
||
| 进程模型 | 单进程一体化 | 双进程分离架构 |
|
||
| 通信方式 | 直接函数调用/协程调度 | RPC跨进程通信 |
|
||
| 前后端 | 耦合在一起 | 完全分离独立部署 |
|
||
| 架构复杂度 | 要么太简单,要么过度拆分 | 恰到好处的双进程 |
|
||
| 稳定性 | Web重启影响交易 | Web重启不影响交易 |
|
||
| 安全性 | 交易核心直接暴露 | 分层防护更安全 |
|
||
|
||
---
|
||
|
||
## 下一步行动建议
|
||
|
||
1. 按照双进程架构重构当前Web Trader实现
|
||
2. 基于官方vnpy_webtrader模块进行扩展,不重复造轮子
|
||
3. 前端独立开发,通过REST+WebSocket与后端交互
|
||
4. 先实现基础功能(登录、账户查询、持仓查询、下单撤单)
|
||
5. 逐步扩展支持更多策略模块
|
||
|
||
---
|
||
|
||
*调研完成时间:2026-03-31*
|
||
*调研人:姜维 伯约*
|