Files
sanguo_quant_live/strategies/factors-dynamic-weight-timing-20260327/run_local_rpc.py
T
2026-04-02 08:55:07 +08:00

157 lines
5.3 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
# -*- coding: utf-8 -*-
"""
本地执行回测 - 通过RPC连接vnpy回测引擎
SingleStockStopLossStrategy with 15% stop loss
510300.SSE 2021-01-01 ~ 2026-03-01
Author: Guan Yu YunChang
Date: 2026-03-31
"""
import sys
import os
import pickle
import zmq
from typing import Dict, Any
# RPC配置 - 容器外连接(当前运行在容器外 NAS Mac mini 192.168.2.153
RPC_ENDPOINT = "tcp://192.168.2.154:8008"
# 回测参数
BACKTEST_CONFIG = {
"strategy_name": "SingleStockStopLossStrategy",
"description": "进阶多因子动态加权 + 关羽15%单票止损风控 - 510300.SSE",
"symbol": "510300.SSE",
"interval": "1d",
"start": 1609459200,
"end": 1772515200,
"start_date": "2021-01-01",
"end_date": "2026-03-01",
"initial_capital": 1000000,
"commission_fee": 3e-5,
"slippage": 0.002,
"contract_size": 10000,
"price_tick": 0.001,
"data_source": "sqlite",
"strategy_module_path": os.path.abspath("main_strategy_single_file.py"),
"strategy_class": "MultiFactorDynamicStrategy",
"stop_loss_pct": 0.15,
"parameters": {
"stop_loss_pct": 0.15,
"enabled": True
}
}
def main():
"""主函数"""
print("=" * 60)
print("SingleStockStopLossStrategy 回测 - 本地RPC执行")
print("标的: 510300.SSE 沪深300ETF")
print("区间: 2021-01-01 ~ 2026-03-01")
print("止损: 15%")
print("初始资金: 1,000,000")
print("=" * 60)
# 读取策略代码
code_path = os.path.join(os.path.dirname(__file__), "main_strategy_single_file.py")
with open(code_path, 'r', encoding='utf-8') as f:
strategy_code = f.read()
BACKTEST_CONFIG["strategy_code"] = strategy_code
# 连接RPC
context = zmq.Context()
socket = context.socket(zmq.REQ)
socket.connect(RPC_ENDPOINT)
print(f"\n连接RPC服务器: {RPC_ENDPOINT}")
try:
# 发送回测请求 - 使用pickle序列化匹配服务器端
print("发送回测请求... (pickle)")
socket.send_pyobj(BACKTEST_CONFIG)
# 接收响应
print("等待回测结果... (全区间回测需要几分钟,请耐心等待)")
result = socket.recv_pyobj()
# 检查结果
if isinstance(result, dict):
if result.get("code") == 200 or result.get("status") == "ok" or "metrics" in result:
print("\n✅ 回测成功完成!")
else:
print(f"\n❌ 回测失败: {result.get('msg') or result.get('error')}")
print(f"详细信息: {result}")
sys.exit(1)
else:
print(f"\n❌ 返回结果不是字典: {type(result)}")
print(f"结果: {result}")
sys.exit(1)
# 保存结果
output_file = os.path.join(
os.path.dirname(__file__),
f"backtest_result_510300_stoploss_{int(BACKTEST_CONFIG['stop_loss_pct'] * 100)}.json"
)
# 保存为json方便查看
with open(output_file, 'w', encoding='utf-8') as f:
import json
json.dump(result, f, indent=2, ensure_ascii=False)
print(f"\n💾 完整结果已保存到: {output_file}")
# 打印关键指标
print("\n" + "=" * 60)
print("📊 回测结果摘要")
print("=" * 60)
metrics = result.get('metrics') or result.get('data', {}).get('metrics', result)
print(f"\n📋 基本信息:")
print(f" 策略名称: {BACKTEST_CONFIG['strategy_name']}")
print(f" 标的: {BACKTEST_CONFIG['symbol']} 沪深300ETF")
print(f" 回测区间: {BACKTEST_CONFIG['start_date']} ~ {BACKTEST_CONFIG['end_date']}")
print(f" 初始资金: {BACKTEST_CONFIG['initial_capital']:,}")
print(f" 单票止损: {BACKTEST_CONFIG['stop_loss_pct'] * 100:.0f}%")
print(f"\n📈 绩效指标:")
def print_metric(key, name, fmt="{:.2%}"):
if key in metrics:
print(f" {name}: {fmt.format(metrics[key])}")
elif key.lower() in metrics:
print(f" {name}: {fmt.format(metrics[key.lower()])}")
print_metric('total_return', '总收益率')
print_metric('annual_return', '年化收益率')
print_metric('max_drawdown', '最大回撤')
print_metric('sharpe_ratio', '夏普比率', '{:.2f}')
print_metric('calmar_ratio', '卡玛比率', '{:.2f}')
print_metric('sortino_ratio', '索提诺比率', '{:.2f}')
print_metric('win_rate', '胜率')
print_metric('profit_loss_ratio', '盈亏比', '{:.2f}')
print(f"\n⚠️ 交易统计:")
if 'total_trades' in metrics:
print(f" 总交易次数: {metrics['total_trades']}")
if 'stop_loss_count' in metrics or 'stop_loss_triggered' in metrics:
print(f" 触发止损次数: {metrics.get('stop_loss_count') or metrics.get('stop_loss_triggered', 0)}")
if 'final_capital' in metrics:
print(f" 最终资金: {metrics['final_capital']:,.2f}")
print("\n" + "=" * 60)
print("回测完成!")
return result
except Exception as e:
print(f"\n❌ 执行异常: {type(e).__name__}: {e}")
import traceback
traceback.print_exc()
sys.exit(1)
if __name__ == "__main__":
main()