
等级: 标准版
- 注册:
- 2023-4-13
- 曾用名:
|
class MACDCalculator:
"""MACD指标计算器"""
def __init__(self, state_manager):
self.state = state_manager
def calculate(self, period, closes, short=12, long=26, m=9, current_time=None):
"""
MACD计算逻辑
:param period: 周期(如'30m')
:param closes: 收盘价序列
:param short: 短周期
:param long: 长周期
:param m: 信号周期
:return: (DEA, DIFF, MACD柱) 值
"""
try:
# 获取前值
ema_s_prev = self.state.get_state(period, 'ema_s')
ema_l_prev = self.state.get_state(period, 'ema_l')
dea_prev = self.state.get_state(period, 'dea')
# 初始化
if ema_s_prev is None or ema_l_prev is None:
if len(closes) > 0:
ema_s_prev = closes[-1]
ema_l_prev = closes[-1]
dea_prev = 0
else:
return 0, 0, 0
# 使用最新收盘价
current_close = closes[-1] if len(closes) > 0 else ema_s_prev
# 金字塔原版递归公式
ema_s = (2 * current_close + (short - 1) * ema_s_prev) / (short + 1)
ema_l = (2 * current_close + (long - 1) * ema_l_prev) / (long + 1)
diff = ema_s - ema_l
dea = (2 * diff + (m - 1) * dea_prev) / (m + 1)
macd_bar = 2 * (diff - dea)
# 更新状态
self.state.update_state(period, 'ema_s', ema_s, current_time)
self.state.update_state(period, 'ema_l', ema_l, current_time)
self.state.update_state(period, 'dea', dea, current_time)
self.state.update_state(period, 'diff', diff, current_time)
return format_value(dea), format_value(diff), format_value(macd_bar)
except Exception as e:
logger.error(f"MACD计算错误({period}): {str(e)}")
return None, None, None
def get_multi_period_data(context, period, field, bars_needed):
"""
获取多周期数据
自动处理跨周期数据对齐问题
"""
try:
# 计算需要获取的K线数量(增加缓冲)
multiplier = 1
if period == '30m': multiplier = 2
elif period == '60m': multiplier = 4
bars_to_get = max(bars_needed * multiplier, 100)
# 获取数据(包含当前未完成K线)
data = history_bars(
context.s1,
bars_to_get,
period,
field,
include_now=True, # 关键修正:包含当前未完成K线
skip_suspended=True,
adjusted_price=False
)
if len(data) < bars_needed:
logger.warning(f"获取{period}周期{field}数据不足,需要{bars_needed},实际{len(data)}")
return None
return data[-bars_needed:] # 返回所需长度的最新数据
except Exception as e:
logger.error(f"获取{period}周期数据错误: {str(e)}")
return None
def handle_bar(context):
"""K线处理函数"""
logger.info("======handle_bar开始======")
try:
logger.info("开始获取历史数据")
# 获取基础数据(15分钟)
bars_needed = max(100, context.bdw_period, context.long, context.m)
highs = get_multi_period_data(context, '15m', 'high', bars_needed)
lows = get_multi_period_data(context, '15m', 'low', bars_needed)
closes = get_multi_period_data(context, '15m', 'close', bars_needed)
opens = get_multi_period_data(context, '15m', 'open', bars_needed)
# 提取数据
logger.info("开始提取数据")
current_close = closes[-1]
current_high = highs[-1]
current_low = lows[-1]
current_open = opens[-1]
current_time = context.now.strftime("%Y-%m-%d %H:%M")
logger.info("提取数据完成")
# === 计算指标 ===
logger.info("开始计算指标")
# 1. 计算15分钟MACD
dea15, diff15, macd_bar15 = context.macd_calculator.calculate(
'15m',
closes,
context.short,
context.long,
context.m,
current_time
)
# 如果MACD计算失败,直接返回
if dea15 is None or diff15 is None or macd_bar15 is None:
logger.warning("MACD指标计算失败,跳过当前K线")
return
logger.info("计算15分钟MACD指标完成")
# 2. 计算多周期指标
dea_values = {}
# 定义需要计算的周期
periods = ['30m', '60m']
for period in periods:
# 获取多周期数据
period_highs = get_multi_period_data(context, period, 'high', 50)
period_lows = get_multi_period_data(context, period, 'low', 50)
period_closes = get_multi_period_data(context, period, 'close', 50)
if period_highs is None or period_lows is None or period_closes is None:
logger.warning(f"跳过{period}周期计算")
bdw_values[period] = None
dea_values[period] = None
continue
# 计算MACD DEA
dea_val, _, _ = context.macd_calculator.calculate(
period,
period_closes,
context.short,
context.long,
context.m,
current_time
)
dea_values[period] = dea_val
logger.info("计算多周期DEA指标完成")
logger.info("计算指标完成")
现在问题是计算出来的15分钟MACD指标和行情版面的指标值一致,但其他大周期的值就与图表程序中小周期引用大周期的值相差甚远,为什么这样?要怎样解决?在图表程序中小周期引用大周期的值是非常接近甚至等于行情版面中指标的数值的。下面是图表程序的小引大[size=13.0667px]//计算15分钟对应的60分钟MACDEMA_S601:="EXPMA.M1##MIN60"(S);EMA_L601:="EXPMA.M1##MIN60"(LONG);DEA601:="MACD.DEA##MIN60";EMA_S60:=(2*CLOSE+(S-1)*EMA_S601)/(S+1);//对应15分钟此刻的60分钟EMA(CLOSE,S)EMA_L60:=(2*CLOSE+(LONG-1)*EMA_L601)/(LONG+1);//对应15分钟此刻的60分钟EMA(CLOSE,LONG)//下面的DIFF60和DEA60就是所需要的60分钟里DIFF和DEADIFF600:=EMA_S60-EMA_L60;DEA600:=(2*DIFF600+(M-1)*DEA601)/(M+1);
|
|