🚀 AI 一键生成 joinquant 策略代码

如何在 JoinQuant 回测结束后生成并导出自定义的详细交易分析报告?

joinquant | 发布时间: 2025/12/18
以下内容由 EasyQuant 生成。

问题描述

如何在回测结束时,把所有的交易记录和当时的决策理由保存到一个文件里?

解决方案

在JoinQuant(聚宽)平台中,要实现回测结束时保存交易记录和决策理由,主要涉及以下三个步骤:

  1. 初始化存储容器:在 initialize 中定义一个全局列表(如 g.records)用于暂存数据。
  2. 记录决策:在下单的同时,将时间、标的、操作、数量以及决策理由写入上述列表。
  3. 保存文件:利用 on_strategy_end(context) 回调函数,在回测结束时将列表转换为 DataFrame,并使用 write_file API 保存为 CSV 文件。

以下是一个完整的策略示例代码,展示了如何实现这一功能。

策略代码示例

# -*- coding: utf-8 -*-
import pandas as pd
from jqdata import *

def initialize(context):
    # 设置基准
    set_benchmark('000300.XSHG')
    # 开启动态复权
    set_option('use_real_price', True)
    
    # 定义一个全局列表,用于保存交易决策记录
    g.decision_records = []
    
    # 设置要操作的股票
    g.security = '000001.XSHE'
    
    # 每天运行
    run_daily(market_open, time='every_bar')

def market_open(context):
    security = g.security
    
    # 获取过去5天和10天的收盘价
    close_data = attribute_history(security, 10, '1d', ['close'])
    ma5 = close_data['close'][-5:].mean()
    ma10 = close_data['close'].mean()
    
    # 获取当前持仓
    curr_position = context.portfolio.positions[security].total_amount
    cash = context.portfolio.available_cash
    
    # --- 策略逻辑与记录 ---
    
    # 金叉买入
    if ma5 > ma10 and curr_position == 0:
        # 下单
        order_value(security, cash)
        
        # 记录决策理由
        record_decision(context, security, 'BUY', '5日均线上穿10日均线,形成金叉,看多买入')
        
        log.info("买入 %s" % security)

    # 死叉卖出
    elif ma5 < ma10 and curr_position > 0:
        # 下单
        order_target(security, 0)
        
        # 记录决策理由
        record_decision(context, security, 'SELL', '5日均线下穿10日均线,形成死叉,止盈/止损卖出')
        
        log.info("卖出 %s" % security)

def record_decision(context, security, action, reason):
    """
    自定义函数:用于将单次决策记录添加到全局列表中
    """
    record = {
        'datetime': context.current_dt,  # 当前时间
        'security': security,            # 标的代码
        'action': action,                # 操作方向 (BUY/SELL)
        'price': context.portfolio.positions[security].price, # 当前持仓价格或最新价
        'reason': reason                 # 决策理由
    }
    g.decision_records.append(record)

def on_strategy_end(context):
    """
    策略运行结束时调用
    在此处将记录保存为文件
    """
    if len(g.decision_records) > 0:
        # 将列表转换为 DataFrame
        df = pd.DataFrame(g.decision_records)
        
        # 调整列的顺序,使其更易读
        cols = ['datetime', 'security', 'action', 'price', 'reason']
        df = df[cols]
        
        # 将 DataFrame 转换为 CSV 格式的字符串
        # encoding='utf_8_sig' 是为了防止 Excel 打开中文乱码
        content = df.to_csv(index=False, encoding='utf_8_sig')
        
        # 文件名
        file_name = 'backtest_records.csv'
        
        # 保存文件到研究环境根目录
        write_file(file_name, content, append=False)
        
        print("策略结束,交易记录已保存至研究环境根目录: %s" % file_name)
    else:
        print("策略结束,无交易记录。")

代码解析

  1. g.decision_records: 在 initialize 中初始化为空列表。这是内存中的临时存储容器。
  2. record_decision 函数: 这是一个自定义的辅助函数。每当策略触发 order 相关函数时,我们手动调用这个函数,把当时的上下文(时间、股票、操作类型)和最重要的reason(理由) 存入字典,并追加到 g.decision_records 中。
  3. on_strategy_end(context): 这是聚宽提供的标准回调函数,仅在回测结束或模拟交易终止时运行一次。
    • 我们在这里利用 pandas 将列表整理成表格形式。
    • 使用 df.to_csv 将数据序列化为 CSV 格式字符串。
    • 关键 API: write_file(path, content) 将内容写入到聚宽的“研究”环境中。

如何查看保存的文件?

回测结束后,请前往聚宽官网顶部的 “研究” (Research) 选项卡。在研究环境的文件列表中,你将看到名为 backtest_records.csv 的文件。你可以直接点击下载或在线编辑查看。

Q&A

Q: write_file 保存的文件在哪里?
A: 文件保存在您的“研究”环境根目录下。您可以在聚宽导航栏点击“研究”查看。

Q: 为什么不直接使用 get_trades() 获取记录?
A: get_trades() 只能获取成交的客观数据(如时间、价格、数量),它无法记录您当时下单的“逻辑”或“理由”(例如“因为MACD金叉”)。如果您需要保存决策理由,必须像示例中那样手动记录。

Q: 如果回测中途报错停止,on_strategy_end 会执行吗?
A: 不会。on_strategy_end 仅在策略正常结束(完成所有日期的回测)时调用。如果担心报错导致数据丢失,可以在 after_trading_end(每天收盘后)中进行保存,但这样会频繁进行 IO 操作,降低回测速度。

Q: 可以保存为 Excel 格式吗?
A: write_file 接收的是字符串或二进制数据。虽然可以保存为 .csv(Excel可打开),但如果必须保存为 .xlsx 格式,需要使用 pandasto_excel 配合 BytesIO 流,并将 write_file 的内容设为二进制流。通常情况下,CSV 格式已足够通用。