auto-sync: 2026-03-28 12:07:55
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
# sanguo_quant_live CI/CD 自动化回测
|
||||
|
||||
## 📋 概述
|
||||
|
||||
这是 sanguo_quant_live 全自动化回测 CI/CD 流程,**全程零干预,一条命令搞定**。
|
||||
|
||||
---
|
||||
|
||||
## 👥 明确职责分工
|
||||
|
||||
| 角色 | 你是谁 | 你需要做什么 | 你永远不需要做什么 |
|
||||
|------|------|-------------|-----------------|
|
||||
| **各位将军** | 策略开发者 | 写策略 / 改策略 → 一条命令触发回测 → 看结果 | **永远不要碰 vnpy 框架**,永远不要执行 `sanguo_nas_ci_cd.sh` |
|
||||
| **姜维** | CI/CD 负责人 / vnpy 维护者 | 维护 vnpy 框架 / 修复 bug / 新增功能 → 触发完整重建 | 不需要写策略 |
|
||||
|
||||
> 💡 **记住:**
|
||||
> - 如果你是将军写策略,你永远只用 `./sync_and_redeploy.sh`
|
||||
> - 如果你是姜维维护框架,你才用 `./sanguo_nas_ci_cd.sh`
|
||||
|
||||
---
|
||||
|
||||
## 🚀 使用方法(给各位将军)
|
||||
|
||||
### 📝 你写完策略/改完策略,要回测了:
|
||||
|
||||
```bash
|
||||
# 记住!你只用这个命令!
|
||||
cd management/cicd
|
||||
./sync_and_redeploy.sh
|
||||
```
|
||||
|
||||
**全自动完成:**
|
||||
1. ✅ 同步你本地最新策略代码到 NAS
|
||||
2. ✅ 重启 Docker 容器
|
||||
3. ✅ 自动运行回测
|
||||
4. ✅ 自动保存结果
|
||||
5. ✅ 输出回测统计结果
|
||||
|
||||
**全程不用你管,等着看结果就行!** 🎉
|
||||
|
||||
---
|
||||
|
||||
## 🚀 使用方法(给姜维)
|
||||
|
||||
### 🔧 你修改了 vnpy 框架/修复了 bug/新增了功能,需要重建环境:
|
||||
|
||||
```bash
|
||||
# 只有姜维能用这个命令!
|
||||
cd management/cicd
|
||||
./sanguo_nas_ci_cd.sh
|
||||
```
|
||||
|
||||
**全自动完成:**
|
||||
1. ✅ 同步本地最新完整代码(包括 vnpy 框架)到 NAS
|
||||
2. ✅ 停止旧容器
|
||||
3. ✅ 完全重新构建 Docker 镜像(包含所有修改)
|
||||
4. ✅ 启动新容器
|
||||
5. ✅ 运行回测验证
|
||||
6. ✅ 保存结果
|
||||
|
||||
---
|
||||
|
||||
## 🛟 特殊情况:rsync 同步有权限问题
|
||||
|
||||
```bash
|
||||
cd management/cicd
|
||||
./sync_with_tar.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 回测结果在哪里
|
||||
|
||||
结果自动保存到**两个地方**:
|
||||
|
||||
1. **全局汇总**:
|
||||
- NAS: `/volume1/stock/sanguo_vnpy/backtest_results/`
|
||||
- 本地: `./backtest_results/`
|
||||
|
||||
2. **和策略放在一起(便于查看)**:
|
||||
- `./strategies/{your_strategy}/backtest_results/`
|
||||
- 结果和策略代码放在一起,找起来方便!
|
||||
|
||||
每个回测生成两个文件:
|
||||
- `{strategy}_{YYYYMMDD_HHMMSS}.txt` - 回测统计结果(年化收益、夏普比率、最大回撤、胜率等)
|
||||
- `{strategy}_{YYYYMMDD_HHMMSS}.png` - 资金曲线图
|
||||
|
||||
---
|
||||
|
||||
## 🔄 完整工作流
|
||||
|
||||
```
|
||||
1. 各位将军开发
|
||||
↓
|
||||
✍️ 在本地 sanguo_quant_live 写策略 / 改策略
|
||||
↓
|
||||
🚀 触发回测(记住只用这个):
|
||||
cd management/cicd
|
||||
./sync_and_redeploy.sh
|
||||
↓
|
||||
🔄 自动化执行
|
||||
✓ 同步最新策略到 NAS
|
||||
✓ 重启容器
|
||||
✓ 运行回测
|
||||
✓ 保存结果(全局一份 + 策略目录一份)
|
||||
↓
|
||||
👀 各位将军看结果
|
||||
去你的策略目录下 backtest_results/ 看结果
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ 维护流程(给姜维)
|
||||
|
||||
```
|
||||
1. 发现 vnpy 框架有 bug / 需要新增功能
|
||||
↓
|
||||
🔧 在本地 sanguo_vnpy 修改代码
|
||||
↓
|
||||
🚀 触发完整重建:
|
||||
cd management/cicd
|
||||
./sanguo_nas_ci_cd.sh
|
||||
↓
|
||||
🔄 自动化执行
|
||||
✓ 同步完整代码到 NAS
|
||||
✓ 重建 Docker 镜像
|
||||
✓ 启动新容器
|
||||
↓
|
||||
✅ 完成,各位将军继续用
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 配置信息
|
||||
|
||||
- **NAS 地址:** `192.168.2.154`
|
||||
- **NAS 目标目录:** `/volume1/stock/sanguo_vnpy/`
|
||||
- **本地项目根目录:** `/Users/chufeng/.openclaw/sanguo_projects/sanguo_quant_live/`
|
||||
|
||||
---
|
||||
|
||||
## ✨ 方案特点
|
||||
|
||||
- 🤖 **全程零干预** - 你触发后全自动,不需要任何手动操作
|
||||
- ⚡ **增量更新** - 策略修改不用重建 Docker,更快出结果
|
||||
- 🔒 **职责隔离** - 将军只管策略,姜维只管框架,互不干扰
|
||||
- 📂 **结果好查找** - 结果同时保存到全局和策略目录,方便查看
|
||||
- 📊 **结果自动保存** - 统计结果 + 资金曲线图都自动保存
|
||||
- 🎯 **分工清晰** - 每个人只干自己擅长的,命令记一个就行
|
||||
|
||||
---
|
||||
|
||||
**版本:** 1.0
|
||||
**最后更新:** 2026-03-28
|
||||
**维护负责人:** 姜维
|
||||
Executable
+64
@@ -0,0 +1,64 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ============================================
|
||||
# 配置定时自动回测
|
||||
# 安装:./auto_backtest_crontab.sh install
|
||||
# 查看:crontab -l
|
||||
# 卸载:./auto_backtest_crontab.sh uninstall
|
||||
# ============================================
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
CI_CD_SCRIPT="$SCRIPT_DIR/sanguo_nas_ci_cd.sh"
|
||||
CRON_ENTRY="0 8 * * * $CI_CD_SCRIPT >> $SCRIPT_DIR/auto_backtest.log 2>&1"
|
||||
|
||||
install() {
|
||||
echo "安装定时自动回测..."
|
||||
echo ""
|
||||
|
||||
# 添加到 crontab
|
||||
(crontab -l 2>/dev/null; echo "$CRON_ENTRY") | crontab -
|
||||
|
||||
echo ""
|
||||
echo "✅ 安装完成!"
|
||||
echo "每天早上 8:00 自动运行一次全流程回测"
|
||||
echo "日志位置: $SCRIPT_DIR/auto_backtest.log"
|
||||
echo ""
|
||||
}
|
||||
|
||||
uninstall() {
|
||||
echo "卸载定时自动回测..."
|
||||
echo ""
|
||||
|
||||
# 移除 crontab
|
||||
crontab -l 2>/dev/null | grep -v "sanguo_nas_ci_cd.sh" | crontab -
|
||||
|
||||
echo ""
|
||||
echo "✅ 卸载完成!"
|
||||
echo ""
|
||||
}
|
||||
|
||||
status() {
|
||||
echo "当前定时任务:"
|
||||
echo ""
|
||||
crontab -l | grep "sanguo"
|
||||
echo ""
|
||||
}
|
||||
|
||||
case "${1:-help}" in
|
||||
install)
|
||||
install
|
||||
;;
|
||||
uninstall)
|
||||
uninstall
|
||||
;;
|
||||
status)
|
||||
status
|
||||
;;
|
||||
help)
|
||||
echo "使用方法:"
|
||||
echo " $0 install - 安装每天 8:00 自动回测"
|
||||
echo " $0 uninstall - 卸载定时回测"
|
||||
echo " $0 status - 查看当前状态"
|
||||
echo ""
|
||||
;;
|
||||
esac
|
||||
Executable
+218
@@ -0,0 +1,218 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
通用自动化回测脚本
|
||||
自动保存结果到:
|
||||
1. 全局目录: /volume1/stock/sanguo_vnpy/backtest_results/
|
||||
2. 策略目录: ./strategies/{your_strategy}/backtest_results/ 便于和策略放在一起查看
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import argparse
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
# 添加路径
|
||||
sys.path.insert(0, '/volume1/stock/sanguo_vnpy')
|
||||
sys.path.insert(0, '/volume1/stock/sanguo_vnpy/strategies')
|
||||
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
from vnpy.trader.constant import Interval
|
||||
from vnpy_ctabacktester import BacktesterEngine
|
||||
|
||||
|
||||
def run_backtest(
|
||||
strategy_class,
|
||||
strategy_name: str,
|
||||
vt_symbol: str = "IF888.CFFEX",
|
||||
interval: Interval = Interval.DAILY,
|
||||
start_date: str = "20200101",
|
||||
end_date: str = "20251231",
|
||||
capital: int = 1000000,
|
||||
rate: float = 0.3 / 10000,
|
||||
slippage: float = 0.2,
|
||||
size: int = 300,
|
||||
pricetick: float = 0.2,
|
||||
strategy_config: dict = None,
|
||||
):
|
||||
"""运行单个策略回测"""
|
||||
|
||||
# 创建结果保存目录
|
||||
# 1. 全局目录
|
||||
GLOBAL_RESULT_DIR = Path('/volume1/stock/sanguo_vnpy/backtest_results')
|
||||
GLOBAL_RESULT_DIR.mkdir(exist_ok=True, parents=True)
|
||||
|
||||
# 2. 策略目录(和策略放在一起便于查看)
|
||||
# 找到策略目录
|
||||
strategy_file = sys.modules[strategy_class.__module__].__file__
|
||||
strategy_dir = Path(strategy_file).parent
|
||||
STRATEGY_RESULT_DIR = strategy_dir / "backtest_results"
|
||||
STRATEGY_RESULT_DIR.mkdir(exist_ok=True, parents=True)
|
||||
|
||||
print("=" * 60)
|
||||
print(f" 开始回测: {strategy_name}")
|
||||
print(f" 结果保存:")
|
||||
print(f" 全局: {GLOBAL_RESULT_DIR}")
|
||||
print(f" 策略: {STRATEGY_RESULT_DIR}")
|
||||
print("=" * 60)
|
||||
print()
|
||||
|
||||
# 打印配置
|
||||
print(f"📋 回测配置:")
|
||||
print(f" 标的: {vt_symbol}")
|
||||
print(f" 周期: {interval}")
|
||||
print(f" 时间: {start_date} - {end_date}")
|
||||
print(f" 初始资金: {capital:,}")
|
||||
print()
|
||||
|
||||
# 创建回测引擎
|
||||
print("🚀 创建回测引擎...")
|
||||
engine = BacktesterEngine()
|
||||
|
||||
# 添加策略
|
||||
print("🧩 添加策略...")
|
||||
if strategy_config is None:
|
||||
strategy_config = {}
|
||||
engine.add_strategy(strategy_class, strategy_config)
|
||||
|
||||
# 运行回测
|
||||
print("🔄 开始运行回测...")
|
||||
start_time = datetime.now()
|
||||
|
||||
engine.run_backtest(
|
||||
vt_symbol=vt_symbol,
|
||||
interval=interval,
|
||||
start=start_date,
|
||||
end=end_date,
|
||||
rate=rate,
|
||||
slippage=slippage,
|
||||
size=size,
|
||||
pricetick=pricetick,
|
||||
capital=capital
|
||||
)
|
||||
|
||||
end_time = datetime.now()
|
||||
duration = (end_time - start_time).total_seconds()
|
||||
|
||||
print(f"✅ 回测完成!耗时: {duration:.2f} 秒")
|
||||
print()
|
||||
|
||||
# 获取结果文本
|
||||
import io
|
||||
from contextlib import redirect_stdout
|
||||
|
||||
output = io.StringIO()
|
||||
with redirect_stdout(output):
|
||||
engine.show_results()
|
||||
result_text = output.getvalue()
|
||||
|
||||
# 保存结果到全局目录
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
global_result_file = GLOBAL_RESULT_DIR / f"{strategy_name}_{timestamp}.txt"
|
||||
|
||||
with open(global_result_file, 'w', encoding='utf-8') as f:
|
||||
f.write(f"{strategy_name} 回测结果\n")
|
||||
f.write("=" * 50 + "\n")
|
||||
f.write(f"时间: {timestamp}\n")
|
||||
f.write(f"标的: {vt_symbol}\n")
|
||||
f.write(f"周期: {interval}\n")
|
||||
f.write(f"时间范围: {start_date} - {end_date}\n")
|
||||
f.write(f"初始资金: {capital:,}\n")
|
||||
f.write("\n")
|
||||
f.write(result_text)
|
||||
|
||||
print(f"💾 全局结果已保存: {global_result_file}")
|
||||
|
||||
# 保存结果到策略目录
|
||||
strategy_result_file = STRATEGY_RESULT_DIR / f"{strategy_name}_{timestamp}.txt"
|
||||
with open(strategy_result_file, 'w', encoding='utf-8') as f:
|
||||
f.write(f"{strategy_name} 回测结果\n")
|
||||
f.write("=" * 50 + "\n")
|
||||
f.write(f"时间: {timestamp}\n")
|
||||
f.write(f"标的: {vt_symbol}\n")
|
||||
f.write(f"周期: {interval}\n")
|
||||
f.write(f"时间范围: {start_date} - {end_date}\n")
|
||||
f.write(f"初始资金: {capital:,}\n")
|
||||
f.write("\n")
|
||||
f.write(result_text)
|
||||
|
||||
print(f"📂 策略结果已保存: {strategy_result_file}")
|
||||
print()
|
||||
|
||||
# 保存图表
|
||||
print("📈 绘制资金曲线...")
|
||||
plt.figure(figsize=(12, 6))
|
||||
engine.plot_chart()
|
||||
|
||||
# 保存到全局目录
|
||||
global_chart_file = GLOBAL_RESULT_DIR / f"{strategy_name}_{timestamp}.png"
|
||||
plt.savefig(global_chart_file)
|
||||
print(f"📊 全局图表已保存: {global_chart_file}")
|
||||
|
||||
# 保存到策略目录
|
||||
strategy_chart_file = STRATEGY_RESULT_DIR / f"{strategy_name}_{timestamp}.png"
|
||||
plt.savefig(strategy_chart_file)
|
||||
print(f"📊 策略图表已保存: {strategy_chart_file}")
|
||||
|
||||
print()
|
||||
print("=" * 60)
|
||||
print(f" 🎉 回测完成!")
|
||||
print(f" 📄 全局结果: {global_result_file}")
|
||||
print(f" 📂 策略结果: {strategy_result_file}")
|
||||
print("=" * 60)
|
||||
|
||||
return global_result_file, strategy_result_file
|
||||
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
|
||||
parser = argparse.ArgumentParser(description='自动化运行策略回测')
|
||||
parser.add_argument('strategy', help='策略模块名,例如: strategies.guanyu_value_tech_strategy')
|
||||
parser.add_argument('--symbol', default='IF888.CFFEX', help='回测标的')
|
||||
parser.add_argument('--start', default='20200101', help='开始日期')
|
||||
parser.add_argument('--end', default='20251231', help='结束日期')
|
||||
parser.add_argument('--capital', type=int, default=1000000, help='初始资金')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# 导入策略模块
|
||||
import importlib
|
||||
module = importlib.import_module(args.strategy)
|
||||
|
||||
# 找到策略类(假设第一个类就是策略类)
|
||||
strategy_class = None
|
||||
for name, obj in module.__dict__.items():
|
||||
if isinstance(obj, type) and 'Strategy' in name:
|
||||
strategy_class = obj
|
||||
break
|
||||
|
||||
if strategy_class is None:
|
||||
print(f"❌ 在模块 {args.strategy} 中没找到策略类")
|
||||
sys.exit(1)
|
||||
|
||||
strategy_name = strategy_class.__name__
|
||||
|
||||
# 获取策略配置(如果有)
|
||||
strategy_config = {}
|
||||
if hasattr(module, 'STRATEGY_CONFIG'):
|
||||
strategy_config = module.STRATEGY_CONFIG
|
||||
|
||||
# 运行回测
|
||||
run_backtest(
|
||||
strategy_class=strategy_class,
|
||||
strategy_name=strategy_name,
|
||||
vt_symbol=args.symbol,
|
||||
start_date=args.start,
|
||||
end_date=args.end,
|
||||
capital=args.capital,
|
||||
strategy_config=strategy_config,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Executable
+209
@@ -0,0 +1,209 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ============================================
|
||||
# sanguo_vnpy 端到端全自动化 CI/CD 回测
|
||||
# 作者:姜维 伯约
|
||||
# 日期:2026年3月28日
|
||||
# ============================================
|
||||
|
||||
set -e
|
||||
|
||||
# 配置信息
|
||||
NAS_IP="192.168.2.154"
|
||||
NAS_USER="admin"
|
||||
SANGUO_PROJECT_DIR="/Users/chufeng/.openclaw/sanguo_projects/sanguo_quant_live"
|
||||
NAS_TARGET_DIR="/volume1/stock/sanguo_vnpy"
|
||||
DOCKER_CONTAINER_NAME="sanguo_vnpy"
|
||||
|
||||
# 说明:
|
||||
# 这个方案会同步整个 sanguo_quant_live 项目,包括:
|
||||
# - strategies/ 所有策略
|
||||
# - sanguo_vnpy/ 框架代码(包括修改后的vnpy)
|
||||
# - jiangwei-platform/ 三国量化实战项目
|
||||
# - pangtong-value/ 价值投资研究
|
||||
# - 所有其他模块
|
||||
|
||||
# 颜色
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
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"
|
||||
}
|
||||
|
||||
# 步骤 1: 拉取最新代码
|
||||
pull_latest_code() {
|
||||
log_info "步骤 1/6: 拉取最新代码"
|
||||
|
||||
cd "$SANGUO_PROJECT_DIR"
|
||||
|
||||
if git pull origin main; then
|
||||
log_info "✅ 代码已更新到最新版本"
|
||||
return 0
|
||||
else
|
||||
log_error "❌ 拉取代码失败"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 步骤 2: 同步所有文件到 NAS
|
||||
sync_to_nas() {
|
||||
log_info "步骤 2/6: 同步所有文件到 NAS"
|
||||
|
||||
# 确保目标目录存在
|
||||
ssh "$NAS_USER@$NAS_IP" "mkdir -p $NAS_TARGET_DIR"
|
||||
|
||||
# 使用 rsync 同步所有文件(包括策略和框架代码)
|
||||
# 会同步整个 sanguo_quant_live 项目,包括:
|
||||
# - strategies/ 所有策略
|
||||
# - sanguo_vnpy/ 框架代码(包括您修改后的 vnpy)
|
||||
# - jiangwei-platform/ 三国量化实战
|
||||
# - pangtong-value/ 价值投资研究
|
||||
# - 所有其他模块
|
||||
rsync -av --delete \
|
||||
"$SANGUO_PROJECT_DIR"/ \
|
||||
"$NAS_USER@$NAS_IP:$NAS_TARGET_DIR"/ \
|
||||
--exclude='.git' \
|
||||
--exclude='__pycache__' \
|
||||
--exclude='*.log' \
|
||||
--exclude='*.pyc' \
|
||||
--exclude='.ipynb_checkpoints' \
|
||||
--exclude='backtest_results/*.png' \
|
||||
--exclude='.DS_Store'
|
||||
|
||||
log_info "✅ 文件同步完成"
|
||||
}
|
||||
|
||||
# 步骤 3: 重建 Docker 容器
|
||||
rebuild_docker() {
|
||||
log_info "步骤 3/6: 重建 Docker 容器"
|
||||
|
||||
ssh "$NAS_USER@$NAS_IP" << 'EOF'
|
||||
export PATH=$PATH:/var/packages/Docker/target/usr/bin
|
||||
cd /volume1/stock/sanguo_vnpy/docker
|
||||
|
||||
# 停止并删除旧容器
|
||||
if docker ps -a | grep -q sanguo_vnpy; then
|
||||
docker stop sanguo_vnpy
|
||||
docker rm sanguo_vnpy
|
||||
fi
|
||||
|
||||
# 构建新镜像
|
||||
docker-compose build --no-cache
|
||||
|
||||
# 启动新容器
|
||||
docker-compose up -d
|
||||
|
||||
# 等待容器启动
|
||||
sleep 10
|
||||
|
||||
# 检查容器状态
|
||||
if docker ps | grep -q sanguo_vnpy; then
|
||||
echo "✅ 容器启动成功"
|
||||
else
|
||||
echo "❌ 容器启动失败"
|
||||
exit 1
|
||||
fi
|
||||
EOF
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
log_info "✅ Docker 容器重建完成"
|
||||
return 0
|
||||
else
|
||||
log_error "❌ Docker 容器重建失败"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 步骤 4: 运行自动化回测
|
||||
run_backtest() {
|
||||
log_info "步骤 4/6: 运行自动化回测"
|
||||
|
||||
ssh "$NAS_USER@$NAS_IP" << 'EOF'
|
||||
cd /volume1/stock/sanguo_vnpy/scripts
|
||||
|
||||
# 运行全自动化回测
|
||||
./run_backtest_auto.sh
|
||||
EOF
|
||||
|
||||
if [ $? -eq -ne 0 ]; then
|
||||
log_warn "回测运行中,请等待完成..."
|
||||
fi
|
||||
|
||||
log_info "✅ 回测已启动"
|
||||
}
|
||||
|
||||
# 步骤 5: 获取结果
|
||||
get_results() {
|
||||
log_info "步骤 5/6: 获取回测结果"
|
||||
|
||||
# 创建本地结果目录
|
||||
mkdir -p "./backtest_results"
|
||||
|
||||
# 下载最新结果
|
||||
rsync -av --delete \
|
||||
"$NAS_USER@$NAS_IP:$NAS_TARGET_DIR/backtest_results/"* \
|
||||
"./backtest_results"/
|
||||
|
||||
log_info "✅ 结果已下载到本地: ./backtest_results/"
|
||||
|
||||
# 显示最新结果
|
||||
LATEST_RESULT=$(ls -t ./backtest_results/*.txt | head -1)
|
||||
if [ -f "$LATEST_RESULT" ]; then
|
||||
echo ""
|
||||
echo "============================================"
|
||||
echo " 📊 最新回测结果"
|
||||
echo "============================================"
|
||||
echo ""
|
||||
cat "$LATEST_RESULT"
|
||||
echo ""
|
||||
echo "============================================"
|
||||
fi
|
||||
}
|
||||
|
||||
# 步骤 6: 完成通知
|
||||
finish() {
|
||||
log_info "步骤 6/6: 完成!"
|
||||
|
||||
echo ""
|
||||
echo "╔═════════════════════════════════════════════════════════════════╗"
|
||||
echo "║ 🎉 端到端自动化回测完成! ║"
|
||||
echo "╚═════════════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
echo "📍 结果位置:"
|
||||
echo " NAS: $NAS_TARGET_DIR/backtest_results/"
|
||||
echo " 本地: ./backtest_results/"
|
||||
echo ""
|
||||
echo "🚀 下次更新代码后,直接运行 ./sanguo_nas_ci_cd.sh 就能全自动完成!"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# 主函数
|
||||
main() {
|
||||
echo "============================================"
|
||||
echo " sanguo_vnpy 端到端全自动化回测"
|
||||
echo "============================================"
|
||||
echo ""
|
||||
|
||||
pull_latest_code && \
|
||||
sync_to_nas && \
|
||||
rebuild_docker && \
|
||||
run_backtest && \
|
||||
get_results && \
|
||||
finish
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# 运行
|
||||
main
|
||||
Executable
+101
@@ -0,0 +1,101 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ============================================
|
||||
# 增量同步代码到 NAS 并重新部署
|
||||
# 当修复 bug 后,运行这个脚本自动同步并重新部署
|
||||
# ============================================
|
||||
|
||||
set -e
|
||||
|
||||
# 配置信息
|
||||
NAS_IP="192.168.2.154"
|
||||
NAS_USER="admin"
|
||||
LOCAL_PROJECT="/Users/chufeng/.openclaw/sanguo_projects/sanguo_quant_live"
|
||||
NAS_TARGET="/volume1/stock/sanguo_vnpy"
|
||||
|
||||
# 颜色
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
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"
|
||||
}
|
||||
|
||||
echo "============================================"
|
||||
echo " 增量同步 + 自动重新部署"
|
||||
echo "============================================"
|
||||
echo ""
|
||||
|
||||
# 拉取最新代码
|
||||
log_info "1/4: 拉取最新代码"
|
||||
cd "$LOCAL_PROJECT"
|
||||
git pull origin main
|
||||
log_info "✅ 代码已更新"
|
||||
echo ""
|
||||
|
||||
# 增量同步到 NAS
|
||||
log_info "2/4: 增量同步到 NAS"
|
||||
# 同步整个项目,包括策略和框架代码
|
||||
# 任何文件修改(包括 vnpy 框架代码)都会同步到 NAS
|
||||
rsync -av --delete \
|
||||
"$LOCAL_PROJECT"/ \
|
||||
"$NAS_USER@$NAS_IP:$NAS_TARGET"/ \
|
||||
--exclude='.git' \
|
||||
--exclude='__pycache__' \
|
||||
--exclude='*.log' \
|
||||
--exclude='*.pyc' \
|
||||
--exclude='.ipynb_checkpoints' \
|
||||
--exclude='backtest_results/*.png' \
|
||||
--exclude='.DS_Store'
|
||||
|
||||
log_info "✅ 同步完成"
|
||||
echo ""
|
||||
|
||||
# 重启 Docker 容器
|
||||
log_info "3/4: 重启 Docker 容器"
|
||||
ssh "$NAS_USER@$NAS_IP" << 'EOF'
|
||||
cd /volume1/stock/sanguo_vnpy
|
||||
|
||||
# 添加 docker 到 PATH
|
||||
export PATH=$PATH:/var/packages/Docker/target/usr/bin
|
||||
|
||||
# 停止旧容器
|
||||
if docker ps -q -f name=sanguo_vnpy | grep -q .; then
|
||||
docker stop sanguo_vnpy
|
||||
fi
|
||||
|
||||
# 重新构建启动
|
||||
/var/packages/Docker/target/usr/bin/docker-compose up -d --build
|
||||
|
||||
# 等待启动
|
||||
sleep 10
|
||||
|
||||
# 检查状态
|
||||
if docker ps -q -f name=sanguo_vnpy | grep -q .; then
|
||||
echo "✅ 容器重启成功"
|
||||
else
|
||||
echo "❌ 容器启动失败"
|
||||
exit 1
|
||||
fi
|
||||
EOF
|
||||
|
||||
log_info "✅ 容器重启完成"
|
||||
echo ""
|
||||
|
||||
# 运行回测
|
||||
log_info "4/4: 启动自动化回测"
|
||||
ssh "$NAS_USER@$NAS_IP" "cd /volume1/stock/sanguo_vnpy/scripts && ./run_backtest_auto.sh"
|
||||
|
||||
echo ""
|
||||
log_info "🎉 完成!代码已同步,容器已重启,回测已启动!"
|
||||
echo ""
|
||||
Executable
+122
@@ -0,0 +1,122 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ============================================
|
||||
# 同步策略 + 全自动回测,不需要重启 Docker!
|
||||
# 使用方法:
|
||||
# ./sync_and_run_backtest.sh --strategy strategies.pangtong-value.strategy_A
|
||||
# ============================================
|
||||
|
||||
set -e
|
||||
|
||||
# 配置信息
|
||||
NAS_IP="192.168.2.154"
|
||||
NAS_USER="admin"
|
||||
LOCAL_PROJECT="/Users/chufeng/.openclaw/sanguo_projects/sanguo_quant_live"
|
||||
NAS_TARGET="/volume1/stock/sanguo_vnpy"
|
||||
DOCKER_CONTAINER="sanguo_vnpy"
|
||||
|
||||
# 颜色
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
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"
|
||||
}
|
||||
|
||||
# 解析参数
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--strategy)
|
||||
STRATEGY="$2"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# 检查参数
|
||||
if [[ -z "$STRATEGY" ]]; then
|
||||
log_error "必须指定 --strategy 参数"
|
||||
echo ""
|
||||
echo "使用方法:"
|
||||
echo " $0 --strategy strategies.pangtong-value.strategy_A"
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 提取策略路径(用于同步)
|
||||
# strategies.pangtong-value.strategy_A → strategies/pangtong-value
|
||||
STRATEGY_PATH=$(echo "$STRATEGY" | tr '.' '/')
|
||||
STRATEGY_PATH=$(dirname "$STRATEGY_PATH")
|
||||
|
||||
echo "============================================"
|
||||
echo " 同步策略 + 全自动回测(无需重启 Docker)"
|
||||
echo "============================================"
|
||||
echo ""
|
||||
log_info "策略: $STRATEGY"
|
||||
log_info "策略路径: $STRATEGY_PATH"
|
||||
echo ""
|
||||
|
||||
# 第一步:同步策略代码到 NAS
|
||||
log_info "1/3: 同步策略代码到 NAS"
|
||||
rsync -av --delete \
|
||||
"$LOCAL_PROJECT/$STRATEGY_PATH"/ \
|
||||
"$NAS_USER@$NAS_IP:$NAS_TARGET/$STRATEGY_PATH"/ \
|
||||
--exclude='__pycache__' \
|
||||
--exclude='*.pyc' \
|
||||
--exclude='.ipynb_checkpoints' \
|
||||
--exclude='.DS_Store'
|
||||
|
||||
log_info "✅ 同步完成"
|
||||
echo ""
|
||||
|
||||
# 第二步:在容器中运行回测
|
||||
log_info "2/3: 在运行的容器中执行回测"
|
||||
echo ""
|
||||
|
||||
ssh "$NAS_USER@$NAS_IP" "export PATH=\$PATH:/var/packages/Docker/target/usr/bin && docker exec $DOCKER_CONTAINER python /app/scripts/run_backtest_auto.py $STRATEGY"
|
||||
|
||||
log_info "✅ 回测执行完成"
|
||||
echo ""
|
||||
|
||||
# 第三步:同步回测结果回本地
|
||||
log_info "3/3: 同步回测结果回本地"
|
||||
echo ""
|
||||
|
||||
# 结果目录
|
||||
RESULT_PATH="$STRATEGY_PATH/backtest_results"
|
||||
mkdir -p "$LOCAL_PROJECT/$RESULT_PATH"
|
||||
|
||||
rsync -av \
|
||||
"$NAS_USER@$NAS_IP:$NAS_TARGET/$RESULT_PATH"/ \
|
||||
"$LOCAL_PROJECT/$RESULT_PATH"/ \
|
||||
--exclude='__pycache__'
|
||||
|
||||
log_info "✅ 结果同步完成"
|
||||
echo ""
|
||||
|
||||
echo "============================================"
|
||||
echo " 🎉 回测完成!"
|
||||
echo "============================================"
|
||||
echo ""
|
||||
echo "📄 结果位置:"
|
||||
echo " NAS: $NAS_TARGET/$RESULT_PATH/"
|
||||
echo " 本地: $LOCAL_PROJECT/$RESULT_PATH/"
|
||||
echo ""
|
||||
echo "📊 直接查看结果:"
|
||||
echo " cat $LOCAL_PROJECT/$RESULT_PATH/*.txt"
|
||||
echo " open $LOCAL_PROJECT/$RESULT_PATH/*.png"
|
||||
echo ""
|
||||
Executable
+72
@@ -0,0 +1,72 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ============================================
|
||||
# 只同步策略,不需要重启 Docker
|
||||
# vnpy 支持动态加载策略,所以同步完成后直接就能在 UI 里加载新策略
|
||||
# ============================================
|
||||
|
||||
set -e
|
||||
|
||||
# 配置信息
|
||||
NAS_IP="192.168.2.154"
|
||||
NAS_USER="admin"
|
||||
LOCAL_PROJECT="/Users/chufeng/.openclaw/sanguo_projects/sanguo_quant_live"
|
||||
NAS_TARGET="/volume1/stock/sanguo_vnpy"
|
||||
|
||||
# 颜色
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
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"
|
||||
}
|
||||
|
||||
echo "============================================"
|
||||
echo " 同步策略到 NAS(不重启 Docker)"
|
||||
echo " vnpy 支持动态加载,同步完直接在 UI 加载新策略"
|
||||
echo "============================================"
|
||||
echo ""
|
||||
|
||||
# 检查参数
|
||||
if [ $# -eq 0 ]; then
|
||||
log_error "请指定要同步的策略目录"
|
||||
echo ""
|
||||
echo "使用方法:"
|
||||
echo " ./sync_strategy_only.sh strategies/pangtong-value/strategy_A"
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
STRATEGY_PATH="$1"
|
||||
|
||||
log_info "1/2: 同步策略 $STRATEGY_PATH 到 NAS"
|
||||
rsync -av --delete \
|
||||
"$LOCAL_PROJECT/$STRATEGY_PATH"/ \
|
||||
"$NAS_USER@$NAS_IP:$NAS_TARGET/$STRATEGY_PATH"/ \
|
||||
--exclude='__pycache__' \
|
||||
--exclude='*.pyc' \
|
||||
--exclude='.ipynb_checkpoints' \
|
||||
--exclude='.DS_Store'
|
||||
|
||||
log_info "✅ 同步完成"
|
||||
echo ""
|
||||
log_info "2/2: 完成!"
|
||||
echo ""
|
||||
echo "🎯 下一步:"
|
||||
echo " 1. 在 vnpy UI 里刷新策略"
|
||||
echo " 2. 加载你的策略 $STRATEGY_PATH"
|
||||
echo " 3. 运行回测"
|
||||
echo " 4. 结果自动保存到 $STRATEGY_PATH/backtest_results/"
|
||||
echo ""
|
||||
echo "✅ 完成!不需要重启 Docker!直接用就行!"
|
||||
echo ""
|
||||
Executable
+69
@@ -0,0 +1,69 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ============================================
|
||||
# 使用 tar 打包方式同步文件到 NAS
|
||||
# 绕过 rsync 权限问题
|
||||
# ============================================
|
||||
|
||||
set -e
|
||||
|
||||
# 配置信息
|
||||
NAS_IP="192.168.2.154"
|
||||
NAS_USER="admin"
|
||||
LOCAL_PROJECT="/Users/chufeng/.openclaw/sanguo_projects/sanguo_quant_live"
|
||||
NAS_TARGET="/volume1/stock/sanguo_vnpy"
|
||||
|
||||
# 颜色
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
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"
|
||||
}
|
||||
|
||||
echo "============================================"
|
||||
echo " 使用 tar 打包方式同步文件到 NAS"
|
||||
echo "============================================"
|
||||
echo ""
|
||||
|
||||
cd "$LOCAL_PROJECT"
|
||||
|
||||
log_info "1/3: 打包本地项目"
|
||||
# 打包排除一些文件
|
||||
tar -czf /tmp/sanguo_quant_live.tar.gz \
|
||||
--exclude='.git' \
|
||||
--exclude='__pycache__' \
|
||||
--exclude='*.log' \
|
||||
--exclude='*.pyc' \
|
||||
--exclude='.ipynb_checkpoints' \
|
||||
--exclude='backtest_results/*.png' \
|
||||
--exclude='.DS_Store' \
|
||||
.
|
||||
|
||||
log_info "✅ 打包完成"
|
||||
echo ""
|
||||
|
||||
log_info "2/3: 上传并解压到 NAS"
|
||||
# 上传并解压
|
||||
cat /tmp/sanguo_quant_live.tar.gz | ssh "$NAS_USER@$NAS_IP" "cd '$NAS_TARGET' && tar -xzf - && echo '✅ 解压完成'"
|
||||
|
||||
log_info "✅ 同步完成"
|
||||
echo ""
|
||||
|
||||
log_info "3/3: 清理本地临时文件"
|
||||
rm /tmp/sanguo_quant_live.tar.gz
|
||||
log_info "✅ 清理完成"
|
||||
echo ""
|
||||
|
||||
log_info "🎉 文件同步完成!"
|
||||
echo ""
|
||||
@@ -1 +1 @@
|
||||
35771
|
||||
5279
|
||||
|
||||
Reference in New Issue
Block a user