问题描述
一创聚宽的实盘策略,在def initialize(context)设置了:run_daily(after_market_close, time='15:30', reference_security='000300.XSHG'),回测after_market_close内代码能正常执行,但是实盘却不会执行,是什么原因呢?
解决方案
在 JoinQuant(聚宽)平台上,回测环境和实盘/模拟盘环境在底层运行机制上存在一定差异。针对您在一创聚宽实盘中遇到的 run_daily(..., time='15:30') 不执行的问题,主要有以下几个原因及相应的解决方案:
1. 一创聚宽实盘项目已终止(最核心原因)
根据聚宽官方 API 文档的最新说明:一创聚宽已于 2023-12-29 停止维护,并且聚宽目前已不再提供任何形式的实盘及交易通道服务。如果您近期还在尝试运行,实盘环境的底层服务可能已经断开或不再维护,导致定时任务无法正常触发。
2. 券商实盘系统的结算断开机制
即使在实盘服务有效期间,实盘环境与回测环境也有很大不同:
- 回测环境:是一个理想化的连续时间轴,
15:30的事件会被引擎准时放入队列并执行。 - 实盘环境:A股市场在
15:00收盘后,券商系统通常会很快进入日终清算(结算)模式。为了保护系统和进行数据结算,实盘网关或策略进程往往会在15:00之后不久(例如 15:05 或 15:15)被强制断开连接或休眠。因此,设定在15:30的run_daily任务在实盘中极有可能因为进程已经结束或休眠而无法被触发。
3. 解决方案与代码优化建议
如果您在模拟盘或其他支持的实盘通道中需要执行收盘后的逻辑,建议采用以下替代方案:
方案一:使用官方原生的 after_trading_end 函数
聚宽 API 提供了专门用于收盘后处理的内置函数 after_trading_end(context)。该函数会在每天交易结束后(通常是 15:00 之后到 15:30 之间,由系统底层控制触发时机)自动调用,比手动设置 run_daily 更加稳定。
def initialize(context):
# 不需要在这里用 run_daily 注册 15:30 的任务
pass
# 直接实现内置的收盘后函数
def after_trading_end(context):
log.info("收盘后逻辑开始执行:" + str(context.current_dt))
# 在这里编写您的盘后处理代码,如打印日志、计算指标、撤销未完成订单等
orders = get_open_orders()
for _order in orders.values():
cancel_order(_order)
方案二:将 run_daily 的时间提前至 15:00
如果您必须使用 run_daily,为了防止实盘进程过早休眠,建议将时间提前到 15:00(即收盘的最后一分钟)。此时市场刚刚停止撮合,但实盘进程绝对还在活跃状态。
def initialize(context):
# 将时间提前到 15:00
run_daily(after_market_close, time='15:00', reference_security='000300.XSHG')
def after_market_close(context):
log.info("执行盘后逻辑")
# 注意:此时不能再下市价单或限价单,否则会成为废单或挂单到下一个交易日
总结
实盘中 15:30 不执行主要是因为券商通道结算导致进程休眠/断开,以及一创聚宽服务本身已终止。建议在编写策略时,尽量使用平台标准的 after_trading_end 钩子函数来处理盘后逻辑,以获得最佳的兼容性。