金字塔决策交易系统

 找回密码
 

微信登录

微信扫一扫,快速登录

搜索
查看: 55|回复: 3

python回测策略,小周期计算大周期

[复制链接]

2

主题

96

帖子

96

积分

Rank: 2

等级: 标准版

注册:
2023-4-13
曾用名:
发表于 2025-7-16 16:15 | 显示全部楼层 |阅读模式
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("计算指标完成")

微信图片_20250716160058.png 现在问题是计算出来的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);


回复

使用道具 举报

21

主题

1万

帖子

1万

积分

Rank: 8Rank: 8

等级: 超级版主

注册:
2021-5-18
曾用名:
FireScript
发表于 2025-7-17 15:20 | 显示全部楼层
重新贴一下吧。


你这个根本没法查阅的:
截图202507171520202260.png
金字塔提供一对一VIP专业技术指导服务,技术团队实时响应您的日常使用问题与策略编写。联系电话:021-20339086
回复

使用道具 举报

2

主题

96

帖子

96

积分

Rank: 2

等级: 标准版

注册:
2023-4-13
曾用名:
 楼主| 发表于 2025-7-17 15:32 | 显示全部楼层

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分钟对应的60分钟MACD数据
EMA_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和DEA
DIFF600:=EMA_S60-EMA_L60;
DEA600:=(2*DIFF600+(M-1)*DEA601)/(M+1);


现在问题是计算出来的15分钟MACD指标和行情版面的指标值一致,但其他大周期的值就与图表程序中小周期引用大周期的值相差甚远,为什么这样?要怎样解决?在图表程序中小周期引用大周期的值是非常接近甚至等于行情版面中指标的数值的。
回复

使用道具 举报

21

主题

1万

帖子

1万

积分

Rank: 8Rank: 8

等级: 超级版主

注册:
2021-5-18
曾用名:
FireScript
发表于 2025-7-17 17:15 | 显示全部楼层
你这个结构比较复杂,我们尽量尝试下。
金字塔提供一对一VIP专业技术指导服务,技术团队实时响应您的日常使用问题与策略编写。联系电话:021-20339086
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 微信登录

本版积分规则

手机版|小黑屋|上海金之塔信息技术有限公司 ( 沪ICP备13035422号 )

GMT+8, 2025-7-20 05:40 , Processed in 0.284349 second(s), 25 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表