Files
2026-04-29 20:15:25 +08:00

210 lines
8.2 KiB
Python
Raw Permalink 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
"""
本地直接测试回测 - 直接在容器内运行,找到崩溃原因
策略来自关羽将军:single_stock_stop_loss_final_correct.py
参数:510300.SSE2021-01-01 ~ 2026-03-01stop_loss_pct=0.15
"""
# 先读取策略代码
with open('/Users/chufeng/.openclaw/workspace-guanyu/pangtong-value/research/task-20260329-strategy-backtest/guanyu/single_stock_stop_loss_final_correct.py', 'r') as f:
strategy_code = f.read()
# 导入我们的RPC函数,直接调用测试
import sys
sys.path.insert(0, '/app')
# 这里我们直接复制 final_rpc_correct.py 中的兼容性代码和run_strategy_backtest函数
# 然后直接调用,看看哪里崩溃
import types
# ============================================
# 🔥 复制vnpy.app兼容性模块
# ============================================
print("🔧 [TEST] 加载vnpy.app兼容性模块...")
# 创建顶级模块
vnpy_app_module = types.ModuleType('vnpy.app')
sys.modules['vnpy.app'] = vnpy_app_module
# 创建子模块
submodules = ['cta_strategy', 'cta_backtester', 'data_manager']
for name in submodules:
full_name = f'vnpy.app.{name}'
submodule = types.ModuleType(full_name)
sys.modules[full_name] = submodule
setattr(vnpy_app_module, name, submodule)
# 从实际模块映射类
from vnpy_ctastrategy import CtaTemplate, CtaStrategyApp
sys.modules['vnpy.app.cta_strategy'].CtaTemplate = CtaTemplate
sys.modules['vnpy.app.cta_strategy'].CtaStrategyApp = CtaStrategyApp
vnpy_app_module.CtaTemplate = CtaTemplate
vnpy_app_module.CtaStrategyApp = CtaStrategyApp
from vnpy_ctabacktester import BacktesterEngine
sys.modules['vnpy.app.cta_backtester'].BacktesterEngine = BacktesterEngine
vnpy_app_module.BacktesterEngine = BacktesterEngine
print("✅ [TEST] vnpy.app兼容性模块加载完成!")
print(f" 确认: BacktesterEngine 的类型 = {type(BacktesterEngine)}, 是否是类 = {isinstance(BacktesterEngine, type)}")
# ============================================
# 兼容性修复完成,现在导入其他模块
# ============================================
from vnpy.event import EventEngine
from vnpy.trader.engine import MainEngine
import traceback
def test_run_strategy_backtest(strategy_code: str, symbol: str, interval: str, start: int, end: int, **kwargs):
"""直接测试run_strategy_backtest"""
try:
print(f"\n🚀 [TEST] 开始回测: {symbol} [{start} - {end}]")
# 动态加载策略
local_vars = {}
exec(strategy_code, globals(), local_vars)
# 查找CtaTemplate子类
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:
return {
"error": "策略代码中未找到CtaTemplate子类",
"hint": "请确保策略继承自CtaTemplate"
}
StrategyClass = strategy_classes[0]
print(f"✅ [TEST] 找到策略类: {StrategyClass.__name__}")
# ============================================
# 创建引擎 - 按照vnpy 4.x最新规范
# ============================================
print(f"🔧 [TEST] 创建引擎...")
event_engine = EventEngine()
print(f"✅ [TEST] event_engine = EventEngine()")
main_engine = MainEngine(event_engine)
print(f"✅ [TEST] main_engine = MainEngine(event_engine)")
# ✅ vnpy 4.x 正确用法:add_app 添加类,MainEngine负责实例化
print(f"🔧 [TEST] main_engine.add_app(BacktesterEngine) // 添加类,不是实例")
print(f"🔧 [TEST] 确认: BacktesterEngine 的类型 = {type(BacktesterEngine)}, 是否是类 = {isinstance(BacktesterEngine, type)}")
main_engine.add_app(BacktesterEngine)
print(f"✅ [TEST] 添加到主引擎完成")
print(f"🔧 [TEST] backtester_engine = main_engine.get_app(BacktesterEngine)")
backtester_engine = main_engine.get_app(BacktesterEngine)
print(f"✅ [TEST] get_app 返回: 类型 = {type(backtester_engine)}, 是否是实例 = {not isinstance(backtester_engine, type)}")
# 双重保险:如果get_app返回的还是类,我们自己实例化
if isinstance(backtester_engine, type):
print(f"⚠️ [TEST] get_app 返回的还是类,手动实例化: backtester_engine = BacktesterEngine(main_engine, event_engine)")
backtester_engine = BacktesterEngine(main_engine, event_engine)
print(f"✅ [TEST] 手动实例化成功,现在是实例: 类型 = {type(backtester_engine)}")
print(f"🔧 [TEST] backtester_engine.init_engine()")
backtester_engine.init_engine()
print(f"✅ [TEST] 初始化完成")
# ============================================
# 修复完成
# ============================================
# 格式化日期
start_str = str(start)
if len(start_str) == 8:
start_str = f"{start_str[:4]}-{start_str[4:6]}-{start_str[6:8]}"
end_str = str(end)
if len(end_str) == 8:
end_str = f"{end_str[:4]}-{end_str[4:6]}-{end_str[6:8]}"
setting = {
"vt_symbol": symbol,
"interval": interval,
"start_date": start_str,
"end_date": end_str,
"rate": kwargs.get("rate", 0.00003),
"slippage": kwargs.get("slippage", 0.2),
"size": kwargs.get("size", 1),
"pricetick": kwargs.get("pricetick", 0.2),
"capital": kwargs.get("capital", 1000000.0),
}
print(f"✅ [TEST] 回测参数: {setting}")
# ============================================
# 🔥 这里确认:正确调用方法,不直接调用实例
# ============================================
print(f"🔧 [TEST] 执行回测: backtester_engine.run_backtesting(...)")
# ✅ 正确写法:调用方法,不直接调用实例
# ❌ 错误写法:result = backtester_engine(...)
# ✅ 正确写法:result = backtester_engine.run_backtesting(...)
result = backtester_engine.run_backtesting(
strategy_class=StrategyClass,
setting=setting
)
print(f"✅ [TEST] 回测完成: result = backtester_engine.run_backtesting(...)")
# 获取结果
statistics = backtester_engine.get_result_statistics()
print(f"✅ [TEST] 回测完成,统计指标: {list(statistics.keys()) if statistics else ''}")
# 获取每日数据
daily_df = backtester_engine.get_daily_df()
if daily_df is not None and hasattr(daily_df, 'to_dict'):
daily_data = daily_df.to_dict(orient='records')
else:
daily_data = []
# 获取交易记录
trades = backtester_engine.get_all_trades()
trade_list = [t.__dict__ for t in trades] if trades else []
return {
"statistics": statistics,
"trades": trade_list,
"daily_data": daily_data
}
except Exception as e:
error_info = {
"error": str(e),
"traceback": traceback.format_exc()
}
print(f"❌ [TEST] 回测错误: {error_info['error']}")
print(error_info['traceback'])
return error_info
if __name__ == '__main__':
print("\n=== 开始本地测试 ===")
result = test_run_strategy_backtest(
strategy_code=strategy_code,
symbol="510300.SSE",
interval="1d",
start=20210101,
end=20260301,
rate=0.00003,
slippage=0.002,
size=10000,
pricetick=0.001,
capital=1000000,
)
print("\n=== 测试结果 ===")
if 'error' in result:
print(f"❌ 测试失败: {result['error']}")
print("\n完整traceback:")
print(result['traceback'])
else:
print(f"✅ 测试成功!")
print(f"📊 统计指标: {list(result['statistics'].keys())}")
print(f"💹 交易记录数量: {len(result['trades'])}")
print(f"📈 每日数据行数: {len(result['daily_data'])}")