3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
你的思路非常敏锐,“尾盘交易”确实是量化交易中用来规避日线级别未来函数、同时尽可能利用当日行情信息的一种非常经典且有效的策略。
不过,针对你提到的 14:59:59 交易以及 avoid_future_data 的使用,在 JoinQuant 回测机制和 A 股实际交易规则中,有一些细节需要特别注意。
结论是:大方向完全可行,但时间点建议提前到 14:50 或 14:55,而不是 14:59:59。
在日线级别的策略中,最常见的未来函数就是“用今天的收盘价计算出买卖信号,然后又以今天的开盘价或收盘价买入”。
如果你将策略运行频率设置为分钟级,并在每天的尾盘(例如 14:50)运行:
14:59:59?14:57 - 15:00 是收盘集合竞价时间。在这个时间段内,订单是集中撮合的,且通常不允许撤单。如果你在 14:59:59 下单,实盘中极有可能因为网络延迟直接废单,或者只能以最终的收盘价成交(且不保证能成交,取决于你的报价和对手盘)。14:59:00(包含 14:58-14:59 的数据)。如果你设定在 14:59 运行,下单后引擎只能尝试用最后一分钟(14:59-15:00)的 Bar 来撮合,这与实盘集合竞价的复杂性存在微小差异。最佳实践:将交易时间定在 14:50 或 14:55。此时处于连续竞价阶段,流动性好,价格接近收盘价,且有足够的时间完成订单撮合。
你可以放弃 handle_data,改用 run_daily 定时运行函数。这样可以精准控制计算信号和下单的时间。
import jqdata
def initialize(context):
set_benchmark('000300.XSHG')
set_option('use_real_price', True)
g.security = '000001.XSHE'
# 每天 14:50 运行策略逻辑
run_daily(tail_trading, time='14:50')
def tail_trading(context):
# 获取截至 14:50 的过去 5 天的日线数据(注意:这里不包含今天)
# 如果要包含今天,可以使用 get_bars 获取分钟数据合成,或者直接用当前价格近似
hist = attribute_history(g.security, 5, '1d', ['close'])
# 获取当前时刻(14:50)的最新价
current_data = get_current_data()
current_price = current_data[g.security].last_price
# 近似计算包含今天的 5 日均线
# 将前 4 天的收盘价与今天的最新价结合
ma5_approx = (hist['close'][-4:].sum() + current_price) / 5
# 产生信号并交易
if current_price > ma5_approx:
order_target_value(g.security, context.portfolio.available_cash)
log.info(f"尾盘买入 {g.security}")
else:
order_target(g.security, 0)
log.info(f"尾盘卖出 {g.security}")
set_option('avoid_future_data', True)你提到开启这个选项会导致技术分析等数据无法使用。这是因为该选项的机制非常严格:它会拦截所有试图获取当前逻辑时间之后数据的 API 调用。
09:30 运行策略,试图用 get_price 获取当天的 close,它会报错,因为当天的收盘价在 09:30 是未知的。avoid_future_data,只要你调用的 API 参数正确(不跨越当前时间),依然可以正常使用。initialize 中设置 set_option('use_real_price', True),防止复权因子变动带来的价格穿越。09:30 以开盘价买入。14:50 用最新价计算信号,今天 14:50 以现价买入。history 和 attribute_history 取当天数据:在日线回测中,这两个 API 默认不包含当天数据。如果需要盘中实时数据,请使用 get_current_data() 或 get_bars(..., include_now=True)。get_fundamentals 默认按 date 查询,会自动返回该日期之前已发布的最新财报,平台底层已经帮你规避了财务数据的未来函数,直接放心使用即可。