问题描述
之前反映过的模拟交易信号延迟问题,经过打印系统时间确认,run daily函数在刚开始运行(函数计算前)就已经延迟。而后面的函数计算时间只花了0.02秒,所以延迟是由run daily引起的。
下图为两个模拟交易中设定为9:31的run daily的实际运行时间,之前有几天甚至延迟了3分钟以上,请问这个问题能解决吗?
解决方案
在JoinQuant(聚宽)平台的模拟交易中,遇到 run_daily 函数实际触发时间(物理时间)晚于设定时间(如9:31)的情况,是一个比较常见的现象。根据聚宽的底层架构和API文档,这种延迟主要由以下几个原因引起,并可以通过一些方法进行缓解。
一、 延迟产生的原因
-
服务器并发排队(主要原因)
9:30、9:31、14:55、15:00 是绝大多数用户设定策略运行的绝对高峰期。在这些时间点,聚宽的服务器需要同时唤醒并执行海量的模拟盘进程。由于服务器计算资源有限,任务会被放入队列中排队执行。如果排在队列靠后,就会出现物理时间上的延迟(如您观察到的延迟几秒甚至几分钟)。 -
逻辑时间与物理时间的差异
聚宽API文档中明确指出:“模拟盘有10s系统延迟, 日志中的时间并非实际时间而是逻辑时间”。策略内部的context.current_dt是严格对齐的逻辑时间(例如永远是 09:31:00),而您通过datetime.datetime.now()打印出的是服务器当前的物理时间。撮合引擎在处理分钟Bar限价单时,主要依赖逻辑时间,因此物理延迟对按Bar撮合的限价单影响相对可控,但对市价单的即时成交价格会有影响。 -
日级策略的特殊处理
文档提到:“对于使用当日开盘价撮合的日级模拟盘...出于减少并发运行模拟盘数量的目的,我们会提前到9:27~9:30之间运行”。虽然这主要针对9:30的日频策略,但也侧面说明了平台为了应对并发所做的调度调整。
二、 解决方案与缓解建议
由于这是平台公共资源分配导致的物理延迟,作为普通用户无法直接修改底层调度,但可以通过以下策略层面的调整来最大程度规避或解决:
1. 错峰运行(最有效的方法)
尽量避开全网最拥堵的 9:30 和 9:31。如果您的策略逻辑允许,可以尝试将运行时间延后1-2分钟。
# 避开9:31的高峰,改为9:32运行
run_daily(my_trade_func, time='09:32')
2. 升级为 Tick 级别频率
如果您对交易信号的即时性要求极高(例如高频抢单、追涨停等),分钟级别的 run_daily 调度可能无法满足需求。建议将策略频率升级为 Tick级别,并使用 handle_tick 函数。
- Tick级别策略是事件驱动的,每当交易所推送新的Tick数据时就会触发,实时性远高于分钟级别的定时任务。
- 注意:Tick级别回测和模拟需要开通相应权限,且必须开启真实价格模式
set_option('use_real_price', True)。
3. 使用盘口撮合模式
如果延迟导致您的市价单成交价格偏离预期,可以在模拟盘中开启盘口撮合模式,这样订单会根据真实的买卖盘口进行撮合,更贴近真实交易环境。
def initialize(context):
# 开启盘口撮合模式(仅模拟盘有效)
set_option('match_with_order_book', True)
4. 检查是否使用了耗时的初始化操作
虽然您提到核心计算只花了0.02秒,但请确保在 process_initialize 或全局作用域中没有进行耗时的网络请求或大规模数据加载,因为模拟盘每天重启恢复状态时会执行这些代码,可能会拖慢进程的启动速度。
总结
这种物理时间的延迟本质上是SaaS量化平台在早盘高峰期的并发瓶颈。错峰执行或改用Tick驱动是目前最切实可行的解决方案。如果您的资金量较大且对延迟零容忍,通常需要考虑将策略迁移至本地化部署的实盘交易软件(如Ptrade/QMT)中运行。