🚀 AI 一键生成 joinquant 策略代码
立即体验
👉 AI 生成代码 👈

JoinQuant 聚宽量化平台如何有效避免未来函数?尾盘交易可行性分析

joinquant | 发布时间: 2026/6/1
以下内容由 EasyQuant 生成。

问题描述

如何尽量避免未来函数?

有时候防不胜防,而且手工检查起来很麻烦。
如果用set_option('avoid_future_data',True),可能有些数据就无法使用,比如技术分析。
既然这样,我把交易时间放在收盘前一秒,比如14:59:59,并假设流动性最够大且标的能买到。
那么,是不是就可以很接近真实的交易情况?未来函数的影响也可以降到最低?

解决方案

你的思路非常敏锐,“尾盘交易”确实是量化交易中用来规避日线级别未来函数、同时尽可能利用当日行情信息的一种非常经典且有效的策略。

不过,针对你提到的 14:59:59 交易以及 avoid_future_data 的使用,在 JoinQuant 回测机制和 A 股实际交易规则中,有一些细节需要特别注意。

一、 你的思路可行吗?

结论是:大方向完全可行,但时间点建议提前到 14:5014:55,而不是 14:59:59

为什么尾盘交易能避免未来函数?

在日线级别的策略中,最常见的未来函数就是“用今天的收盘价计算出买卖信号,然后又以今天的开盘价或收盘价买入”。
如果你将策略运行频率设置为分钟级,并在每天的尾盘(例如 14:50)运行:

  1. 此时当天的 K 线形态(开、高、低)已经基本确定,此时的“最新价”非常接近最终的“收盘价”。
  2. 你用截至 14:50 的数据计算技术指标(如 MA、MACD),这属于已发生的数据,没有任何未来函数。
  3. 你在 14:50 下单,回测引擎会以 14:50 之后的分钟 Bar 进行撮合,逻辑严密,完全符合实盘情况。

为什么不建议用 14:59:59

  1. A股交易规则限制:A股在 14:57 - 15:00 是收盘集合竞价时间。在这个时间段内,订单是集中撮合的,且通常不允许撤单。如果你在 14:59:59 下单,实盘中极有可能因为网络延迟直接废单,或者只能以最终的收盘价成交(且不保证能成交,取决于你的报价和对手盘)。
  2. 回测引擎的限制:JoinQuant 的分钟回测每天执行 240 次,最后一次执行是在 14:59:00(包含 14:58-14:59 的数据)。如果你设定在 14:59 运行,下单后引擎只能尝试用最后一分钟(14:59-15:00)的 Bar 来撮合,这与实盘集合竞价的复杂性存在微小差异。

最佳实践:将交易时间定在 14:5014:55。此时处于连续竞价阶段,流动性好,价格接近收盘价,且有足够的时间完成订单撮合。

二、 如何在 JoinQuant 中实现尾盘交易?

你可以放弃 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 是未知的。
  • 如果你改用尾盘交易(如 14:50),此时你获取截至 14:50 的数据,本身就不涉及未来数据,因此即使开启 avoid_future_data,只要你调用的 API 参数正确(不跨越当前时间),依然可以正常使用。

四、 总结:彻底告别未来函数的 4 个原则

  1. 开启真实价格回测:必须在 initialize 中设置 set_option('use_real_price', True),防止复权因子变动带来的价格穿越。
  2. 分离“信号计算”与“交易执行”
    • 模式A(盘前/开盘):用昨天的收盘价计算信号,今天 09:30 以开盘价买入。
    • 模式B(尾盘):今天 14:50 用最新价计算信号,今天 14:50 以现价买入。
  3. 慎用 historyattribute_history 取当天数据:在日线回测中,这两个 API 默认不包含当天数据。如果需要盘中实时数据,请使用 get_current_data()get_bars(..., include_now=True)
  4. 财务数据注意发布日期:JoinQuant 的 get_fundamentals 默认按 date 查询,会自动返回该日期之前已发布的最新财报,平台底层已经帮你规避了财务数据的未来函数,直接放心使用即可。