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