🚀 AI 一键生成 joinquant 策略代码

JoinQuant 实战:利用 after_trading_end 函数实现每日自动化盘后分析

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

问题描述

如何在每天收盘后自动进行数据分析和记录?

解决方案

在 JoinQuant(聚宽)平台中,要在每天收盘后自动进行数据分析和记录,主要有两种标准方法:使用内置的事件回调函数 after_trading_end,或者使用定时运行函数 run_daily 指定时间。

以下是具体的实现方案和代码示例。

方法一:使用 after_trading_end 函数(推荐)

这是聚宽框架提供的标准生命周期函数。该函数会在每天交易结束后(通常是 15:30)自动被系统调用。此时当天的订单已全部处理完毕,适合进行账户盘点、日志记录或计算当日策略表现。

# -*- coding: utf-8 -*-
def initialize(context):
    # 初始化策略,设置基准等
    set_benchmark('000300.XSHG')
    set_option('use_real_price', True)
    # 这里不需要注册 after_trading_end,系统会自动识别

def handle_data(context, data):
    # 盘中交易逻辑
    pass

# 每天收盘后(15:30)自动运行
def after_trading_end(context):
    # 1. 获取账户信息进行分析
    total_value = context.portfolio.total_value
    returns = context.portfolio.returns
    daily_return = context.portfolio.daily_return
    
    # 2. 打印日志记录 (会在回测日志中显示)
    log.info("【收盘总结】日期: %s, 总资产: %.2f, 累计收益: %.2f%%, 今日收益: %.2f%%" % (
        context.current_dt.date(), 
        total_value, 
        returns * 100, 
        daily_return * 100
    ))
    
    # 3. 使用 record 函数绘制曲线 (会在回测收益图中显示额外曲线)
    # 注意:record 只能记录数值类型
    record(daily_ret=daily_return * 100)
    
    # 4. (可选) 将复杂数据写入文件,便于后续研究
    # 比如记录当天的持仓详情到 CSV 文件
    if len(context.portfolio.positions) > 0:
        content = "Date,Security,Amount,Value\n"
        for stock, position in context.portfolio.positions.items():
            row = "%s,%s,%d,%.2f\n" % (
                context.current_dt.date(),
                stock,
                position.total_amount,
                position.value
            )
            content += row
        # 追加写入文件
        write_file('positions_log.csv', content, append=True)

方法二:使用 run_daily 定时运行

如果你需要更灵活的时间控制(例如在 15:05 或 16:00 运行),或者想把分析逻辑拆分成多个函数,可以在 initialize 中使用 run_daily

# -*- coding: utf-8 -*-
def initialize(context):
    set_benchmark('000300.XSHG')
    
    # 指定在每天 15:40 运行自定义的分析函数
    run_daily(my_analysis_func, time='15:40')

def handle_data(context, data):
    pass

# 自定义的收盘分析函数
def my_analysis_func(context):
    # 获取当前持仓列表
    positions = context.portfolio.positions.keys()
    
    if len(positions) > 0:
        # 获取持仓股票的收盘价(注意:history取天数据不包含当天,建议取分钟数据或使用get_current_data)
        # 这里演示获取当天的收盘价
        current_data = get_current_data()
        
        log.info("=== 开始进行收盘持仓分析 ===")
        for stock in positions:
            price = current_data[stock].last_price
            cost = context.portfolio.positions[stock].avg_cost
            # 计算单只股票盈亏比例
            pnl_ratio = (price - cost) / cost if cost > 0 else 0
            
            log.info("标的: %s, 现价: %.2f, 成本: %.2f, 盈亏比: %.2f%%" % (
                stock, price, cost, pnl_ratio * 100
            ))
        log.info("=== 分析结束 ===")

关键API说明

  1. after_trading_end(context):

    • 触发时间: 15:30。
    • 用途: 此时交易已结束,未成交订单已被撤销。适合计算当日净值、记录持仓、发送微信消息(模拟盘)等。
  2. record(key=value):

    • 用途: 在回测结果页面的收益率曲线下方绘制额外的曲线。
    • 限制: 只能在回测开始后调用,且 value 必须是数字。
  3. write_file(path, content, append=False):

    • 用途: 将文本或二进制数据写入“投资研究”目录下的文件。
    • 场景: 如果你需要导出详细的交易记录到 Excel 或 CSV 进行本地分析,这是一个非常有用的函数。
  4. log.info(content):

    • 用途: 输出信息到日志面板。适合调试和查看每日简报。

常见问题 (Q&A)

Q: after_trading_end 中可以使用 order 下单函数吗?
A: 不可以。15:30 已经闭市,此时调用下单函数会失败或被系统拒绝。如果需要下单,请在 handle_datarun_daily 指定的交易时间内(如 09:30 - 15:00)进行。

Q: 收盘后获取 history 数据包含当天的数据吗?
A: 在聚宽中,history 获取日线级别('1d')数据时,默认不包含当天的数据(为了防止未来函数)。如果你在收盘后想获取当天的行情,建议使用 get_current_data() 获取最新价,或者获取分钟级别('1m')的 history 数据来合成。

Q: record 函数画的图在哪里看?
A: 回测结束后,在回测详情页面的收益曲线图下方,会有一个折线图区域,你通过 record 记录的每一个 key 都会对应一条曲线。

Q: 模拟交易中 after_trading_end 也会运行吗?
A: 是的。在模拟交易中,该函数同样会在每天 15:30 运行。你可以在这里配合 send_message 函数向微信发送当日的收益日报。