问题描述
设置了每个bar运行一次:run_daily(market_open, time='every_bar', reference_security='RB9999.XSGE')
订阅的是30分钟K线:bar_data = get_bars(IF_current_month, count=context.long_extend,
unit='30m', fields=['close'])["close"]
按理说应该每30分钟运行一遍,但看日志,每天就开盘的时候运行了一遍,就结束了,这是为啥?
解决方案
出现这个问题的原因在于您对 time='every_bar' 的理解与 JoinQuant 引擎的实际运行机制存在偏差。
为什么每天只运行了一次?
在 JoinQuant 平台中,time='every_bar' 的触发频率完全取决于您在回测/模拟交易界面(右上方)设置的“运行频率”(按天或按分钟),而不取决于您在代码中使用 get_bars 获取数据的周期(如 unit='30m')。
根据 JoinQuant API 文档的说明:
- 如果您在界面上选择了“按天”回测:
time='every_bar'会在每天开盘时调用一次(即每天只运行一次)。 - 如果您在界面上选择了“按分钟”回测:
time='every_bar'会在交易时间内每分钟调用一次。
JoinQuant 引擎底层只支持“天”、“分钟”和“Tick”三种基础驱动频率,并不存在原生的“按 30 分钟”驱动频率。因此,即使您获取了 30 分钟的 K 线数据,只要您的回测频率选的是“按天”,策略就只会每天开盘运行一次。
如何实现每 30 分钟运行一次策略?
要在 JoinQuant 中实现每 30 分钟执行一次交易逻辑,您需要将回测频率设置为“按分钟”,然后通过以下两种方案之一来实现:
方案一:在分钟回调中进行时间判断(推荐)
将回测频率设置为“按分钟”,every_bar 会每分钟触发一次。我们在函数内部通过 context.current_dt 判断当前分钟数,只有在符合 30 分钟节点时才执行核心逻辑。
def initialize(context):
# 必须在回测界面将频率设置为“按分钟”
run_daily(market_open, time='every_bar', reference_security='RB9999.XSGE')
def market_open(context):
# 获取当前时间
current_minute = context.current_dt.minute
# 判断是否是 30 分钟的节点 (例如 09:30, 10:00, 10:30 等)
# 注意:期货夜盘和白盘的时间节点可能需要根据具体品种交易时间微调
if current_minute % 30 == 0:
# 在这里获取 30 分钟 K 线并执行交易逻辑
bar_data = get_bars('IF9999.CCFX', count=context.long_extend, unit='30m', fields=['close'])
close_price = bar_data['close'][-1]
log.info(f"当前时间 {context.current_dt},执行 30 分钟策略逻辑")
# 您的下单逻辑...
方案二:使用多个 run_daily 定时触发
如果您不想每分钟都触发函数,可以使用多个 run_daily 明确指定每天需要运行的具体时间点。这种方法比较死板,但对于交易时间固定的品种很有效。
def initialize(context):
# 明确指定每天的 30 分钟节点运行
# 注意:这里的时间需要根据您交易品种的实际交易时间来设定
run_daily(market_open, time='09:30', reference_security='RB9999.XSGE')
run_daily(market_open, time='10:00', reference_security='RB9999.XSGE')
run_daily(market_open, time='10:30', reference_security='RB9999.XSGE')
run_daily(market_open, time='11:00', reference_security='RB9999.XSGE')
run_daily(market_open, time='11:30', reference_security='RB9999.XSGE')
run_daily(market_open, time='13:30', reference_security='RB9999.XSGE')
run_daily(market_open, time='14:00', reference_security='RB9999.XSGE')
run_daily(market_open, time='14:30', reference_security='RB9999.XSGE')
run_daily(market_open, time='15:00', reference_security='RB9999.XSGE')
# 如果有夜盘,还需要继续添加夜盘的时间节点
def market_open(context):
# 获取 30 分钟 K 线并执行交易逻辑
bar_data = get_bars('IF9999.CCFX', count=context.long_extend, unit='30m', fields=['close'])
log.info(f"当前时间 {context.current_dt},执行策略")
总结
- 检查您的回测/模拟设置,确保运行频率选的是**“按分钟”**。
get_bars的unit='30m'只是决定了您获取的数据切片是 30 分钟一根,它不能改变策略引擎的驱动频率。- 结合分钟级回测和代码内的时间判断,是实现自定义周期(如 5m, 15m, 30m, 60m)策略的标准做法。