Files
sanguo_vnpy/docs/06-nas-infrastructure.md
T
2026-05-03 12:40:13 +08:00

663 lines
25 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 06 - NAS 基础设施部署全纪录
**版本**: v1.0
**日期**: 2026-05-03
**作者**: 姜维(平台总督)
---
## 1. 概述
本文档记录 sanguo_vnpy 项目在群晖 NAS192.168.2.154)上的完整部署方案,包括需求、设计、构建、部署、测试、运维全流程,以及历史踩坑记录。
---
## 2. 需求定义
### 2.1 基础设施需求
| 编号 | 需求 | 优先级 | 状态 |
|------|------|--------|------|
| INF-001 | NAS Docker 容器化部署 vnpy 环境 | P0 | ✅ |
| INF-002 | 回测服务 API 化(HTTP 接口) | P0 | ✅ |
| INF-003 | Jupyter Lab 开发环境 | P1 | ✅ |
| INF-004 | SSH 运维通道 | P1 | ✅ |
| INF-005 | 数据自动增量更新 | P1 | ✅ |
| INF-006 | 容器异常自动重启 | P1 | ✅ |
| INF-007 | VS Code Server Web IDE | P2 | ❌ 跳过(网络问题) |
### 2.2 硬件环境
| 项目 | 规格 |
|------|------|
| NAS 型号 | 群晖 DS220+ |
| NAS IP | 192.168.2.154 |
| CPU 架构 | x86_64 |
| 内核版本 | Linux 3.10.108(重要:影响 SSH 选型) |
| Docker | 群晖套件 Docker 20.x |
| 存储路径 | `/volume1/stock/` |
### 2.3 网络拓扑
```
Mac Mini (192.168.2.153) 群晖 NAS (192.168.2.154)
┌──────────────────────┐ ┌─────────────────────────────────────┐
│ OpenClaw Gateway │ │ Docker: sanguo_vnpy 容器 │
│ 开发机/调度中心 │ 局域网 │ ┌─ Jupyter Lab (8888) │
│ │◄──────────────►│ ├─ 回测服务 (8088) │
│ /Volumes/stock/ │ SMB 挂载 │ ├─ SSH/dropbear (22→2222) │
│ (NAS SMB 挂载) │◄──────────────►│ └─ WebTrader (8000) 预留 │
└──────────────────────┘ │ │
│ 数据库: quant_trading.db (1.4GB) │
│ 原始数据: /volume1/stock/A股数据/ │
└─────────────────────────────────────┘
```
---
## 3. 详细设计
### 3.1 Docker 镜像设计
#### 3.1.1 镜像分层策略
```
镜像: sanguo_vnpy:with-scripts (4.08GB)
┌─────────────────────────────────────────┐
│ Layer 1: python:3.10-slim (基础镜像) │ ← 永不重构建
├─────────────────────────────────────────┤
│ Layer 2: 系统工具 (git/curl/vim/sudo等) │ ← 极少重构建
├─────────────────────────────────────────┤
│ Layer 3: 编译工具链 (build-essential) │ ← 极少重构建
├─────────────────────────────────────────┤
│ Layer 4: 图形库 + OpenSSH │ ← 极少重构建
├─────────────────────────────────────────┤
│ Layer 5: pip 基础依赖 (vnpy/numpy等) │ ← 低频变更
│ requirements-base.txt │
├─────────────────────────────────────────┤
│ Layer 6: pip 额外依赖 (akshare等) │ ← 可能变更
│ requirements-extra.txt │
├─────────────────────────────────────────┤
│ Layer 7: 用户配置 + scripts 拷贝 │ ← 每次构建
└─────────────────────────────────────────┘
```
**关键原则**
- 分层构建利用 Docker 缓存,修改额外依赖不需要重装 vnpy/numpy
- `with-scripts` 镜像在 `latest` 基础上增加了 `/app/scripts/backtest_service/` 目录
- **禁止随意重构建镜像**,优先通过 volume 挂载更新代码
#### 3.1.2 当前镜像版本
| 镜像 | 大小 | 构建时间 | 说明 |
|------|------|----------|------|
| `sanguo_vnpy:latest` | 4.08GB | 2026-04-11 | 基础镜像(无回测服务代码) |
| `sanguo_vnpy:with-scripts` | 4.08GB | 2026-04-28 | 含回测服务代码(**当前使用**) |
### 3.2 容器运行设计
#### 3.2.1 容器启动参数
```bash
docker run -d \
--name sanguo_vnpy \
--restart unless-stopped \
--privileged \
-p 2222:22 \
-p 8000:8000 \
-p 8088:8088 \
-p 8888:8888 \
-v /volume1/stock/sanguo_vnpy/bt-service:/app/scripts/backtest_service:ro \
-v /volume1/stock/sanguo_vnpy/entrypoint.sh:/app/entrypoint.sh:ro \
sanguo_vnpy:with-scripts
```
**参数说明**
| 参数 | 说明 | 选型理由 |
|------|------|----------|
| `--restart unless-stopped` | 异常自动重启 | NAS 重启后自动恢复服务 |
| `--privileged` | 特权模式 | 群晖内核 3.10 不支持 seccompSSH dropbear 需要特权执行 |
| `-p 2222:22` | SSH 端口映射 | 避免和 NAS 自身 SSH 冲突 |
| `-v bt-service:ro` | 回测服务代码挂载 | 代码更新不需要重建镜像 |
| `-v entrypoint.sh:ro` | 启动脚本挂载 | 配置变更不需要重建镜像 |
#### 3.2.2 Volume 挂载设计
| NAS 路径 | 容器路径 | 权限 | 用途 |
|----------|----------|------|------|
| `/volume1/stock/sanguo_vnpy/bt-service/` | `/app/scripts/backtest_service/` | ro | 回测服务代码 |
| `/volume1/stock/sanguo_vnpy/entrypoint.sh` | `/app/entrypoint.sh` | ro | 容器启动脚本 |
**设计理由**:代码通过 volume 挂载(非 commit),修改后 `docker restart` 即生效,无需重建镜像。
#### 3.2.3 端口映射
| 容器端口 | NAS 端口 | 服务 | 状态 |
|----------|----------|------|------|
| 22 | 2222 | SSH (dropbear) | ✅ 运行 |
| 8000 | 8000 | WebTrader (预留) | — |
| 8088 | 8088 | 回测 API (uvicorn) | ✅ 运行 |
| 8888 | 8888 | Jupyter Lab | ✅ 运行 |
### 3.3 服务启动流程(entrypoint.sh
```bash
entrypoint.sh 执行顺序:
1. pip3 install vnpy_ctastrategy vnpy_sqlite # 运行时依赖(容器层无持久化)
2. apt-get install dropbear-bin # SSH 替代方案
3. 生成 SSH host keys + 配置 dropbear # SSH 服务启动
4. jupyter lab & # Jupyter 开发环境
5. uvicorn backtest_service.main:app & # 回测 API 服务
6. 健康检查 # 验证服务就绪
7. tail -f /dev/null # 保持容器运行
```
**注意事项**
- pip 包安装在容器可写层,容器重启后丢失,每次启动自动重装
- dropbear 在 entrypoint 中自动安装,无需包含在镜像中
- 回测服务代码通过 volume 挂载,代码更新 `docker restart` 即生效
### 3.4 数据层设计
#### 3.4.1 数据目录结构(NAS
```
/volume1/stock/
├── A股数据/
│ ├── 日线数据/daily/
│ │ ├── 2010/ # 按年份组织,每年 ~5000+ parquet 文件
│ │ ├── 2011/
│ │ └── ... /2026/
│ ├── 分钟线数据/
│ ├── 财务数据/financial/
│ └── stock_info/ # 股票基础信息 CSV/JSON
├── sanguo_vnpy/
│ ├── data/
│ │ ├── quant_trading.db # vnpy 交易数据库 (1.4GB)
│ │ ├── quant_trading.db.bak # 备份
│ │ └── all_stocks.csv # 股票列表
│ ├── bt-service/ # 回测服务代码 (volume 挂载)
│ ├── entrypoint.sh # 容器启动脚本 (volume 挂载)
│ ├── docker/ # Dockerfile + requirements
│ ├── scripts/ # 工具脚本
│ ├── strategies/ # 策略代码
│ └── config/ # 配置文件
├── 回测结果/ # 回测产出
├── 代码库/ # 代码归档
└── 临时文件/
```
#### 3.4.2 vnpy 交易数据库
| 项目 | 详情 |
|------|------|
| 文件 | `quant_trading.db`SQLite |
| 大小 | 1.4 GB |
| 位置 | `/volume1/stock/sanguo_vnpy/data/` |
| 表 | `dbbardata`K线数据)、`dbbaroverview`5191条概览) |
| 数据类型 | 日线(interval=d |
| 时间范围 | 2010-01-04 ~ 2026-03-27 |
| 覆盖股票 | 5191 只(SSE + SZSE 全 A 股) |
#### 3.4.3 数据增量更新
```
Mac Mini cron (每交易日 15:30)
→ daily_update.sh
→ 检查 NAS SMB 是否挂载
→ updater.py(腾讯 K 线 API → DB 增量写入)
→ 清理 30 天前日志
```
- **数据源**:腾讯 K 线 API(主源)
- **写入方式**:Mac 本机通过 SMB 直接读写 NAS 上的 DB 文件
- **兜底**:NAS 未挂载时脚本检测到后跳过,不会损坏数据
- **待改进**:改为容器内 API 触发,避免 SMB 依赖
---
## 4. 构建指南
### 4.1 构建基础镜像(极少执行)
```bash
# 在 NAS 上执行
cd /volume1/stock/sanguo_vnpy
# 基础镜像
docker build -t sanguo_vnpy:latest -f docker/Dockerfile .
# 含回测代码的镜像(推荐)
# 在 Dockerfile 构建后,将 bt-service 目录拷入镜像
docker build -t sanguo_vnpy:with-scripts -f docker/Dockerfile .
```
**⚠️ 纪律**:非必要不构建。代码更新走 volume 挂载 + `docker restart`
### 4.2 依赖管理
| 文件 | 内容 | 变更频率 |
|------|------|----------|
| `requirements-base.txt` | vnpy, numpy, pandas, scipy, matplotlib, sklearn | 低 |
| `requirements-extra.txt` | akshare, tushare, debugpy, ipywidgets | 中 |
| entrypoint.sh `pip install` | vnpy_ctastrategy, vnpy_sqlite | 每次启动 |
---
## 5. 部署指南
### 5.1 首次部署
```bash
# 1. 确保 NAS SSH 可用
ssh admin@192.168.2.154
# 2. 确认镜像存在
/usr/local/bin/docker images sanguo_vnpy
# 3. 启动容器
/usr/local/bin/docker run -d \
--name sanguo_vnpy \
--restart unless-stopped \
--privileged \
-p 2222:22 \
-p 8000:8000 \
-p 8088:8088 \
-p 8888:8888 \
-v /volume1/stock/sanguo_vnpy/bt-service:/app/scripts/backtest_service:ro \
-v /volume1/stock/sanguo_vnpy/entrypoint.sh:/app/entrypoint.sh:ro \
sanguo_vnpy:with-scripts
# 4. 等待启动完成(约 40 秒,pip install 需要时间)
sleep 40
# 5. 验证
curl http://192.168.2.154:8088/api/backtest/health
sshpass -p sanguo123 ssh -p 2222 vnpy@192.168.2.154 "echo OK"
```
### 5.2 代码更新(不需要重建镜像)
```bash
# 1. 修改 NAS 上的代码(通过 SMB 挂载)
# /Volumes/stock/sanguo_vnpy/bt-service/ 下的文件
# 2. 重启容器
ssh admin@192.168.2.154 "/usr/local/bin/docker restart sanguo_vnpy"
# 3. 等待启动完成
sleep 40
# 4. 验证
curl http://192.168.2.154:8088/api/backtest/health
```
### 5.3 完全重建容器
当需要修改容器启动参数(端口、volume、安全选项)时:
```bash
ssh admin@192.168.2.154 "/usr/local/bin/docker stop sanguo_vnpy && \
/usr/local/bin/docker rm sanguo_vnpy && \
/usr/local/bin/docker run -d \
--name sanguo_vnpy \
--restart unless-stopped \
--privileged \
-p 2222:22 -p 8000:8000 -p 8088:8088 -p 8888:8888 \
-v /volume1/stock/sanguo_vnpy/bt-service:/app/scripts/backtest_service:ro \
-v /volume1/stock/sanguo_vnpy/entrypoint.sh:/app/entrypoint.sh:ro \
sanguo_vnpy:with-scripts"
```
**注意**:重建容器会丢失容器内 `/app/backtest_jobs/` 的历史任务数据(如有)。
---
## 6. 测试验证
### 6.1 服务健康检查
```bash
# 回测服务
curl http://192.168.2.154:8088/api/backtest/health
# 预期: {"code":0,"msg":"ok","data":{...}}
# Jupyter Lab
curl -s -o /dev/null -w "%{http_code}" http://192.168.2.154:8888/
# 预期: 302
# SSH
sshpass -p sanguo123 ssh -o StrictHostKeyChecking=no -p 2222 vnpy@192.168.2.154 "echo OK"
# 预期: OK
# Swagger 文档
curl -s -o /dev/null -w "%{http_code}" http://192.168.2.154:8088/docs
# 预期: 200
```
### 6.2 容器重启自动恢复测试
```bash
# 重启容器
ssh admin@192.168.2.154 "/usr/local/bin/docker restart sanguo_vnpy"
sleep 40
# 验证所有服务
curl http://192.168.2.154:8088/api/backtest/health
sshpass -p sanguo123 ssh -p 2222 vnpy@192.168.2.154 "echo OK"
```
### 6.3 回测功能测试
```bash
curl -X POST http://192.168.2.154:8088/api/backtest/submit \
-H "Content-Type: application/json" \
-d '{
"strategy_name": "test_ma",
"strategy_code": "from vnpy_ctastrategy import CtaTemplate\n\nclass TestMA(CtaTemplate):\n fast_window = 5\n slow_window = 20\n parameters = [\"fast_window\", \"slow_window\"]\n variables = []\n def on_init(self): pass\n def on_start(self): pass\n def on_stop(self): pass\n def on_bar(self, bar): pass",
"symbol": "000001.SZSE",
"interval": "d",
"start_date": "2025-01-01",
"end_date": "2025-12-31",
"capital": 1000000,
"engine_type": "cta"
}'
```
---
## 7. 服务地址汇总
### 7.1 用户访问地址
| 服务 | 地址 | 账号 | 说明 |
|------|------|------|------|
| **Jupyter Lab** | `http://192.168.2.154:8888` | token: `sanguo123` | Python 开发环境 |
| **回测 API** | `http://192.168.2.154:8088` | — | 回测任务提交/查询 |
| **回测文档** | `http://192.168.2.154:8088/docs` | — | Swagger 交互式文档 |
| **SSH** | `ssh -p 2222 vnpy@192.168.2.154` | vnpy / `sanguo123` | 运维通道(dropbear |
### 7.2 管理命令(在 NAS 上执行)
```bash
# 查看容器状态
/usr/local/bin/docker ps | grep sanguo_vnpy
# 查看容器日志
/usr/local/bin/docker logs sanguo_vnpy --tail 50
# 重启容器
/usr/local/bin/docker restart sanguo_vnpy
# 进入容器
/usr/local/bin/docker exec -it sanguo_vnpy bash
# 查看容器内进程
/usr/local/bin/docker exec sanguo_vnpy ps aux
```
### 7.3 Mac 端访问命令
```bash
# SSH 连接
sshpass -p sanguo123 ssh -p 2222 vnpy@192.168.2.154
# 回测健康检查
curl http://192.168.2.154:8088/api/backtest/health
# NAS Docker 管理(通过 admin SSH
ssh admin@192.168.2.154 "/usr/local/bin/docker ps"
```
---
## 8. 运维手册
### 8.1 日常巡检
```bash
# 一键检查所有服务
echo "=== 回测 ===" && curl -s http://192.168.2.154:8088/api/backtest/health && \
echo "" && echo "=== Jupyter ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://192.168.2.154:8888/ && \
echo "" && echo "=== SSH ===" && sshpass -p sanguo123 ssh -o ConnectTimeout=3 -o StrictHostKeyChecking=no -p 2222 vnpy@192.168.2.154 "echo OK" 2>&1
```
### 8.2 故障排查
| 症状 | 检查方法 | 可能原因 | 解决方案 |
|------|----------|----------|----------|
| API 无响应 | `curl :8088/health` | uvicorn 未启动或已挂 | `docker restart` |
| SSH 连接被拒 | `ssh -p 2222 vnpy@NAS` | dropbear 未启动 | `docker exec -u root sanguo_vnpy bash -c 'dropbear -R -B -p 22'` |
| 容器未运行 | `docker ps` | NAS 重启或异常 | `docker start sanguo_vnpy` |
| pip 安装超时 | 查看容器日志 | NAS 网络问题 | 等待网络恢复后 restart |
| 数据更新失败 | `cat /Volumes/stock/.../logs/cron.log` | NAS SMB 未挂载 | 手动挂载后重跑 |
### 8.3 数据备份
```bash
# vnpy DB 备份
cp /Volumes/stock/sanguo_vnpy/data/quant_trading.db \
/Volumes/stock/sanguo_vnpy/data/quant_trading.db.bak.$(date +%Y%m%d)
```
---
## 9. 历史 Q&A 与踩坑记录
### Q1: SSH 为什么不能用 OpenSSH,要用 dropbear
**问题现象**SSH 连接返回 `Connection closed``Connection reset`,反复修过多次,每次重建容器就复发。
**排查过程**
```
ssh -vvv → "kex_exchange_identification: banner line 0: Not allowed at this time"
→ 以为是 PAM 问题 → 关闭 UsePAM → 还是挂
sshd -ddd → "ssh_sandbox_child: prctl(PR_SET_SECCOMP): Invalid argument"
→ mm_reap: preauth child terminated by signal 25
```
**根因**:群晖 NAS 内核版本 3.10.108,不支持 `prctl(PR_SET_SECCOMP)` 系统调用。OpenSSH 10.0 的 `sshd-auth` 子进程硬编码使用 seccomp-bpf sandbox,在认证阶段调用 `prctl(PR_SET_SECCOMP)` 失败(`EINVAL`),preauth 子进程被信号 25 杀死。
**尝试过的方案**
1. ❌ 创建 `/var/run/utmp` — 只修了 symptom,不解决 sandbox
2. ❌ 创建 sshd 系统用户 — 解决了 `Privilege separation user does not exist`,但 sandbox 还是挂
3. ❌ 关闭 `UsePAM` — 和 sandbox 无关
4.`--security-opt seccomp=unconfined` — 这是 Docker 层的 seccomp,和 OpenSSH 内部的 seccomp-bpf 无关
5.**dropbear 替代 OpenSSH** — dropbear 不使用 seccomp sandbox,完美兼容
**最终方案**:用 `dropbear-bin` 替代 `openssh-server`,在 entrypoint.sh 中自动安装和配置。
---
### Q2: Mac 本地有一个同名废弃容器,和 NAS 容器混淆了
**问题现象**Mac 上 `docker ps` 显示 sanguo_vnpy 运行 3 周,但容器内找不到回测服务。
**根因**Mac 本地的 Docker Desktop 也运行了一个 `sanguo_vnpy` 容器(旧的 `latest` 镜像),和 NAS 上的 `with-scripts` 容器同名但完全不同。Mac 的 `docker` 命令操作的是本地 Docker,不是 NAS。
**教训**:检查远程 Docker 时必须通过 SSH 执行:
```bash
ssh admin@192.168.2.154 "/usr/local/bin/docker ps"
# 而不是本地的 docker ps
```
**解决**:清理 Mac 本地废弃容器 `docker stop sanguo_vnpy && docker rm sanguo_vnpy`
---
### Q3: 为什么 entrypoint.sh 里要 pip install 而不是写进镜像?
**问题**vnpy_ctastrategy 和 vnpy_sqlite 没有写进 requirements.txt,而是在 entrypoint.sh 里每次启动时安装。
**原因**
1. 这两个包在构建基础镜像时可能版本不匹配
2. 容器可写层的 pip 包在容器删除后会丢失,但 `docker restart` 不会丢
3. 灵活性:可以随时调整版本而不重建镜像
**代价**:每次容器重建后首次启动多约 30 秒安装时间。
---
### Q4: 为什么有 `latest` 和 `with-scripts` 两个镜像?
**问题**Mac 本地 `sanguo_vnpy:latest` 和 NAS `sanguo_vnpy:with-scripts` 的区别。
**说明**
- `latest`:基础镜像,`/app/scripts/` 里只有 deployment/utils/verify 工具脚本,没有 `backtest_service` 目录
- `with-scripts`:在 `latest` 基础上,将 `scripts/backtest-service/` 拷贝为 `/app/scripts/backtest_service/`,使回测服务可以从镜像内启动
**当前设计**:回测服务代码通过 volume 挂载(`bt-service → /app/scripts/backtest_service`),镜像内是否有已不重要。但 `with-scripts` 镜像确保即使 volume 没挂载,容器内也有基础代码。
---
### Q5: 为什么需要 `--privileged` 模式?
**问题**`--privileged` 安全性较差,为什么不用 `--security-opt seccomp=unconfined`
**尝试过程**
1. 先用 `--security-opt seccomp=unconfined` — 不够,OpenSSH 内部的 seccomp-bpf 不受 Docker seccomp profile 控制
2. 改用 `--privileged` — 解决了所有问题
**风险**`--privileged` 给容器几乎完整的 host 权限。当前容器跑在内网 NAS 上,风险可接受。如果未来有安全需求,可以降级为 `--security-opt seccomp=unconfined` + `--cap-add ALL`,配合 dropbear 使用。
---
### Q6: 回测服务代码在 NAS 上有两份,`bt-service/` 和 `backtest-service-new/`,区别是什么?
**说明**
- `/volume1/stock/sanguo_vnpy/bt-service/`**当前生效的**volume 挂载到容器内使用
- `/volume1/stock/sanguo_vnpy/backtest-service-new/` — 开发/备份目录
- `/volume1/stock/sanguo_vnpy/scripts/backtest-service/` — 镜像内置的旧版
三者内容基本相同,**以 `bt-service/` 为准**。
---
### Q7: 容器内 SSH 的 host keys 每次重启都会变,导致 known_hosts 报错
**原因**:host keys 在容器可写层,容器删除重建后会重新生成。
**解决方案**
1. 首次连接时用 `-o StrictHostKeyChecking=no` 跳过验证
2. 或将 host keys 持久化到 NAS volume(待实现)
---
### Q8: 数据增量更新走 SMB 而非容器 API,有什么问题?
**当前状态**Mac 端 cron 每交易日 15:30 触发 `daily_update.sh → updater.py`,通过 SMB 直接读写 NAS 上的 `quant_trading.db`
**风险**
1. Mac 重启后 SMB 未自动挂载,更新会跳过
2. SMB 读写大文件(1.4GB DB)偶尔有锁文件问题
3. 数据写入绕过了 vnpy 框架的数据接口
**待改进**:改为通过回测服务 API 触发数据更新,或直接在容器内跑 cron。
---
### Q9: Docker 镜像构建时为什么 scripts 目录总是少文件?
**历史问题**2026-04-14):Dockerfile 里 `COPY scripts /app/scripts` 拷贝的是本地仓库的 `scripts/` 目录,而 NAS 上的 `scripts/` 目录和本地不同步。
**根因**:代码仓库(gitee)和 NAS 上的文件不是同一份。Dockerfile 构建时用的是 NAS 上的文件,但 `COPY` 的路径是相对 Dockerfile 的。
**教训**:确保在正确的目录执行 `docker build`,且构建上下文中包含所有需要的文件。
---
### Q10: 为什么 code-server 没有启用?
**原因**Dockerfile 中注释掉了 code-server 安装(网络环境问题),entrypoint.sh 中的 `code-server &` 会静默失败。当前不影响使用,有 Jupyter Lab 足够。
---
## 10. 待改进项
| # | 问题 | 优先级 | 方案 |
|---|------|--------|------|
| 1 | `--privileged` 安全风险 | 低 | 内网环境可接受,未来可降级 |
| 2 | SSH host keys 不持久 | 低 | 挂载 volume 到 `/etc/dropbear/` |
| 3 | 数据更新走 SMB | 中 | 改为容器内 cron 或 API 触发 |
| 4 | NAS SMB 开机无自动挂载 | 中 | Mac 端配置 LaunchDaemon automount |
| 5 | DB 导入非全自动 | 中 | 编写导入脚本自动化 |
| 6 | 分钟线数据不完整 | 中 | 赵云补充分钟线数据导入 |
| 7 | DB 数据只到 2026-03-27 | 高 | cron 可能未持续跑,需检查 |
| 8 | pip 每次启动重装耗时 ~30s | 低 | 可接受,或写入镜像 |
| 9 | dropbear 安装需要 apt 联网 | 低 | 未来可写入镜像 |
---
## 11. 附录
### 11.1 回测服务代码结构(bt-service/
```
bt-service/
├── main.py # FastAPI 应用入口
├── api.py # API 路由定义
├── executor.py # vnpy 回测执行器(核心)
├── models.py # Pydantic 数据模型
├── config.py # 配置管理
├── task_queue.py # 任务队列(线程池)
├── result_storage.py # 结果持久化
└── README.md # 服务说明文档
```
### 11.2 NAS 目录完整结构
```
/volume1/stock/sanguo_vnpy/
├── bt-service/ # 回测服务代码(volume 挂载,当前生效)
├── backtest-service-new/ # 回测服务代码(开发备份)
├── entrypoint.sh # 容器启动脚本(volume 挂载)
├── entrypoint.sh.backup # 旧版启动脚本备份
├── data/
│ ├── quant_trading.db # vnpy 交易数据库(1.4GB
│ ├── quant_trading.db.bak # 备份
│ └── all_stocks.csv # 股票列表
├── docker/
│ ├── Dockerfile # 镜像构建文件
│ ├── entrypoint.sh # 镜像内置启动脚本
│ └── requirements/
│ ├── requirements-base.txt
│ └── requirements-extra.txt
├── scripts/
│ ├── backtest-service/ # 旧版回测服务(镜像内置)
│ ├── deployment/ # 部署脚本
│ ├── utils/ # 工具脚本
│ └── verify/ # 验证脚本
├── strategies/ # 策略代码
├── config/
│ ├── nginx/ # Nginx 配置(预留)
│ └── systemd/ # Systemd 配置(预留)
├── jiangwei-platform/ # 姜维平台脚本
├── pangtong-value/ # 庞统价值策略
├── zhangfei-technical/ # 张飞技术策略
├── vnpy_webtrader/ # Web Trader 项目
├── research/ # 研究资料
├── test/ # 测试代码
├── archives/ # 归档
├── backup/ # 备份
├── logs/ # 日志
└── README-NAS-DEPLOY.md # NAS 部署说明
```
### 11.3 关键环境变量
| 变量 | 值 | 说明 |
|------|-----|------|
| `PYTHONUNBUFFERED` | 1 | Python 输出不缓冲 |
| `PYTHONDONTWRITEBYTECODE` | 1 | 不生成 .pyc |
| `DEBIAN_FRONTEND` | noninteractive | apt 非交互 |
| `TZ` | Asia/Shanghai | 时区 |
---
*三国量化团队 · 姜维(平台总督)*