问题描述
我在模拟交易中的initialize函数中设置了run_monthly函数
# 每月第3个交易日进行操作
run_monthly(before_market_open,3,time='16:15', reference_security='000300.XSHG',force=False)
我想问一下在模拟交易的途中,我想换成每月第五个交易日操作,参数改成5就行吗?还是说要重新设置模拟运行?
解决方案
在聚宽(JoinQuant)的模拟交易中,不能仅仅把 initialize 函数里的参数改成 5 就完事,但你也不需要重新设置(新建)模拟运行。
为什么直接改 initialize 无效?
根据聚宽的底层机制,initialize 函数在整个模拟盘的生命周期中只执行一次(即创建模拟交易的那一刻)。在模拟交易运行途中替换代码,initialize 函数是不会被再次执行的。因此,直接修改里面的 run_monthly 参数,系统根本读取不到新的设置,依然会按照原来的“每月第3个交易日”执行。
正确的修改方法:使用 after_code_changed 和 unschedule_all
为了在不中断模拟交易的情况下修改定时任务,你需要利用聚宽提供的 after_code_changed(context) 函数。当模拟盘在每天开盘前恢复并发现代码被修改时,会自动执行这个函数。
具体步骤如下:
- 调用
unschedule_all()取消之前设定的所有定时任务。 - 重新设定你需要的定时任务(包括修改后的
run_monthly以及其他原本在initialize里的run_daily等)。
代码示例
假设你原来的代码是这样的:
def initialize(context):
# 原来的设置:每月第3个交易日
run_monthly(before_market_open, 3, time='16:15', reference_security='000300.XSHG', force=False)
# 假设你还有其他的定时任务
run_daily(market_open, time='09:30')
你需要将代码修改并替换为如下形式:
def initialize(context):
# 这里改成5,虽然对当前运行的模拟盘无效,但为了代码一致性和以后回测,建议同步修改
run_monthly(before_market_open, 5, time='16:15', reference_security='000300.XSHG', force=False)
run_daily(market_open, time='09:30')
# 添加这个函数来处理代码变更
def after_code_changed(context):
# 1. 取消所有旧的定时运行任务
unschedule_all()
# 2. 重新设定新的定时运行任务(注意:要把 initialize 里所有的 run_xxx 都重新写一遍)
# 将参数修改为每月第5个交易日
run_monthly(before_market_open, 5, time='16:15', reference_security='000300.XSHG', force=False)
# 别忘了把其他的定时任务也加回来
run_daily(market_open, time='09:30')
log.info("代码已更新,定时任务已修改为每月第5个交易日执行。")
注意事项
- 必须重写所有定时任务:
unschedule_all()会无差别地清除所有已注册的定时任务。因此,如果你在initialize中还定义了其他的run_daily或run_weekly,必须在after_code_changed中一并重新注册,否则它们将不再执行。 - 替换代码即可生效:将上述修改后的代码在模拟交易页面的“替换代码”处提交即可。系统在下一次唤醒时(通常是第二天开盘前)会检测到代码变更,执行
after_code_changed,从而成功更新你的定时任务。