Files
sanguo_vnpy/test/backtest/run_backtest_final.py
T
2026-04-11 21:18:55 +08:00

175 lines
5.1 KiB
Python
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.
#!/usr/bin/env python3
"""
在Docker容器内执行回测 - 完整版
不经过HTTP API,直接运行
"""
# ============================================
# 导入 vnpy.app 兼容性模块
# ============================================
import types
import sys
vnpy_app = types.ModuleType('vnpy.app')
sys.modules['vnpy.app'] = vnpy_app
for name in ['cta_strategy', 'cta_backtester', 'data_manager']:
mod = types.ModuleType(f'vnpy.app.{name}')
sys.modules[f'vnpy.app.{name}'] = mod
setattr(vnpy_app, name, mod)
from vnpy_ctastrategy import (
CtaTemplate, StopOrder, TickData, BarData, TradeData, OrderData, BarGenerator, ArrayManager
)
sys.modules['vnpy.app.cta_strategy'].CtaTemplate = CtaTemplate
from vnpy_ctabacktester import BacktesterEngine
sys.modules['vnpy.app.cta_backtester'].BacktesterEngine = BacktesterEngine
# ============================================
# 导入其他必要模块
# ============================================
from vnpy.event import EventEngine
from vnpy.trader.engine import MainEngine
from vnpy.trader.constant import Exchange, Interval, Direction, Offset
from vnpy.trader.database import get_database
from datetime import datetime
import traceback
# ============================================
# 读取关羽策略代码
# ============================================
strategy_file = "/Users/chufeng/.openclaw/workspace-guanyu/pangtong-value/research/task-20260329-strategy-backtest/guanyu/single_stock_stop_loss_final_correct.py"
with open(strategy_file, 'r', encoding='utf-8') as f:
strategy_code = f.read()
print("=" * 80)
print("🚀 在Docker容器内执行回测")
print("=" * 80)
print(f"✅ 策略代码: {len(strategy_code)} 字符")
# ============================================
# 执行回测
# ============================================
print("\n初始化引擎...")
event_engine = EventEngine()
main_engine = MainEngine(event_engine)
backtester_engine = BacktesterEngine(main_engine, event_engine)
print("✅ 引擎初始化完成")
# 动态加载策略代码
print("\n加载策略代码...")
local_vars = {
'CtaTemplate': CtaTemplate,
'StopOrder': StopOrder,
'TickData': TickData,
'BarData': BarData,
'TradeData': TradeData,
'OrderData': OrderData,
'BarGenerator': BarGenerator,
'ArrayManager': ArrayManager,
'Direction': Direction,
'Offset': Offset,
}
exec(strategy_code, globals(), local_vars)
# 查找策略类
strategy_classes = [
v for k, v in local_vars.items()
if isinstance(v, type) and issubclass(v, CtaTemplate) and v != CtaTemplate
]
if not strategy_classes:
print("❌ 未找到CtaTemplate子类")
sys.exit(1)
StrategyClass = strategy_classes[0]
class_name = StrategyClass.__name__
print(f"✅ 找到策略类: {class_name}")
backtester_engine.classes[class_name] = StrategyClass
# 解析参数
symbol_full = "510300.SSE"
if '.' in symbol_full:
symbol_part, exchange_part = symbol_full.split('.', 1)
try:
exchange = Exchange(exchange_part)
except ValueError:
exchange = Exchange.SSE
else:
symbol_part = symbol_full
exchange = Exchange.SSE
start = datetime(2021, 1, 1)
end = datetime(2026, 3, 1)
print(f"\n回测参数:")
print(f" 标的: {symbol_full}")
print(f" symbol: {symbol_part}, exchange: {exchange}")
print(f" 时间: {start} ~ {end}")
print(f" 资金: 1,000,000")
print(f" 费率: 3e-5")
print(f" 滑点: 0.002")
print(f" 合约大小: 10,000")
print(f" 最小价格变动: 0.001")
# 运行回测
print("\n运行回测...")
try:
back = backtester_engine.run_backtesting(
class_name=class_name,
vt_symbol=symbol_full,
interval="1d",
start=start,
end=end,
rate=3e-5,
slippage=0.002,
size=10000,
pricetick=0.001,
capital=1000000,
setting={"stop_loss_pct": 0.15} # 默认15%止损
)
print("✅ 回测完成")
except Exception as e:
print(f"❌ 回测失败: {e}")
traceback.print_exc()
sys.exit(1)
# 获取结果
print("\n获取结果...")
result = backtester_engine.get_result_statistics()
print("\n" + "=" * 80)
print("回测结果:")
print("=" * 80)
print(f"\n📊 绩效指标:")
print(f" 总收益率: {result.get('total_return', 0):.2%}")
print(f" 年化收益率: {result.get('annual_return', 0):.2%}")
print(f" 最大回撤: {result.get('max_drawdown', 0):.2%}")
print(f" 夏普比率: {result.get('sharpe_ratio', 0):.2f}")
print(f" 卡玛比率: {result.get('calmar_ratio', 0):.2f}")
print(f" 总交易次数: {result.get('total_trades', 0)}")
print(f" 胜率: {result.get('win_rate', 0):.2%}")
print(f" 盈亏比: {result.get('profit_loss_ratio', 0):.2f}")
# 获取交易记录
trades = backtester_engine.get_all_trades()
print(f"\n📝 交易记录: 共 {len(trades)}")
for idx, trade in enumerate(trades, 1):
direction_str = "买入" if trade.direction == Direction.LONG else "卖出"
offset_str = "开仓" if trade.offset == Offset.OPEN else "平仓"
print(f" {idx}. {trade.datetime} {direction_str}{offset_str} {trade.symbol} @ {trade.price:.2f} × {trade.volume}")
print("\n" + "=" * 80)
print("✅ 回测执行完成!")
print("=" * 80)