问题描述
请问我一分钟内想分多笔下单,可以用time.sleep()吗?因为我的策略是按天回测的,不知道可不可以这样。
解决方案
核心解答
不可以,强烈不建议在 JoinQuant(聚宽)的回测或模拟交易中使用 time.sleep() 来实现分笔下单。
特别是在按天回测的策略中,这种做法不仅无法达到你预期的“分时段下单”效果,还可能导致策略运行失败。
为什么不能用 time.sleep()?
-
逻辑时间 vs 物理时间:
JoinQuant 的回测和模拟交易引擎是基于逻辑时间(即context.current_dt)驱动的。在按天回测模式下,引擎每天只会在固定的时间点(通常是 09:30:00)调用一次你的交易函数。使用time.sleep()只会暂停服务器上 Python 进程的物理时间,但逻辑时间并不会随之流逝。这意味着你 sleep 完之后下的单,在回测引擎看来,依然是在同一个逻辑时间点(09:30:00)下的单。 -
超时被杀进程的风险:
根据 JoinQuant API 文档规定,每个函数运行时间不能超过 1800 秒。如果你在策略中大量使用time.sleep(),很容易导致函数执行超时,系统会强制终止你的策略进程,并抛出TimeoutError。 -
撮合机制的限制:
在按天频率下,市价单是按最新价+滑点撮合,限价单是按分钟 Bar 撮合。在同一个逻辑时间点连续下多笔单,引擎会将其视为同一时刻的批量订单,无法模拟出真实市场中“隔几秒下一笔”的盘口冲击效果。
正确的日内分笔下单解决方案
如果你希望在日内(甚至一分钟内)分多笔下单,应该改变策略的时间驱动方式,而不是使用物理休眠。以下是推荐的做法:
方案一:使用多个 run_daily 定时任务(推荐)
如果你只是想在每天的特定几个时间点分别下单,可以在 initialize 函数中注册多个定时任务。引擎会在到达指定的逻辑时间时自动触发这些函数。
def initialize(context):
# 每天 09:30 执行第一笔
run_daily(order_part_1, time='09:30')
# 每天 09:31 执行第二笔
run_daily(order_part_2, time='09:31')
# 每天 09:35 执行第三笔
run_daily(order_part_3, time='09:35')
def order_part_1(context):
order('000001.XSHE', 100)
def order_part_2(context):
order('000001.XSHE', 100)
def order_part_3(context):
order('000001.XSHE', 100)
方案二:将回测频率改为“按分钟”
如果你的分笔逻辑比较复杂(例如根据上一分钟的成交情况决定下一分钟的下单),你需要将策略的运行频率从“天”改为“分钟”。
def initialize(context):
# 设定为每分钟运行一次
run_daily(handle_minute, time='every_bar')
g.order_count = 0
def handle_minute(context):
# 例如:在 09:30 到 09:35 之间,每分钟下一次单
if context.current_dt.hour == 9 and 30 <= context.current_dt.minute <= 35:
if g.order_count < 5:
order('000001.XSHE', 100)
g.order_count += 1
方案三:Tick 级别回测(针对极高频)
如果你真的需要在一分钟内(例如每隔几秒)进行精确的下单控制,分钟频率也无法满足,你需要申请开通 Tick 级回测权限,并使用 handle_tick 函数来处理每 3 秒(股票)或 0.5 秒(期货)一次的行情快照。
总结:量化平台的引擎是事件驱动和逻辑时间驱动的,请始终使用平台提供的定时 API(run_daily)或频率设置来控制执行时机,切勿使用 time.sleep()。