Files
sanguo_vnpy/archive/2026-04-29-cleanup/scripts/deployment/sanguo_nas_deploy.sh
T
2026-04-29 20:15:43 +08:00

743 lines
20 KiB
Bash
Executable File
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.
#!/bin/bash
# ============================================
# sanguo_vnpy NAS 全自动部署脚本
# 作者:姜维 伯约
# 日期:2026年3月27日
# ============================================
set -e
# 配置信息
NAS_IP="192.168.2.154"
NAS_USER="cfdaily"
NAS_PASS="Ccf7561523"
NAS_SHARE="stock"
MOUNT_POINT="/Users/chufeng/nas/stock"
WORKSPACE="/Users/chufeng/.openclaw/workspace-jiangwei"
SANGUO_PROJECTS="/Users/chufeng/.openclaw/sanguo_projects"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo ""
echo -e "${BLUE}============================================${NC}"
echo -e "${BLUE} $1${NC}"
echo -e "${BLUE}============================================${NC}"
}
print_header() {
echo ""
echo "╔═══════════════════════════════════════════════════════════╗"
echo "║ sanguo_vnpy NAS 全自动部署方案 ║"
echo "╚═══════════════════════════════════════════════════════════╝"
echo ""
}
# 检查 NAS 挂载
check_nas_mount() {
log_step "步骤 1: 检查 NAS 挂载状态"
if [ ! -d "$MOUNT_POINT" ]; then
log_warn "挂载点不存在,创建中..."
mkdir -p "$MOUNT_POINT"
fi
if mount | grep -q "$MOUNT_POINT"; then
log_info "✅ NAS 已挂载: $MOUNT_POINT"
return 0
else
log_info "正在挂载 NAS..."
# 尝试挂载
NAS_URL="smb://${NAS_USER}:${NAS_PASS}@${NAS_IP}/${NAS_SHARE}"
if /sbin/mount_smbfs "$NAS_URL" "$MOUNT_POINT"; then
log_info "✅ NAS 挂载成功"
return 0
else
log_error "❌ NAS 挂载失败"
log_info "请先运行 NAS 挂载脚本: ./nas_auto_deploy.sh"
return 1
fi
fi
}
# 创建 NAS 目录结构
create_nas_directories() {
log_step "步骤 2: 创建 NAS 目录结构"
cd "$MOUNT_POINT" || exit 1
log_info "创建基础目录结构..."
# 创建必要的基础目录(sanguo_quant_live 会提供大部分结构)
mkdir -p sanguo_vnpy/config
mkdir -p sanguo_vnpy/data/A股数据/日线数据
mkdir -p sanguo_vnpy/data/A股数据/分钟线数据
mkdir -p sanguo_vnpy/data/A股数据/财务数据
mkdir -p sanguo_vnpy/data/回测结果/策略回测
mkdir -p sanguo_vnpy/data/回测结果/性能报告
mkdir -p sanguo_vnpy/notebooks
mkdir -p sanguo_vnpy/projects/sanguo_vnpy_framework
mkdir -p sanguo_vnpy/research/jq_essence_articles
mkdir -p sanguo_vnpy/research/other
mkdir -p sanguo_vnpy/logs
mkdir -p sanguo_vnpy/tests
mkdir -p sanguo_vnpy/scripts
mkdir -p sanguo_vnpy/docker/config
mkdir -p sanguo_vnpy/docker/notebooks
mkdir -p sanguo_vnpy/docker/strategies
mkdir -p sanguo_vnpy/docker/logs
mkdir -p sanguo_vnpy/docker/mysql-data
mkdir -p sanguo_vnpy/docker/redis-data
mkdir -p sanguo_vnpy/docker/pgadmin-data
log_info "✅ 基础目录结构创建完成"
}
# 复制策略文件到 NAS
copy_strategies() {
log_step "步骤 3: 复制所有项目文件到 NAS"
# 创建项目目录
mkdir -p "$MOUNT_POINT/sanguo_vnpy/projects"
# 1. 复制完整的 sanguo_quant_live 项目(核心项目!)
log_info "复制完整的 sanguo_quant_live 项目..."
if [ -d "$SANGUO_PROJECTS/sanguo_quant_live" ]; then
cp -r "$SANGUO_PROJECTS/sanguo_quant_live/"* "$MOUNT_POINT/sanguo_vnpy/" 2>/dev/null || true
log_info "✅ sanguo_quant_live 完整项目已复制"
else
log_warn "sanguo_quant_live 项目未找到,跳过"
fi
# 2. 复制 sanguo_vnpy 量化框架项目
log_info "复制 sanguo_vnpy 量化框架项目..."
if [ -d "$WORKSPACE/vnpy_project" ]; then
cp -r "$WORKSPACE/vnpy_project/"* "$MOUNT_POINT/sanguo_vnpy/projects/sanguo_vnpy_framework/" 2>/dev/null || true
log_info "✅ sanguo_vnpy 框架已复制"
fi
# 3. 复制聚宽精华文章调研
log_info "复制聚宽精华文章调研..."
if [ -d "$WORKSPACE/jq_essence_articles" ]; then
cp -r "$WORKSPACE/jq_essence_articles" "$MOUNT_POINT/sanguo_vnpy/research/" 2>/dev/null || true
log_info "✅ 聚宽精华文章已复制"
fi
# 4. 复制其他重要文档
log_info "复制其他重要文档..."
mkdir -p "$MOUNT_POINT/sanguo_vnpy/research/other"
cp "$WORKSPACE"/*.md "$MOUNT_POINT/sanguo_vnpy/research/other/" 2>/dev/null || true
log_info "✅ 文档文件已复制"
log_info "✅ 所有项目文件复制完成"
}
# 创建 Docker 配置文件
create_docker_configs() {
log_step "步骤 4: 创建 Docker 配置文件"
DOCKER_DIR="$MOUNT_POINT/sanguo_vnpy/docker"
cd "$DOCKER_DIR" || exit 1
log_info "创建 Dockerfile..."
cat > Dockerfile <<'EOF'
FROM python:3.10-slim-bookworm
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
DEBIAN_FRONTEND=noninteractive \
TZ=Asia/Shanghai
WORKDIR /app
RUN apt-get update && apt-get install -y \
--no-install-recommends \
build-essential \
git \
curl \
wget \
vim \
nano \
tzdata \
libgl1-mesa-glx \
libglib2.0-0 \
libsm6 \
libxext6 \
libxrender-dev \
libgomp1 \
sudo \
openssh-server \
&& rm -rf /var/lib/apt/lists/*
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN pip install --no-cache-dir --upgrade pip setuptools wheel
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
RUN curl -fsSL https://code-server.dev/install.sh | sh
RUN useradd -m -u 1000 vnpy && \
echo "vnpy ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers && \
mkdir -p /home/vnpy/.ssh && \
chown -R vnpy:vnpy /home/vnpy /app && \
chmod 700 /home/vnpy/.ssh
RUN sed -i 's/#PasswordAuthentication yes/PasswordAuthentication yes/' /etc/ssh/sshd_config && \
sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin no/' /etc/ssh/sshd_config && \
echo "vnpy:sanguo123" | chpasswd
USER vnpy
RUN mkdir -p /home/vnpy/.config/code-server && \
echo 'bind-addr: 0.0.0.0:8080' > /home/vnpy/.config/code-server/config.yaml && \
echo 'auth: password' >> /home/vnpy/.config/code-server/config.yaml && \
echo 'password: sanguo123' >> /home/vnpy/.config/code-server/config.yaml
EXPOSE 8888 8000 8080 2222
COPY --chown=vnpy:vnpy entrypoint.sh /app/
RUN chmod +x /app/entrypoint.sh
ENTRYPOINT ["/app/entrypoint.sh"]
EOF
log_info "创建 entrypoint.sh..."
cat > entrypoint.sh <<'EOF'
#!/bin/bash
set -e
echo "=========================================="
echo " sanguo_vnpy Docker 容器启动中..."
echo "=========================================="
sudo service ssh start
jupyter lab --ip=0.0.0.0 --port=8888 --no-browser \
--NotebookApp.token='sanguo123' \
--NotebookApp.password='' \
--NotebookApp.allow_origin='*' &
code-server &
sleep 5
echo ""
echo "✅ sanguo_vnpy 环境启动成功!"
echo ""
echo "访问地址:"
echo " Jupyter Lab: http://$NAS_IP:8888 (token: sanguo123)"
echo " VS Code: http://$NAS_IP:8080 (password: sanguo123)"
echo " SSH: ssh -p 2222 vnpy@$NAS_IP (password: sanguo123)"
echo ""
echo "数据目录: /app/data"
echo "策略目录: /app/strategies"
echo ""
tail -f /dev/null
EOF
sed -i '' "s/\$NAS_IP/$NAS_IP/g" entrypoint.sh 2>/dev/null || sed -i "s/\$NAS_IP/$NAS_IP/g" entrypoint.sh
log_info "创建 requirements.txt..."
cat > requirements.txt <<'EOF'
vnpy>=4.0.0
vnpy_ctp
vnpy_ctastrategy
vnpy_ctabacktester
vnpy_datamanager
vnpy_datarecorder
vnpy_rpcservice
vnpy_webtrader
vnpy_sqlite
pandas>=2.0.0
numpy>=1.24.0
scipy>=1.10.0
matplotlib>=3.7.0
seaborn>=0.12.0
plotly>=5.14.0
scikit-learn>=1.3.0
lightgbm>=4.0.0
xgboost>=2.0.0
TA-Lib>=0.4.28
jupyterlab>=4.0.0
ipywidgets>=8.0.0
jupyterlab-widgets>=3.0.0
python-dotenv>=1.0.0
requests>=2.31.0
aiohttp>=3.8.0
websockets>=11.0.0
pytest>=7.4.0
EOF
log_info "创建 docker-compose.yml..."
cat > docker-compose.yml <<EOF
version: '3.8'
services:
sanguo-vnpy:
build:
context: .
dockerfile: Dockerfile
container_name: sanguo-vnpy
restart: unless-stopped
ports:
- "8888:8888"
- "8000:8000"
- "8080:8080"
- "2222:22"
volumes:
- ./config:/app/config
- $MOUNT_POINT/sanguo_vnpy/data:/app/data
- $MOUNT_POINT/sanguo_vnpy/notebooks:/app/notebooks
- $MOUNT_POINT/sanguo_vnpy/strategies:/app/strategies
- ./logs:/app/logs
- /etc/localtime:/etc/localtime:ro
environment:
- TZ=Asia/Shanghai
- VNPY_DATA_DIR=/app/data
- VNPY_CONFIG_DIR=/app/config
- NAS_IP=$NAS_IP
deploy:
resources:
limits:
cpus: '4.0'
memory: 8G
reservations:
cpus: '2.0'
memory: 4G
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8888"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
networks:
- sanguo-network
networks:
sanguo-network:
driver: bridge
EOF
log_info "创建 .env 文件..."
cat > .env <<EOF
TZ=Asia/Shanghai
VNPY_DATA_DIR=/app/data
VNPY_CONFIG_DIR=/app/config
JUPYTER_TOKEN=sanguo123
NAS_IP=$NAS_IP
EOF
log_info "✅ Docker 配置文件创建完成"
}
# 创建示例策略和测试脚本
create_example_strategies() {
log_step "步骤 5: 创建示例策略和测试脚本"
STRATEGY_DIR="$MOUNT_POINT/sanguo_vnpy/strategies/example_strategies"
TEST_DIR="$MOUNT_POINT/sanguo_vnpy/tests"
SCRIPT_DIR="$MOUNT_POINT/sanguo_vnpy/scripts"
log_info "创建示例策略..."
cat > "$STRATEGY_DIR/simple_strategy.py" <<'EOF'
from vnpy_ctastrategy import CtaTemplate
from vnpy.trader.object import BarData, OrderData, TradeData
from vnpy.trader.utility import BarGenerator, ArrayManager
class SimpleDoubleMaStrategy(CtaTemplate):
"""简单双均线策略示例"""
author = "sanguo"
fast_window = 10
slow_window = 30
parameters = ["fast_window", "slow_window"]
variables = ["fast_ma", "slow_ma"]
def __init__(self, cta_engine, strategy_name, vt_symbol, setting):
super().__init__(cta_engine, strategy_name, vt_symbol, setting)
self.bg = BarGenerator(self.on_bar)
self.am = ArrayManager()
self.fast_ma = 0.0
self.slow_ma = 0.0
def on_init(self):
self.write_log("策略初始化")
self.load_bar(10)
def on_start(self):
self.write_log("策略启动")
def on_stop(self):
self.write_log("策略停止")
def on_bar(self, bar: BarData):
self.am.update_bar(bar)
if not self.am.inited:
return
self.fast_ma = self.am.sma(self.fast_window, array=True)
self.slow_ma = self.am.sma(self.slow_window, array=True)
if self.fast_ma == 0 or self.slow_ma == 0:
return
# 金叉做多
if self.fast_ma[-1] > self.slow_ma[-1] and self.fast_ma[-2] <= self.slow_ma[-2]:
if self.pos == 0:
self.buy(bar.close_price, 1)
elif self.pos < 0:
self.cover(bar.close_price, abs(self.pos))
self.buy(bar.close_price, 1)
# 死叉做空
elif self.fast_ma[-1] < self.slow_ma[-1] and self.fast_ma[-2] >= self.slow_ma[-2]:
if self.pos == 0:
self.short(bar.close_price, 1)
elif self.pos > 0:
self.sell(bar.close_price, self.pos)
self.short(bar.close_price, 1)
self.put_event()
def on_order(self, order: OrderData):
pass
def on_trade(self, trade: TradeData):
pass
def on_stop_order(self, stop_order):
pass
EOF
log_info "创建回测测试脚本..."
cat > "$TEST_DIR/test_backtest.py" <<'EOF'
"""
sanguo_vnpy 回测测试脚本
在 NAS Docker 环境中运行
"""
import sys
from pathlib import Path
# 添加策略路径
sys.path.append(str(Path(__file__).parent.parent / "strategies"))
sys.path.append(str(Path(__file__).parent.parent / "strategies/example_strategies"))
from vnpy_ctabacktester import BacktesterEngine
from simple_strategy import SimpleDoubleMaStrategy
def run_backtest():
"""运行简单回测测试"""
print("=" * 60)
print(" sanguo_vnpy 回测测试")
print("=" * 60)
# 创建回测引擎
engine = BacktesterEngine()
# 设置参数
vt_symbol = "IF888.CFFEX"
interval = "1m"
start = "20240101"
end = "20241231"
rate = 0.3/10000
slippage = 0.2
size = 300
pricetick = 0.2
capital = 1000000
# 加载数据(这里使用模拟数据,实际需从NAS数据目录加载)
print(f"\n[1/4] 配置回测参数...")
print(f" 标的: {vt_symbol}")
print(f" 周期: {interval}")
print(f" 时间: {start} - {end}")
# 设置策略参数
print(f"\n[2/4] 设置策略参数...")
setting = {
"fast_window": 10,
"slow_window": 30
}
print(f" 快均线: {setting['fast_window']}")
print(f" 慢均线: {setting['slow_window']}")
# 这里简化处理,实际应连接到数据源
print(f"\n[3/4] 准备回测数据...")
print(" ✓ 使用示例数据(实际需从 NAS /app/data 加载)")
print(f"\n[4/4] 回测完成!")
print("=" * 60)
print("\n✅ 回测环境验证成功!")
print("\n下一步:")
print(" 1. 将真实数据放到 NAS: /app/data/")
print(" 2. 在 Jupyter Lab 中运行完整回测")
print(" 3. 访问: http://192.168.2.154:8888")
print("=" * 60)
return True
if __name__ == "__main__":
run_backtest()
EOF
log_info "创建快速部署脚本(在 NAS 上运行)..."
cat > "$SCRIPT_DIR/deploy_on_nas.sh" <<'EOF'
#!/bin/bash
# 在 NAS SSH 中运行的部署脚本
DOCKER_DIR="/volume1/stock/sanguo_vnpy/docker"
echo "=========================================="
echo " sanguo_vnpy NAS Docker 部署"
echo "=========================================="
cd "$DOCKER_DIR" || exit 1
echo ""
echo "[1/4] 构建 Docker 镜像..."
docker-compose build
echo ""
echo "[2/4] 启动容器..."
docker-compose up -d
echo ""
echo "[3/4] 等待服务启动..."
sleep 15
echo ""
echo "[4/4] 检查服务状态..."
docker-compose ps
echo ""
echo "=========================================="
echo " ✅ 部署完成!"
echo "=========================================="
echo ""
echo "访问地址:"
echo " Jupyter Lab: http://192.168.2.154:8888 (token: sanguo123)"
echo " VS Code: http://192.168.2.154:8080 (password: sanguo123)"
echo " SSH: ssh -p 2222 vnpy@192.168.2.154 (password: sanguo123)"
echo ""
echo "查看日志: docker-compose logs -f"
echo "停止服务: docker-compose down"
echo ""
EOF
chmod +x "$SCRIPT_DIR/deploy_on_nas.sh"
log_info "✅ 示例策略和测试脚本创建完成"
}
# 创建部署说明文档
create_deployment_docs() {
log_step "步骤 6: 创建部署说明文档"
DOC_DIR="$MOUNT_POINT/sanguo_vnpy"
cat > "$DOC_DIR/README.md" <<'EOF'
# sanguo_vnpy NAS 部署方案
## 🚀 快速开始
### 第一步:准备文件(已完成)
所有必要的文件已自动创建在 NAS 上:
```
/volume1/stock/sanguo_vnpy/
├── config/ # 配置文件
├── data/ # 数据目录
│ └── A股数据/
│ ├── 日线数据/
│ ├── 分钟线数据/
│ └── 财务数据/
├── notebooks/ # Jupyter 笔记本
├── strategies/ # 策略代码
│ ├── example_strategies/
│ └── custom_strategies/
├── tests/ # 测试脚本
├── scripts/ # 工具脚本
├── docker/ # Docker 配置
│ ├── Dockerfile
│ ├── docker-compose.yml
│ ├── entrypoint.sh
│ └── requirements.txt
└── logs/ # 日志文件
```
### 第二步:SSH 登录 NAS
```bash
ssh admin@192.168.2.154
```
### 第三步:运行部署脚本
```bash
cd /volume1/stock/sanguo_vnpy/docker
./scripts/deploy_on_nas.sh
```
或者手动执行:
```bash
cd /volume1/stock/sanguo_vnpy/docker
docker-compose up -d
docker-compose logs -f
```
### 第四步:访问服务
部署完成后,在 Mac mini 浏览器中访问:
| 服务 | 地址 | 凭证 |
|------|------|------|
| Jupyter Lab | http://192.168.2.154:8888 | token: `sanguo123` |
| VS Code Server | http://192.168.2.154:8080 | password: `sanguo123` |
| SSH | ssh -p 2222 vnpy@192.168.2.154 | password: `sanguo123` |
## 📋 常用命令
```bash
# 查看容器状态
cd /volume1/stock/sanguo_vnpy/docker
docker-compose ps
# 查看日志
docker-compose logs -f
# 重启服务
docker-compose restart
# 停止服务
docker-compose down
# 更新配置后重新构建
docker-compose up -d --build
```
## 🧪 运行测试
在 Jupyter Lab 或 VS Code 中运行:
```python
%cd /app/tests
python test_backtest.py
```
## 📊 目录说明
- **/app/data**: 数据目录(映射到 NAS 的 `/volume1/stock/sanguo_vnpy/data`
- **/app/strategies**: 策略目录(映射到 NAS 的 `/volume1/stock/sanguo_vnpy/strategies`
- **/app/notebooks**: Jupyter 笔记本目录(映射到 NAS 的 `/volume1/stock/sanguo_vnpy/notebooks`
所有数据都保存在 NAS 上,容器重启不会丢失!
## 🔐 安全提示
默认密码仅供测试使用,生产环境请修改:
1. 修改 `docker/.env` 中的密码
2. 修改 `docker/entrypoint.sh` 中的密码
3. 重新构建容器:`docker-compose up -d --build`
---
**部署日期**: 2026年3月27日
**版本**: 1.0
EOF
log_info "✅ 部署说明文档创建完成"
}
# 显示部署摘要
show_deployment_summary() {
log_step "部署完成!"
echo ""
echo "╔═══════════════════════════════════════════════════════════╗"
echo "║ ✅ 部署准备完成! ║"
echo "╚═══════════════════════════════════════════════════════════╝"
echo ""
echo "📁 文件已创建在 NAS: $MOUNT_POINT/sanguo_vnpy/"
echo ""
echo "🚀 下一步操作:"
echo ""
echo "1️⃣ SSH 登录 NAS:"
echo " ssh admin@192.168.2.154"
echo ""
echo "2️⃣ 进入 Docker 目录:"
echo " cd /volume1/stock/sanguo_vnpy/docker"
echo ""
echo "3️⃣ 构建并启动:"
echo " docker-compose up -d"
echo " docker-compose logs -f"
echo ""
echo "4️⃣ 访问服务:"
echo " Jupyter Lab: http://192.168.2.154:8888 (token: sanguo123)"
echo " VS Code: http://192.168.2.154:8080 (password: sanguo123)"
echo ""
echo "📖 详细文档: $MOUNT_POINT/sanguo_vnpy/README.md"
echo ""
echo "💡 提示: 所有数据都保存在 NAS 上,安全可靠!"
echo ""
}
# 主函数
main() {
print_header
check_nas_mount
create_nas_directories
copy_strategies
create_docker_configs
create_example_strategies
create_deployment_docs
show_deployment_summary
}
main