问题描述
解决方案
在 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说明
-
after_trading_end(context):- 触发时间: 15:30。
- 用途: 此时交易已结束,未成交订单已被撤销。适合计算当日净值、记录持仓、发送微信消息(模拟盘)等。
-
record(key=value):- 用途: 在回测结果页面的收益率曲线下方绘制额外的曲线。
- 限制: 只能在回测开始后调用,且
value必须是数字。
-
write_file(path, content, append=False):- 用途: 将文本或二进制数据写入“投资研究”目录下的文件。
- 场景: 如果你需要导出详细的交易记录到 Excel 或 CSV 进行本地分析,这是一个非常有用的函数。
-
log.info(content):- 用途: 输出信息到日志面板。适合调试和查看每日简报。
常见问题 (Q&A)
Q: after_trading_end 中可以使用 order 下单函数吗?
A: 不可以。15:30 已经闭市,此时调用下单函数会失败或被系统拒绝。如果需要下单,请在 handle_data 或 run_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 函数向微信发送当日的收益日报。