问题描述
run_weekly(weekly_adjustment,2,'10:00')
def weekly_adjustment(context):
log.info("每周二调仓")
2024-09-19 10:00:00 - INFO - 每周二调仓
以上是部分代码和日志输出,函数定义的是每周二调仓,但通过回测策略查看日志,发现2024-09-19这天也有触发这个函数,但实际上这天是周四,所以理应不触发。so有哪位大佬知道这是什么问题吗?
解决方案
您好!出现这个问题的原因在于对 run_weekly 函数中 weekday 参数的理解存在偏差。
原因分析
在 JoinQuant 的 API 中,run_weekly(func, weekday, time, ...) 的 weekday 参数代表的是**“每周的第几个交易日”**,而不是自然日历中的“星期几”。
我们来看一下 2024 年 9 月中旬的日历和 A 股休市安排:
- 2024 年 9 月 16 日(周一)和 9 月 17 日(周二)是中秋节假期,A 股休市。
- 因此,该周的第一个交易日是 9 月 18 日(周三)。
- 该周的第二个交易日是 9 月 19 日(周四)。
您的代码 run_weekly(weekly_adjustment, 2, '10:00') 意思是:在每周的第二个交易日的 10:00 执行。所以,在 2024-09-19(周四)触发是完全符合 API 设计逻辑的。
此外,API 文档中还提到:“开始策略的那一周第一个交易日是从策略开始的那一天计算的。” 这也可能导致在策略刚启动的第一周,触发的自然日与您预期的不同。
解决方案
如果您希望策略严格在每周二执行(如果周二休市则跳过,或者顺延),可以通过以下两种方式实现:
方法一:在回调函数中增加星期几的判断(推荐)
您可以将定时任务设置为每天运行,或者每周的某一天运行,然后在函数内部使用 Python 的 datetime 模块判断当天是否为星期二(isoweekday() == 2)。
def initialize(context):
# 每天 10:00 运行
run_daily(weekly_adjustment, time='10:00')
def weekly_adjustment(context):
# isoweekday() 返回 1-7 代表周一到周日
if context.current_dt.isoweekday() != 2:
# 如果不是周二,直接返回,不执行调仓逻辑
return
log.info("今天是周二,执行调仓")
# 下面写您的调仓逻辑
方法二:结合 run_weekly 和 isoweekday
如果您希望尽量减少函数的调用次数,可以保留 run_weekly,但为了防止节假日导致的错位,依然需要在函数内进行判断:
def initialize(context):
# 尝试在每周的第2个交易日运行
run_weekly(weekly_adjustment, 2, time='10:00')
def weekly_adjustment(context):
if context.current_dt.isoweekday() != 2:
log.info("本周第二个交易日不是周二,跳过调仓")
return
log.info("每周二调仓")
注意:方法二在遇到周一或周二休市的周时,会导致该周完全不调仓。如果您希望在周二休市时顺延到周三调仓,建议使用方法一,并自行编写顺延逻辑。
总结来说,量化回测中处理时间时,一定要区分**“交易日”和“自然日”**的概念,JoinQuant 的 run_weekly 和 run_monthly 默认都是基于“交易日”来计算的。