本文是《以AI量化为生》系列的第九篇,我们将继续优化vnpy回测框架,实现参数回测结果的CSV导出功能,以及滚动夏普比率图表设计,让回测分析更加实用。

全新回测模块界面

全新回测模块界面

写在前面

上一篇文章中,我们实现了回测框架的优化和重要指标的增强,包括综合评分系统、月度统计、区间统计等功能。今天我们继续优化回测框架,主要实现两个功能:

  1. 参数回测结果窗口的导出功能 - 将优化结果导出为CSV文件和详细报告

  2. 回测图表的优化 - 去掉盈亏分布图,增加滚动夏普比率图

在实际使用中,参数优化结果如果不能导出保存,每次都要重新跑优化,效率很低。而盈亏分布图实际价值不大,滚动夏普比率能更好地反映策略在不同时期的表现。

滚动夏普比率功能实现

什么是滚动夏普比率

滚动夏普比率是在固定时间窗口内计算的夏普比率,能够动态反映策略在不同时期的风险调整收益表现。与传统的整体夏普比率相比,滚动夏普比率能够:

  • 识别策略性能的时间变化:看出策略在哪些时期表现好,哪些时期表现差

  • 及时发现策略衰退:如果滚动夏普比率持续下降,可能意味着策略失效

  • 优化策略参数:通过观察不同参数下的滚动夏普比率,选择更稳定的参数组合

滚动夏普比率的计算实现

def calculate_rolling_sharpe(self, pnl_series, window=30):
    """
    计算滚动夏普比率
    
    Args:
        pnl_series: 收益序列
        window: 滚动窗口大小,默认30天
    """
    rolling_sharpe = []
    
    for i in range(window, len(pnl_series) + 1):
        # 获取窗口内的收益数据
        window_pnl = pnl_series[i-window:i]
        
        # 计算平均收益和标准差
        mean_return = np.mean(window_pnl)
        std_return = np.std(window_pnl, ddof=1)  # 使用样本标准差
        
        # 计算夏普比率 (假设无风险利率为0)
        # 年化处理:日收益率标准差 * sqrt(252)
        if std_return > 0:
            sharpe = mean_return / std_return * np.sqrt(252)
        else:
            sharpe = 0
        
        rolling_sharpe.append(sharpe)
    
    return rolling_sharpe

关键点说明:

  • ddof=1:使用样本标准差,因为窗口数据是样本

  • **sqrt(252)**:年化处理,252是一年的交易日数

  • 无风险利率为0:简化处理,实际应用中可以使用国债收益率

参数回测结果导出功能实现

参数优化结果导出功能能够让我们保存优化结果,避免重复计算,并进行更深入的数据分析。

CSV导出功能实现

在参数优化结果监控器中添加导出按钮:

# 导出按钮
export_button = QtWidgets.QPushButton("导出CSV")
export_button.clicked.connect(self.export_csv)
toolbar_layout.addWidget(export_button)

# 导出详细报告按钮
export_detail_button = QtWidgets.QPushButton("导出详细报告")
export_detail_button.clicked.connect(self.export_detailed_report)
toolbar_layout.addWidget(export_detail_button)

智能默认路径设置

设置默认导出路径到backtests文件夹,提高用户体验:

def export_csv(self):
    """导出CSV文件"""
    import os
    from datetime import datetime
    
    # 创建默认导出路径
    current_dir = os.getcwd()
    backtests_dir = os.path.join(current_dir, "backtests")
    ifnot os.path.exists(backtests_dir):
        os.makedirs(backtests_dir)
    
    # 生成默认文件名(包含时间戳)
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    default_filename = f"optimization_results_{timestamp}.csv"
    default_path = os.path.join(backtests_dir, default_filename)
    
    path, _ = QtWidgets.QFileDialog.getSaveFileName(
        self, "导出优化结果", default_path, "CSV(*.csv)")

这样设计的优点:

  1. 自动创建目录:如果backtests文件夹不存在,会自动创建

  2. 时间戳命名:避免文件名冲突,便于版本管理

  3. 默认路径:用户可以直接保存,也可以修改路径

CSV导出核心逻辑

try:
    with open(path, "w", newline="", encoding="utf-8") as f:
        writer = csv.writer(f)

        # 写入表头
        headers = [self.table.horizontalHeaderItem(i).text() 
                  for i in range(self.table.columnCount())]
        writer.writerow(headers)

        # 写入数据(只导出显示的行)
        for row in range(self.table.rowCount()):
            ifnot self.table.isRowHidden(row):
                row_data = []
                for col in range(self.table.columnCount()):
                    item = self.table.item(row, col)
                    row_data.append(item.text() if item else"")
                writer.writerow(row_data)

    QtWidgets.QMessageBox.information(self, "导出成功", f"结果已导出到: {path}")
    
except Exception as e:
    QtWidgets.QMessageBox.warning(self, "导出失败", f"导出过程中发生错误: {str(e)}")

主要特性:

  • UTF-8编码:确保中文正常显示

  • 筛选支持:只导出当前筛选条件下的结果

  • 错误处理:完善的异常处理机制

  • 用户反馈:成功或失败都有明确提示

详细报告生成功能

除了CSV格式,还提供详细的文本报告:

def export_detailed_report(self):
    """导出详细报告"""
    # 设置默认路径和文件名
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    default_filename = f"optimization_detailed_report_{timestamp}.txt"
    default_path = os.path.join(backtests_dir, default_filename)
    
    try:
        with open(path, "w", encoding="utf-8") as f:
            f.write("参数优化详细报告\n")
            f.write("=" * 80 + "\n\n")
            
            for i, tp in enumerate(self.result_values):
                ifnot self.table.isRowHidden(i):
                    setting = tp[0]
                    statistics = tp[2]
                    
                    f.write(f"结果 {i+1}: {setting}\n")
                    f.write("-" * 60 + "\n")
                    f.write(self.format_detailed_statistics(statistics))
                    f.write("\n\n")

详细报告包含每个参数组合的完整统计信息:

  • 基础信息(回测期间、起始资金等)

  • 收益指标(总收益率、年化收益等)

  • 风险指标(最大回撤、夏普比率等)

  • 交易统计(胜率、盈亏比等)

实际测试效果

让我们运行一下回测,看看新功能的效果:

# 启动vnpy主程序
python main.py

测试步骤:

  1. 在CTA回测模块中选择一个策略

  2. 进行参数优化

  3. 查看优化后的滚动夏普比率图

  4. 观察优化后的净值回撤图显示效果

  5. 测试CSV导出和详细报告生成功能

下一步计划

下一篇文章我们将实现:

  1. 策略信号可视化系统 - 在K线图上显示买卖信号和持仓变化

  2. 实时监控面板 - 实时显示策略运行状态和关键指标

这些功能将让我们的量化交易系统更加完善和实用。

写在最后

今天我们优化了回测框架,实现了实用的导出功能,并增加了滚动夏普比率图表。这些功能看似简单,但在实际使用中很有价值。

滚动夏普比率能帮我们及时发现策略的衰退,导出功能让我们能够更好地管理和分析优化结果。

量化交易的核心是风险管理。再好的策略,如果不能控制风险,最终都会失败。这些工具和指标,都是为了帮助我们更好地理解和控制风险。


本文是《以AI量化为生》系列文章的第九篇,完整代码已开源至GitHub:https://github.com/seasonstar/atmquant

本文内容仅供学习交流,不构成任何投资建议。交易有风险,投资需谨慎。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐