问题描述
解决方案
在 JoinQuant(聚宽)平台中,让策略只在每个月的最后一个交易日运行,最简单且推荐的方法是使用 run_monthly 定时运行函数,并将参数 monthday 设置为 -1。
核心方法:使用 run_monthly
在 initialize 函数中调用 run_monthly,具体设置如下:
- func: 你想要执行的交易函数名称。
- monthday: 设置为 -1。在聚宽 API 中,负数表示倒数第几个交易日,-1 即代表该月的最后一个交易日。
- time: 设置具体的运行时间(如 '09:30' 或 '14:50')。
完整代码示例
# -*- coding: utf-8 -*-
from jqdata import *
def initialize(context):
# 设置基准
set_benchmark('000300.XSHG')
# 开开启真实价格
set_option('use_real_price', True)
# 设定定时运行:
# monthday=-1 表示每月的最后一个交易日
# time='09:30' 表示在开盘时运行(也可以设为 '14:50' 进行尾盘调仓)
run_monthly(monthly_adjustment, monthday=-1, time='09:30')
def monthly_adjustment(context):
"""
该函数只会在每个月的最后一个交易日被调用
"""
log.info("当前时间: %s,是本月最后一个交易日,开始执行调仓逻辑" % context.current_dt)
# --- 下面写你的策略逻辑 ---
# 示例:获取当前持仓并简单的打印
positions = context.portfolio.positions
if len(positions) > 0:
log.info("当前持仓: ", positions.keys())
else:
log.info("当前空仓")
# 示例下单:买入平安银行 100 股
# order('000001.XSHE', 100)
为什么推荐这种方式?
- 自动处理节假日:聚宽的
run_monthly基于交易日历。如果某个月的31号是周日,30号是周六,那么“最后一个交易日”会自动识别为29号(周五)。你不需要自己写复杂的日期判断逻辑。 - 代码简洁:只需要一行代码即可实现,避免了在
handle_data中进行繁琐的if判断。 - 回测效率高:定时运行函数比每日轮询检查日期的效率更高。
Q&A 常见问题解答
Q1: 如果我想在每个月倒数第二个交易日运行怎么办?
A: 将 run_monthly 中的 monthday 参数设置为 -2 即可。
Q2: time 参数可以设置为收盘前吗?
A: 可以。如果你希望在月末收盘前进行调仓(以利用当天的收盘价作为结算参考),可以将 time 设置为 '14:50' 或 '14:55'。
Q3: 如果我在 handle_data 中想判断今天是不是月末怎么办?
A: 虽然不推荐,但可以通过获取下一交易日来判断。逻辑是:如果“下一个交易日”的月份与“当前日期”的月份不同,则今天就是本月最后一个交易日。
# 仅作逻辑参考,推荐使用 run_monthly
def check_is_month_end(date):
# 获取包含今天在内的未来2个交易日
days = get_trade_days(start_date=date, count=2)
if len(days) < 2:
return True # 回测最后一天
# 如果明天的月份不等于今天的月份,说明今天是月末
return days[0].month != days[1].month
Q4: run_monthly 会在回测的第一天运行吗?
A: 这取决于回测的开始日期。如果回测开始日期恰好是该月的最后一个交易日,且开始时间早于你设定的 time,它就会运行。否则,它会等到下一个月的最后一个交易日才运行。