auto-sync: 2026-03-28 12:07:55

This commit is contained in:
cfdaily
2026-03-28 12:07:55 +08:00
parent 488d115213
commit fe6aa11a5f
102 changed files with 1293 additions and 2 deletions
+155
View File
@@ -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
**维护负责人:** 姜维
+64
View File
@@ -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
+218
View File
@@ -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()
+209
View File
@@ -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
+101
View File
@@ -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 ""
+122
View File
@@ -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 ""
+72
View File
@@ -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 ""
+69
View File
@@ -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
View File
@@ -1 +1 @@
35771
5279
+28
View File
@@ -0,0 +1,28 @@
vnpy>=4.0.0
vnpy_ctabacktester
vnpy_ctastrategy
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
python-dotenv>=1.0.0
requests>=2.31.0
aiohttp>=3.8.0
websockets>=11.0.0
pytest>=7.4.0
+218
View File
@@ -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()
+35
View File
@@ -0,0 +1,35 @@
#!/bin/bash
# 创建软链接脚本
# 将本地data目录中的文件链接到NAS
SOURCE_ROOT="/Users/chufeng/.openclaw/sanguo_projects/sanguo_quant_live/zhaoyun-data/data/"
TARGET_ROOT="/Users/chufeng/nas/stock-data/sanguo_quant_live/zhaoyun-data/data/"
echo "🚀 开始创建软链接..."
echo " 源目录: $SOURCE_ROOT"
echo " 目标目录: $TARGET_ROOT"
# 创建目录结构
find "$SOURCE_ROOT" -type d | while read dir; do
target_dir="$TARGET_ROOT$dir"
mkdir -p "$target_dir"
echo " 创建目录: $target_dir"
done
# 创建文件软链接
count=0
find "$SOURCE_ROOT" -type f | while read file; do
target_file="$TARGET_ROOT$file"
target_dir=$(dirname "$target_file")
mkdir -p "$target_dir"
rm -f "$target_file"
ln -s "$file" "$target_file"
count=$((count+1))
if [ $((count % 100)) -eq 0 ]; then
echo " 已创建 $count 个软链接..."
fi
done
echo "✅ 软链接创建完成!"
echo " 总计: $count 个软链接"
echo

Some files were not shown because too many files have changed in this diff Show More