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

如何解决 JoinQuant 中 MACD 金叉判断的未来函数问题?

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

问题描述

请哪位大神帮忙解决MACD代码有未来函数问题?

我用了一个MACD金叉死叉的代码,但里面有未来函数,哪位大神可以帮忙解决吗?

def isMACDGold(context,security):
'''
判断是否 MACD 金叉
return True or False
'''

#当天和前一个交易日的日期
check_date = context.current_dt.strftime('%Y-%m-%d')
previous_date = context.previous_date.strftime('%Y-%m-%d')
# 计算并输出 security 的 MACD 值
macd_dif, macd_dea, macd_macd = MACD(security,check_date=check_date, SHORT = 12, LONG = 26, MID = 9)
previous_date_macd_dif, previous_date_macd_dea, previous_date_macd_macd = MACD(security,check_date=previous_date, SHORT = 12, LONG = 26, MID = 9)
if previous_date_macd_macd[security] < 0 and macd_macd[security] > 0:
return True
else:
return False

解决方案

你好!你提供的代码中确实存在未来函数。在量化回测中,未来函数是导致回测结果虚高、实盘却亏损的罪魁祸首。

为什么原代码有未来函数?

在你的代码中,使用了 check_date = context.current_dt.strftime('%Y-%m-%d') 来获取当天的 MACD 值。如果你在盘中(例如 09:30)调用这个函数,系统为了计算当天的 MACD,会默认使用当天的收盘价。而在现实交易中,早上 09:30 是绝对不可能知道下午 15:00 的收盘价的。这就是典型的引入了未来数据。

解决思路

要解决这个问题,我们在今天(current_dt)做交易决策时,只能使用昨天前天的数据来判断金叉。即:前天的 MACD < 0 且 昨天的 MACD > 0,则今天开盘买入。

这里为你提供两种彻底解决未来函数的方案:


方案一:修正原代码(使用昨天和前天的日期)

继续使用 jqlib.technical_analysis 库,但将日期往前推一天。

from jqlib.technical_analysis import MACD
from jqdata import *

def isMACDGold(context, security):
    '''
    判断是否 MACD 金叉 (无未来函数版)
    return True or False
    '''
    # 获取昨天的日期
    yesterday = context.previous_date
    
    # 获取前天的日期 (获取截至昨天的过去2个交易日)
    trade_days = get_trade_days(end_date=yesterday, count=2)
    day_before_yesterday = trade_days[0]
    
    yesterday_str = yesterday.strftime('%Y-%m-%d')
    day_before_yesterday_str = day_before_yesterday.strftime('%Y-%m-%d')
    
    # 计算昨天和前天的 MACD 值
    macd_dif_y, macd_dea_y, macd_macd_y = MACD(security, check_date=yesterday_str, SHORT=12, LONG=26, MID=9)
    macd_dif_dby, macd_dea_dby, macd_macd_dby = MACD(security, check_date=day_before_yesterday_str, SHORT=12, LONG=26, MID=9)
    
    # 判断:前天 MACD < 0 且 昨天 MACD > 0
    if macd_macd_dby[security] < 0 and macd_macd_y[security] > 0:
        return True
    else:
        return False

方案二:使用 talib 库结合 attribute_history(强烈推荐 ⭐)

在 JoinQuant 中,更高效且不容易踩坑的做法是使用 attribute_history 获取历史 K 线,然后用 talib 库计算指标。attribute_history 默认不包含当天数据,天生免疫未来函数。

import talib
from jqdata import *

def isMACDGold(context, security):
    '''
    判断是否 MACD 金叉 (基于 talib,无未来函数)
    return True or False
    '''
    # 获取过去 35 天的收盘价 (35天足够 MACD 均线平滑计算)
    # attribute_history 默认不包含当天数据,获取到的最后一个值是昨天的收盘价
    close_data = attribute_history(security, 35, '1d', ['close'], df=False)['close']
    
    # 如果上市时间不足35天,直接返回 False
    if len(close_data) < 35:
        return False
        
    # 使用 talib 计算 MACD
    macd_dif, macd_dea, macd_macd = talib.MACD(close_data, fastperiod=12, slowperiod=26, signalperiod=9)
    
    # macd_macd 数组的最后一个值 [-1] 代表昨天,倒数第二个值 [-2] 代表前天
    # 判断:前天 MACD < 0 且 昨天 MACD > 0
    if macd_macd[-2] < 0 and macd_macd[-1] > 0:
        return True
    else:
        return False

总结建议

  1. 推荐使用方案二talib 是 C 语言编写的底层库,计算速度远快于 Python 层的指标库,且 attribute_history 接口设计非常安全。
  2. 注意 MACD 柱子的倍数talib.MACD 计算出的 macd_macd 柱子值是 DIF - DEA,而国内炒股软件(如同花顺、通达信)通常会乘以 2,即 (DIF - DEA) * 2。但这不影响金叉/死叉的判断,因为正负号是一致的。